使用 spring-hateoas 反序列化 JSON 包含(_links 和 _embedded)
Deserialize JSON containing (_links and _embedded) using spring-hateoas
我正在尝试调用非常简单的 json 网络服务,return 这种形式的数据:
{
"_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(根元素)
public class UsersJson extends ResourceSupport {
private List<UserJson> users;
[... getters and setters ...]
}
UserJson
public class UserJson extends ResourceSupport {
private Long identifier;
private String firstName;
private String lastName;
[... getters and setters ...]
}
事情是我期待杰克逊和 spring 足够聪明来解析 _embedded 属性 并填充我的 UsersJson.users 属性,但事实并非如此。
我尝试了在互联网上找到的各种东西,但我唯一能正常工作的是创建一个新的 class 作为 _embedded 包装器:
UsersJson(根元素)
public class UsersJson extends ResourceSupport {
@JsonProperty("_embedded")
private UsersEmbeddedListJson embedded;
[... getters and setters ...]
}
嵌入式"wrapper"
public class UsersEmbeddedListJson extends ResourceSupport {
private List<UserJson> users;
[... getters and setters ...]
}
可以用,但我觉得很丑。
然而我虽然 RestTemplate 的以下配置会起作用(尤其是当我在 Jackson2HalModule 中看到 EmbeddedMapper 时),但它没有:
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);
有人能告诉我我错过了什么吗?
最后,我找到了一种更好的方式来使用这些 application/hal+json API。
Spring hateoas 实际上提供了一个几乎可以使用的客户端:org.springframework.hateoas.client.Traverson.
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依赖
<dependency>
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
<version>0.19.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-core</artifactId>
<version>1.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.0.0</version>
</dependency>
必须将此添加到我的 DTO:
@JsonProperty("_links")
public void setLinks(final Map<String, Link> links) {
links.forEach((label, link) -> add(link.withRel(label)) );
}
因为 ResourceSupport 没有 POJO standard/Json-signaled setter/constructor 用于链接
我不得不使用自定义 setter 扩展我的 DTO POJO,通过使用 jackson 作为映射器在 REST 客户端解析 Spring Hateos 的生成输出:
HREF = "href" 并且 REL 是 "rel" 作为常量。
@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]));
}
}
);
}
}
我正在尝试调用非常简单的 json 网络服务,return 这种形式的数据:
{
"_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(根元素)
public class UsersJson extends ResourceSupport {
private List<UserJson> users;
[... getters and setters ...]
}
UserJson
public class UserJson extends ResourceSupport {
private Long identifier;
private String firstName;
private String lastName;
[... getters and setters ...]
}
事情是我期待杰克逊和 spring 足够聪明来解析 _embedded 属性 并填充我的 UsersJson.users 属性,但事实并非如此。
我尝试了在互联网上找到的各种东西,但我唯一能正常工作的是创建一个新的 class 作为 _embedded 包装器:
UsersJson(根元素)
public class UsersJson extends ResourceSupport {
@JsonProperty("_embedded")
private UsersEmbeddedListJson embedded;
[... getters and setters ...]
}
嵌入式"wrapper"
public class UsersEmbeddedListJson extends ResourceSupport {
private List<UserJson> users;
[... getters and setters ...]
}
可以用,但我觉得很丑。
然而我虽然 RestTemplate 的以下配置会起作用(尤其是当我在 Jackson2HalModule 中看到 EmbeddedMapper 时),但它没有:
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);
有人能告诉我我错过了什么吗?
最后,我找到了一种更好的方式来使用这些 application/hal+json API。
Spring hateoas 实际上提供了一个几乎可以使用的客户端:org.springframework.hateoas.client.Traverson.
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依赖
<dependency>
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
<version>0.19.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-core</artifactId>
<version>1.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.0.0</version>
</dependency>
必须将此添加到我的 DTO:
@JsonProperty("_links")
public void setLinks(final Map<String, Link> links) {
links.forEach((label, link) -> add(link.withRel(label)) );
}
因为 ResourceSupport 没有 POJO standard/Json-signaled setter/constructor 用于链接
我不得不使用自定义 setter 扩展我的 DTO POJO,通过使用 jackson 作为映射器在 REST 客户端解析 Spring Hateos 的生成输出:
HREF = "href" 并且 REL 是 "rel" 作为常量。
@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]));
}
}
);
}
}