12

Assume serialization to json includes the class name of the actual object, using this annotation on the Class:

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@type")
class MyClass {
    String foo;
}

So json is for example:

{"@type": "com.example.MyClass", "foo": "bar"}

Can this be deserialized without specifying the type? And I mean not even the super type. Just something like:

objectMapper.readValue(value, Object.class);

which doesn't actually work, it brings back a Map.

Nazaret K.
  • 3,409
  • 6
  • 22
  • 31

4 Answers4

10

Well, it is certainly possible to do that although I have personally never used Jackson that way. You can deserialize it to a JsonNode object and then convert it to the proper type.

final ObjectMapper objectMapper = new ObjectMapper();
final MyClass myClass = new MyClass();
myClass.foo = "bar";

// Serialize
final String json = objectMapper.writeValueAsString(myClass);

// Deserialize
final JsonNode jsonNode = objectMapper.readTree(json);

// Get the @type
final String type = jsonNode.get("@type").asText();

// Create a Class-object
final Class<?> cls = Class.forName(type);

// And convert it
final Object o = objectMapper.convertValue(jsonNode, cls);

System.out.println(o.getClass());

The output is:

MyClass

wassgren
  • 18,651
  • 6
  • 63
  • 77
  • 2
    Oh, yeah, I guess that works. I was wondering if there was a more built-in way but I guess that wouldn't make any sense as Jackson could not possibly know how I have configured the JsonTypeInfo, without knowing the class. Thanks a lot. – Nazaret K. Feb 07 '15 at 16:42
3
    ObjectMapper mapper = new ObjectMapper();
    mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

    MyClass original = new MyClass();
    original.foo = "hello";

    String json = mapper.writeValueAsString(original);
    MyClass foo = (MyClass) mapper.readValue(json, MyClass.class);

This should work and is very convenient.

sydraz
  • 653
  • 6
  • 12
  • It works if you know the JSON represents `MyClass` at deserialization time. I took the question to refer to a scenario where you don't know the type of the object. That's the situation I'm currently trying to handle. – Rob Fletcher Jun 17 '15 at 16:47
  • If you don't know the type, you can just assign to an object. The object.getClass() will tell you what type it is. – sydraz Jun 19 '15 at 22:01
2

Yes, but there is a caveat: type you give MUST be something that includes @JsonTypeInfo you specify. Object.class will not have, unless you use "mix-in annotations" to associate it.

However, if you need to add type information for properties of (declared type of) java.lang.Object, you probably want to enable default typing: see ObjectMapper.enableDefaultTyping(...) for more information. That will actually enable inclusion (and use) of type information for larger categories of classes, without need to add annotations.

StaxMan
  • 113,358
  • 34
  • 211
  • 239
1

What you want to use is Jackson Polymorphic Deserialization.

Farrukh Najmi
  • 5,055
  • 3
  • 35
  • 54