Deserialize JSON containing (_links and _embedded) using spring-hateoas
我正在尝试开发非常简单的json网络服务,这些服务返回以下形式的数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | { "_embedded": { "users": [{ "identifier":"1", "firstName":"John", "lastName":"Doe", "_links": { "self": { "href":"http://localhost:8080/test/users/1" } } }, { "identifier":"2", "firstName":"Paul", "lastName":"Smith", "_links": { "self": { "href":"http://localhost:8080/test/users/2" } } }] }, "_links": { "self": { "href":"http://localhost:8080/test/users" } }, "page": { "size": 20, "totalElements": 2, "totalPages": 1, "number": 0 } } |
如您所见,它非常简单。
我的POJO扩展了ResourceSupport,因此解析链接没有问题。
它们是这样的:
UsersJson(根元素)
1 2 3 4 5 | public class UsersJson extends ResourceSupport { private List<UserJson> users; [... getters and setters ...] } |
UserJson
1 2 3 4 5 6 7 8 9 10 |
事实是,我期望jackson和spring足够聪明,可以解析_embedded属性并填充我的UsersJson.users属性,但事实并非如此。
我尝试了各种在Internet上找到的东西,但是我唯一能正常工作的是创建一个充当_embeddedpackage器的新类:
UsersJson(根元素)
1 2 3 4 5 6 | public class UsersJson extends ResourceSupport { @JsonProperty("_embedded") private UsersEmbeddedListJson embedded; [... getters and setters ...] } |
嵌入式"package器"
1 2 3 4 5 | public class UsersEmbeddedListJson extends ResourceSupport { private List<UserJson> users; [... getters and setters ...] } |
它可以工作,但我觉得它很丑。
虽然我可以使用RestTemplate的以下配置(特别是当我在Jackson2HalModule中看到EmbeddedMapper时),但是却没有:
1 2 3 4 5 6 7 8 9 10 11 12 | ObjectMapper mapper = new ObjectMapper(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); mapper.registerModule(new Jackson2HalModule()); MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json")); converter.setObjectMapper(mapper); RestTemplate restTemplate = new RestTemplate(Collections.singletonList(converter)); ResponseEntity<UsersJson> result = restTemplate.getForEntity("http://localhost:8089/test/users", UsersJson.class, new HashMap<String, Object>()); System.out.println(result); |
有人可以告诉我我在想什么吗?
最后,我找到了一种更好的使用这些应用程序/ hal json API的方法。
Spring hateoas实际上提供了几乎可以使用的客户端:org.springframework.hateoas.client.Traverson。
1 2 3 4 5 | Traverson traverson = new Traverson(new URI("http://localhost:8080/test"), MediaTypes.HAL_JSON); TraversalBuilder tb = traverson.follow("users"); ParameterizedTypeReference<Resources<UserJson>> typeRefDevices = new ParameterizedTypeReference<Resources<UserJson>>() {}; Resources<UserJson> resUsers = tb.toObject(typeRefDevices); Collection<UserJson> users= resUsers .getContent(); |
如您所见,我摆脱了UsersJson和UsersEmbeddedListJson。
这是我添加的Maven依赖项
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <dependency> <groupId>org.springframework.hateoas</groupId> spring-hateoas</artifactId> <version>0.19.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.plugin</groupId> spring-plugin-core</artifactId> <version>1.2.0.RELEASE</version> </dependency> <dependency> <groupId>com.jayway.jsonpath</groupId> json-path</artifactId> <version>2.0.0</version> </dependency> |
必须将此添加到我的DTO中:
1 2 3 4 | @JsonProperty("_links") public void setLinks(final Map<String, Link> links) { links.forEach((label, link) -> add(link.withRel(label)) ); } |
因为ResourceSupport没有用于链接的POJO标准/ Json信号设置器/构造函数,所以
我不得不使用自定义设置程序扩展我的DTO POJO,以使用杰克逊作为映射器来解析REST客户端中Spring Hateos的输出:
HREF = " href ",并且REL作为常量为" rel "。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | @JsonProperty("link") public void setLink(final List<Map<String, String>> links) { if (links != null) { links.forEach(l -> { final String[] rel = new String[1]; final String[] href = new String[1]; l.entrySet().stream().filter((e) -> e.getValue() != null) .forEach(e -> { if (e.getKey().equals(REL)) { rel[0] = e.getValue(); } if (e.getKey().equals(HREF)) { href[0] = e.getValue(); } }); if (rel[0] != null && href[0] != null) { add(new Link(href[0], rel[0])); } } ); } } |