在 Spring Data Rest 中使用自定义 json 序列化程序时的不同 JSON 输出 [英] Different JSON output when using custom json serializer in Spring Data Rest
问题描述
基于官方文档 我观察到 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屋!