Search code examples
mapstruct

Mapping from JSON Array/JSON Object in DTO to String in JPA DB POJO using Mapstruct


My requirement is as below

My DTO API will have a field which can receive a JSON array or JSON object as a input.

for example

{
"name" : { "firstName" : "ABC", "lastName" : "pqr", "email" : "[email protected]" },
"skills" : ["Java", "JS", "Mongo", "JPA"]
}

This needs to be stored in DB using JPA in the Domain POJO as string

field name : "{\"firstName\":\"ABC\",\"lastName\":\"pqr\",\"email\":\"[email protected]\"}"

field skills : "[\"Java\",\"JS\",\"Mongo\",\"JPA\"]"

On DB retrieval by GET API the reverse should happen, the strings should be converted back to JSON in the response payload.

Is there any example to do this using the mapstruct library


Solution

  • Mapstruct cannot map unknown states that well, but if a field is always either a JSONArray or a JSONObject then it is possible. In case of an unknown state, (For example it is typed as an Object) using the @SubclassMapping annotation might be an option. See here for more information about subclass mappings

    In either case it is needed that a way to go from JSONArray to String and back again is introduced. Same for JSONObject.

    for example:

    
        String from(JSONArray array) {
            return array.toJSONString( JSONStyle.NO_COMPRESS );
        }
    
        String from(JSONObject object) {
            return object.toJSONString( JSONStyle.NO_COMPRESS );
        }
    
        JSONArray toArray(String array) {
            try {
                return (JSONArray) new JSONParser( JSONParser.MODE_JSON_SIMPLE ).parse( array );
            }
            catch ( ParseException e ) {
                throw new RuntimeException( e );
            }
        }
    
        JSONObject toObject(String object) {
            try {
                return (JSONObject) new JSONParser( JSONParser.MODE_JSON_SIMPLE ).parse( object );
            }
            catch ( ParseException e ) {
                throw new RuntimeException( e );
            }
        }
    

    Say the DTO is named ProgrammerDto and the domain object Programmer adding 2 more methods to the mapper will allow the conversion between the two. Assuming the POJO fields are called the same as the DTO fields, otherwise you will need to add mappings.

        ProgrammerDto map(Programmer programmer);
        Programmer map(ProgrammerDto programmerDto);
    

    ps. either the map methods are abstract, or the others are default. This would depend on whether an abstract class or an interface is used.