1

I'm trying to use Jackson as a generic serialization engine instead of Java serialization. By initializing the mapper in the following way:

objectMapper = new ObjectMapper();
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

All type information in stored in JSON so I'm able to write and read all my objects back with:

objectMapper.readValue(json, Object.class)

I'm having problems when I try to serialize and then deserialize java arrays. Since Jackson doesn't store the array type into the JSON it fails later in the deserialization phase. In the following code:

    String [] strings = {"A", "B", "C"};
    try {
        String json = objectMapper.writeValueAsString(strings);
        String [] stringsBack = (String [])objectMapper.readValue(json, Object.class);
        if (!strings.equals(stringsBack)) {
            System.err.println("ERROR, stringsBack not the same!!!\n\n");
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

json will be set to "["A","B","C"]" but on deserialization I get the following exception:

Exception in thread "main" java.lang.IllegalArgumentException: Invalid type id 'A' (for id type 'Id.class'): no such class found
at com.fasterxml.jackson.databind.jsontype.impl.ClassNameIdResolver._typeFromId(ClassNameIdResolver.java:66)
at com.fasterxml.jackson.databind.jsontype.impl.ClassNameIdResolver.typeFromId(ClassNameIdResolver.java:48)
at com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase._findDeserializer(TypeDeserializerBase.java:157)
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:94)
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromAny(AsArrayTypeDeserializer.java:68)
at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.deserializeWithType(UntypedObjectDeserializer.java:494)
at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:42)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3560)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2576)
at Main.run(Main.java:86)

Is there a way to instruct Jackson to store java arrays types information as well into JSON? My serialization engine is generic and doesn't know in advance the type it is going to read from the JSON string.

2
  • Is there a reason you're not using objectMapper.readValue(json, String[].class);? You told Jackson to deserialize an Object, and of course it has no idea what type of object it is. Commented Feb 16, 2015 at 9:11
  • The reason is that I need to be able to store and read the objects from the strings without additional knowledge of its type. For all other scenario it works since the class names are stored in the JSON. I'm looking for a flag which will instruct Jackson to store java arrays types into the string too and then it will be able to find the type by itself. Commented Feb 16, 2015 at 9:45

3 Answers 3

2

The best solution I've found for now is checking before serialization if the object is an array (Class.isArray) and then doing the serialization:

TypeReference ref = new TypeReference<List[]>() { };
String json = objectMapper.writerFor(ref).writeValueAsString(strings);

This will add the array type into JSON and enable reading it back.

Sign up to request clarification or add additional context in comments.

Comments

2

There are Multiple issue with code.

1) Firstly let us see why the Exception

Exception in thread "main" java.lang.IllegalArgumentException: Invalid type id 'A' (for id type 'Id.class'): no such class found 

The above error says that it did not find some Class and refers A as Invalid type id 'A'and it seems like an issue in Json .

The issue is because of the lines

objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

This enabled Default Typing for all Non Final types. Default typing prints the type of Object with the actual value of Object thus enable deserialization into the same type. Declaring it NON_FINAL would not add the "natural" types such as String.

and

String [] stringsBack = (String [])objectMapper.readValue(json, Object.class);

Now while Deserialization the Json ["A", "B", "C"], the deserializer didnt know waht object the json is to be converted too and took A as a Class Type and tried to find the class which it did not get.

2) Commenting the First Line would probably give a ClassCastException because

objectMapper.readValue(json, Object.class);

would return an Object of ArrayList and it cannot be cast to String[].

3) !strings.equals(stringsBack) will always return true as strings and stringsBack both are different objects of String[].

Correcting all the things following code would work

    ObjectMapper objectMapper = new ObjectMapper();
    //You can remove the below line if Default Typing is not Required.  
    objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    String[] strings = { "A", "B", "C" };
    try
    {
        String json = objectMapper.writeValueAsString(strings);
        System.out.println(json);
        String[] stringsBack = (String[]) objectMapper.readValue(json, new TypeReference<String[]>()
        {});
        if (!Arrays.equals(strings, stringsBack))
        {
            System.err.println("ERROR, stringsBack not the same!!!\n\n");
        }
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }

1 Comment

Thanks for the answer, but the solution doesn't answer the requirement to be able to read the data without any knowledge of object type inside.
0

Correct way is:

String[] strings = { "A", "B", "C" };
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(strings);
List<String> data = mapper.readValue(json,
        mapper.getTypeFactory().constructCollectionType(List.class, String.class));
for (String string : data) {
    System.out.println(string);
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.