У вас есть следующие классы:
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. Как решить эту проблему?
EDIT: Наконец, я использовал JsonTypeInfo.As.EXISTING_PROPERTY
который был представлен после выпуска 2.3.0. Он использует существующее свойство для определения фактического типа.
Тип стирания на TrackedChange.tracked
- ваша проблема. Во время выполнения ваш тип теряется из-за стирания типа, и сериализатор Jackson не может определить тип и, следовательно, не распознает его как B
и не находит для него @JsonTypeInfo
; таким образом, во время выполнения Джексон считывает TrackedChange.tracked
как тип Object
.
Существуют различные способы смягчения стирания стилей в Джексоне, но они, как правило, основываются на дженериках коллекций.
Там только один способ в основном достичь вашей цели, которую я вижу, вы можете настроить 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
типов во время сериализации (это охватывает случай TrackedChange.tracked
). К сожалению, я не вижу возможности предварительно зарегистрировать, что этот configure будет использовать соответствующее имя b_type
как в вашем примере. Самое лучшее, что у меня есть, - это изменить конфигурацию вашего класса, чтобы использовать следующее, которое соответствует описанному выше поведению:
@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"
}