Reputation: 855
I have a JSON string:
{
"entities": [
{
"type": "fio",
"value": {
"firstName": "first",
"lastName": "last"
}
},
{
"type": "geo",
"value": {
"country": "the country",
"city": "the city"
}
},
{
"type": "number",
"value": 100
},
{
"type": "number",
"value": 3.14
}
]
}
It's a list of some entities, that have params type and value. Depending of the type, param value has specific representation.
For example:
I created an absract class EntityValue with few implementations. I used jackson annotations:
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@Type(value = GeoEntityValue.class, name = "geo"),
@Type(value = FioEntityValue.class, name = "fio"),
...
})
public class Entity {
private final EntityType type;
private final EntityValue value;
... constructor and getters ...
}
It works pretty well for a complex types like fio or geo, but I struggle with a number type. It serializes and deserializes like a complex object, not like the example mentioned at the beginning.
Can you please help me to manage with jackson annotations or reorganize class hierarchy to make serialization and deserialization works ?
Thanks!
Upvotes: 1
Views: 649
Reputation: 1134
Here is a solution that works:
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = As.PROPERTY,
property = "type")
@JsonSubTypes(value = {
@Type(value = GeoEntity.class, name = "geo"),
@Type(value = FioEntity.class, name = "fio"),
@Type(value = Number.class, name ="number")
})
public abstract class Entity {
public void setType(String type) {
this.type = type;
}
private String type;
@Override
public String toString(){
return ToStringBuilder.reflectionToString(this);
}
}
FioEntity class (similar way we can create GeoEntity )
public class FioEntity extends Entity {
public FioEntityValue getValue() {
return value;
}
public void setValue(FioEntityValue value) {
this.value = value;
}
private FioEntityValue value;
public class FioEntityValue extends EntityValue{
private String firstName;
private String lastName;
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
}
Number class:
public class Number extends Entity {
private Double value;
public Double getValue() {
return value;
}
public void setValue(Double value) {
this.value = value;
}
}
Test class:
public class Test {
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
String content = "{\n"
+ " \"entities\": [\n"
+ " {\n"
+ " \"type\": \"fio\",\n"
+ " \"value\": {\n"
+ " \"firstName\": \"first\",\n"
+ " \"lastName\": \"last\"\n"
+ " }\n"
+ " },\n"
+ "\n"
+ " {\n"
+ " \"type\": \"geo\",\n"
+ " \"value\": {\n"
+ " \"country\": \"the country\",\n"
+ " \"city\": \"the city\"\n"
+ " }\n"
+ " },\n"
+ "\n"
+ " {\n"
+ " \"type\": \"number\",\n"
+ " \"value\": 100\n"
+ " },\n"
+ "\n"
+ " {\n"
+ " \"type\": \"number\",\n"
+ " \"value\": 3.14\n"
+ " }\n"
+ " ]\n"
+ "}";
Entities test = mapper.readValue(content, Entities.class);
System.out.println(mapper.writeValueAsString(test));
}
}
outPut:
{"entities":[{"type":"fio","value":{"firstName":"first","lastName":"last"}},{"type":"geo","value":{"city":"the city","country":"the country"}},{"type":"number","value":100.0},{"type":"number","value":3.14}]}
Upvotes: 1