Các tên khác nhau của thuộc tính JSON trong quá trình tuần tự hóa và giải tuần tự hóa


149

Có thể: có một trường trong lớp, nhưng các tên khác nhau cho nó trong quá trình tuần tự hóa / giải tuần tự hóa trong thư viện Jackson?

Ví dụ, tôi có lớp "Điều phối viên".

class Coordinates{
  int red;
}

Để khử lưu huỳnh từ JSON muốn có định dạng như thế này:

{
  "red":12
}

Nhưng khi tôi sẽ tuần tự hóa đối tượng, kết quả sẽ như thế này:

{
  "r":12
}

Tôi đã cố gắng thực hiện điều này bằng cách áp dụng @JsonPropertychú thích cả trên getter và setter (với các giá trị khác nhau):

class Coordiantes{
    int red;

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

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

nhưng tôi có một ngoại lệ:

org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Trường không được nhận dạng "đỏ"

Câu trả lời:


203

Chỉ cần thử nghiệm và điều này hoạt động:

public class Coordinates {
    byte red;

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

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

Ý tưởng là tên phương thức nên khác nhau, vì vậy jackson phân tích nó thành các trường khác nhau, không phải là một trường.

Đây là mã kiểm tra:

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

Kết quả:

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

điều tương tự có thể xảy ra với jaxb?
Cui Pengfei 崔鹏飞 22/03/14

38

Bạn có thể sử dụng @jsonAliasđã được giới thiệu trong jackson 2.9.0

Thí dụ:

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

Điều này sử dụng rtrong quá trình tuần tự hóa, nhưng cho phép rednhư một bí danh trong quá trình khử lưu huỳnh. Điều này vẫn cho phép rđược khử lưu huỳnh là tốt, mặc dù.


8
Các tài liệu cho @JsonAlias một cách rõ ràng rằng nó has no effect during serialization where primary name is always used. Đây không phải là những gì OP muốn.
Xaero Degreaz

3
@XaeroDegreaz Tôi đoán @Asura có nghĩa là, bạn có thể sử dụng rlàm tên chính, nhưng redđối với @JsonAlias, cho phép tuần tự hóa nó thành r, nhưng thêm vào redđể được công nhận về khử lưu huỳnh . Chú thích @JsonProperty("r")và bổ sung @JsonAlias("red")sẽ hoạt động tốt cho vấn đề nhất định.
Jerrot

16

Bạn có thể sử dụng kết hợp @JsonSetter@JsonGetter để kiểm soát quá trình khử lưu huỳnh và tuần tự hóa tài sản của bạn, tương ứng. Điều này cũng sẽ cho phép bạn giữ các tên phương thức getter và setter được tiêu chuẩn hóa tương ứng với tên trường thực tế của bạn.

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

Tôi sẽ liên kết hai cặp getters / setters khác nhau với một biến:

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
Nhưng trong trường hợp này, trong quá trình tuần tự hóa, chúng ta sẽ nhận được cả hai thuộc tính: "r" và "red", với cùng các giá trị.
kiRach

6

Có thể có cặp getter / setter bình thường. Bạn chỉ cần xác định chế độ truy cập trong@JsonProperty

Đây là bài kiểm tra đơn vị cho điều đó:

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

Tôi đã nhận được đầu ra như sau:

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

5

Đây không phải là điều tôi mong đợi như một giải pháp (mặc dù đây là trường hợp sử dụng hợp pháp). Yêu cầu của tôi là cho phép một máy khách có lỗi (một ứng dụng di động đã được phát hành) sử dụng tên thay thế.

Giải pháp nằm ở việc cung cấp một phương thức setter riêng như thế này:

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

2

Tôi biết đó là một câu hỏi cũ nhưng đối với tôi, tôi đã làm cho nó hoạt động khi tôi phát hiện ra rằng nó mâu thuẫn với thư viện Gson vì vậy nếu bạn đang sử dụng Gson thì hãy sử dụng @SerializedName("name")thay vì @JsonProperty("name")hy vọng điều này sẽ giúp


2

Chú thích @JsonAliasđược giới thiệu với Jackson 2.9+, mà không đề cập đến@JsonProperty mục được với nhiều hơn một bí danh (tên khác nhau cho thuộc tính json) hoạt động tốt.

Tôi đã sử dụng com.fasterxml.jackson.annotation.JsonAliasđể thống nhất gói với com.fasterxml.jackson.databind.ObjectMappertrường hợp sử dụng của tôi.

Ví dụ:

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

}

chỉ hoạt động tốt


1

Chúng phải bao gồm tính năng này như một tính năng, bởi vì bây giờ việc đặt khác nhau @JsonPropertycho getter và setter sẽ mang lại kết quả chính xác như bạn mong đợi (tên thuộc tính khác nhau trong quá trình tuần tự hóa và giải tuần tự hóa cho cùng một trường). Jackson phiên bản 2.6.7


0

Bạn có thể viết một lớp serialization để làm điều đó:

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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.