使用Jackson将JSON数组反序列化为Map

5
我有一个JSON结构如下:
{
  "id" : "123",
  "name" : [ {
    "stuff" : [ {
      "id" : "234",
      "name" : "Bob"
    }, {
      "id" : "345",
      "name" : "Sally"
    } ]
  } ]
}

我希望将以下内容映射到以下数据结构:
MyInterface1
@Value.Immutable
@JsonSerialize(as = ImmutableMyInterface1.class)
@JsonDeserialize(as = ImmutableMyInterface1.class)
public interface MyInterface1 {
    String id();
    @JsonDeserialize(using = MyInterface1Deserializer.class)
    List<MyInterface2> name();
}

我的接口2

@Value.Immutable
@JsonSerialize(as = ImmutableMyInterface2.class)
@JsonDeserialize(as = ImmutableMyInterface2.class)
public interface MyInterface2 {
    @JsonDeserialize(using = StuffDeserializer.class)
    Map<String, MyInterface3> stuff();
}

MyInterface3

@Value.Immutable
@JsonSerialize(as = ImmutableMyInterface3.class)
@JsonDeserialize(as = ImmutableMyInterface3.class)
public interface MyInterface3 {
      String id();
      String name();
}

我正在使用ObjectMapper和readValue(stringWithJson,MyInterface1.class)将此JSON映射到MyInterface1,应该继续向下映射到MyInterface3。当我在MyInterface2中使用List时,即List<MyInterface3> name();时,这个设置是有效的。
然而,我希望这是一个映射,而不是一个列表,理想情况下,内部JSON的"id"作为键。这将允许我使用以下语法获取值:MyInterface1.get(0).MyInterface2.get("id1").name(); 问题是,在尝试创建自定义StuffDeserializer.class时,我遇到了错误:Can not deserialize instance of com.foo.ImmutableMyInterface2$Json out of START_ARRAY token
public Map<String, MyInterface3> deserialize(JsonParser jsonParser, DeserializationContext ctxt)
        throws IOException {

    MyInterface2 foo = Unmarshaller.OBJECT_MAPPER.readValue(jsonParser, MyInterface2.class); // error here
    ...

我认为这是因为Jackson期望"stuff"是一个List,因为JSON数组的存在。最佳方法是如何将此JSON反序列化为一个使用内部JSON值作为键的映射?
1个回答

4

我会创建一个自定义的JsonDeserializer,将idname映射到一个map中:

public class StringHashMapValueDeserializer extends JsonDeserializer<HashMap<String, String>>{

    @Override
    public HashMap<String, String> deserialize(JsonParser parser, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        HashMap<String, String> ret = new HashMap<String, String>();

        ObjectCodec codec = parser.getCodec();
        TreeNode node = codec.readTree(parser);

        if (node.isArray()){
            for (JsonNode n : (ArrayNode)node){
                JsonNode id = n.get("id");
                if (id != null){
                    JsonNode name = n.get("name");
                    ret.put(id.asText(), name.asText());
                }
            }
        }
        return ret;
    }
}

然后我会使用注释创建简单的 bean,并将 stuff 属性与反序列化程序进行注释:

@Getter
@Setter
public class Name {

    @JsonDeserialize(using = StringHashMapValueDeserializer.class)
    Map<String, String> stuff;

    @Override
    public String toString() {
        return "Name [stuff=" + stuff + "]";
    }
}

外部类型:

@Getter
@Setter
public class OuterType {

    String id;
    List<Name> name;

    @Override
    public String toString() {
        return "OuterType [id=" + id + ", stuff=" + name + "]";
    }
}

反序列化:

ObjectMapper mapper = new ObjectMapper();

OuterType response;
response = mapper.readValue(json, OuterType.class);

System.out.println(response);
System.out.println(response.getName().get(0).getStuff().get("234"));

控制台输出:

OuterType [id=123, stuff=[Name [stuff={234=Bob, 345=Sally}]]]
Bob

希望这能有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接