Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson deserializing nested polymorphic type

Tags:

java

json

jackson

I'm trying to use Jakson to deserialize a nested polymorphic type. Meaning my top level type referes to another polymorphic type that finally is extended by class that's not abstract. This does not work and it throws an exception.

Here is a reduced example of what I'm trying to do.

package com.adfin;

import junit.framework.TestCase;
import org.codehaus.jackson.annotate.JsonSubTypes;
import org.codehaus.jackson.annotate.JsonTypeInfo;
import org.codehaus.jackson.map.ObjectMapper;

import java.io.IOException;

public class JaksonDouble extends TestCase {

  @JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "name"
  )
  @JsonSubTypes({
    @JsonSubTypes.Type(value = SecondLevel.class, name = "SECOND")
  })
  public static abstract class FirstLevel {
    public abstract String getTestValue();
  }

  @JsonTypeInfo(
    use = JsonTypeInfo.Id.CLASS,
    include = JsonTypeInfo.As.PROPERTY,
    property = "@class"
  )
  public static abstract class SecondLevel extends FirstLevel {

  }

  public static class FinalLevel extends SecondLevel {
    String test;
    @Override public String getTestValue() { return test; }
  }

  public void testDoubleAbstract() throws IOException {
    String testStr = "{ \"name\": \"SECOND\", \"@class\": \"com.adfin.JasksonDouble.FinalLevel\", \"test\": \"foo\"}";

    ObjectMapper mapper = new ObjectMapper();
    FirstLevel result = mapper.readValue(testStr, FirstLevel.class);
  }
}

I get the standard exception about abstract types.

org.codehaus.jackson.map.JsonMappingException: Can not construct instance of com.adfin.JaksonDouble$SecondLevel, problem: abstract types can only be instantiated with additional type information at [Source: java.io.StringReader@f2a55aa; line: 1, column: 19]

Let me explain my use case. I have a Json document describing a workflow on data. I have an abstract type at "level one" describing an operation on a single value. I derive a bunch of classes that are not abstract that implement common operations (I annotate all of them with @JsonSubTypes).

I have one special @JsonSubTypes that is called "CUSTOM". This is another abstract class that represents custom operations that someone else wrote (outside of the normal jar) and they can specify a fully qualified class name using the "@class" property. It looks like the Jakson parser never reads the @JsonTypeInfo annotation on the second lavel class.

How can I make this work. Or at least how can I make this use case work.

like image 656
user1959154 Avatar asked Nov 25 '25 17:11

user1959154


1 Answers

Your definitions are messed up -- you are trying to use two type identifiers, type name AND class. This does not make any sense. You should choose one method or the other, not both.

If you choose Java class name as type information, just leave out the name. Also, you only need to include @JsonTypeInfo for FirstLevel; sub-classes inherit this definition.

If you prefer use of logical type name, drop the class property. You will also need to specify sub-type list, either with annotation, or by registering them via ObjectMapper.

like image 101
StaxMan Avatar answered Nov 27 '25 07:11

StaxMan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!