Hibernate + PostgreSQL +网络地址类型(inet,cdir)

时间:2013-11-16 15:01:20

标签: java sql hibernate postgresql

我已经使用Hibernate 4.2.7和PostgreSQL 9.3.1启动了我的示例项目,一切进展顺利。

目前我想使用INET PostgreSQL type,但我无法使用Hibernate进行映射。

我遇到了这个休眠错误:无法确定类型:inet,在表:DEVICE_IP_ADDRESS,列...

我使用 org.hibernate.dialect.PostgreSQLDialect 和hbm.xml配置文件。

我的hibernate映射文件:

<property name="ipAddress" type="inet">
     <column name="IP_ADDRESS" not-null="true" />
</property>

我问谷歌,但我找不到任何有用的解决方案。 你能帮帮我吗?

THX!

编辑: 如果我想使用'额外'postgresql类型和PostGIS类型,我认为我需要使用什么样的ORM实现?

或者我需要使用简单的JDBC?

2 个答案:

答案 0 :(得分:5)

我只是解决了像你这样的问题。关于此事的信息很少。正如@ ms03所说...更好的方法是创建一个新类型和一个实现此类型的类,并处理java对象以设置/获取数据库。

首先在您的实体上,您必须为您的实体声明类型。

@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
  }

第二个创建为java处理的新对象,它必须有一个默认构造,一个从DB处理数据的构造,并且是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
 }

最后一步你必须创建一个自定义类型

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);
}

 }

当我插入或从DB获取一行时,这种方式对我来说很好。

答案 1 :(得分:2)

我最近遇到了类似的问题,Hibernate 3&amp; Postgres 9.由于hibernate没有为post String中的String Array提供内置映射到Java String [],我最终实现了一个自定义映射类。您可以尝试以下步骤。

  1. 创建实现“org.hibernate.usertype.UserType”的自定义类“PgInet”(此UserType类是根据我的hibernate 3知识。不确定在Hibernate 4中是否已更改)。
  2. 以下方法实施至关重要。

    • 等于
    • nullSafeGet
    • nullSafeSet
    • returnedClass return InetAddress.class;
    • 的SQLType return new int [] {java.sql.Types。}
  3. 完成上述操作后,我们只需要将HBM.xml中的属性类型设置为此类,即PgInet。

    对于自定义类实现,请尝试引用现有的类型实现类。您应该能够找到类文件。使用以下链接作为参考。

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

    希望这有帮助。

    感谢。