在 Spring Data Rest 中使用自定义 json 序列化程序时的不同 JSON 输出 [英] Different JSON output when using custom json serializer in Spring Data Rest

查看:24
本文介绍了在 Spring Data Rest 中使用自定义 json 序列化程序时的不同 JSON 输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基于官方文档 我观察到 json 输出格式略有不同.

After adding a custom Jackson serializer based on the official documenation I've observed a slightly different json output format.

此示例基于 spring-restbucks.

RepositoryRestMvcConfiguration 扩展 org.springsource.restbucks.WebConfiguration 并覆盖 configureJacksonObjectMapper:

Extend org.springsource.restbucks.WebConfiguration from RepositoryRestMvcConfiguration and override configureJacksonObjectMapper:

@Override
protected void configureJacksonObjectMapper(ObjectMapper objectMapper) {
    final SimpleSerializers serializers = new SimpleSerializers();
    serializers.addSerializer(Order.class, new OrderSerializer());
    objectMapper.registerModule(new SimpleModule("CustomSerializerModule"){
        @Override public void setupModule(SetupContext context) {
            context.addSerializers(serializers);
        }
    });
}

创建类org.springsource.restbucks.order.OrderSerializer.为简洁起见,只需将属性 paid 写为 JSON.

Create class org.springsource.restbucks.order.OrderSerializer. For the sake of brevity just write attribute paid as JSON.

public class OrderSerializer extends JsonSerializer<Order> {
    @Override
    public void serialize(Order value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
        jgen.writeStartObject();
        jgen.writeBooleanField("paid", value.isPaid());
        jgen.writeEndObject();
    }
}

在为 http://localhost:8080/orders/1 添加 OrderSerializer json 响应之前看起来像:

Before adding OrderSerializer json response for http://localhost:8080/orders/1 looks like:

{
  "location": "TAKE_AWAY",
  "status": "PAYMENT_EXPECTED",
  "orderedDate": "2014-03-24T15:05:09.988+01:00",
  "items": [
    {
      "name": "Java Chip",
      "quantity": 1,
      "milk": "SEMI",
      "size": "LARGE",
      "price": {
        "currency": "EUR",
        "value": 4.2
      }
    }
  ],
  "_links": {
    ...
  }
}

http://localhost:8080/orders/1 添加 OrderSerializer json 响应后看起来像

After adding OrderSerializer json response for http://localhost:8080/orders/1 looks like

{
  "content": {
    "paid": false
  },
  "_links": {
    ...
  }
}

主要的一点是,payed 的属性被包装到另一个对象内容中,该内容是 org.springframework.hateoas.Resource.我期待没有此属性的响应:

The main pinpoint is that attribute paid is wrapped into another object content which is an attribute of org.springframework.hateoas.Resource. I've expected a response without this attribute:

{
  "paid": false,  
  "_links": {
    ...
  }
}

我查看了 Jackson 代码,发现 UnwrappingBeanSerializer 可能是我正在寻找的解决方案.在查看了如何初始化 UnwrappingBeanSerializer 之后,我认为这个序列化器不应该被子类化以供自定义使用.

I've looked into Jackson code and found that UnwrappingBeanSerializer might be the solution I'm looking for. After looking at how to initialize UnwrappingBeanSerializer I think that this serializer is not meant to be subclassed for custom use.

我想知道在使用自定义序列化程序时这种偏离的 json 格式是 Spring Data Rest 中的正常行为还是错误.任何形式的帮助表示赞赏.

I would like to know whether this deviating json format when using a custom serializer is a normal behaviour or a bug in Spring Data Rest. Any kind of help is appreciated.

推荐答案

这不是 Spring Data Rest 的错误,它实际上是 Jackson Serializer 的正常行为.每当您将 @JsonUnwrapped Annotation(如 Resource content 字段所做的)与自定义序列化程序一起使用时,Jackson Serializer 将明确写入字段名称(在本例中为内容).有关更多详细信息,请查看 UnwrappingBeanPropertyWriter.无论如何,您使用 UnwrappingBeanSerializer 一直在正确的轨道上,但设置与通常的 Serializer 注册略有不同.以下示例应该可以解决您的问题:

This is not a bug of Spring Data Rest it is actually the normal behaviour of the Jackson Serializer. Whenever you use the @JsonUnwrapped Annotation (as the Resource content field does) together with a custom Serializer the Jackson Serializer will explicitly write the field name (in this case content). Have a look at the UnwrappingBeanPropertyWriter for more details. Anyhow you have been on the right track using the UnwrappingBeanSerializer but the setup is slightly different then the usual Serializer registration. The following example should fix your problem:

@Override
protected void configureJacksonObjectMapper(ObjectMapper objectMapper) {
    mapper.registerModule(new Module() {
        @Override
        public String getModuleName() {
            return "my.module";
        }

        @Override
        public Version version() {
            return Version.unknownVersion();
        }

        @Override
        public void setupModule(SetupContext context) {

            context.addBeanSerializerModifier(new BeanSerializerModifier() {
                @Override
                public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
                    if(beanDesc.getBeanClass().equals(Order.class)) {
                        return new UnwrappingOrderSerializer((BeanSerializerBase) serializer, NameTransformer.NOP);
                    }
                    return serializer;
                }
            });
        }
    });
}

public class UnwrappingOrderSerializer extends UnwrappingBeanSerializer {
    public UnwrappingBarSerializer(BeanSerializerBase src, NameTransformer transformer) {
        super(src, transformer);
    }

    @Override
    public JsonSerializer<Object> unwrappingSerializer(NameTransformer transformer) {
        return new UnwrappingOrderSerializer(this, transformer);
    }

    @Override
    protected void serializeFields(Object bean, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
        Order order = (Order) bean;
        jgen.writeStringField("paid", order.isPaid();
    }

    @Override
    public boolean isUnwrappingSerializer() {
        return true;
    }
}

这篇关于在 Spring Data Rest 中使用自定义 json 序列化程序时的不同 JSON 输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆