如何使用 JPA 将映射 JSON 列映射到 Java 对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25738569/
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 map a map JSON column to Java Object with JPA
提问by Rad
We have a big table with a lot of columns. After we moved to MySQL Cluster, the table cannot be created because of:
我们有一张有很多列的大桌子。我们迁移到 MySQL Cluster 后,无法创建表,因为:
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 14000. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
错误 1118 (42000):行大小太大。所用表类型的最大行大小(不包括 BLOB)为 14000。这包括存储开销,请查看手册。您必须将某些列更改为 TEXT 或 BLOB
As an example:
举个例子:
@Entity @Table (name = "appconfigs", schema = "myproject")
public class AppConfig implements Serializable
{
@Id @Column (name = "id", nullable = false)
@GeneratedValue (strategy = GenerationType.IDENTITY)
private int id;
@OneToOne @JoinColumn (name = "app_id")
private App app;
@Column(name = "param_a")
private ParamA parama;
@Column(name = "param_b")
private ParamB paramb;
}
It's a table for storing configuration parameters. I was thinking that we can combine some columns into one and store it as JSON object and convert it to some Java object.
它是一个用于存储配置参数的表。我在想我们可以将一些列合并为一个并将其存储为 JSON 对象并将其转换为某个 Java 对象。
For example:
例如:
@Entity @Table (name = "appconfigs", schema = "myproject")
public class AppConfig implements Serializable
{
@Id @Column (name = "id", nullable = false)
@GeneratedValue (strategy = GenerationType.IDENTITY)
private int id;
@OneToOne @JoinColumn (name = "app_id")
private App app;
@Column(name = "params")
//How to specify that this should be mapped to JSON object?
private Params params;
}
Where we have defined:
我们定义的地方:
public class Params implements Serializable
{
private ParamA parama;
private ParamB paramb;
}
By using this we can combine all columns into one and create our table. Or we can split the whole table into several tables. Personally I prefer the first solution.
通过使用它,我们可以将所有列合并为一并创建我们的表。或者我们可以将整个表拆分成几个表。我个人更喜欢第一种解决方案。
Anyway my question is how to map the Params column which is text and contains JSON string of a Java object?
无论如何,我的问题是如何映射作为文本并包含 Java 对象的 JSON 字符串的 Params 列?
采纳答案by Alessandro Polverini
You can use a JPA converter to map your Entity to the database. Just add an annotation similar to this one to your params field:
您可以使用 JPA 转换器将您的实体映射到数据库。只需在您的 params 字段中添加一个与此类似的注释:
@Convert(converter = JpaConverterJson.class)
and then create the class in a similar way (this converts a generic Object, you may want to specialize it):
然后以类似的方式创建类(这将转换一个通用对象,您可能想要专门化它):
@Converter(autoApply = true)
public class JpaConverterJson implements AttributeConverter<Object, String> {
private final static ObjectMapper objectMapper = new ObjectMapper();
@Override
public String convertToDatabaseColumn(Object meta) {
try {
return objectMapper.writeValueAsString(meta);
} catch (JsonProcessingException ex) {
return null;
// or throw an error
}
}
@Override
public Object convertToEntityAttribute(String dbData) {
try {
return objectMapper.readValue(dbData, Object.class);
} catch (IOException ex) {
// logger.error("Unexpected IOEx decoding json from database: " + dbData);
return null;
}
}
}
That's it: you can use this class to serialize any object to json in the table.
就是这样:您可以使用此类将任何对象序列化为表中的 json。
回答by Magic Wand
I had a similar problem, and solved it by using @Externalizer annotation and Hymanson to serialize/deserialize data (@Externalizer is OpenJPA-specific annotation, so you have to check with your JPA implementation similar possibility).
我有一个类似的问题,并通过使用 @Externalizer 注释和 Hymanson 来序列化/反序列化数据来解决它(@Externalizer 是 OpenJPA 特定的注释,所以你必须检查你的 JPA 实现类似的可能性)。
@Persistent
@Column(name = "params")
@Externalizer("toJSON")
private Params params;
Params class implementation:
参数类实现:
public class Params {
private static final ObjectMapper mapper = new ObjectMapper();
private Map<String, Object> map;
public Params () {
this.map = new HashMap<String, Object>();
}
public Params (Params another) {
this.map = new HashMap<String, Object>();
this.map.putAll(anotherHolder.map);
}
public Params(String string) {
try {
TypeReference<Map<String, Object>> typeRef = new TypeReference<Map<String, Object>>() {
};
if (string == null) {
this.map = new HashMap<String, Object>();
} else {
this.map = mapper.readValue(string, typeRef);
}
} catch (IOException e) {
throw new PersistenceException(e);
}
}
public String toJSON() throws PersistenceException {
try {
return mapper.writeValueAsString(this.map);
} catch (IOException e) {
throw new PersistenceException(e);
}
}
public boolean containsKey(String key) {
return this.map.containsKey(key);
}
// Hash map methods
public Object get(String key) {
return this.map.get(key);
}
public Object put(String key, Object value) {
return this.map.put(key, value);
}
public void remove(String key) {
this.map.remove(key);
}
public Object size() {
return map.size();
}
}
HTH
HTH
回答by Vlad Mihalcea
As I explained in this article, the JPA AttributeConverter
is way too limited to map JSON object types, especially if you want to save them as JSON binary.
正如我在本文中所解释的,JPAAttributeConverter
对映射 JSON 对象类型的限制太多,尤其是当您想将它们保存为 JSON 二进制文件时。
You don't have to create a custom Hibernate Type to get JSON support, All you need to do is use the Hibernate Types OSS project.
For instance, if you're using Hibernate 5.2 or newer versions, then you need to add the following dependency in your Maven
pom.xml
configuration file:<dependency> <groupId>com.vladmihalcea</groupId> <artifactId>hibernate-types-52</artifactId> <version>${hibernate-types.version}</version> </dependency>
您不必创建自定义 Hibernate Type 来获得 JSON 支持,您需要做的就是使用Hibernate Types OSS 项目。
例如,如果您使用的是 Hibernate 5.2 或更新版本,那么您需要在 Maven
pom.xml
配置文件中添加以下依赖项:<dependency> <groupId>com.vladmihalcea</groupId> <artifactId>hibernate-types-52</artifactId> <version>${hibernate-types.version}</version> </dependency>
Now, to explain how it all works.
现在,解释这一切是如何运作的。
As I explained in this article, for MySQL, you need to send the JSON object in a text form, so you need to use the JsonStringType
provided by the Hibernate Types project.
正如我在这篇文章中所解释的,对于 MySQL,您需要以文本形式发送 JSON 对象,因此您需要使用JsonStringType
Hibernate Types 项目提供的。
Now, you need to declare the new type on either at the entity attribute level, or, even better, at the class level in a base class using @MappedSuperclass
:
现在,您需要在实体属性级别或更好地在基类中的类级别使用@MappedSuperclass
以下命令声明新类型:
@TypeDef(name = "json", typeClass = JsonStringType.class)
And the entity mapping will look like this:
实体映射将如下所示:
@Type(type = "json")
@Column(columnDefinition = "json")
private Location location;
If you're using Hibernate 5.2 or later, then the JSON
type is registered automatically by MySQL57Dialect
.
如果您使用的是 Hibernate 5.2 或更高版本,则该JSON
类型由MySQL57Dialect
.
Otherwise, you need to register it yourself:
否则,您需要自己注册:
public class MySQLJsonDialect extends MySQL55Dialect {
public MySQLJsonDialect() {
super();
this.registerColumnType(Types.JAVA_OBJECT, "json");
}
}
And, set the hibernate.dialect
Hibernate property to use the fully-qualified class name of the MySQLJsonDialect
class you have just created.
并且,将hibernate.dialect
Hibernate 属性设置为使用MySQLJsonDialect
您刚刚创建的类的完全限定类名。