Pull to refresh

Пользовательские типы в Hibernate

Reading time4 min
Views11K
Hibernate — это прекрасный ORM инструмент, который можно настроить практически под любые свои нужны. В этом топике я покажу, как можно хранить поля произвольного типа. Для примера, возьмем массив строк (String[]) и POJO объект, который мы хотим хранить в БД:
  1. public class StringArrayContainer {
  2.     private Integer id;
  3.     private String[] tags;
  4. //  Место для геттеров и сеттеров.    
  5. }

Для того, чтобы хибернейт мог сохранять в базу поле типа «массив строк» необходимо (и достаточно) написать класс, который реализует интерфейс UserType, а также сослаться на него в мэппинге (файл hbm.xml).
  1. public class StringArrayCustomType implements UserType {
  2. //  TODO: написать реализацию.  
  3. }


Напишем реализацию класса StringArrayCustomType метод за методом.
  • sqlTypes — массив типов колонки в БД. В нашем случае это CLOB.
    1. private static final int[] SQL_TYPES = new int[]{Types.CLOB};
    2. @Override
    3. public int[] sqlTypes() {
    4.     return SQL_TYPES;
    5. }
  • returnedClass — тип объекта, возвращаемого методом nullSafeGet. У нас это массив строк.
    1. @Override
    2. public Class returnedClass() {
    3.     return String[].class;
    4. }
  • equals — проверяет на равенства два значения . Мы считаем наш массив неизменным (хоть в Java и можно менять содержимое массива, но в этом случае мы это административно запрещаем;-)), поэтому просто проверяем на равенство ссылки.
    1. @Override
    2. public boolean equals(Object x, Object y) throws HibernateException {
    3.     return x == y;
    4. }
  • hashCode — делегируем генерацию hashCode самому массиву.
    1. @Override
    2. public int hashCode(Object x) throws HibernateException {
    3.     return x.hashCode();
    4. }
  • nullSafeGet — восстанавливает значение поля при чтении из базы.
    1. @Override
    2. public Object 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.         return null;
    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 — кодирует значение поля для записи в базу.
    1. @Override
    2. public void 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 = new String[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 — осуществляет полное копирование объекта. Нам не интересен, так как наш массив не изменяется.
    1. @Override
    2. public Object deepCopy(Object value) throws HibernateException {
    3.     return value;
    4. }
  • isMutable — возвращает true, если объект может меняться.
    1. @Override
    2. public boolean isMutable() {
    3.     return false;
    4.     }
  • disassemble — восстанавливает объект из вида, пригодного для хранения в кэше второго уровня.
    1. @Override
    2. public Serializable disassemble(Object value) throws HibernateException {
    3.    return (Serializable) value;
    4. }
  • assemble — конвертирует объект в вид, пригодный для хранения в кэше второго уровня.
    1. @Override
    2. public Object assemble(Serializable cached, Object owner) throws HibernateException {
    3.    return cached;
    4. }
  • replace — копирует изменения из нового значения в старое. Нам не интересен, так как наш массив не изменяется.
    1. @Override
    2.     public Object replace(Object original, Object target, Object owner) throws HibernateException {
    3.         return original;
    4.     }


В завершении, обновляем файл мэппинга (hbm.xml):
  1. <class name="StringArrayContainer" table="containers">
  2.     <id name="id">
  3.         <generator class="native"/>
  4.     </id>
  5.     <property name="tags" column="tags" type="StringArrayCustomType"/>
  6. </class>


И наслаждаемся хранением массива строк.

P.S. В следующей статье прикрутим специальный критерий для фильтрации по этому полю.
______________________
Текст подготовлен в Редакторе Блогов от © SoftCoder.ru
Tags:
Hubs:
+29
Comments8

Articles

Change theme settings