Jackson typeId 未包含在生成的 json 中

Jackson typeId is not included in generated json

有以下课程:

public class BaseEntity<E> {
    public TrackedChange<E> trackChange;
}


@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({ @JsonSubTypes.Type(value=B.class, name="b_type") })
public abstract class A extends BaseEntity<A> implements Cloneable{
    public String aFoo;

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

@JsonTypeName("b_type")
public class B extends A {
    public String bFoo;
}

public class TrackedChange<E> {
    public E tracked;
}

public class Runner {

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

        B bInstance = new B();
        bInstance.bFoo = "bFoo";
        bInstance.aFoo = "aFoo";
        B clone = (B) bInstance.clone();
        bInstance.trackChange = new TrackedChange<A>();
        bInstance.trackChange.tracked = clone;
        ObjectMapper mapper = new ObjectMapper();
        System.out.println(mapper.writeValueAsString(bInstance));
    }
}

生成的JSON为:

{
   "type":"b_type",
   "trackChange":{
      "tracked":{
         "trackChange":null,
         "aFoo":"aFoo",
         "bFoo":"bFoo"
      }
   },
   "aFoo":"aFoo",
   "bFoo":"bFoo"
}

类型 ("type":"b_type") 信息未包含在 trackChange.tracked 对象中。如何解决这个问题?

编辑:最后我使用了 JsonTypeInfo.As.EXISTING_PROPERTY,它是在 2.3.0 版本之后引入的。它利用现有属性来确定实际类型。

TrackedChange.tracked 上的类型擦除是您的问题。在运行时,您的类型由于类型擦除而丢失,并且 Jackson 序列化程序无法确定类型,因此无法将其识别为 B 并且找不到它的 @JsonTypeInfo ;因此在运行时杰克逊读取 TrackedChange.tracked 类型 Object.

有多种方法可以减轻 Jackson 中的类型擦除,但它们通常围绕集合的泛型。

只有一种方法可以基本实现你的目标,你可以像这样配置 ObjectMapper:

ObjectMapper mapper = new ObjectMapper();
TypeResolverBuilder<?> typer = new ObjectMapper.DefaultTypeResolverBuilder(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);
typer = typer.init(JsonTypeInfo.Id.CLASS, null);
typer = typer.inclusion(JsonTypeInfo.As.PROPERTY);
typer = typer.typeProperty("type");
mapper.setDefaultTyping(typer);

这将在序列化期间为对象和非具体类型注册类型映射器配置(这涵盖了 TrackedChange.tracked 情况)。不幸的是,我没有看到任何方式来预先注册此配置将使用匹配的 b_type 名称,如您的示例所示。我的最佳建议是更改您的 class 配置以使用以下内容,这与上面配置的行为相匹配:

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "type")

给你这样的输出:

{
  "type" : "so.json.typeinfo.B",
  "trackChange" : {
    "tracked" : {
      "type" : "so.json.typeinfo.B",
      "trackChange" : null,
      "aFoo" : "aFoo",
      "bFoo" : "bFoo"
    }
  },
  "aFoo" : "aFoo",
  "bFoo" : "bFoo"
}