杰克逊多态性序列化:如何删除超级类型的属性包装器?

发布于 2025-02-12 01:37:35 字数 1408 浏览 1 评论 0原文

我有这种情况:

@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 {
}

每个子类的定义都如下:

@JsonTypeName("flying_car")
public class FlyingCar extends Product {
     private double verticalSpeed; 
     private String name;
}

当我序列化下面的类时,我想在JSON中不包含product属性:

public class Cart {
   private long id;
   private LocalDateTime date;
   private Product product;
}

示例序列化此配置:

Product product = new FlyingCar(123.5,"StarShip");
Cart cart = new Cart();
cart.setProduct(product);

String json = objectMapper.writeValueAsString(cart);

生成此json:

{
  "id":..,
  "product": { <--- How can I remove this wrapper ?
    "flying_car":{
      "vertical_speed": 123.5,
      "name": "StarShip"
    }
  }
}

如何只需这样的JSON,没有超级型包装器?

{
  "id":..,
  "flying_car":{
      "vertical_speed": 123.5,
      "name": "StarShip"
   }
}

我尝试了@jsonunwrapped product,但它无法正常工作。

感谢您的帮助

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

时光无声 2025-02-19 01:37:35

如评论中所述,您必须使用自定义序列化器来实现它。

以下序列化器实现应按预期工作。

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();
    }


}

而且您需要为您的购物车课程设置此序列利亚:

@JsonSerialize(using = CustomSerializer.class)
public class Cart {
...

}

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 {
...

}
挥剑断情 2025-02-19 01:37:35

要完成 @nemanja的答案,我使用@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
  }
}

这更简单,我们不必定义自定义序列化器

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

能否归途做我良人 2025-02-19 01:37:35

有确切的问题。使用了 @akuma8的@jsonanygetter的更清洁的更新。将@jsontypename放在多态类上,并在Getter中阅读以减少代码维护。

@JsonAnyGetter
public Map<String, Product> determineProduct() {
    JsonTypeName[] typeName = this.product.getClass().getDeclaredAnnotationsByType(JsonTypeName.class);
    if (typeName.length > 0) {
        return ImmutableMap.of(typeName[0].value(), this.product);
    }
    return Collections.emptyMap();
}

Had the exact problem. Used a slightly cleaner update to @akuma8's @JsonAnyGetter. Put @JsonTypeName on your polymorphic classes and read it in the getter for less code maintenance.

@JsonAnyGetter
public Map<String, Product> determineProduct() {
    JsonTypeName[] typeName = this.product.getClass().getDeclaredAnnotationsByType(JsonTypeName.class);
    if (typeName.length > 0) {
        return ImmutableMap.of(typeName[0].value(), this.product);
    }
    return Collections.emptyMap();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文