Deserialize String เป็น List of Strings

Sep 23 2020

ฉันมี POJO ที่มีคุณสมบัติดังต่อไปนี้

public class Example {
  @JsonProperty("inputFoo")
  private String foo
  @JsonProperty("inputBar")
  private String bar
  @JsonProperty("inputBaz")
  @JsonDeserialize(using = MyDeserializer.class)
  private Set<String> baz
}

JSON ที่ฉันใช้เพื่อแสดงข้อมูลนี้ในปัจจุบันแสดงถึงแอตทริบิวต์ baz เป็นสตริงเดียว:

{"inputFoo":"a", "inputBar":"b", "inputBaz":"c"}

ฉันใช้ Jackson ObjectMapper เพื่อพยายามแปลง JSON เป็น POJO ของฉัน ฉันรู้ว่า input baz String จาก JSON เคยชินแมปไปยัง Set ที่ฉันพยายามจะแทนมันดังนั้นฉันจึงกำหนด Deserializer แบบกำหนดเอง:

public class MyDeserializer extends StdDeserializer<Set<String>> {
   public MyDeserializer(){}

   public MyDeserializer(Class<?> vc) {
      super(vc);
   }

   public Set<String> deserialize(JsonParser p, DeserializationContext cxt) throws IOException, JsonProcessingException {
      String input = p.readValueAs(String.class);
      Set<String> output = new HashSet<>();
      if(input != null) {
         output.add(input);
      }
      return output;
   }
}

ฉันได้รับ IllegalArgumentException ที่อ้างถึงแอตทริบิวต์ "inputBaz" ซึ่งฉันสามารถให้รายละเอียดได้ มีใครเห็นปัญหาที่ชัดเจนเกี่ยวกับการใช้งาน deserializer ของฉันบ้าง ขอบคุณ

คำตอบ

2 MichałZiober Sep 22 2020 at 23:33

คุณไม่จำเป็นต้องติดตั้ง deserialiser ที่กำหนดเองใช้คุณลักษณะACCEPT_SINGLE_VALUE_AS_ARRAY มันใช้ได้กับชุดเช่นกัน:

คุณลักษณะที่พิจารณาว่าสามารถบังคับค่าที่ไม่ใช่อาร์เรย์ (ใน JSON) เพื่อทำงานกับชนิดคอลเลกชัน Java (อาร์เรย์, java.util.Collection)ได้หรือไม่ หากเปิดใช้งานคอลเลกชัน deserializers จะพยายามจัดการค่าที่ไม่ใช่อาร์เรย์ราวกับว่ามี "โดยนัย" รอบอาร์เรย์ JSON คุณลักษณะนี้มีไว้เพื่อใช้สำหรับเหตุผลด้านความเข้ากันได้ / ความสามารถในการทำงานร่วมกันเพื่อทำงานกับแพ็คเกจ (เช่นตัวแปลง XML เป็น JSON) ที่เว้นอาร์เรย์ JSON ในกรณีที่มีเพียงองค์ประกอบเดียวในอาร์เรย์ คุณลักษณะถูกปิดใช้งานโดยค่าเริ่มต้น

ดูสิ่งนี้ด้วย:

  • com.fasterxml.jackson.databind.exc.MismatchedInputException: ไม่สามารถ deserialize อินสแตนซ์java.util.ArrayListจากโทเค็น START_OBJECT
Andreas Sep 22 2020 at 23:44

แทนที่ตัวสร้าง 2 ตัวด้วยตัวสร้างที่ไม่มีอาร์กิวเมนต์นี้:

public MyDeserializer() {
    super(TypeFactory.defaultInstance().constructCollectionType(Set.class, String.class));
}
pirho Sep 23 2020 at 02:00

ACCEPT_SINGLE_VALUE_AS_ARRAY ตามที่แนะนำเป็นตัวเลือกที่ดี

บางทีปัญหาที่แท้จริงของคุณอาจซับซ้อนกว่านี้ แต่หากไม่เป็นเช่นนั้นคุณสามารถลอง@JsonCreatorแทน deserializer แบบกำหนดเองได้ ชอบ:

public class Example {

    @JsonCreator
    public Example(@JsonProperty("inputFoo") String foo,
            @JsonProperty("inputBar") String bar,
            @JsonProperty("inputBaz") String strBaz) {
        this.foo = foo;
        this.bar = bar;
        this.baz = new HashSet<>();
        baz.add(strBaz);
    }

    private String foo;
    private String bar;
    private Set<String> baz;
}

เพียงเพื่อแสดงให้เห็นว่าในกรณีทั่วไปคุณอาจหลีกเลี่ยงการใช้ deserializer ที่กำหนดเองด้วย@JsonCreatorแต่ยังคงทำการแปลงแบบง่ายๆ