如何在 JPA 中使用 Postgres JSONB 数据类型?
How to use Postgres JSONB datatype with JPA?
我找不到使用 JPA (EclipseLink) 从 PostgreSQL 映射 JSON 和 JSONB 数据类型的方法。有人在 JPA 中使用这种数据类型并且可以给我一些工作示例吗?
编辑:我现在看到这在很大程度上取决于 Hibernate
。但也许您可以为 EclipseLink
.
找到类似的东西
我将添加我的答案,它来自另一个 SO 答案,但无论如何。这会将 jsonb
映射到 Google gson
的 JsonObject
,但您可以根据需要将其更改为其他内容。要更改为其他内容,请更改 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);
}
}
要使用它,请执行以下操作:
public class SomeEntity {
@Column(name = "jsonobject")
@Type(type = "com.myapp.JsonbType")
private JsonObject jsonObject;
此外,你需要设置你的方言来表示 JAVA_OBJECT
= jsonb
:
registerColumnType(Types.JAVA_OBJECT, "jsonb");
我想我找到了 Hibernate 的 UserType for EclipseLink 的类比。
http://www.eclipse.org/eclipselink/documentation/2.6/jpa/extensions/annotations_ref.htm#CHDEHJEB
您必须制作一个 class 实现 org.eclipse.persistence.mappings.converters.Converter
并为您进行转换,然后在您使用该类型的每个字段上使用 @Convert
注释。
所有的答案都帮助我找到了为 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);
}
}
}
对于正在寻找具有 JSON 列类型的 Mysql 解决方案的任何人,这里就是。 FWIW 我正在使用 EclipseLink,但这是一个纯 JPA 解决方案。
@Column(name = "JSON_DATA", columnDefinition="JSON")
@Convert(converter=JsonAttributeConverter.class)
private Object jsonData;
和
@Converter
public class JsonAttributeConverter implements AttributeConverter <Object, String>
{
private JsonbConfig cfg = new JsonbConfig().withFormatting(true);
private Jsonb jsonb = JsonbBuilder.create(cfg);
@Override
public String convertToDatabaseColumn(Object object)
{
if (object == null) return null;
return jsonb.toJson(object);
}
@Override
public Object convertToEntityAttribute(String value)
{
if (value == null) return null;
return jsonb.fromJson(value, value.getClass());
}
}
我找不到使用 JPA (EclipseLink) 从 PostgreSQL 映射 JSON 和 JSONB 数据类型的方法。有人在 JPA 中使用这种数据类型并且可以给我一些工作示例吗?
编辑:我现在看到这在很大程度上取决于 Hibernate
。但也许您可以为 EclipseLink
.
我将添加我的答案,它来自另一个 SO 答案,但无论如何。这会将 jsonb
映射到 Google gson
的 JsonObject
,但您可以根据需要将其更改为其他内容。要更改为其他内容,请更改 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);
}
}
要使用它,请执行以下操作:
public class SomeEntity {
@Column(name = "jsonobject")
@Type(type = "com.myapp.JsonbType")
private JsonObject jsonObject;
此外,你需要设置你的方言来表示 JAVA_OBJECT
= jsonb
:
registerColumnType(Types.JAVA_OBJECT, "jsonb");
我想我找到了 Hibernate 的 UserType for EclipseLink 的类比。
http://www.eclipse.org/eclipselink/documentation/2.6/jpa/extensions/annotations_ref.htm#CHDEHJEB
您必须制作一个 class 实现 org.eclipse.persistence.mappings.converters.Converter
并为您进行转换,然后在您使用该类型的每个字段上使用 @Convert
注释。
所有的答案都帮助我找到了为 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);
}
}
}
对于正在寻找具有 JSON 列类型的 Mysql 解决方案的任何人,这里就是。 FWIW 我正在使用 EclipseLink,但这是一个纯 JPA 解决方案。
@Column(name = "JSON_DATA", columnDefinition="JSON")
@Convert(converter=JsonAttributeConverter.class)
private Object jsonData;
和
@Converter
public class JsonAttributeConverter implements AttributeConverter <Object, String>
{
private JsonbConfig cfg = new JsonbConfig().withFormatting(true);
private Jsonb jsonb = JsonbBuilder.create(cfg);
@Override
public String convertToDatabaseColumn(Object object)
{
if (object == null) return null;
return jsonb.toJson(object);
}
@Override
public Object convertToEntityAttribute(String value)
{
if (value == null) return null;
return jsonb.fromJson(value, value.getClass());
}
}