I'm trying to create mapping that will store my custom object as a String to a single column in a database table.
Article.java
@Entity
public class Article {
@Getter @Setter
@Embedded
@Column(name = "name", columnDefinition = "TEXT")
@Convert(converter = LocalizedFieldConverter.class,
attributeName = "name")
private LocalizedField name = new LocalizedField();
@Getter @Setter
@Embedded
@Column(name = "name", columnDefinition = "TEXT")
@Convert(converter = LocalizedFieldConverter.class,
attributeName = "description")
private LocalizedField description = new LocalizedField();
}
LocalizedField.java
@Embeddable @Getter @Setter
public class LocalizedField {
// map key is "en-US", value is a translation
private Map<String, String> data = new HashMap<>();
}
LocalizedFieldConverter.java
@Converter
public class LocalizedFieldConverter
implements AttributeConverter<LocalizedField, String>, Serializable
{
@Override
public String convertToDatabaseColumn(LocalizedField attribute) {
if (attribute == null) { return null; }
try {
return new ObjectMapper().writeValueAsString(attribute);
}
catch (JsonProcessingException e) { return null; }
}
@Override
public LocalizedField convertToEntityAttribute(String dbData) {
if (dbData == null) { return null; }
try {
return new ObjectMapper().readValue(dbData, typeReference());
}
catch (JsonProcessingException e) { return null; }
}
private static final TypeReference<LocalizedField> typeReference() {
return new TypeReference<>() { /* */ };
}
}
When Hibernate tries to create the database, I get this one:
Caused by: org.hibernate.MappingException: Could not determine type for: java.util.Map, at table: article, for columns: [org.hibernate.mapping.Column(data)]
I don't want to use @ElementCollection as this would create additional table in my database.
Next try was to change mapping to this:
Article.java
@Getter @Setter
private LocalizedField name = new LocalizedField();
LocalizedField.java
@Convert(converter = LocalizedFieldMapConverter.class)
private Map<String, String> data = new HashMap<>();
LocalizedFieldMapConverter.java
@Converter
public class LocalizedFieldMapConverter
implements AttributeConverter<Map<String, String>, String>, Serializable {
@Override
public String convertToDatabaseColumn(Map<String, String> attribute) {
if (attribute == null) { return null; }
try {
return new ObjectMapper().writeValueAsString(attribute);
}
catch (JsonProcessingException e) { return null; }
}
@Override
public Map<String, String> convertToEntityAttribute(String dbData) {
if (dbData == null) { return null; }
try {
return new ObjectMapper().readValue(dbData, typeReference());
}
catch (JsonProcessingException e) { return null; }
}
private static final TypeReference<Map<String, String>> typeReference() {
return new TypeReference<>() { /* */ };
}
}
In second case I had to remove description property from entity because database column gets a name data which is a name of Map inside LocalizedField class.
In the final I would like to have more than one LocalizedField property handled by the same @Converter (of course, if possible).
But in cotrary to first attempt, at least I get column stored as expected, in JSON format but it's named data instead of name:
{
"hr-HR" : "Sončnica & vitamin E šampon za kosu i tijelo 1000 ml",
"en-US" : "Sunflower & Vitamin E Hair & Body Shampoo 1000 ml",
"sr-RS" : "Сончница & витамин Е шампон за косу и тело 1000 мл"
}
What did I do wrong?
@EmbeddedI get the same exception:org.hibernate.MappingException: Could not determine type for: java.util.Map, at table: article, for columns: [org.hibernate.mapping.Column(data)]