Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Map JSON string column of a JPA entity to Java object automatically

I have a JPA entity object with following structure:

@Table(name="item_info")
class Item(){
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @Column(name="item_name")
    private String itemName;

    @Column(name="product_sku")
    private String productSku;

    @Column(name="item_json")
    private String itemJsonString;

    @Transient
    private ItemJson itemJson;

    //Getters and setters

}

The itemJsonString field contains a json string value such as '{"key1":"value1","key2":"value2"}'

And the itemJson field contains the corresponding object which maps to the json string.

I get this entity object from database as follows:

Item item = itemRepository.findOne(1L);    // Returns item with id 1

Now, the itemJson field is null since it is a transient field. And I have to set it manually using Jackson's ObjectMapper as follows:

itemJson = objectMapper.readValue(item.getItemJsonString(), ItemJson.class);

How can I make it such that when I do itemRepository.findOne(), it returns an Item object with the itemJson field mapped to the json String automatically?

like image 408
drunkenfist Avatar asked Feb 24 '16 21:02

drunkenfist


People also ask

How do I Map a mysql JSON column to a Java entity property?

The code is bellow. ... @Column(name = "meta_data", columnDefinition = "json") @Convert(attributeName = "data", converter = JsonToMapConverter. class) private Map<String, Object> metaData = new HashMap<>(); ...

Can we convert JSON to Map in Java?

We can easily convert JSON data into a map because the JSON format is essentially a key-value pair grouping and the map also stores data in key-value pairs. Let's understand how we can use both JACKSON and Gson libraries to convert JSON data into a Map.

How does ObjectMapper work in Java?

The Jackson ObjectMapper can parse JSON from a string, stream or file, and create a Java object or object graph representing the parsed JSON. Parsing JSON into Java objects is also referred to as to deserialize Java objects from JSON. The Jackson ObjectMapper can also create JSON from Java objects.

How is JPA mapping done?

Association mappings are one of the key features of JPA and Hibernate. They model the relationship between two database tables as attributes in your domain model. That allows you to easily navigate the associations in your domain model and JPQL or Criteria queries.


2 Answers

Your best bet would be to implement a javax.persistence.Converter. It would look something like:

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter(autoApply = true)
public class LocalDateAttributeConverter implements AttributeConverter<ItemJson, String> {

    @Override
    public String convertToDatabaseColumn(ItemJson entityValue) {
        if( entityValue == null )
            return null;

        ObjectMapper mapper = new ObjectMapper();

        return mapper.writeValueAsString(entityValue);
    }

    @Override
    public ItemJson convertToEntityAttribute(String databaseValue) {
        if( databaseValue == null )
            return null;

        ObjectMapper mapper = new ObjectMapper();

        return mapper.readValue(databaseValue, ItemJson.class);

    }
}

I've used this with WildFly and didn't have to do anything except have it be in the war file I was deploying.

like image 134
stdunbar Avatar answered Oct 07 '22 01:10

stdunbar


Here is the full working version of AttributeConverter + JPA + Kotlin.

Entity Class

In my case, database was mysql (8.x), which supports JSON as the underlying data type for column definition, and we can apply a custom converter using @Convert annotation.

@Entity
data class Monitor (
    @Id
    val id: Long? = null,

    @Column(columnDefinition = "JSON")
    @Convert(converter = AlertConverter::class)
    var alerts: List<Alert> = emptyList(),

    var active: Boolean = false
)

Converter Definition Attribute converter needs to specify the conversion mechanism from data to db and reverse. We are using Jackson to convert a java object into String format and vice versa.

@Converter(autoApply = true)
class AlertConverter : AttributeConverter<List<Alert>, String> {

private val objectMapper = ObjectMapper()

 override fun convertToDatabaseColumn(data: List<Alert>?): String {
    return if (data != null && !data.isEmpty())
        objectMapper.writeValueAsString(data)
    else ""
 }

 override fun convertToEntityAttribute(dbData: String?): List<Alert> {
    if (StringUtils.isEmpty(dbData)) {
        return emptyList()
    }
    return objectMapper.readValue(dbData, object : TypeReference<List<Alert>>() {})
 }
}
like image 44
Munish Chandel Avatar answered Oct 07 '22 01:10

Munish Chandel