在Spring Data Rest中使用自定义json序列化程序时输出不同的JSON

Kam*_*kol 12 jackson spring-data-rest spring-hateoas

Jackson根据官方文档添加自定义序列化程序后,我观察到了略微不同的json输出格式.

这个例子是基于弹簧垫的叉子.

扩展org.springsource.restbucks.WebConfigurationRepositoryRestMvcConfiguration并重写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);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

创建类org.springsource.restbucks.order.OrderSerializer.为简洁起见,只需将属性写paid为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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

{
  "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": {
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

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

{
  "content": {
    "paid": false
  },
  "_links": {
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

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

{
  "paid": false,  
  "_links": {
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

小智 8

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

@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;
    }
}
Run Code Online (Sandbox Code Playgroud)