2015-09-24 17 views
5

とテキストフィールドにJSONとしてリスト の保存: 私は休止状態で、次のモデルのようなものを持って休止状態

class Person { 
    String name; 
    List<Address> addresses; 
} 

class Address { 
    String street; 
    String city; 
} 

私は今、すべての人のアドレスがにシリアライズされるテーブルに人を永続化したいですJSON文字列に変換され、Personテーブルの列に格納されます。データベース内のPersonレコードは次のようになります。

name: 'Benjamin Franklin', addresses: '[{"street"="...","city"="..."}, {...}]' 

は、この使用して休止状態を達成するための方法はありますか?

アドレスがリストでない場合は、シリアル化を実行するためにUserTypeを登録できます。

JPAの@Converterも使用できません。これは、Hibernate実装が変更を検出しないためです。HHH-10111を参照してください。基本的にはカスタム注釈を追加するように提案し

+0

どのデータベースを使用していますか?たとえば、Postgresにはjson列型があります。私はそれを試したことはありませんが、ハイバネーションを使用することは可能でなければなりません... http://www.vivekpatidar.com/?p = 13 –

+1

特定のDBに依存したくないので、私はVARCHARまたはCLOB/TEXT列 – Jochen

+0

実際にはUserTypeを使用できます。回答を追加しました。 – NikolaB

答えて

3

は、カスタムタイプを作成することができますする必要があります

import com.fasterxml.jackson.core.type.TypeReference; 
import com.fasterxml.jackson.databind.JavaType; 
import com.fasterxml.jackson.databind.ObjectMapper; 
import org.hibernate.usertype.ParameterizedType; 
import org.hibernate.usertype.UserType; 

public class JsonListType implements UserType, ParameterizedType { 

    public static final String LIST_TYPE = "LIST"; 
    private static final int[] SQL_TYPES = new int[]{Types.LONGVARCHAR}; 
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); 
    private static final TypeReference LIST_TYPE_REF = new TypeReference<List<?>>() {}; 

    private JavaType valueType = null; 
    private Class<?> classType = null; 

    @Override 
    public int[] sqlTypes() { 
     return SQL_TYPES; 
    } 

    @Override 
    public Class<?> returnedClass() { 
     return classType; 
    } 

    @Override 
    public boolean equals(Object x, Object y) throws HibernateException { 
     return Objects.equals(x, y); 
    } 

    @Override 
    public int hashCode(Object x) throws HibernateException { 
     return Objects.hashCode(x); 
    } 

    @Override 
    public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException,  SQLException { 
     return nullSafeGet(rs, names, owner); 
    } 

    @Override 
    public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { 
     nullSafeSet(st, value, index); 
    } 

    public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { 
     String value = rs.getString(names[0]); 
     Object result = null; 
     if (valueType == null) { 
      throw new HibernateException("Value type not set."); 
     } 
     if (value != null && !value.equals("")) { 
      try { 
       result = OBJECT_MAPPER.readValue(value, valueType); 
      } catch (IOException e) { 
       throw new HibernateException("Exception deserializing value " + value, e); 
      } 
     } 
     return result; 
    } 

    public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { 
     StringWriter sw = new StringWriter(); 
     if (value == null) { 
      st.setNull(index, Types.VARCHAR); 
     } else { 
      try { 
       OBJECT_MAPPER.writeValue(sw, value); 
       st.setString(index, sw.toString()); 
      } catch (IOException e) { 
       throw new HibernateException("Exception serializing value " + value, e); 
      } 
     } 
    } 

    @Override 
    public Object deepCopy(Object value) throws HibernateException { 
     if (value == null) { 
      return null; 
     } else if (valueType.isCollectionLikeType()) { 
      try { 
       Object newValue = value.getClass().newInstance(); 
       Collection newValueCollection = (Collection) newValue; 
       newValueCollection.addAll((Collection) value); 
       return newValueCollection; 
      } catch (InstantiationException e) { 
       throw new HibernateException("Failed to deep copy the collection-like value object.", e); 
      } catch (IllegalAccessException e) { 
       throw new HibernateException("Failed to deep copy the collection-like value object.", e); 
      } 
     } 
    } 

    @Override 
    public boolean isMutable() { 
     return true; 
    } 

    @Override 
    public Serializable disassemble(Object value) throws HibernateException { 
     return (Serializable) deepCopy(value); 
    } 

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

    @Override 
    public void setParameterValues(Properties parameters) { 
     String type = parameters.getProperty("type"); 
     if (type.equals(LIST_TYPE)) { 
      if (parameters.getProperty("element") != null) { 
       try { 
        valueType = OBJECT_MAPPER.getTypeFactory().constructCollectionType(ArrayList.class, Class.forName(parameters.getProperty("element"))); 
       } catch (ClassNotFoundException e) { 
        throw new IllegalArgumentException("Type " + type + " is not a valid type."); 
       } 
      } else { 
       valueType = OBJECT_MAPPER.getTypeFactory().constructType(LIST_TYPE_REF); 
      } 
      classType = List.class; 
     } 
    } 

など、それを使用します。

@Type(type = "com.company.util.JsonListType", parameters = {@org.hibernate.annotations.Parameter(name = "type", value = "LIST"), @org.hibernate.annotations.Parameter(name = "element", value = "com.company.model.MyCustomClass")}) 
private List<MyCustomClass> myCustomClasses; 

このソリューションはDB固有ではなく、簡単に拡張してマップやカスタムクローン可能なエンティティをサポートできます。

+0

必ず輸入品を追加してください。私はここに座って、ObjectMapperとTypeReferenceのどちらのバージョンを使用する必要があるか推測しています。 – Sonny

+1

@ソニー申し訳ありませんが、輸入を追加しました。 – NikolaB

+0

@NikolaB上記の注釈は、同じ表に新しい列を作成します。新しいテーブルを作成し、実際のテーブルへの外部キー参照を持つアノテーションがありますか? – Aditya

0

私は自分自身を試してみましたが、ここに言及する価値があるブログですされていない... https://dzone.com/articles/annotating-custom-types

。例えばAddressJSONParserと呼ばれる注釈付きクラスは、AddressオブジェクトをJSON(パーサのものを使用)に変換し、Stringとして返す必要があります。また、バックアドレスオブジェクトにJSON文字列から、逆を行うパーサを持つについて考える...