Serialización personalizada Jackson JSON para ciertos campos

¿Hay alguna manera de usar Jackson JSON Processor para hacer una serialización personalizada a nivel de campo? Por ejemplo, me gustaría tener la clase

public class Person { public String name; public int age; public int favoriteNumber; } 

serializado al siguiente JSON:

 { "name": "Joe", "age": 25, "favoriteNumber": "123" } 

Tenga en cuenta que age = 25 está codificado como un número, mientras que favoriteNumber = 123 está codificado como una cadena . Fuera de la caja, Jackson llama a un número. En este caso, quiero que favoriteNumber se codifique como una cadena.

Puede implementar un serializador personalizado de la siguiente manera:

 public class Person { public String name; public int age; @JsonSerialize(using = IntToStringSerializer.class, as=String.class) public int favoriteNumber: } public class IntToStringSerializer extends JsonSerializer { @Override public void serialize(Integer tmpInt, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException { jsonGenerator.writeObject(tmpInt.toString()); } } 

Java debe manejar el autoboxing de int a Integer por usted.

Jackson-databind (al menos 2.1.3) proporciona ToStringSerializer especial ( com.fasterxml.jackson.databind.ser.std.ToStringSerializer )

Ejemplo:

 public class Person { public String name; public int age; @JsonSerialize(using = ToStringSerializer.class) public int favoriteNumber: } 

Agregue un @JsonProperty anotado @JsonProperty , que devuelve un String , para el campo favoriteNumber :

 public class Person { public String name; public int age; private int favoriteNumber; public Person(String name, int age, int favoriteNumber) { this.name = name; this.age = age; this.favoriteNumber = favoriteNumber; } @JsonProperty public String getFavoriteNumber() { return String.valueOf(favoriteNumber); } public static void main(String... args) throws Exception { Person p = new Person("Joe", 25, 123); ObjectMapper mapper = new ObjectMapper(); System.out.println(mapper.writeValueAsString(p)); // {"name":"Joe","age":25,"favoriteNumber":"123"} } } 

jackson-annotations proporciona @JsonFormat que puede manejar muchas personalizaciones sin la necesidad de escribir el serializador personalizado.

Por ejemplo, al solicitar una forma STRING para un campo con tipo numérico, se generará el valor numérico como cadena

 public class Person { public String name; public int age; @JsonFormat(shape = JsonFormat.Shape.STRING) public int favoriteNumber; } 

dará como resultado la salida deseada

 {"name":"Joe","age":25,"favoriteNumber":"123"} 

con la ayuda de @JsonView podemos decidir campos de clases de modelos para serializar que satisfagan los criterios mínimos (tenemos que definir los criterios) como que podemos tener una clase central con 10 propiedades, pero solo se pueden serializar 5 propiedades que son necesarias para el cliente solamente

Defina nuestras Vistas simplemente creando la siguiente clase:

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

Clase modelo anotada con vistas:

 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 ... .. } 

Ahora tenemos que escribir el convertidor json personalizado simplemente extendiendo la clase HttpMessageConverter desde la spring como:

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

Ahora hay que decirle a la spring que use esta conversión JSON personalizada simplemente colocando esto en dispatcher-servlet.xml

       

Así es como podrá decidir qué campos se serializarán.