How to map a map JSON column to Java Object with JPA
Solution 1:
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:
@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.
Solution 2:
The JPA AttributeConverter
is way too limited to map JSON object types, especially if you want to save them as JSON binary.
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>
Now, you need to declare the new type either at the entity attribute level or, even better, at the class level in a base class using @MappedSuperclass
:
@TypeDef(name = "json", typeClass = JsonType.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
.
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.