web-dev-qa-db-fra.com

Différents noms de propriété JSON lors de la sérialisation et de la désérialisation

Est-il possible: d'avoir un champ dans la classe, mais des noms différents pour celui-ci lors de la sérialisation/désérialisation dans la bibliothèque de Jackson?

Par exemple, j'ai la classe "Coordiantes".

class Coordinates{
  int red;
}

Pour la désérialisation à partir de JSON, vous souhaitez que le format soit le suivant:

{
  "red":12
}

Mais quand je vais sérialiser un objet, le résultat devrait être comme celui-ci:

{
  "r":12
}

J'ai essayé d'implémenter cela en appliquant l'annotation @JsonProperty à la fois sur le getter et le setter (avec des valeurs différentes):

class Coordiantes{
    int red;

    @JsonProperty("r")
    public byte getRed() {
      return red;
    }

    @JsonProperty("red")
    public void setRed(byte red) {
      this.red = red;
    }
}

mais j'ai eu une exception:

org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Champ non reconnu "rouge"

131
kiRach

Vient de tester et cela fonctionne:

public class Coordinates {
    byte red;

    @JsonProperty("r")
    public byte getR() {
      return red;
    }

    @JsonProperty("red")
    public void setRed(byte red) {
      this.red = red;
    }
}

L'idée est que les noms de méthodes doivent être différents, afin que Jackson les analyse comme des champs différents et non comme un seul champ.

Voici le code de test:

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

Résultat:

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

Vous pouvez utiliser @jsonAlias ​​qui a été introduit dans jackson 2.9.0

Exemple:

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

Je voudrais lier deux paires différentes de getters/setters à une 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
DRCB

Vous pouvez utiliser une combinaison de @ JsonSetter et @ JsonGetter pour contrôler la désérialisation et la sérialisation de votre propriété, respectivement. Cela vous permettra également de conserver des noms de méthodes getter et setter standardisés qui correspondent à votre nom de champ actuel.

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;
    }
}
11
Xaero Degreaz

Ce n'était pas ce à quoi je m'attendais comme solution (bien que ce soit un cas d'utilisation légitime). Mon exigence était d'autoriser un client buggy existant (une application mobile déjà publiée) à utiliser d'autres noms.

La solution consiste à fournir une méthode de définition distincte comme celle-ci:

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

Il est possible d'avoir une paire de getter/setter normale. Il vous suffit de spécifier le mode d'accès dans @JsonProperty

Voici le test unitaire pour cela:

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

J'ai eu la sortie comme suit:

Serialized colotObject: {"device_color":"red"}
5
Raman Yelianevich

Ils doivent l'avoir incluse en tant que fonctionnalité, car la définition d'un @JsonProperty différent pour un getter et un setter donne exactement ce que vous attendez (nom de propriété différent lors de la sérialisation et de la désérialisation pour le même champ). Jackson version 2.6.7

1
fetta

Je sais que c’est une vieille question, mais pour moi j’ai eu du succès quand j’ai découvert que c’était en conflit avec la bibliothèque Gson, donc si vous utilisez Gson, utilisez @SerializedName("name") au lieu de @JsonProperty("name") espérons que cela aide

0
Khaled

Vous pouvez écrire une classe sérialiser pour le faire:

public class Symbol

{
     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;
    }
}
public class SymbolJsonSerializer extends JsonSerializer<Symbol> {

    @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
Vernon Kujyio