Jackson:反序列化一个Map< MyType,String>,它在MyType上使用@JsonIdentityInfo

nbnkbykc  于 10个月前  发布在  其他
关注(0)|答案(2)|浏览(79)

如何使用MyType密钥反序列化Map,该密钥仅使用json格式的MyType的id?
例如,给定

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
        property = "id")
public class MyType {

   String id;
   ... // Getters and setters for id

   String longText;
}

public class MyData {

   List<MyType> types;

   @JsonIdentityReference(alwaysAsId = true) // Does not work
   Map<MyType, Integer> countMap;
}

字符串
它正确地序列化MyData

{
  "types": [
    {
      "id": "123",
      "longText": "very long text 1 ..."
    },
    {
      "id": "456",
      "longText": "very long text 2 ..."
    }
  ],
  "countMap": {
    "123": 100,
    "456": 200
  }
}


但是当我反序列化它时,我得到一个错误:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot find a (Map) Key deserializer for type [simple type, class MyType]


如何让Jackson正确地反序列化它?

yshpjwxd

yshpjwxd1#

使用您在评论中提供的引用,可以使用扩展KeyDeserializer类的类来反序列化所提供的json。从你在下面的问题中定义的类的简化版本开始:

@Data
public class MyType {
    String id;
    String longText;
}

@Data
public class MyData {

    private List<MyType> types;

    //added annotation to the original class
    @JsonDeserialize(keyUsing = MyKeyDeserializer.class)
    private Map<MyType, Integer> countMap;
}

字符串
假设 types 字段始终存在,您可以创建一个扩展KeyDeserializer的自定义类:

public class MyKeyDeserializer extends KeyDeserializer {

    @Override
    public MyType deserializeKey(String id, DeserializationContext dc) throws IOException {
        
        MyType myType = new MyType();
        myType.setId(id);
        MyData myData = (MyData) dc.getParser()
                                .getParsingContext()
                                .getParent()
                                .getCurrentValue();
        
        MyType elem = myData.getTypes()
                                .stream()
                                .filter(el -> el.id.equals(id))
                                .findFirst()
                                .orElse(null);
        
        if (elem != null) { myType.setLongText(elem.getLongText()); }
        return myType;
    }

}


基本上,在CountMapMap的每个键的代码中,json将被解析为MyData示例,然后搜索 types 元素以提取具有相同 id 的type元素,返回新的 MyType 键,并完成 longText 字段。

nfs0ujit

nfs0ujit2#

我能够反序列化的唯一方法是使用自定义反序列化器。所以上这门课

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
    property = "id")
@JsonIdentityReference(alwaysAsId = true)
public class MyType {

  String id;
  String longText;

  public MyType() {
  }

  public MyType(String id) {
    this.id = id;
  }
//getter&setters
}

字符串
和/或

public class MyData {

  List<MyType> types;
  // Does not work
  @JsonDeserialize(keyUsing = MyTypeDeserializer.class)
  Map<MyType, Integer> countMap;
//getters&setters
}

public class MyTypeDeserializer extends KeyDeserializer {
  @Override
  public Object deserializeKey(String key, DeserializationContext deserializationContext) throws IOException {
    return new MyType(key);
  }
}


运行下面的测试,我能够看到正确的json反序列化。

@Test
  public void testDeserialize() throws IOException {
    final String testData = "{\n" +
        "  \"types\": [\n" +
        "    {\n" +
        "      \"id\": \"123\",\n" +
        "      \"longText\": \"very long text 1 ...\"\n" +
        "    },\n" +
        "    {\n" +
        "      \"id\": \"456\",\n" +
        "      \"longText\": \"very long text 2 ...\"\n" +
        "    }\n" +
        "  ],\n" +
        "  \"countMap\": {\n" +
        "    \"123\": 100,\n" +
        "    \"456\": 200\n" +
        "  }\n" +
        "}\n";
    ObjectMapper mapper = new ObjectMapper();
    MyData myData = mapper.readValue(testData, MyData.class);
  }

相关问题