Diferentes nombres de propiedad JSON durante serialización y deserialización

¿Es posible: tener un campo en la clase, pero diferentes nombres durante la serialización / deserialización en la biblioteca de Jackson?

Por ejemplo, tengo la clase “Coordiantes”.

class Coordinates{ int red; } 

Para la deserialización de JSON, quiero tener un formato como este:

 { "red":12 } 

Pero cuando serialice el objeto, el resultado debería ser como este:

 { "r":12 } 

Intenté implementar esto aplicando la anotación @JsonProperty tanto en getter como en setter (con diferentes valores):

 class Coordiantes{ int red; @JsonProperty("r") public byte getRed() { return red; } @JsonProperty("red") public void setRed(byte red) { this.red = red; } } 

pero tengo una excepción:

org.codehaus.jackson.map.exc.UnrecognizedPropertyException: campo no reconocido “rojo”

Acabo de probar y esto funciona:

 public class Coordinates { byte red; @JsonProperty("r") public byte getR() { return red; } @JsonProperty("red") public void setRed(byte red) { this.red = red; } } 

La idea es que los nombres de los métodos sean diferentes, por lo que jackson lo analiza como campos diferentes, no como un campo.

Aquí está el código de prueba:

 Coordinates c = new Coordinates(); c.setRed((byte) 5); ObjectMapper mapper = new ObjectMapper(); System.out.println("Serialization: " + mapper.writeValueAsString(c)); Coordinates r = mapper.readValue("{\"red\":25}",Coordinates.class); System.out.println("Deserialization: " + r.getR()); 

Resultado:

 Serialization: {"r":5} Deserialization: 25 

Puedes usar @jsonAlias ​​que se introdujo en jackson 2.9.0

Ejemplo:

 public class Info { @JsonAlias({ "r", "red" }) public String r; } 

Me gustaría enlazar dos pares de getters / setters diferentes a una variable:

 class Coordinates{ int red; @JsonProperty("red") public byte getRed() { return red; } public void setRed(byte red) { this.red = red; } @JsonProperty("r") public byte getR() { return red; } public void setR(byte red) { this.red = red; } } 

Puede usar una combinación de @JsonSetter y @JsonGetter para controlar la deserialización y la serialización de su propiedad, respectivamente.

 import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.annotation.JsonGetter; class Coordinates { private int red; //# Used during serialization @JsonGetter("r") public int getRed() { return red; } //# Used during deserialization @JsonSetter("red") public void setRed(int red) { this.red = red; } } 

Esto no era lo que esperaba como solución (aunque es un caso de uso legítimo). Mi requisito era permitir que un cliente con errores existente (una aplicación móvil que ya se lanzó) use nombres alternativos.

La solución radica en proporcionar un método setter separado como este:

 @JsonSetter( "r" ) public void alternateSetRed( byte red ) { this.red = red; } 

Es posible tener un par getter / setter normal. Solo necesita especificar el modo de acceso en @JsonProperty

Aquí hay una prueba unitaria para eso:

 public class JsonPropertyTest { private static class TestJackson { private String color; @JsonProperty(value = "device_color", access = JsonProperty.Access.READ_ONLY) public String getColor() { return color; }; @JsonProperty(value = "color", access = JsonProperty.Access.WRITE_ONLY) public void setColor(String color) { this.color = color; } } @Test public void shouldParseWithAccessModeSpecified() throws Exception { String colorJson = "{\"color\":\"red\"}"; ObjectMapper mapper = new ObjectMapper(); TestJackson colotObject = mapper.readValue(colorJson, TestJackson.class); String ser = mapper.writeValueAsString(colotObject); System.out.println("Serialized colotObject: " + ser); } } 

Obtuve el resultado de la siguiente manera:

 Serialized colotObject: {"device_color":"red"} 

Deben haber incluido esto como una característica, porque ahora establecer una @JsonProperty diferente para un getter y un setter da como resultado exactamente lo que cabría esperar (nombre de propiedad diferente durante la serialización y deserialización para el mismo campo). Jackson versión 2.6.7

Puede escribir una clase de serialización para hacer eso:

símbolo de clase pública

{private String symbol;

  private String name; public String getSymbol() { return symbol; } public void setSymbol(String symbol) { this.symbol = symbol; } public String getName() { return name; } public void setName(String name) { this.name = name; } 

}

la clase pública SymbolJsonSerializer extiende JsonSerializer {

 @Override public void serialize(Symbol symbol, JsonGenerator jgen, SerializerProvider serializers) throws IOException, JsonProcessingException { jgen.writeStartObject(); jgen.writeStringField("symbol", symbol.getSymbol()); //Changed name to full_name as the field name of Json string jgen.writeStringField("full_name", symbol.getName()); jgen.writeEndObject(); } 

}

  ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addSerializer(Symbol.class, new SymbolJsonSerializer()); mapper.registerModule(module); //only convert non-null field, option... mapper.setSerializationInclusion(Include.NON_NULL); String jsonString = mapper.writeValueAsString(symbolList);