I am working with the following structure:
class Family {
//...
Parent parent;
}
class Parent {
//...
}
class ChildA extends Parent {
//...
}
class ChildB extends Parent {
//...
}
I am trying to deserialize a JSON object of type Family
(with a Child
object and not Parent
), but I need to tweak one of the Child
so I tried to start by pulling the Parent
property from the Family
object and then set it equal to a Child
. However, the compiler was saying that I needed to typecast it, so I tried but then I got an error basically saying that I couldn't typecast a superclass as a subclass, which makes sense.
I see now that the Family
object gets deserialized with Parent
only, and no subtypes. How can I deserialize Family
with a Child
property rather than a Parent
type? I don't understand because the Family
object gets posted to the server with a Child
object, but it gets deserialized only with the Parent
properties.
Thanks
After doing some research, I came across what I believe might be part of the solution (although now I have a new problem)
I have revised my classes in the following way:
class Family {
String address;
Parent parent;
}
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = ChildA.class, name = "A"),
@JsonSubTypes.Type(value = ChildB.class, name = "B")
})
class Parent {
String parentAttribute;
}
@JsonSubType("A")
class ChildA extends Parent {
String attributeA;
}
@JsonSubType("B")
class ChildB extends Parent {
String attributeB;
}
Now however, when I try to deserialize the Family
class, I get the following error: com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve subtype of [simple type, class Family ]: missing type id property 'type' (for POJO property 'Parent')
There is no type
field in any of my classes, I think this might have something to do with it.
Here is my JSON string that gets serialized:
{
"Address": "123 Main St",
"Parent": {
"parentAttribute": "Mom",
"attributeA": "Child A Type"
}
}
Ideally, when I perform deserialization, I would do it on the same JSON string above, but the string above doesn't include any type
attributes. Is there a way I can sort of pre-process the deserialization and add an intermediary step (i.e. adding a type field?)
CodePudding user response:
Before adding these annotations, I was able to serialize a POJO into a JSON string like this:
{ "Address": "123 Main St", "Parent": { "parentAttribute": "Mom", "attributeA": "Child A Type" } }
Ideally, when I perform deserialization, I would do it on the same JSON string above, but the dto getting deserialized doesn't use any of the Child types -- I suppose it doesn't know how to map which Child object so it just uses Parent, but my knowledge is limited here.
As far as I know, this is not (easily) possible, I'm afraid. Not out-of-the-box and unlikely easily with custom deserialization code.
Try to think from a deserializer point of view: You need something to destinguish JSON objects to map them to a Java class. Currently I only see the presence and absence of some child properties. This would need quite some logic to do the mapping.
If you can change the JSON format, the easiest thing would be to add the property to the Parent which you specified in the following annotation (here: type):
@JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
You can e.g. pass the value for this property hardcoded to the parent constructor to make sure serialized object has always the correct value.
CodePudding user response:
I was able to resolve this by taking advantage of the fact that one of the properties on the Parent
class could be leveraged in the absence of a "type" field.
The problem was that the JSON string being serialized does not include a "type" field, so rather than using:
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
I changed "type" to that property name:
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "theOtherProperty")
This resolved my issues when attempting to deserialize the object. However, it is ultimately a workaround since it is not solving the original issue (doing some form of modification during the deserialization process to add an additional "type" field) but I am unsure of how to go about doing this anyhow.