添加自定义后 Jackson
基于的序列化器 官方文件 我观察到一种略有不同的json输出格式。
这个例子是基于fork的 弹簧restbucks。
延伸 org.springsource.restbucks.WebConfiguration
从 RepositoryRestMvcConfiguration
和覆盖 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。
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();
}
}
在添加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": {
...
}
}
添加OrderSerializer json响应后 http://localhost:8080/orders/1
好像
{
"content": {
"paid": false
},
"_links": {
...
}
}
主要的观点是,付费属性被包装到另一个对象内容中,该内容是属性 org.springframework.hateoas.Resource。我期望没有这个属性的响应:
{
"paid": false,
"_links": {
...
}
}
我查看了杰克逊代码并发现了这一点 UnwrappingBeanSerializer 可能是我正在寻找的解决方案。
在查看如何初始化UnwrappingBeanSerializer之后,我认为这个序列化程序并不是为了自定义使用而进行子类化。
我想知道在使用自定义序列化程序时这种偏离json格式是正常行为还是Spring Data Rest中的错误。任何形式的帮助表示赞赏。
这不是Spring Data Rest的错误,它实际上是Jackson Serializer的正常行为。每当您使用@JsonUnwrapped Annotation(与资源内容字段一起使用)和自定义序列化程序时,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;
}
}
这不是Spring Data Rest的错误,它实际上是Jackson Serializer的正常行为。每当您使用@JsonUnwrapped Annotation(与资源内容字段一起使用)和自定义序列化程序时,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;
}
}
投影是一种解决方案,并且超越了一种方法 JsonSerializer
是另一个:
@Override
public boolean isUnwrappingSerializer() {
return true;
}
然后你应该能够省略对象的开始和结束。
找到我的博客文章 这里。
除了上面的andreast00解决方案 - 确保也覆盖其他构造函数和...方法,或者它可能在后台创建默认的UnwrappingBeanSerializer并忽略您的自定义序列化代码:
public UnwrappingOrderSerializer(UnwrappingBeanSerializer src, ObjectIdWriter objectIdWriter) {
super(src, objectIdWriter);
}
public UnwrappingOrderSerializer(UnwrappingBeanSerializer src, ObjectIdWriter objectIdWriter, Object filterId) {
super(src, objectIdWriter, filterId);
}
public UnwrappingOrderSerializer(UnwrappingBeanSerializer src, Set<String> toIgnore) {
super(src, toIgnore);
}
@Override
public BeanSerializerBase withObjectIdWriter(ObjectIdWriter objectIdWriter) {
return new UnwrappingOrderSerializer(this, objectIdWriter);
}
@Override
public BeanSerializerBase withFilterId(Object filterId) {
return new UnwrappingOrderSerializer(this, this._objectIdWriter, filterId);
}
@Override
protected BeanSerializerBase withIgnorals(Set<String> toIgnore) {
return new UnwrappingOrderSerializer(this, toIgnore);
}
此外,根据序列化是从@JsonUnwrapped对象发生,作为数组中的对象还是作为单个对象,jsonGenerater.writeStartObject可能需要在天气对象已经启动或未启动时进行调用。我用了:
boolean writeStartEnd = !jsonGenerator.getOutputContext().inObject()
|| jsonGenerator.getOutputContext().getCurrentName() != null;
if (writeStartEnd) jsonGenerator.writeStartObject(entity);
...serialisation code...
if (writeStartEnd) {
jsonGenerator.writeEndObject();
}
我有同样的问题。我没有使用Jackson Serializer,而是使用了@Projecton并定制了我的输出。你可以找到一个参考 这里