java 使用 spring-hateoas 反序列化包含(_links 和 _embedded)的 JSON

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37813797/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 02:50:20  来源:igfitidea点击:

Deserialize JSON containing (_links and _embedded) using spring-hateoas

javajsonspringHymansonspring-hateoas

提问by Heyjojo

I am trying to invoque very simple json webservices that return data of this form:

我正在尝试调用返回这种形式的数据的非常简单的 json webservices:

{
    "_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
   }
}

As you can see, it is pretty straight forward. I have no problems parsing the links, having my POJOs extending form ResourceSupport. Here is what they look like:

如您所见,它非常简单。我解析链接没有问题,我的 POJO 扩展了 ResourceSupport。这是它们的样子:

UsersJson (the root element)

UsersJson(根元素)

public class UsersJson extends ResourceSupport {
    private List<UserJson> users;

    [... getters and setters ...]
}

UserJson

用户Json

public class UserJson extends ResourceSupport {

    private Long identifier;

    private String firstName;

    private String lastName;

    [... getters and setters ...]
}

The thing is that I was expecting Hymanson and spring to be smart enough to parse the _embedded property and populate my UsersJson.users attribute but it isn't.

问题是我希望 Hymanson 和 spring 足够聪明,可以解析 _embedded 属性并填充我的 UsersJson.users 属性,但事实并非如此。

I tried various things I found on the internet but the only thing I could get to work properly was to create a new class acting as an _embedded wrapper:

我尝试了在互联网上找到的各种东西,但我唯一能正常工作的方法是创建一个充当 _embedded 包装器的新类:

UsersJson (the root element)

UsersJson(根元素)

public class UsersJson extends ResourceSupport {
    @JsonProperty("_embedded")
    private UsersEmbeddedListJson  embedded;

    [... getters and setters ...]
}

Embedded "wrapper"

嵌入式“包装器”

public class UsersEmbeddedListJson extends ResourceSupport {
    private List<UserJson> users;

    [... getters and setters ...]
}

It works but I find it quite ugly.

它有效,但我觉得它很丑。

Yet I though the following configuration of the RestTemplate would have worked (especially when I saw EmbeddedMapper in Hymanson2HalModule), but it didn't:

然而,我虽然 RestTemplate 的以下配置会起作用(尤其是当我在 Hymanson2HalModule 中看到 EmbeddedMapper 时),但它没有:

        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.registerModule(new Hymanson2HalModule());

        MappingHymanson2HttpMessageConverter converter = new MappingHymanson2HttpMessageConverter();
        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);

Can somebody tell me what I am missing?

有人可以告诉我我缺少什么吗?

采纳答案by Heyjojo

Finally, I found a better a way to consume those application/hal+json APIs.

最后,我找到了一种更好的方式来使用那些 application/hal+json API。

Spring hateoas actually provides a client almost ready to use: org.springframework.hateoas.client.Traverson.

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();

As you can see, I got rid UsersJson and UsersEmbeddedListJson.

如您所见,我摆脱了 UsersJson 和 UsersEmbeddedListJson。

Here are the maven dependencies I added

这是我添加的 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>

回答by Whimusical

Had to add this to my DTO:

必须将此添加到我的 DTO:

@JsonProperty("_links")
public void setLinks(final Map<String, Link> links) {
    links.forEach((label, link) ->  add(link.withRel(label)) );
}

since ResourceSupport has no POJO standard/Json-signaled setter/constructor for links

因为 ResourceSupport 没有用于链接的 POJO 标准/Json 信号设置器/构造器

回答by k_o_

I had to extend my DTO POJO with a custom setter parsing the produced output of Spring Hateos in the REST client side by using Hymanson as mapper:

我必须使用 Hymanson 作为映射器,使用自定义 setter 扩展我的 DTO POJO,在 REST 客户端解析 Spring Hateos 的生成输出:

HREF= "href"and RELis "rel"as constants.

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]));
                    }
                }
        );
    }
}