【问题标题】:Using @JsonUnwrapped and having a custom Serializer (StdSerializer<T>)使用 @JsonUnwrapped 并拥有一个自定义序列化器 (StdSerializer<T>)
【发布时间】:2021-04-02 03:23:05
【问题描述】:

我需要为我的一个实体“付款”编写一个自定义序列化程序,我必须通过扩展 StdSerializer 来实现它:

class Payment {
}

class PaymentSerializer extends StdSerializer<Payment> {

    public PaymentSerializer() {
        this(null);
    }

    public PaymentSerializer(Class<Payment> t) {
        super(t);
    }

    @Override
    public void serialize(Payment value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        // some logics
    }

}

由于我使用的是 Spring,所以我注册了这个 Serializer,以便 Spring 可以识别它:

@Bean
public Jackson2ObjectMapperBuilder serializersObjectMapperBuilder() {
    SimpleModule module = new SimpleModule();
    module.addSerializer(Payment.class, applicationContext.getBean(PaymentSerializer.class));
    return new Jackson2ObjectMapperBuilder().modules(module);
}

现在我有一个控制器可以将数据返回给客户端,它使用这个序列化器没有任何问题:

@RestController
@RequestMapping("/payment")
class PaymentController {

    @GetMapping
    public List<Payment> getAll() {
        return Arrays.asList(new Payment());
    }

}

从现在开始,我的序列化器工作正常,一切都很好。

问题出在另一个实体“订单”上,该实体将支付作为@JsonUnwrapped 的属性:

class Order {

    @JsonUnwrapped
    private Payment payment;

}

我需要解开Order 中的Payment,并且我想使用相同的PaymentSerializer,但问题是当我使用这个自定义序列化器时,@JsonUnwrapped 注释将被忽略输出将是这样的:

{
  "payment": {
    .....
  }
}

正如我所提到的,我想消除“付款”字段并打开它。 我知道要为自定义序列化器模拟@JsonUnwrapped,我需要扩展UnwrappingBeanSerializer 类,但正如我一开始提到的,我也需要标准序列化器。

更改我的实体模型不是我的选择。

有没有办法做到这一点?

我使用Spring Boot 2.1.3.RELEASE,我相信它使用Jackson 2.9

【问题讨论】:

    标签: spring-boot jackson jackson2 jackson-modules


    【解决方案1】:

    我提出以下解决问题的方法: 我们可以在单个自定义序列化器中组合两个StdSerializer。

    @Component
    class PaymentSerializer extends StdSerializer<Payment> {
    
        private final JsonSerializer<Payment> delegate = new UnwrappingPaymentSerializer(NameTransformer.NOP);
    
        public PaymentSerializer() {
            this(null);
        }
    
        public PaymentSerializer(Class<Payment> t) {
            super(t);
        }
    
        @Override
        public void serialize(Payment value, JsonGenerator generator, SerializerProvider provider) throws IOException {
            generator.writeStartObject();
            this.delegate.serialize(value, generator, provider);
            generator.writeEndObject();
        }
    
        @Override
        public JsonSerializer<Payment> unwrappingSerializer(final NameTransformer nameTransformer) {
            return new UnwrappingPaymentSerializer(nameTransformer);
        }
    
    }
    

    然后展开:

    public class UnwrappingPaymentSerializer extends JsonSerializer<Payment> {
    
        private NameTransformer transformer;
    
        public UnwrappingPaymentSerializer(NameTransformer transformer) {
            this.transformer = transformer;
        }
    
        @Override
        public void serialize(Payment value, JsonGenerator generator, SerializerProvider provider) throws IOException {
            // some logics
        }
    
        @Override
        public boolean isUnwrappingSerializer() {
            return true;
        }
    }
    

    因此,您有一个用于序列化和展开的序列化程序。 更多详情见:https://michael-simons.github.io/simple-meetup/unwrapping-custom-jackson-serializer

    如果解决方案不适用,请告诉我,我会根据项目要求尝试提出其他方式。

    【讨论】:

    • 感谢您的回答,对于标准的 PaymentSerializer(而不是展开的),我处理了一些关于支付值的逻辑,然后将序列化委托给已注册的 ObjectMapper:myObjectMapper.getSerializerProviderInstance().defaultSerializeValue(value, gen); 现在我想UnwrappingPaymentSerializer 也一样,是否可以使用 ObjectMapper 来展开对象的序列化?请检查以下问题:stackoverflow.com/questions/65741099/…
    • 我认为在Serializers 内部使用ObjectMapper 不是一个好主意,因为ObjectMapper 就像Serializers 和Deserializers 的注册表,这会在Jackson 组件之间产生无限循环。关于我的解决方案:这两个类是相互关联的,并且通过默认的 JsonUnwrapped 注释将起作用,我测试过,没有额外的配置,除了你的代码 module.addSerializer(Payment.class ...,就像你已经完成的那样。
    • 因为我已经注册了默认的ObjectMapper,所以不会有无限循环。问题是如何从ObjectMapper 访问默认展开序列化程序,例如:myObjectMapper...unwrappingSerializer(NameTransformer.NOP).serialize(value, gen, serializers) 如何从ObjectMapper 调用/访问这个默认展开序列化程序
    • @DanielSmith 我没有找到从ObjectMapper 获取unwrappingSerializer 的方法,无论如何,在两种解决方案中,您应该创建两个类,其中包含两个用于序列化和展开的逻辑位置。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-09
    • 2021-03-03
    相关资源
    最近更新 更多