Hibernate + PostgreSQL + Network Address Type (inet, cdir)

前端 未结 2 1020
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-09 13:44

I have started my example project with Hibernate 4.2.7 and PostgreSQL 9.3.1 and everything is going well.

At the moment I would like to use INET PostgreSQL type but

相关标签:
2条回答
  • 2020-12-09 14:01

    I just solve a problem like yours.There is little info about this matter. As @ms03 said...better way is create a new type and a class which implements this type and handler the java object for setting/ getting on database.

    First on your entity you must declare types for yours params.

    @Entity
    @Table(name="user_app")
    @TypeDefs(value={@TypeDef(name="convertInet",typeClass=PgInetType.class),
             @TypeDef(name="convertMacaddr",typeClass=PgMacaddrType.class)})
    public class User implements Serializable {
    
        //some parameters
    
      @Type(type="convertMacaddr")
      private PgMacaddr mac;
    
      @Type(type="convertInet")
      private PgInet ip;
    
         //getters and setters, equals, hashcode, toString
      }
    

    Second create the new object handled for java, it must got a default construct, a construct to handler data from DB and to be Seriarizable.

    public class PgInet implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    private String address;
    
    public PgInet(String address){
        this.address=address;
    }
    
    public PgInet(){
        this.address=null;
    }
    
        //Getters,setters,hashcode, equal and toString
     }
    

    And final step you must create a custom type

    public class PgInetType implements UserType{
    
    @Override
    public int[] sqlTypes() {
    
                //Because inet,macaddr,cdir...and unkwon type for java, yo must
                // define Types.OTHER
        return new int[] { Types.OTHER };
    }
    
    @Override
    public Class returnedClass() {
    
                //Object created to be handled for java
        return PgInet.class;
    }
    
    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        return ObjectUtils.nullSafeEquals(x, y);
    }
    
    @Override
    public int hashCode(Object x) throws HibernateException {
        if(x!=null)
            return x.hashCode();
        else
            return 0;
    }
    
    @Override
    public Object nullSafeGet(ResultSet rs, String[] names,
            SessionImplementor session, Object owner)
            throws HibernateException, SQLException {
    
                //Translation from DB to Java
        PgInet address=null;
    
        String ip=rs.getString(names[0]);
    
        if(ip!=null){
            address=new PgInet(ip);
        }
    
        return address;
    }
    
    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index,
            SessionImplementor session) throws HibernateException, SQLException {
    
        //Translation from java to DB
    
        if(value==null){
            st.setNull(index, Types.VARCHAR);
        }else{
    
                    //As inet,macaddr,cdir...are new types object on Postgresql you must
                    //create the specific postgresql object and to insert it
    
                    //I created 2 new cast on postgresql: inet As varchar, varchar AS inet
                    //but I think it's not neccesary because macaddr type works fine without
                    //postgresl casting
    
            st.setObject(index, getInet(value, st.getConnection()));
        }
    
    }
    
    private Object getInet(Object value, Connection connection) {
    
               //Expected object on postgresql
    
           Object tempInet = null;
           ClassLoader connectionClassLoader = connection.getClass().getClassLoader();
    
           try {
    
               //Class which will create the postgresql
    
               Class aPGObjectClass =connectionClassLoader.loadClass("org.postgresql.util.PGobject");
               Constructor ct = aPGObjectClass.getConstructor(null);
               try {
                tempInet = ct.newInstance(null);
            } catch (InstantiationException | IllegalAccessException
                    | IllegalArgumentException | InvocationTargetException e2) {
                // TODO Auto-generated catch block
                e2.printStackTrace();
            }
    
               Method setTypeMethod = aPGObjectClass.getMethod("setType", new Class[]{String.class});
               try {
    
                   //Setting postgresql type, inet in this case
    
                setTypeMethod.invoke(tempInet, new Object[]{"inet"});
            } catch (IllegalAccessException | IllegalArgumentException
                    | InvocationTargetException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
    
               Method setValueMethod = aPGObjectClass.getMethod("setValue", new Class[]{String.class});
               try {
                setValueMethod.invoke(tempInet, new Object[]{value.toString()});
            } catch (IllegalAccessException | IllegalArgumentException
                    | InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
           } catch (ClassNotFoundException e) {
    
           } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    
           return tempInet;
       }
    
    @Override
    public Object deepCopy(Object value) throws HibernateException {
        if(value==null)
            return null;
        else{
            PgInet PgInetNew=new PgInet();
            PgInet PgInetOriginal=(PgInet)value;
    
            PgInetNew.setAddress(PgInetOriginal.getAddress());
    
            return PgInetNew;
        }
    }
    
    @Override
    public boolean isMutable() {
        return false;
    }
    
    @Override
    public Serializable disassemble(Object value) throws HibernateException {
         Object  deepCopy=deepCopy(value);
    
          if(!(deepCopy instanceof Serializable))
           return (Serializable)deepCopy;
    
          return null;
    }
    
    @Override
    public Object assemble(Serializable cached, Object owner)
            throws HibernateException {
        return deepCopy(cached);
    }
    
    @Override
    public Object replace(Object original, Object target, Object owner)
            throws HibernateException {
        return deepCopy(original);
    }
    
     }
    

    This way works fine for me when I insert or get a row from DB.

    0 讨论(0)
  • 2020-12-09 14:03

    I faced similar problem recently with Hibernate 3 & Postgres 9. Since there was no inbuilt mapping provided for String Array in postgres to Java String[] by hibernate, I end up implementing a custom mapping class. You can try following below steps.

    1. Create Custom class "PgInet" which implements "org.hibernate.usertype.UserType" (this UserType class is per my hibernate 3 knowledge. Not sure if this has been changed in Hibernate 4).
    2. Below method implementation would be critical.

      • equals
      • nullSafeGet
      • nullSafeSet
      • returnedClass return InetAddress.class;
      • sqlTypes return new int[] {java.sql.Types.}

    Once above is done, we just need to set type of property in HBM.xml to this class i.e. PgInet.

    For custom class implementation try referring to existing type implementation class. You should be able to locate class files. Use below link as reference.

    http://grepcode.com/file/repo1.maven.org/maven2/hibernate/hibernate/2.1.8/net/sf/hibernate/type/ArrayType.java

    Hope this helps.

    Thanks.

    0 讨论(0)
提交回复
热议问题