Custom Types in Hibernate

    Hibernate is a great ORM tool that you can customize to almost any of your needs. In this topic, I will show how you can store fields of an arbitrary type. For example, take an array of strings (String []) and a POJO object that we want to store in the database:
    1. publicclass StringArrayContainer {
    2.     privateInteger id;
    3.     privateString[] tags;
    4. //  Место для геттеров и сеттеров.    
    5. }

    In order for hibernate to be able to save a field of the “array of strings” type to the database, it is necessary (and sufficient) to write a class that implements the UserType interface, and also refer to it in mapping (hbm.xml file).
    1. publicclass StringArrayCustomType implements UserType {
    2. //  TODO: написать реализацию.  
    3. }


    We will write the implementation of the StringArrayCustomType class method by method.
    • sqlTypes  - an array of column types in the database. In our case, it is CLOB.
      1. privatestaticfinalint[] SQL_TYPES = newint[]{Types.CLOB};
      2. @Override
      3. publicint[] sqlTypes() {
      4.     return SQL_TYPES;
      5. }
    • returnedClass  - The type of object returned by the nullSafeGet method. We have this array of strings.
      1. @Override
      2. publicClass returnedClass() {
      3.     returnString[].class;
      4. }
    • equals  - checks for equality of two values. We consider our array to be unchanged (even in Java you can change the contents of the array, but in this case we prohibit it administratively ;-)), so we just check for equality of the link.
      1. @Override
      2. publicboolean equals(Object x, Object y) throws HibernateException {
      3.     return x == y;
      4. }
    • hashCode  - delegate hashCode generation to the array itself.
      1. @Override
      2. publicint hashCode(Object x) throws HibernateException {
      3.     return x.hashCode();
      4. }
    • nullSafeGet  - restores the value of a field when reading from the database.
      1. @Override
      2. publicObject nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
      3.     String value = (String) Hibernate.TEXT.nullSafeGet(rs, names[0]);
      4.     if (value == null) {
      5.         returnnull;
      6.     } else {
      7.         String[] array = StringUtils.split(value, ' ');
      8.         for (int i = 0; i < array.length; i++) {
      9.             array[i] = WhitespaceEscapeUtil.unescape(array[i]);
      10.         }
      11.         return array;
      12.     }
      13. }
    • nullSafeSet  - encodes the value of the field for writing to the database.
      1. @Override
      2. publicvoid nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
      3.     if (value == null) {
      4.         Hibernate.TEXT.nullSafeSet(st, null, index);
      5.     } else {
      6.         String[] array = (String[]) value;
      7.         String[] copy = newString[array.length];
      8.         for (int i = 0; i < array.length; i++) {
      9.             copy[i] = WhitespaceEscapeUtil.escape(array[i]);
      10.         }
      11.         Hibernate.TEXT.nullSafeSet(st, StringUtils.join(copy, ' '), index);
      12.     }
      13. }
    • deepCopy  - makes a complete copy of the object. We are not interested, since our array does not change.
      1. @Override
      2. publicObject deepCopy(Object value) throws HibernateException {
      3.     return value;
      4. }
    • isMutable  - returns true if the object can change.
      1. @Override
      2. publicboolean isMutable() {
      3.     returnfalse;
      4.     }
    • disassemble  - restores an object from a view suitable for storage in a second level cache.
      1. @Override
      2. publicSerializable disassemble(Object value) throws HibernateException {
      3.    return (Serializable) value;
      4. }
    • assemble  - converts an object into a form suitable for storage in the second level cache.
      1. @Override
      2. publicObject assemble(Serializable cached, Object owner) throws HibernateException {
      3.    return cached;
      4. }
    • replace  - copies changes from the new value to the old. We are not interested, since our array does not change.
      1. @Override
      2.     publicObject replace(Object original, Object target, Object owner) throws HibernateException {
      3.         return original;
      4.     }


    Finally, update the mapping file (hbm.xml):
    1. name="StringArrayContainer" table="containers">
    2.     name="id">
    3.         class="native"/>
    4.     >
    5.     name="tags" column="tags" type="StringArrayCustomType"/>
    6. >


    And enjoy storing an array of strings.

    PS In the next article we fasten a special criterion for filtering by this field.
    ______________________
    The text is prepared in the Blog Editor by © SoftCoder.ru

    Also popular now: