I have this situation:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonSubTypes({
@JsonSubTypes.Type(value = FlyingCar.class, name = "flying_car"),
@JsonSubTypes.Type(value = WaterProofPhone.class, name = "water_proof_phone"),
@JsonSubTypes.Type(value = ElectricBicycle.class, name = "electric_bicycle")
})
public abstract class Product {
}
and every subclass is defined like:
@JsonTypeName("flying_car")
public class FlyingCar extends Product {
private double verticalSpeed;
private String name;
}
When I serialize the class below, I would like to not include a product
property in the json:
public class Cart {
private long id;
private LocalDateTime date;
private Product product;
}
Example serializing this configuration:
Product product = new FlyingCar(123.5,"StarShip");
Cart cart = new Cart();
cart.setProduct(product);
String json = objectMapper.writeValueAsString(cart);
Produces this json:
{
"id":..,
"product": { <--- How can I remove this wrapper ?
"flying_car":{
"vertical_speed": 123.5,
"name": "StarShip"
}
}
}
How to simply have a json like this, without the supertype wrapper?
{
"id":..,
"flying_car":{
"vertical_speed": 123.5,
"name": "StarShip"
}
}
I tried the @JsonUnwrapped
on product
but it does not work as expected.
Thanks for your help
CodePudding user response:
As mentioned in the comments, you have to use a custom serializer to implement that.
The following serializer implementation should work as expected.
public class CustomSerializer extends JsonSerializer<Cart> {
@Override
public void serialize(Cart cart, JsonGenerator gen, SerializerProvider serializers) throws IOException {
final Object product = cart.getProduct();
Class<?> responseClass = product.getClass();
JavaType responseJavaType = serializers.constructType(responseClass);
gen.writeStartObject();
gen.writeFieldName(serializers.findTypeSerializer(responseJavaType).getTypeIdResolver().idFromValue(product));
serializers.findValueSerializer(responseClass).serialize(product, gen, serializers);
/* Here you must manually serialize other properties */
gen.writeObjectField("id", cart.getId());
gen.writeEndObject();
}
}
And you need to set this seriliazer for your Cart class :
@JsonSerialize(using = CustomSerializer.class)
public class Cart {
...
}
CodePudding user response:
To complete @Nemanja's answer, I found a simpler solution using @JsonAnyGetter
:
public class Cart {
private long id;
private LocalDateTime date;
@JsonIgnore
private Product product;
@JsonAnyGetter
Map<String, Product> determineProduct(){
if (this.product instanceof FlyingCar){
return Map.of("flying_car", this.product);
}
....other type checking
}
}
It's a bit simpler and we don't have to define a custom serializer