使用动态字段名反序列化嵌套的JSON对象

3

我正在使用Spring RestTemplate和Jackson 2.1,尝试反序列化下面的JSON字符串。其中第一个数字是唯一的ID,因此会动态变化:

{"2127388":{"name":"John","city":"Amsterdam","country":"The Netherlands"}}

使用 RestTemplate,我做如下操作:
final ResponseEntity<UserDetailsWrapper> re = restTemplate.getForEntity(apiUrl, UserDetailsWrapper.class);

我拥有的POJO如下:

class UserDetailsWrapper {
    private long uniqueId; // [getter + setter]
    private UserDetails userDetails; // [getter + setter]

    // no args constructor + all properties constructor
}

class UserDetails {
    private String name; // [getter + setter]
    private String city; // [getter + setter]
    private String country; // [getter + setter]

    // no args constructor + all properties constructor
}

UserDetailsWrapper类被实例化,但其所有属性仍为null。

当我简单地执行以下操作时:

{"name":"John","city":"Amsterdam","country":"The Netherlands"}

我可以将数据反序列化到UserDetails类中,并填充所有预期的属性,所以我的配置应该没问题。可能我需要在特定位置注释UserDetailsWrapper类,或者需要一个自定义的反序列化器。我尝试了两种方法,但说实话我不知道该怎么做。如果有人能帮助我解决这个问题,我会再次感到幸福。
3个回答

3

从类名来看,你真正需要的不是一个Wrapper,而是一个Map,就像这个答案中的一样:https://dev59.com/f2Ml5IYBdhLWcg3w76sI#18014407

不要使用那里的String,改用Long(未经测试):

TypeFactory typeFactory = mapper.getTypeFactory();
MapType mapType = typeFactory.constructMapType(HashMap.class, Long.class, UserDetails.class);
HashMap<Long, UserDetails> map = mapper.readValue(json, mapType);

深入研究代码后,RestTemplate通过调用来处理您提供的类型,但不幸的是,在此过程中失去了泛型:
restTemplate.getForEntity("apiUrl", Map.class);

你注意到缺乏泛型支持并且与此相关的答案指向了你已经找到的内容:

不是唯一一个

restTemplate.exchange("apiUrl", 
        HttpMethod.GET,
        null,
        new ParameterizedTypeReference<Map<Long, UserDetails>>(){});

谢谢,这帮助了我更进一步。我在下面发布了我的最终解决方案。 - ZT827

1
我基本上通过使用HashMap解决了这个问题,然后获取映射的第一个条目。
final ParameterizedTypeReference<Map<Long, UserDetails>> ptr =
            new ParameterizedTypeReference<Map<Long, UserDetails>>(){};

final ResponseEntity<Map<Long, UserDetails>> re =
    restTemplate.exchange("apiUrl", HttpMethod.GET, null, ptr);

由于RestTemplate :: getForEntity()不支持添加类型引用,因此我不得不使用RestTemplate :: exchange()


0

反映您POJO结构的有效载荷将是:

{"uniqueId":"2127388", "userDetails":{"name":"John","city":"Amsterdam","country":"The Netherlands"}}

我认为在JSON属性名称中使用变量(在您的情况下为2127388)不是一个好主意。只需更改有效载荷结构并按原样使用您的POJO即可。

对评论的反应:

我个人会重新考虑使用这种API,因为它显然是相当糟糕的API。根据JSON规范,属性名称应该是字符串,而在这里,它显然被语义化地视为数字。

如果您被迫使用它,只需将Map<String,UserDetail>用作您的包装器。无论如何,它显然只有一个元素。


很遗憾,我无法更改有效载荷,因为它是由第三方API提供的。 - ZT827

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