jsonschema2pojo
jsonschema2pojo copied to clipboard
Adding support for JsonSubTypes annotation
The generated polymorphic pojo classes had JsonType annotation for the parent class but was missing JsonSubTypes annotation. When using jackson for data binding, it was not able to recognize to which subclass it had to bind the data to and it needs JsonSubTypes annotation to figure out all possible subclasses. This was a requirment for a project that I am working on. Please let me know your feedback.
eg: Annotations for parent class Animal
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT, property = "name")
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "Dog"),
@JsonSubTypes.Type(value = Cat.class, name = "Cat")
})
Couple of comments on this:
- We should support either a string or array as the value of
deserializationClassProperty
, rather than splitting on,
. - I think you may be able to achieve what you need without using javaassist, and instead using
jclass.owner().ref(subClass)
to create a JType. Would this work?
Thank you for the feedback. Will update the pull request
I have updated the pull request after addressing your feedback. jclass.owner().ref(subClass) works perfect.
Thanks, could you also squash these commits into one?
Done. Is it possible to have a release version with these changes?
Is this part a breaking change for anyone using the existing deserializationClassProperty feature?
- jsonTypeInfo.param("use", JsonTypeInfo.Id.CLASS);
- jsonTypeInfo.param("include", JsonTypeInfo.As.PROPERTY);
- jsonTypeInfo.param("property", annotationName);
+ jsonTypeInfo.param("use", JsonTypeInfo.Id.NAME);
+ jsonTypeInfo.param("include", JsonTypeInfo.As.WRAPPER_OBJECT);
+ jsonTypeInfo.param("property", "name");
Yeah, its not backward compatible. I missed it. Let me try to work on it. But looks like when we use JsonTypeInfo.As.PROPERTY we need to use the annotationName(value of deserializationClassProperty) as a string which represents a key in the json object, not as the Sub class itself. The value of the key in json object will hold the details of the subclass. I was able to get jackson to bind the data just with JsonType annotation.
annotationName: type Eg: json object
{
"animal":{
"type":"Dog",
"colour":"black"
}
}
This object gets binded to the DOG class. But if we need JsonTypeInfo.As.WRAPPER_OBJECT then the annotationName will be a subClass in the schema. And the json will look like below
json object
{
"Dog":{
"colour":"black"
}
}
I think this is very useful especially to solve for user cases with class type hierarchy. But i think this change is not configurable enough.
I suggest we make it more configurable.
- class and the name value could be different, and user must be able to specific that as well.
"deserializationClassProperty" : [
{
"class" : "SummaryReport",
"discriminiatorValue" : "SUMMARY"
},
{
"class" : "DetailReport",
"discriminiatorValue" : "DETAIL"
}
]
- the key to derive the discriminiatorValue must also be configurable in schema instead of hardcode to name, it could be any other as well..
I would very much like to see this implemented. Couldn't be the solution making lsubramanya's change using a slightly different keyword, which would keep the original functionality but add the new one? Something like deserializationClassPropertyWithSubs. I would make the change and a pull request if it is agreeable or lsubramanya could do it.
I've updated the PR so that it does not break any existing changes. Thanks for the comments.
This PR could really use a couple of tests showing JSON input documents being deserialized and verifying that the correct types were used.
@joelittlejohn This would be a really useful feature for a project I'm working on at the moment. Are there plans to include this PR in a future release?
Any update on plans here?
This PR looks promising but its been gathering dust for a long time. What else does it need to move forward?
I am not sure how to use "deserializationClassProperty" in my json schema...
Here is what I have
vehicle.json
{
"type": "object",
"id": "#Vehicle",
"additionalProperties": false,
"javaType": "Vehicle",
"deserializationClassProperty" : "Car.class,Truck.class",
"properties": {
"color": {
"type": "string"
}
}
}
car.json
{
"type": "object",
"id": "#Car",
"additionalProperties": false,
"javaType": "Car",
"extends": {
"type": "object",
"existingJavaType": "Vehicle"
}
}
truck.json
{
"type": "object",
"id": "#Truck",
"additionalProperties": false,
"javaType": "Truck",
"extends": {
"type": "object",
"existingJavaType": "Vehicle"
}
}
inventoryitem.json
{
"type": "object",
"id": "#InventoryItem",
"additionalProperties": false,
"javaType": "InventoryItem",
"properties": {
"vehicle": {
"#ref": "vehicle.json"
}
}
}
Here is my input that I am trying to unmarshall using XmlMapper
<InventoryItem><Vehicle xis:type="ns2:car"/></InventoryItem>
The generated code for the above schema
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "Car.class, Truck.class")
public class Vehicle
But I need to generate as shown below to get it working I need to generate the following through json schema
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@JsonSubTypes ({
@JsonSubTypes.Type(value = Truck.class, name = "truck"),
@JsonSubTypes.Type(value = Car.class, name = "car")
})
public class Vehicle
Also how to avoid the namespace "ns2:car"
Thanks for you time
ping @joelittlejohn
Hello, I would like to generate @JsonSubTypes same way like ravim786 mentioned. Is there some possibility that this feature will be released?