Serileştirme ve seriyi kaldırma sırasında JSON özelliğinin farklı adları


160

Mümkün mü: sınıfta bir alana sahip olmak, ancak Jackson kütüphanesinde serileştirme / serileştirmeden çıkarma sırasında bunun için farklı isimler olması mümkün mü?

Örneğin, "Coordiantes" sınıfım var.

class Coordinates{
  int red;
}

JSON'dan seriyi kaldırma için aşağıdaki gibi bir biçime sahip olmak istiyorum:

{
  "red":12
}

Ama nesneyi serileştirdiğimde, sonuç şöyle olmalı:

{
  "r":12
}

Bunu @JsonPropertyhem alıcıya hem de ayarlayıcıya (farklı değerlerle) açıklama uygulayarak uygulamaya çalıştım :

class Coordiantes{
    int red;

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

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

ama bir istisnam var:

org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Tanınmayan alan "kırmızı"

Yanıtlar:


211

Sadece test edildi ve bu işe yarıyor:

public class Coordinates {
    byte red;

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

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

Buradaki fikir, yöntem adlarının farklı olması gerektiğidir, bu nedenle Jackson bunu tek bir alan olarak değil, farklı alanlar olarak ayrıştırır.

İşte test kodu:

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

Sonuç:

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

jaxb ile aynı şey mümkün mü?
Cui Pengfei 崔鹏飞

43

Sen kullanabilirsiniz @jsonAliasjackson 2.9.0 tanıtılan var olan

Misal:

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

Bu, rserileştirme sırasında kullanılır, ancak redseriyi kaldırma sırasında bir takma ad olarak izin verir . Yine rde bu, seri durumunun kaldırılmasına da izin verir .


9
@JsonAlias için dokümantasyon açıkça bunun belirtiyor has no effect during serialization where primary name is always used. OP'nin istediği bu değil.
Xaero Degreaz

4
@XaeroDegreaz Sanırım @Asura, rbirincil ad olarak kullanabileceğiniz anlamına geliyor, ancak redbu @JsonAlias, onu serileştirmeye izin veren r, ancak redseriyi kaldırmada tanınır. İle @JsonProperty("r")ve ek olarak açıklama eklemek @JsonAlias("red")verilen sorun için iyi çalışacaktır.
Jerrot

17

Sen bir arada kullanabilirsiniz @JsonSetter ve @JsonGetter sırasıyla mülkünüzün deserialization ve seri kontrol etmek. Bu ayrıca, gerçek alan adınıza karşılık gelen standartlaştırılmış alıcı ve ayarlayıcı yöntem adlarını tutmanıza da olanak tanır.

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

15

İki farklı alıcı / ayarlayıcı çiftini bir değişkene bağlardım:

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

13
Ancak bu durumda, serileştirme sırasında her iki özelliği de elde edeceğiz: "r" ve "kırmızı", aynı değerlerle.
kiRach

@JsonIgnore, işlenmesini istemediğiniz yöntemler bu sorunu çözecektir
Stephan

Günümüzde daha uygun ek açıklamalar var: @JsonGetterve @JsonSetter. Böylece, serileştiricinin nasıl davranacağı tam olarak ayarlanabilir.
DRCB

7

Normal alıcı / ayarlayıcı çiftine sahip olmak mümkündür. Erişim modunu belirlemeniz yeterlidir.@JsonProperty

İşte bunun için birim testi:

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

Çıkışı aşağıdaki gibi aldım:

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

Bu aslında doğru cevap olmalı
IQbrod

6

Çözüm olarak beklediğim şey bu değildi (meşru bir kullanım durumu olsa da). Benim gereksinimim, mevcut bir buggy istemcisinin (zaten piyasaya sürülen bir mobil uygulama) alternatif isimler kullanmasına izin vermekti.

Çözüm, aşağıdaki gibi ayrı bir ayarlayıcı yöntem sağlamakta yatıyor:

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

3

Birden fazla takma adla (bir json özelliği için farklı adlar) seri durumdan çıkarılacak öğeye @JsonAliasdeğinmeden, Jackson 2.9+ ile tanıtıldığı açıklama @JsonPropertyiyi çalışıyor.

Kullandığım com.fasterxml.jackson.annotation.JsonAliasile paket tutarlılığı için com.fasterxml.jackson.databind.ObjectMapperbenim bir kullanım örneği için.

Örneğin:

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

}

sadece iyi çalışıyor.


2

Bunun eski bir soru olduğunu biliyorum ama benim için Gson kitaplığıyla çeliştiğini anladığımda çalıştırdım, bu nedenle Gson kullanıyorsanız, ummak @SerializedName("name")yerine bunun @JsonProperty("name")yardımcı olacağını umuyorum


1

Bunu bir özellik olarak eklemiş olmalılar, çünkü şimdi @JsonPropertybir alıcı ve ayarlayıcı için farklı bir ayar ayarlamak , tam olarak beklediğiniz sonucu verir (serileştirme sırasında farklı özellik adı ve aynı alan için seriyi kaldırma). Jackson sürüm 2.6.7


0

Bunu yapmak için bir serileştirme sınıfı yazabilirsiniz:

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

Bu değişkeni kullanabilirsiniz:

import lombok.Getter;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonProperty;

//...

@JsonProperty(value = "rr") // for deserialization
@Getter(onMethod_ = {@JsonGetter(value = "r")}) // for serialization
private String rrrr;

Lombok alıcı ile

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.