Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.5k views
in Technique[技术] by (71.8m points)

java - Jackson deserializing nested polymorphic type

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...