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

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

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

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

更新:

这是我要序列化的类:

 class Student { int age; String firstName; String lastName; double average; int numSubjects // .. more such properties ... } 

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

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

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

 public class EntityCustomSerializationFactory extends CustomSerializerFactory { //ignored fields private static final Set IGNORED_FIELDS = new HashSet( 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 originalWriters = builder.getProperties(); //create actual writers List writers = new ArrayList(); 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); } } } 

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

 objectMapper.setSerializerFactory(new EntityCustomSerializationFactory()); objectMapper.writeValueAsString(new Entity());//response will be without ignored fields 

假设您的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; } } 

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

 public class MyCustomSerializer extends JsonSerializer { @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(); } } } 

然后将其添加到ObjectMapper

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

然后像它一样使用它

 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()); 

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

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

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

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

在@JsonView的帮助下,我们可以决定要序列化的模型类的字段,它们满足最小标准(我们必须定义标准),就像我们可以有一个具有10个属性的核心类,但只有5个属性可以序列化,这对于客户端是必需的只要

只需创建以下类来定义我们的视图:

 public class Views { static class Android{}; static class IOS{}; static class Web{}; } 

带注释的带注释的模型类:

 public class Demo { public Demo() { } @JsonView(Views.IOS.class) private String iosField; @JsonView(Views.Android.class) private String androidField; @JsonView(Views.Web.class) private String webField; // getters/setters ... .. } 

现在我们必须通过简单地从spring扩展HttpMessageConverter类来编写自定义json转换器:

  public class CustomJacksonConverter implements HttpMessageConverter { public CustomJacksonConverter() { super(); //this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView(Views.ClientView.class)); this.delegate.getObjectMapper().configure(MapperFeature.DEFAULT_VIEW_INCLUSION, true); this.delegate.getObjectMapper().setSerializationInclusion(Include.NON_NULL); } // a real message converter that will respond to methods and do the actual work private MappingJackson2HttpMessageConverter delegate = new MappingJackson2HttpMessageConverter(); @Override public boolean canRead(Class clazz, MediaType mediaType) { return delegate.canRead(clazz, mediaType); } @Override public boolean canWrite(Class clazz, MediaType mediaType) { return delegate.canWrite(clazz, mediaType); } @Override public List getSupportedMediaTypes() { return delegate.getSupportedMediaTypes(); } @Override public Object read(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { return delegate.read(clazz, inputMessage); } @Override public void write(Object obj, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { synchronized(this) { String userAgent = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader("userAgent"); if ( userAgent != null ) { switch (userAgent) { case "IOS" : this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView(Views.IOS.class)); break; case "Android" : this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView(Views.Android.class)); break; case "Web" : this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView( Views.Web.class)); break; default: this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView( null )); break; } } else { // reset to default view this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView( null )); } delegate.write(obj, contentType, outputMessage); } } } 

现在需要告诉spring使用这个自定义json转换,只需将它放在dispatcher-servlet.xml中即可

       

这就是你如何决定序列化哪些字段的方法。

感谢名单