2016-10-03 24 views
10

JPA(EclipseLink)を使用してPostgreSQLからJSONとJSONBのデータ型をマップする方法が見つからない。 JPAでこのデータ型を使用している人はいますか?JPAでPostgres JSONBデータ型を使用するには?

+0

例は、私が見つけることができるなら、私は見てみましょう、SO上のどこかにあります...あなたが投稿コード@tobb – Tobb

答えて

10

すべての回答は、JPAのための準備ができていて、具体的にはEclipseLinkやHibernateではなく、最終的なソリューションに到達するのに役立ちました。

import com.fasterxml.jackson.core.type.TypeReference; 
import com.fasterxml.jackson.databind.ObjectMapper; 
import java.io.IOException; 
import javax.json.Json; 
import javax.json.JsonObject; 
import javax.persistence.Converter; 
import org.postgresql.util.PGobject; 

@Converter(autoApply = true) 
public class JsonConverter implements javax.persistence.AttributeConverter<JsonObject, Object> { 

    private static final long serialVersionUID = 1L; 
    private static ObjectMapper mapper = new ObjectMapper(); 

    @Override 
    public Object convertToDatabaseColumn(JsonObject objectValue) { 
    try { 
     PGobject out = new PGobject(); 
     out.setType("json"); 
     out.setValue(objectValue.toString()); 
     return out; 
    } catch (Exception e) { 
     throw new IllegalArgumentException("Unable to serialize to json field ", e); 
    } 
    } 

    @Override 
    public JsonObject convertToEntityAttribute(Object dataValue) { 
    try { 
     if (dataValue instanceof PGobject && ((PGobject) dataValue).getType().equals("json")) { 
     return mapper.reader(new TypeReference<JsonObject>() { 
     }).readValue(((PGobject) dataValue).getValue()); 
     } 
     return Json.createObjectBuilder().build(); 
    } catch (IOException e) { 
     throw new IllegalArgumentException("Unable to deserialize to json field ", e); 
    } 
    } 
} 
+3

私はHibernateのためにこれを試しましたが、 'Object'で終わる' AttributeConverter'は 'Hibernate'で壊れているようです。私は "unknown jdbc type"とかそういうものを言っているだけです。このアプローチはボイラープレートが少なくてはるかにきれいなので、本当に残念です。 – Tobb

+0

質問が尋ねられたときに私はこれを必要としませんでした。私は今日それを必要とし、あなたの解決策を試しました.Postgres JDBCドライバは、特別なメソッド 'setPGobject'を必要としています。 'setObject'を使うと、型を' java.sql.Types.OTHER'に指定する必要がありますが、これはできません。ドライバが不明な場合は正しいクラスに送信し、ClassLoaderの競合を引き起こすように変更しました。私はロード時に競合を取得webappでドライバを読み込むが、設定しないでください。 'tomcat/lib'ディレクトリにロードすると、設定時に競合が発生します。 – coladict

+0

@coladict投稿したクラスはあなたのために働いていませんか?私はあなたの問題をとてもうまく理解していません。メソッドconvertToDatabaseColumnが表示されている場合はオブジェクトを返しますが、このオブジェクトはすでにPostgresに必要なPGobjectタイプです。それ以上のものは必要ありません。 –

4

編集:これはかなり多く、Hibernateに依存しています。私はちょうど私が答えとして持っているものを追加しますおそらくあなたはEclipseLinkのために類似した何かを見つけることができます。..

しかし、それは別の由来するSO答えるが、これはjsonbグーグルgsonJsonObjectにマップされますが、あなたができるものは何でも...必要に応じて別のものに変更してください。変更する場合は、nullSafeGet,nullSafeSetおよびdeepCopyのメソッドを変更してください。

public class JsonbType implements UserType { 

    @Override 
    public int[] sqlTypes() { 
     return new int[] { Types.JAVA_OBJECT }; 
    } 

    @Override 
    public Class<JsonObject> returnedClass() { 
     return JsonObject.class; 
    } 

    @Override 
    public boolean equals(final Object x, final Object y) { 
     if (x == y) { 
      return true; 
     } 
     if (x == null || y == null) { 
      return false; 
     } 
     return x.equals(y); 
    } 

    @Override 
    public int hashCode(final Object x) { 
     if (x == null) { 
      return 0; 
     } 

     return x.hashCode(); 
    } 

    @Nullable 
    @Override 
    public Object nullSafeGet(final ResultSet rs, 
           final String[] names, 
           final SessionImplementor session, 
           final Object owner) throws SQLException { 
     final String json = rs.getString(names[0]); 
     if (json == null) { 
      return null; 
     } 

     final JsonParser jsonParser = new JsonParser(); 
     return jsonParser.parse(json).getAsJsonObject(); 
    } 

    @Override 
    public void nullSafeSet(final PreparedStatement st, 
          final Object value, 
          final int index, 
          final SessionImplementor session) throws SQLException { 
     if (value == null) { 
      st.setNull(index, Types.OTHER); 
      return; 
     } 

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

    @Nullable 
    @Override 
    public Object deepCopy(@Nullable final Object value) { 
     if (value == null) { 
      return null; 
     } 
     final JsonParser jsonParser = new JsonParser(); 
     return jsonParser.parse(value.toString()).getAsJsonObject(); 
    } 

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

    @Override 
    public Serializable disassemble(final Object value) { 
     final Object deepCopy = deepCopy(value); 

     if (!(deepCopy instanceof Serializable)) { 
      throw new SerializationException(
        String.format("deepCopy of %s is not serializable", value), null); 
     } 

     return (Serializable) deepCopy; 
    } 

    @Nullable 
    @Override 
    public Object assemble(final Serializable cached, final Object owner) { 
     return deepCopy(cached); 
    } 

    @Nullable 
    @Override 
    public Object replace(final Object original, final Object target, final Object owner) { 
     return deepCopy(original); 
    } 
} 

これを使用するには、実行します。私はとの類似を見つけたと思う

registerColumnType(Types.JAVA_OBJECT, "jsonb"); 
+0

おかげで、私の場合のための解決策を見つけるために私を助けました。 –

2

:また

public class SomeEntity { 

    @Column(name = "jsonobject") 
    @Type(type = "com.myapp.JsonbType") 
    private JsonObject jsonObject; 

を、あなたはJAVA_OBJECT = jsonbことを示すために、あなたの方言を設定する必要がありますEclipseLink用のHibernateのUserType

http://www.eclipse.org/eclipselink/documentation/2.6/jpa/extensions/annotations_ref.htm#CHDEHJEB

あなたは、あなたはその型を使用しているすべてのフィールドに@Convertアノテーションを使用し、org.eclipse.persistence.mappings.converters.Converterを実装し、あなたのための変換を行うクラスを作成する必要があります。

関連する問題