Unterschiedliche Namen der JSON-Eigenschaft während der Serialisierung und Deserialisierung

149

Ist es möglich, ein Feld in der Klasse zu haben, aber während der Serialisierung / Deserialisierung in der Jackson-Bibliothek unterschiedliche Namen dafür?

Zum Beispiel habe ich Klasse "Coordiantes".

class Coordinates{
  int red;
}

Für die Deserialisierung von JSON möchten Sie ein Format wie das folgende haben:

{
  "red":12
}

Aber wenn ich das Objekt serialisieren werde, sollte das Ergebnis wie folgt aussehen:

{
  "r":12
}

Ich habe versucht, dies zu implementieren, indem ich @JsonPropertyAnnotation sowohl auf Getter als auch auf Setter (mit unterschiedlichen Werten) angewendet habe:

class Coordiantes{
    int red;

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

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

aber ich habe eine Ausnahme:

org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Nicht erkanntes Feld "rot"

kiRach
quelle

Antworten:

203

Gerade getestet und das funktioniert:

public class Coordinates {
    byte red;

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

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

Die Idee ist, dass Methodennamen unterschiedlich sein sollten, also analysiert Jackson sie als verschiedene Felder, nicht als ein Feld.

Hier ist Testcode:

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

Ergebnis:

Serialization: {"r":5}
Deserialization: 25
bezmax
quelle
ist das auch mit jaxb möglich?
Cui Pengfei 崔鹏飞
38

Sie können verwenden, @jsonAliaswas in Jackson 2.9.0 eingeführt wurde

Beispiel:

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

Dies wird rwährend der Serialisierung verwendet, ermöglicht jedoch redals Alias ​​während der Deserialisierung. Dies ermöglicht rjedoch auch eine Deserialisierung.

Asura
quelle
8
In der Dokumentation zu @JsonAlias ​​wird dies ausdrücklich angegeben has no effect during serialization where primary name is always used. Dies ist nicht das, was das OP will.
Xaero Degreaz
3
@XaeroDegreaz Ich denke, @Asura bedeutet, dass Sie rals Primärname verwenden können , aber redfür den @JsonAlias, der es ermöglicht, ihn zu serialisieren r, aber redbei der Deserialisierung erkannt wird. Das Kommentieren mit @JsonProperty("r")und @JsonAlias("red")sollte zusätzlich für das gegebene Problem gut funktionieren.
Jerrot
16

Sie können eine Kombination aus @JsonSetter und @JsonGetter verwenden , um die Deserialisierung bzw. Serialisierung Ihrer Eigenschaft zu steuern. Auf diese Weise können Sie auch standardisierte Getter- und Setter-Methodennamen beibehalten, die Ihrem tatsächlichen Feldnamen entsprechen.

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

Ich würde zwei verschiedene Getter / Setter-Paare an eine Variable binden:

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;
    }
}
DRCB
quelle
13
In diesem Fall erhalten wir während der Serialisierung beide Eigenschaften: "r" und "red" mit denselben Werten.
KiRach
6

Es ist möglich, ein normales Getter / Setter-Paar zu haben. Sie müssen nur den Zugriffsmodus in angeben@JsonProperty

Hier ist ein Unit-Test dafür:

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

Ich habe die Ausgabe wie folgt erhalten:

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

Dies war nicht das, was ich als Lösung erwartet hatte (obwohl es ein legitimer Anwendungsfall ist). Meine Anforderung bestand darin, einem vorhandenen fehlerhaften Client (einer bereits veröffentlichten mobilen App) die Verwendung alternativer Namen zu ermöglichen.

Die Lösung besteht darin, eine separate Setter-Methode wie die folgende bereitzustellen:

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

Ich weiß, dass es eine alte Frage ist, aber für mich hat es funktioniert, als ich herausfand, dass es mit der Gson-Bibliothek in Konflikt steht. Wenn Sie also Gson verwenden, verwenden Sie @SerializedName("name")anstelle der @JsonProperty("name")Hoffnung, dass dies hilft

Khaled
quelle
2

Das @JsonAliasKommentieren, mit dem Jackson 2.9+ eingeführt wurde, ohne zu erwähnen, dass @JsonPropertydas Element mit mehr als einem Alias ​​(verschiedene Namen für eine json-Eigenschaft) deserialisiert werden soll, funktioniert einwandfrei .

Ich habe com.fasterxml.jackson.annotation.JsonAliasfür die Paketkonsistenz mit com.fasterxml.jackson.databind.ObjectMapperfür meinen Anwendungsfall verwendet.

Zum Beispiel:

@Data
@Builder
public class Chair {

    @JsonAlias({"woodenChair", "steelChair"})
    private String entityType;

}


@Test
public void test1() {

   String str1 = "{\"woodenChair\":\"chair made of wood\"}";
   System.out.println( mapper.readValue(str1, Chair.class));
   String str2 = "{\"steelChair\":\"chair made of steel\"}";
   System.out.println( mapper.readValue(str2, Chair.class));

}

funktioniert einfach gut.

Arnab Das
quelle
1

Sie müssen dies als Feature aufgenommen haben, da das Festlegen eines anderen @JsonPropertyfür einen Getter und einen Setter genau das ergibt, was Sie erwarten würden (unterschiedlicher Eigenschaftsname während der Serialisierung und Deserialisierung für dasselbe Feld). Jackson Version 2.6.7

Fetta
quelle
0

Sie können dazu eine Serialisierungsklasse schreiben:

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);
Vernon Kujyio
quelle