2016-11-22 80 views
0

我是hibernate的新手。我使用postgres作为数据库。Hibernate +使用泛型的自定义usertypes

我有一个表用户。其中包含一个名为元数据的列,其类型为jsonb。

我想将此列映射到对象(可序列化)元数据。我通读了一些教程,并知道我们需要实现自定义的userType来实现这一点。

所以我实现了MyMetadataType。现在我有另一个名为jsonb类型的设置。要将此列映射到其对应的对象,我需要另一个userType实现。

是否有可能像下面那样有一个泛型类?只有一个类适用于所有这样的列?

class MyCustomType<T> implements UserType 
{ 
... 
... 
} 

如果是,那么我将如何在实体定义中使用它?

@Entity 
@Table(name = "user") 
@TypeDefs({ @TypeDef(name = "MyCustomType", typeClass = MyCustomType<Metadata>.class) }) 
public class User extends BaseEntity implements Serializable 
{ 

    @Id 
    @Column(name = "id") 
    private int id; 

    @Column(name = "metadata") 
    @Type(type = "MyCustomeType") 
    private Metadata metadata; 

    ......... 
    ......... 
    ......... 

} 

通过查找以前做题,我想出了下面的类:

public class MyCustomType<T> implements UserType 
{ 
    protected static Conversion conversion = new JsonDataConversionImpl(); 
    private static final Logger logger = LogManager.getLogger(MyCustomType.class.getCanonicalName()); 

    @SuppressWarnings("unchecked") 
    private Class<T> genericType = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), MyCustomType.class); 

    /** 
    * Reconstruct an object from the cacheable representation. At the very least this method should 
    * perform a deep copy if the type is mutable. (optional operation) 
    * 
    * @param cached 
    *   the object to be cached 
    * @param owner 
    *   the owner of the cached object 
    * @return a reconstructed object from the cachable representation 
    * @throws HibernateException 
    */ 
    @Override 
    public Object assemble(Serializable cached, Object owner) throws HibernateException 
    { 
     return this.deepCopy(cached); 
    } 

    /** 
    * Return a deep copy of the persistent state, stopping at entities and st collections. It is 
    * not necessary to copy immutable objects, or null values, in which case it is safe to simple 
    * return the argument. 
    * 
    * @param value 
    *   the object to be cloned, which may be null 
    * @return object a copy 
    * @throws HibernateException 
    */ 
    @Override 
    public Object deepCopy(Object value) throws HibernateException 
    { 
     return value; 
    } 

    /** 
    * Transform the object into its cacheable representation. At the very least this method should 
    * perform a deep copy if the type is mutable. That may not be enough for some implementations, 
    * however; for example, associations must be cached as identifier values. (optional operation) 
    * 
    * @param value 
    *   the object to be cached 
    * @return a cachable representation of the object 
    * @throws HibernateException 
    */ 
    @Override 
    public Serializable disassemble(Object value) throws HibernateException 
    { 
     return (String) this.deepCopy(value); 
    } 

    /** 
    * Compare two instances of the class mapped by this type for persistence "equality". Equality 
    * of the persistence state. 
    * 
    * @param x 
    * @param y 
    * @return boolean 
    * @throws HibernateException 
    */ 
    @Override 
    public boolean equals(Object x, Object y) throws HibernateException 
    { 

     if (x == null) 
     { 
      return y == null; 
     } 
     return x.equals(y); 
    } 

    /** 
    * Get a hashcode for the instance, consistent with persistence "equality". 
    */ 
    @Override 
    public int hashCode(Object x) throws HibernateException 
    { 
     return x.hashCode(); 
    } 

    /** 
    * Are objects of this type mutable? 
    * 
    * @return boolean 
    */ 
    @Override 
    public boolean isMutable() 
    { 
     return true; 
    } 

    /** 
    * Retrieve an instance of the mapped class from a JDBC resultset. Implementors should handle 
    * possibility of null values. 
    * 
    * @param rs 
    *   a JDBC result set 
    * @param names 
    *   the column names 
    * @param session 
    * @param owner 
    *   the containing entity 
    * @return 
    * @throws HibernateException 
    * @throws SQLException 
    */ 
    @Override 
    public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException 
    { 
     T t = null; 
     try 
     { 

      if (rs.getString(names[0]) != null) 
      { 
       t = conversion.getObject(rs.getString(names[0]), genericType); 
      } 
     } 
     catch (MyException e) 
     { 
      logger.error("Error while reading data type", e); 
     } 

     return t; 
    } 

    /** 
    * Write an instance of the mapped class to a prepared statement. Implementors should handle 
    * possibility of null values. A multi-column type should be written to parameters starting from 
    * <tt>index</tt> 
    * 
    * @param st 
    *   a JDBC prepared statement 
    * @param value 
    *   the object to write 
    * @param index 
    *   statement parameter index 
    * @param session 
    * @throws HibernateException 
    * @throws SQLException 
    */ 
    @Override 
    public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException 
    { 

     if (value == null) 
     { 
      st.setNull(index, Types.OTHER); 
      return; 
     } 

     st.setObject(index, value, Types.OTHER); 
    } 

    /** 
    * During merge, replace the existing (target) values in the entity we are merging to with a new 
    * (original) value from the detched entity we are merging. For immutable objects, or null 
    * values, it is safe to return a copy of the first parameter. For the objects with component 
    * values, it might make sense to recursively replace component values 
    * 
    * @param original 
    *   the value from the detched entity being merged 
    * @param target 
    *   the value in the managed entity 
    * @param owner 
    * @return the value to be merged 
    * @throws HibernateException 
    */ 
    @Override 
    public Object replace(Object original, Object target, Object owner) throws HibernateException 
    { 
     return original; 
    } 

    /** 
    * The class returned by <tt>nullSafeGet()</tt> 
    * 
    * @return Class 
    */ 
    @Override 
    public Class returnedClass() 
    { 
     return String.class; 
    } 

    /** 
    * Returns the SQL type codes for the columns mapped by this type. The codes are defined on 
    * <tt>java.sql.Types</tt> 
    * 
    * @return int[] the typecodes 
    * @see java.sql.Types 
    */ 
    @Override 
    public int[] sqlTypes() 
    { 
     return new int[] { Types.JAVA_OBJECT }; 
    } 

} 

我只需要知道如何在用户类使用自定义类型。谁能帮我吗?

回答

1

使用类型的全名:

@Type(type = "package.MyCustomType")

您还需要使用ParameterizedType

@Type(type = "package.MyCustomType", 
     parameters = { @Parameter(
          name = "class", value = "package.Metadata.class") }) 

在你UserType,你必须添加这个方法(实施ParameterizedType接口):

void setParameterValues(Properties parameters); 

在那里你会得到的参数,该条目:类= package.Metadata.class

你只需要这些信息存储在一个领域,并且修改标准UserType方法,它改变行为的基础。

+0

但是,hibernate如何知道类型是MyCustomType 而不是别的? – iwekesi

+0

好的,我没有看到你正在寻找这个信息。我正在更新我的回答 – Thierry

+0

首先感谢您的快速回复。另外,如果可能的话,你可以指点我一些你知道的实例吗? – iwekesi