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


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

Por ejemplo, tengo la clase "Coordinantes".

class Coordinates{
  int red;
}

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

{
  "red":12
}

Pero cuando voy a serializar el objeto, el resultado debe ser como este:

{
  "r":12
}

Traté de implementar esto aplicando @JsonProperty anotación 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.asignar.exc.UnrecognizedPropertyException: Campo no reconocido"red"

Author: Paul Rooney, 2011-12-19

8 answers

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 deben ser 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
 156
Author: bezmax,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-19 11:26:51

Puedes usar @jsonAlias que se introdujo en jackson 2.9.0

Ejemplo:

public class Info {
  @JsonAlias({ "r", "red" })
  public String r;
}
 15
Author: Asura,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-09 16:40:37

Enlazaría dos pares 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;
    }
}
 15
Author: DRCB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-02 21:27:53

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;
    }
}
 8
Author: Xaero Degreaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-27 17:45:08

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;
}
 4
Author: Andy Talkowski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-20 22:27:04

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

Aquí está la 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 la salida de la siguiente manera:

Serialized colotObject: {"device_color":"red"}
 4
Author: Raman Yelianevich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-01 11:46:16

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

 1
Author: fetta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-16 10:54:18

Puedes escribir una clase serializada para hacer eso:

Símbolo de clase pública

{ símbolo de cadena privada;

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

}

Public class 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);
 0
Author: Vernon Kujyio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-18 06:02:30