Hibernate — это прекрасный ORM инструмент, который можно настроить практически под любые свои нужны. В этом топике я покажу, как можно хранить поля произвольного типа. Для примера, возьмем массив строк (String[]) и POJO объект, который мы хотим хранить в БД:
Для того, чтобы хибернейт мог сохранять в базу поле типа «массив строк» необходимо (и достаточно) написать класс, который реализует интерфейс UserType, а также сослаться на него в мэппинге (файл hbm.xml).
Напишем реализацию класса StringArrayCustomType метод за методом.
В завершении, обновляем файл мэппинга (hbm.xml):
И наслаждаемся хранением массива строк.
P.S. В следующей статье прикрутим специальный критерий для фильтрации по этому полю.
______________________
- public class StringArrayContainer {
- private Integer id;
- private String[] tags;
- // Место для геттеров и сеттеров.
- }
Для того, чтобы хибернейт мог сохранять в базу поле типа «массив строк» необходимо (и достаточно) написать класс, который реализует интерфейс UserType, а также сослаться на него в мэппинге (файл hbm.xml).
- public class StringArrayCustomType implements UserType {
- // TODO: написать реализацию.
- }
Напишем реализацию класса StringArrayCustomType метод за методом.
- sqlTypes — массив типов колонки в БД. В нашем случае это CLOB.
- private static final int[] SQL_TYPES = new int[]{Types.CLOB};
- @Override
- public int[] sqlTypes() {
- return SQL_TYPES;
- }
- returnedClass — тип объекта, возвращаемого методом nullSafeGet. У нас это массив строк.
- @Override
- public Class returnedClass() {
- return String[].class;
- }
- equals — проверяет на равенства два значения . Мы считаем наш массив неизменным (хоть в Java и можно менять содержимое массива, но в этом случае мы это административно запрещаем;-)), поэтому просто проверяем на равенство ссылки.
- @Override
- public boolean equals(Object x, Object y) throws HibernateException {
- return x == y;
- }
- hashCode — делегируем генерацию hashCode самому массиву.
- @Override
- public int hashCode(Object x) throws HibernateException {
- return x.hashCode();
- }
- nullSafeGet — восстанавливает значение поля при чтении из базы.
- @Override
- public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
- String value = (String) Hibernate.TEXT.nullSafeGet(rs, names[0]);
- if (value == null) {
- return null;
- } else {
- String[] array = StringUtils.split(value, ' ');
- for (int i = 0; i < array.length; i++) {
- array[i] = WhitespaceEscapeUtil.unescape(array[i]);
- }
- return array;
- }
- }
- nullSafeSet — кодирует значение поля для записи в базу.
- @Override
- public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
- if (value == null) {
- Hibernate.TEXT.nullSafeSet(st, null, index);
- } else {
- String[] array = (String[]) value;
- String[] copy = new String[array.length];
- for (int i = 0; i < array.length; i++) {
- copy[i] = WhitespaceEscapeUtil.escape(array[i]);
- }
- Hibernate.TEXT.nullSafeSet(st, StringUtils.join(copy, ' '), index);
- }
- }
- deepCopy — осуществляет полное копирование объекта. Нам не интересен, так как наш массив не изменяется.
- @Override
- public Object deepCopy(Object value) throws HibernateException {
- return value;
- }
- isMutable — возвращает true, если объект может меняться.
- @Override
- public boolean isMutable() {
- return false;
- }
- disassemble — восстанавливает объект из вида, пригодного для хранения в кэше второго уровня.
- @Override
- public Serializable disassemble(Object value) throws HibernateException {
- return (Serializable) value;
- }
- assemble — конвертирует объект в вид, пригодный для хранения в кэше второго уровня.
- @Override
- public Object assemble(Serializable cached, Object owner) throws HibernateException {
- return cached;
- }
- replace — копирует изменения из нового значения в старое. Нам не интересен, так как наш массив не изменяется.
- @Override
- public Object replace(Object original, Object target, Object owner) throws HibernateException {
- return original;
- }
В завершении, обновляем файл мэппинга (hbm.xml):
- <class name="StringArrayContainer" table="containers">
- <id name="id">
- <generator class="native"/>
- </id>
- <property name="tags" column="tags" type="StringArrayCustomType"/>
- </class>
И наслаждаемся хранением массива строк.
P.S. В следующей статье прикрутим специальный критерий для фильтрации по этому полю.
______________________