jsonproperty - json annotation java
Serialización personalizada Jackson JSON para ciertos campos (5)
¿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.
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-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:
}
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<Integer> {
@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.
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 primavera como:
public class CustomJacksonConverter implements HttpMessageConverter<Object>
{
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<MediaType> getSupportedMediaTypes() {
return delegate.getSupportedMediaTypes();
}
@Override
public Object read(Class<? extends Object> 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 primavera que use esta conversión JSON personalizada simplemente colocando esto en dispatcher-servlet.xml
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean id="jsonConverter" class="com.mactores.org.CustomJacksonConverter" >
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
Así es como podrá decidir qué campos se serializarán.
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"}