Using Jackson to / from JSON where each class implements the same interface

I am trying to deserialize a fairly complex JSON structure using Jackson.

Serialization works fine:

Parametric interface:

public interface Param<T> {
}

      

Not.java:

public class Not implements Param<Param<?>> {

    private Param not;

    public Not(){

    }

    public Not(Param not) {
        this.not = not;
    }

    public Param getNot() {
        return not;
    }

}

      

And.java:

public class And implements Param<List<?>> {

    private List<Param> and;

    public List<Param> getAnd() {
        return and;
    }

    public List<Param> add(Param ... params){
        for (Param param : params){
            this.and.add(param);
        }
        return this.and;
    }

    public And() {
        this.and = new ArrayList<>();
    }

    public And(Param ... params){
        this.and = new ArrayList<>();
        for (Param param : params){
            this.and.add(param);
        }
    }

}

      

Company.java:

public class CompanyName implements Param<String> {

    private String companyName;

    public CompanyName(String value) {
        this.companyName = value;
    }

    public String getCompanyName() {
        return companyName;
    }
}

      

Serialization:

ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(new And(new Or(new CompanyName("ABC"), new CompanyName("DEF")), new Not(new CompanyName("GHI")))));

      

Printing

{"and":[{"or":[{"companyName":"ABC"},{"companyName":"DEF"}]},{"not":{"companyName":"GHI"}}]}

      

Now deserializing, how is Jackson able to match and / or / companyName / not return to his objects?

And and = mapper.readValue(json, And.class);

      

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Unable to instantiate com.ahp.messaging.param.Param, problem: abstract types must either be mapped to concrete types, have a custom deserializer, or be instantiated with for more information about the type, see [Source: {"AND": [{"or": [{"COMPANYNAME": "ABC"}, {"COMPANYNAME": "DEF"}]}, {"not": {"COMPANYNAME ":" GHI "}}]}; line: 1, column: 9] (via the reference chain: com.ahp.messaging.param.And ["and"] β†’ java.util.ArrayList [0])

To get rid of the exception, I changed the Param interface as shown below:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "T", visible = false)
@JsonSubTypes({
    @JsonSubTypes.Type(value = Not.class, name = "not"),
    @JsonSubTypes.Type(value = And.class, name = "and"),
    @JsonSubTypes.Type(value = Or.class, name = "or"),
    @JsonSubTypes.Type(value = CompanyName.class, name = "companyName")

})
public interface Param<T> {

}

      

It is now serialized:

{"T":"and","and":[{"T":"or","or":[{"T":"companyName","companyName":"ABC"},{"T":"companyName","companyName":"DEF"}]},{"T":"not","not":{"T":"companyName","companyName":"GHI"}}]}

      

which deserializes fine, but there is information about everything, is there a way to get rid of the type information and only have it where it is really needed?

+3


source to share


1 answer


Short answer, type information is required.



With XML, you get type information with every element, with JSON, you sacrifice type information for smaller representations, but in this case, discarding the type information means there is no way to infer which class it should be bound to.

0


source







All Articles