Java 如何在 JPA 中使用 Postgres JSONB 数据类型?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/39830842/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use Postgres JSONB datatype with JPA?
提问by justcode
Im not finding a way to map the JSON and JSONB datatypes from PostgreSQL using JPA (EclipseLink). Is some one using this datatypes with JPA and can give me some working examples?
我没有找到使用 JPA (EclipseLink) 从 PostgreSQL 映射 JSON 和 JSONB 数据类型的方法。有人在 JPA 中使用这种数据类型,可以给我一些工作示例吗?
采纳答案by justcode
All the answers helped me to reach the final solution that is ready for JPA and not EclipseLink or Hibernate specifically.
所有的答案都帮助我找到了为 JPA 而不是 EclipseLink 或 Hibernate 准备好的最终解决方案。
import com.fasterxml.Hymanson.core.type.TypeReference;
import com.fasterxml.Hymanson.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);
}
}
}
回答by Tobb
Edit: I see now that this is pretty much Hibernate
dependant. But perhaps you can find something similar for EclipseLink
..
编辑:我现在看到这非常Hibernate
依赖。但也许你可以找到类似的东西EclipseLink
......
I'll just add what I have as an answer, it originates from another SO answer but whatever.. This will map jsonb
to JsonObject
of Google gson
, but you can change it to something else if needed. To change to something else, change nullSafeGet
, nullSafeSet
and deepCopy
methods.
我只会添加我所拥有的作为答案,它源自另一个 SO 答案,但无论如何.. 这将映射jsonb
到JsonObject
Google gson
,但如果需要,您可以将其更改为其他内容。要改变别的东西,改变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);
}
}
To use this, do:
要使用它,请执行以下操作:
public class SomeEntity {
@Column(name = "jsonobject")
@Type(type = "com.myapp.JsonbType")
private JsonObject jsonObject;
In addition, you need to set your dialect to indicate that JAVA_OBJECT
= jsonb
:
此外,您需要设置您的方言以指示JAVA_OBJECT
= jsonb
:
registerColumnType(Types.JAVA_OBJECT, "jsonb");
回答by coladict
I think I found an analogy to Hibernate's UserType for EclipseLink.
我想我找到了一个类比 Hibernate 的 UserType for EclipseLink。
http://www.eclipse.org/eclipselink/documentation/2.6/jpa/extensions/annotations_ref.htm#CHDEHJEB
http://www.eclipse.org/eclipselink/documentation/2.6/jpa/extensions/annotations_ref.htm#CHDEHJEB
You have to make a class that implements org.eclipse.persistence.mappings.converters.Converter
and does the conversion for you, then use the @Convert
annotation on every field where you are using that type.
您必须创建一个实现org.eclipse.persistence.mappings.converters.Converter
并为您进行转换的类,然后@Convert
在您使用该类型的每个字段上使用注释。