Jackson:如何在不修改 POJO 的情况下将自定义属性添加到 JSON

我正在为我的应用程序开发一个 REST 接口,使用 Jackson 将我的 POJO 域对象序列化为 JSON 表示形式。我想为某些类型自定义序列化,以向POJO中不存在的JSON表示形式添加其他属性(例如,添加一些元数据,参考数据等)。我知道如何编写我自己的,但是在这种情况下,我需要为对象的每个属性显式调用方法,而我只需要添加一个额外的属性。换句话说,我希望能够写出这样的东西:JsonSerializerJsonGenerator.writeXXX(..)

@Override
public void serialize(TaxonomyNode value, JsonGenerator jgen, SerializerProvider provider) {
    jgen.writeStartObject();
    jgen.writeAllFields(value); // <-- The method I'd like to have
    jgen.writeObjectField("my_extra_field", "some data");
    jgen.writeEndObject();
}

或者(甚至更好)以某种方式在调用之前拦截序列化,例如:jgen.writeEndObject()

@Override void beforeEndObject(....) {
    jgen.writeObjectField("my_extra_field", "some data");
}

我以为我可以扩展和覆盖它的方法,但它是声明的,而且我找不到一个简单的方法来创建一个新的实例,而不向它提供所有类型元数据细节,实际上复制了Jackson的很大一部分。所以我放弃了这样做。BeanSerializerserialize(..)finalBeanSerializer

我的问题是 - 如何自定义Jackson的序列化,以便为特定的POJO的JSON输出添加其他内容,而无需引入太多的样板代码并尽可能多地重用默认的Jackson行为。


答案 1

Jackson 2.5 引入了@JsonAppend注释,可用于在序列化期间添加“虚拟”属性。它可以与mixin功能一起使用,以避免修改原始的POJO。

下面的示例在序列化过程中添加一个属性:ApprovalState

@JsonAppend(
    attrs = {
        @JsonAppend.Attr(value = "ApprovalState")
    }
)
public static class ApprovalMixin {}

使用注册 mixin :ObjectMapper

mapper.addMixIn(POJO.class, ApprovalMixin.class);

使用 在序列化期间设置属性:ObjectWriter

ObjectWriter writer = mapper.writerFor(POJO.class)
                          .withAttribute("ApprovalState", "Pending");

使用编写器进行序列化会将该字段添加到输出中。ApprovalState


答案 2

由于(我认为)Jackson 1.7,你可以用a和扩展来做到这一点。我已经用Jackson 2.0.4测试了下面的示例。BeanSerializerModifierBeanSerializerBase

import java.io.IOException;

import org.junit.Test;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.databind.ser.impl.ObjectIdWriter;
import com.fasterxml.jackson.databind.ser.std.BeanSerializerBase;


public class JacksonSerializeWithExtraField {

    @Test
    public void testAddExtraField() throws Exception
    {
        ObjectMapper mapper = new ObjectMapper();

        mapper.registerModule(new SimpleModule() {

            public void setupModule(SetupContext context) {
                super.setupModule(context);

                context.addBeanSerializerModifier(new BeanSerializerModifier() {

                    public JsonSerializer<?> modifySerializer(
                            SerializationConfig config,
                            BeanDescription beanDesc,
                            JsonSerializer<?> serializer) {
                        if (serializer instanceof BeanSerializerBase) { 
                              return new ExtraFieldSerializer(
                                   (BeanSerializerBase) serializer);
                        } 
                        return serializer; 

                    }                   
                });
            }           
        });

        mapper.writeValue(System.out, new MyClass());       
        //prints {"classField":"classFieldValue","extraField":"extraFieldValue"}
    }


    class MyClass {

        private String classField = "classFieldValue";

        public String getClassField() { 
            return classField; 
        }
        public void setClassField(String classField) { 
            this.classField = classField; 
        }
    }


    class ExtraFieldSerializer extends BeanSerializerBase {

        ExtraFieldSerializer(BeanSerializerBase source) {
            super(source);
        }

        ExtraFieldSerializer(ExtraFieldSerializer source, 
                ObjectIdWriter objectIdWriter) {
            super(source, objectIdWriter);
        }

        ExtraFieldSerializer(ExtraFieldSerializer source, 
                String[] toIgnore) {
            super(source, toIgnore);
        }

        protected BeanSerializerBase withObjectIdWriter(
                ObjectIdWriter objectIdWriter) {
            return new ExtraFieldSerializer(this, objectIdWriter);
        }

        protected BeanSerializerBase withIgnorals(String[] toIgnore) {
            return new ExtraFieldSerializer(this, toIgnore);
        }

        public void serialize(Object bean, JsonGenerator jgen,
                SerializerProvider provider) throws IOException,
                JsonGenerationException {           
            jgen.writeStartObject();                        
            serializeFields(bean, jgen, provider);
            jgen.writeStringField("extraField", "extraFieldValue"); 
            jgen.writeEndObject();
        }
    }
}