3

I have a situation where I need to parse an array of JSON objects that are not identical.

So for example:

[ 
 { "type": "type1", ..... type1 contents .... }, 
 { "type": "type2", ..... type2 contents .... },
 ....
 { "type": "type1", ..... type1 contents .... }
]

The number of types is limited and the contents of each type are well can be defined but it is not possible to define a single type of object that will hold the contents.

Is there a way to parse them with Jackson?

P.S. I am trying to avoid writing a custom parser if I can help it.

Greggz
  • 1,873
  • 1
  • 12
  • 31
Karlson
  • 2,958
  • 1
  • 21
  • 48

2 Answers2

2

I would use

com.fasterxml.jackson.databind.JsonNode.

JsonNode parsed = objectMapper
                   .readValue("[{\"name\": \"a\"},{\"type\":\"b\"}]", JsonNode.class);

This class has tons of utility methods to work with.

Or specific for arrays you can use:

com.fasterxml.jackson.databind.node.ArrayNode

ArrayNode value = objectMapper
                   .readValue("[{\"name\": \"a\"},{\"type\":\"b\"}]", ArrayNode.class);

EDIT

Sorry, I have misread your question, you can use @JsonTypeInfo for polymorphic serialization/deserialization:

public static void main(String args[]) throws JsonProcessingException {

    //language=JSON
    String data = "[{\"type\":\"type1\", \"type1Specific\":\"this is type1\"},{\"type\":\"type2\", \"type2Specific\":\"this is type2\"}]";
    ObjectMapper objectMapper = new ObjectMapper();

    List<BaseType> parsed = objectMapper.readValue(data, new TypeReference<List<BaseType>>() {});
    System.out.println(parsed);
}


@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", include = JsonTypeInfo.As.PROPERTY)
@JsonSubTypes(value = {
        @JsonSubTypes.Type(value = Type1.class, name = "type1"),
        @JsonSubTypes.Type(value = Type2.class, name = "type2")
})
static public abstract class BaseType {
    public String type;
}
static public class Type1 extends BaseType {
    public String type1Specific;
    @Override
    public String toString() {
        return "Type1{" +
                "type1Specific='" + type1Specific + '\'' +
                '}';
    }
}
static public class Type2 extends BaseType {
    public String type2Specific;

    @Override
    public String toString() {
        return "Type2{" +
                "type2Specific='" + type2Specific + '\'' +
                '}';
    }
}

Here are the docs:

https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization

Hope this helps.

And the result would be:

[Type1{type1Specific='this is type1'}, Type2{type2Specific='this is type2'}]
Nonika
  • 2,490
  • 13
  • 15
  • Still basically a custom parser. What I was looking for is something similar to: https://stackoverflow.com/a/50028671/975797 Creating a JsonNode and then figuring out what's the contents I've already done. I was looking for a method of creating POJO array without having to write my own code to parse it. – Karlson Mar 14 '20 at 16:16
  • @Karlson I have edited my answer. I hope this is will work for you. – Nonika Mar 14 '20 at 17:56
0

We can use List.class to map this JSON Array with different types of objects that hold the content. It will return the List of LinkedHashMaps. Different content will be mapped to LinkedHashMap.

@Test
public void testLoadCustom() {
    String json = "[{\"a\":\"A\" } , {\"b\":\"B\" , \"c\":\"C\" } , {\"d\":\"D\" } ]";
    try {
        List custom = objectMapper.readValue(json, List.class);
        System.out.println(custom);
    } catch (Exception ex) {
        ex.getStackTrace();
    }
}


 // Output [{a=A}, {b=B, c=C}, {d=D}] 
Ravi Sharma
  • 160
  • 4
  • You misunderstand the problem. The objects are not entirely different and the type of object in the list is determined based on tag type. – Karlson Mar 13 '20 at 14:39