Jackson - 自定义序列化程序,仅覆盖特定字段

jef*_*eon 18 java serialization jackson

我知道如何在Jackson中使用自定义序列化程序(通过扩展JsonSerializer),但我希望默认的序列化程序适用于所有字段,除了1个字段,我想使用自定义序列化程序覆盖它.

注释不是一个选项,因为我正在序列化生成的类(来自Thrift).

在编写自定义jackson序列化程序时,如何仅指定要覆盖的某些字段?

更新:

这是我要序列化的类:

class Student {
    int age;
    String firstName;
    String lastName;
    double average;
    int numSubjects

    // .. more such properties ...
}
Run Code Online (Sandbox Code Playgroud)

上面的类有许多特性,其中大多数使用本机类型.我想覆盖自定义序列化程序中的一些属性,让Jackson像往常一样处理其余的属性.例如,我只想将"年龄"字段转换为自定义输出.

Aru*_*hny 13

假设您的Target类是

public class Student {
    int age;
    String firstName;
    String lastName;
    double average;
    int numSubjects;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public double getAverage() {
        return average;
    }

    public void setAverage(double average) {
        this.average = average;
    }

    public int getNumSubjects() {
        return numSubjects;
    }

    public void setNumSubjects(int numSubjects) {
        this.numSubjects = numSubjects;
    }

}
Run Code Online (Sandbox Code Playgroud)

您需要编写自定义序列化程序,如下所示

public class MyCustomSerializer extends JsonSerializer<Student> {

    @Override
    public void serialize(Student value, JsonGenerator jgen,
            SerializerProvider provider) throws IOException,
            JsonProcessingException {
        if (value != null) {
            jgen.writeStartObject();
            jgen.writeStringField("age", "Age: " + value.getAge()); //Here a custom way to render age field is used
            jgen.writeStringField("firstName", value.getFirstName());
            jgen.writeStringField("lastName", value.getLastName());
            jgen.writeNumberField("average", value.getAverage());
            jgen.writeNumberField("numSubjects", value.getNumSubjects());
            //Write other properties
            jgen.writeEndObject();
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

然后将其添加到ObjectMapper

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule("custom",
        Version.unknownVersion());
module.addSerializer(Student.class, new MyCustomSerializer());
mapper.registerModule(module);
Run Code Online (Sandbox Code Playgroud)

那就像使用它一样

Student s = new Student();
s.setAge(2);
s.setAverage(3.4);
s.setFirstName("first");
s.setLastName("last");
s.setNumSubjects(3);

StringWriter sw = new StringWriter();
mapper.writeValue(sw, s);
System.out.println(sw.toString());
Run Code Online (Sandbox Code Playgroud)

它会产生ao/p之类的东西

{"age":"年龄:2","firstName":"first","lastName":"last","average":3.4,"numSubjects":3}


Sta*_*Man 12

仅仅因为你不能修改类并不意味着你不能使用注释:只需使用混合注释.例如,请参阅博客条目(或google了解有关"jackson mixin annotations"的更多内容),了解如何使用此条目.

我特意将杰克逊用于protobuf和thrift生成的类,并且它们工作得非常好.对于早期的Thrift版本,我不得不禁用"is-setters"的发现,Thrift生成的方法是为了查看是否已经明确设置了特定属性,但是其他方法工作正常.

  • 是的,知道选项很好,有些在某些情况下效果更好,在其他情况下则有效. (2认同)

n1c*_*las 6

我遇到了同样的问题,我用CustomSerializerFactory解决了它.

此方法允许您忽略所有对象或特定类型的某些特定字段.

public class EntityCustomSerializationFactory extends CustomSerializerFactory {

    //ignored fields
    private static final Set<String> IGNORED_FIELDS = new HashSet<String>(
            Arrays.asList(
                    "class",
                    "value",
                    "some"
            )
    );


    public EntityCustomSerializationFactory() {
        super();
    }

    public EntityCustomSerializationFactory(Config config) {
        super(config);
    }

    @Override
    protected void processViews(SerializationConfig config, BeanSerializerBuilder builder) {
        super.processViews(config, builder);

        //ignore fields only for concrete class
        //note, that you can avoid or change this check
        if (builder.getBeanDescription().getBeanClass().equals(Entity.class)){
            //get original writer
            List<BeanPropertyWriter> originalWriters = builder.getProperties();

            //create actual writers
            List<BeanPropertyWriter> writers = new ArrayList<BeanPropertyWriter>();

            for (BeanPropertyWriter writer: originalWriters){
                String propName = writer.getName();

                //if it isn't ignored field, add to actual writers list
                if (!IGNORED_FIELDS.contains(propName)){
                    writers.add(writer);
                }
            }

            builder.setProperties(writers);
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

之后您可以使用以下内容:

objectMapper.setSerializerFactory(new EntityCustomSerializationFactory());
objectMapper.writeValueAsString(new Entity());//response will be without ignored fields
Run Code Online (Sandbox Code Playgroud)