Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring REST JSON serialization/deserialization of composite polymorphic types

I use Spring/Spring Boot and Spring MVC with @RestController

I have a composite model objects:

public abstract class BaseQuery {

    private final Long characteristicId;

...

}

public abstract class ComparableQuery extends BaseQuery {

    private final Object value;

    private final String comparisonOperator;

...

}

public class GreaterOrEqualQuery extends ComparableQuery {

    public GreaterOrEqualQuery(Long characteristicId, Object value) {
        super(characteristicId, value, ">=");
    }

}

public class EqualQuery extends ComparableQuery {

    public EqualQuery(Long characteristicId, Object value) {
        super(characteristicId, value, "=");
    }

}

public class GreaterQuery extends ComparableQuery {

    public GreaterQuery(Long characteristicId, Object value) {
        super(characteristicId, value, ">");
    }

}

public class CompositQuery extends BaseQuery {

    private final String operator;
    private final BaseQuery[] queries;

    public CompositQuery(Long characteristicId, Operator operator, BaseQuery... queries) {
        super(characteristicId);
        this.operator = operator.value;
        this.queries = queries;
    }

...

}

etc.

The sample usage of this model looks for example like:

Set<BaseQuery> queries = new HashSet<>();

BaseQuery megapixelCharacteristicQuery = new CompositQuery(megapixelCharacteristic.getCharacteristicId(), CompositQuery.Operator.AND, new GreaterOrEqualQuery(megapixelCharacteristic.getCharacteristicId(), 10), new LessOrEqualQuery(megapixelCharacteristic.getCharacteristicId(), 50));
queries.add(megapixelCharacteristicQuery);
queries.add(new EqualQuery(androidCharacteristic.getCharacteristicId(), true));

Serialized JSON object for Set<BaseQuery> queries looks like:

[
   {
      "operator":"AND",
      "queries":[
         {
            "value":10,
            "comparisonOperator":"\u003e\u003d",
            "characteristicId":391
         },
         {
            "value":50,
            "comparisonOperator":"\u003c\u003d",
            "characteristicId":391
         }
      ],
      "characteristicId":391
   },
   {
      "value":true,
      "comparisonOperator":"\u003d",
      "characteristicId":383
   }
]

I have to pass this or similar JSON from client application(AngularJS) to my back end REST API endpoint in order to get correctly deserialized model like described above(Set with appropriate entries like CompositQuery or EqualQuery).

Right now my Spring application back end logic at my Rest controller unable to correctly deserialize this JSON with appropriate classes.

Is any way in Spring to provide some meta information(or something else) to this JSON in order to help Spring correctly deserialize this structure ?

like image 821
alexanoid Avatar asked Dec 22 '16 19:12

alexanoid


1 Answers

You can achieve this using jackson annotations on the superclass like following:

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "javaclass")
@JsonSubTypes({
    @Type(value = GreaterOrEqualQuery.class),
    @Type(value = EqualQuery.class)
    //and so on...
})
public abstract class BaseQuery {
    ...
}

This will add javaclass property into json representation which is a fully-qualified name in case of use = JsonTypeInfo.Id.CLASS. In order to simplify the value of this property consider different options for use parameter of @JsonTypeInfo (JsonTypeInfo.Id.NAME for example).

like image 158
Oleg Kurbatov Avatar answered Oct 12 '22 23:10

Oleg Kurbatov