java JAX-RS 响应对象将对象字段显示为 NULL 值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26675967/
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-02 10:22:41  来源:igfitidea点击:

JAX-RS Response Object displaying Object fields as NULL values

javajsonweb-servicesjax-rsjersey-2.0

提问by Maff

First time implementing JAX-RS Client APIin an application and I am having some small problems when it comes to storing the response data, which is returned as JSONas a Java BEAN. Refer to the following code snippets below which demonstrate how I have implemented it thus far.

第一次JAX-RS Client API在应用程序中实现,在存储JSON作为 Java BEAN返回的响应数据时遇到了一些小问题。请参阅下面的以下代码片段,其中演示了我迄今为止是如何实现它的。

object = client.target(uri).request().post(Entity.entity(requestObject, APPLICATION_JSON), Object.class);

Essentially, I would like to store the returned JSONresponse from the web service into my Java BEAN, which in this scenario is named object. requestObjectis obviously the data which I am sending through to the web service, and I can confirm that POST does perform the operation successfully.

本质上,我想JSON将从 Web 服务返回的响应存储到我的 Java BEAN 中,在这种情况下它被命名为object. requestObject显然是我发送到 Web 服务的数据,我可以确认 POST 确实成功执行了操作。

After the line of code from the above example I have a simple: object.toString();call just to see the values currently stored within this object. However, when this executes and printed out to the console, all the objectfields are printed out as null, which I do not understand why. I have annotated my Java BEAN class with the following @XmlRootElementabove the class, although it still does not work. I do have another object nested as a variable in this Class, would that potentially be the reason why it does not correctly come through?

在上面示例中的代码行之后,我有一个简单的:object.toString();调用只是为了查看当前存储在 this 中的值object。但是,当它执行并打印到控制台时,所有object字段都打印为null,我不明白为什么。我已经在我的 Java BEAN 类@XmlRootElement上面注释了以下内容,尽管它仍然不起作用。我确实有另一个对象作为变量嵌套在这个类中,这可能是它不能正确通过的原因吗?

As an example, this is what my JSON returned object looks like when I invoke the web service through CLI curl:

例如,当我通过 CLI 调用 Web 服务时,我的 JSON 返回对象如下所示curl

"response": {
        "description": "test charge",
        "email": "[email protected]",
        "ip_address": "192.123.234.546",
        "person": {
            "name": "Matthew",
            "address_line1": "42 Test St",
            "address_line2": "",
            "address_city": "Sydney",
            "address_postcode": "2000",
            "address_state": "WA",
            "address_country": "Australia",
            "primary": null
        }
    }

Any reasons why this could be happening?

这可能发生的任何原因?

UPDATE[Response Bean Class Below]

更新[下面的响应 Bean 类]

@XmlRootElement(name = "response")
public class ResponseObject {

    // Instance Variables
    private String description;
    private String email;
    private String ip_address;
    private Person person;
    // Standard Getter and Setter Methods below

Person Object which belongs to the ResponseObject Class

属于的人对象 ResponseObject Class

@XmlRootElement
public class Card {

    // Instance Variables
    private String name;
    private String address_line1;
    private String address_line2;
    private String address_city;
    private int address_postcode;
    private States address_state;
    private String address_country;
    private String primary;
    // Standard Getter and Setter Methods below

采纳答案by Paul Samsotha

So I was able to reproduce the problem, and after a bit of testing, I realized that the problem was pretty obvious, if I had looked at it from the right perspective. I was originally looking at it from the view that maybe something was wrong with the provider configuration. But after a simple "Hymanson only" test, just using the ObjectMapperand trying the read the value, it became clear. The problem is with the json format and the structure of the classes.

所以我能够重现这个问题,经过一些测试后,我意识到如果我从正确的角度来看问题是很明显的。我最初是从提供程序配置可能有问题的角度来看它的。但是经过简单的“仅Hyman逊”测试,只需使用ObjectMapper并尝试读取值,就清楚了。问题在于 json 格式和类的结构。

Here is the structure

这是结构

{
  "response": {
    "description": "test charge",
     ..
    "person": {
      "name": "Matthew",
      ..
    }
  }
}

And here are your classes

这是你的课程

public class ResponseObject {
    private String description;
    private Person person;
    ...
}
public class Person {
    private String name;
}

The problem with this is that the top level object is expecting just a single attribute response. But our top level object is ResponseObject, which hasno attribute response. With the ignore unknown properties on, the unmarhalling succeeds, because the only attribute is response, for which no attribute exists, so nothing gets populated.

这样做的问题是顶级对象只需要一个属性response。但是,我们的顶级对象ResponseObject,它没有属性response。启用忽略未知属性后,解组成功,因为唯一的属性是response,不存在该属性,因此不会填充任何内容。

A simple (Json/JAXB friendly) fix would be to create a wrapper class, with a responseattribute of type ResponseObject

一个简单的(Json/JAXB 友好的)修复是创建一个包装类,具有response类型的属性ResponseObject

public class ResponseWrapper {
    private ResponseObject response;
}

This will allow the unmarshalling to succeed

这将使解组成功

final ResponseWrapper ro = target.request(MediaType.APPLICATION_JSON_TYPE)
            .post(Entity.entity(new ResponseWrapper()
                    , MediaType.APPLICATION_JSON_TYPE), ResponseWrapper.class);


Complete Test

完成测试

ResponseObject

响应对象

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "response")
public class ResponseObject {

    private String description;
    private String email;
    private String ip_address;
    private Person person; 

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getIp_address() {
        return ip_address;
    }

    public void setIp_address(String ip_address) {
        this.ip_address = ip_address;
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    @Override
    public String toString() {
        return "ResponseObject{" 
                + "\n    description=" + description 
                + "\n    email=" + email 
                + "\n    ip_address=" + ip_address 
                + "\n    person=" + person 
                + "\n  }";
    }
}

Person

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Person {
     // Instance Variables
    private String name;
    private String address_line1;
    private String address_line2;
    private String address_city;
    private int address_postcode;
    private String address_state;
    private String address_country;
    private String primary;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress_line1() {
        return address_line1;
    }

    public void setAddress_line1(String address_line1) {
        this.address_line1 = address_line1;
    }

    public String getAddress_line2() {
        return address_line2;
    }

    public void setAddress_line2(String address_line2) {
        this.address_line2 = address_line2;
    }

    public String getAddress_city() {
        return address_city;
    }

    public void setAddress_city(String address_city) {
        this.address_city = address_city;
    }

    public int getAddress_postcode() {
        return address_postcode;
    }

    public void setAddress_postcode(int address_postcode) {
        this.address_postcode = address_postcode;
    }

    public String getAddress_state() {
        return address_state;
    }

    public void setAddress_state(String address_state) {
        this.address_state = address_state;
    }

    public String getAddress_country() {
        return address_country;
    }

    public void setAddress_country(String address_country) {
        this.address_country = address_country;
    }

    public String getPrimary() {
        return primary;
    }

    public void setPrimary(String primary) {
        this.primary = primary;
    }

    @Override
    public String toString() {
        return "Person{" 
                + "\n      name=" + name 
                + "\n      address_line1=" + address_line1 
                + "\n      address_line2=" + address_line2 
                + "\n      address_city=" + address_city 
                + "\n      address_postcode=" + address_postcode 
                + "\n      address_state=" + address_state 
                + "\n      address_country=" + address_country 
                + "\n      primary=" + primary 
                + "\n    }";
    }
}

ResponseWrapper

响应包装器

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class ResponseWrapper {
    private ResponseObject response;

    public ResponseObject getResponse() {
        return response;
    }

    public void setResponse(ResponseObject response) {
        this.response = response;
    } 

    @Override
    public String toString() {
        return "ResponseWrapper{" 
                + "\n  response=" + response
                + "\n}";
    } 
}

TestResource

测试资源

package jersey.stackoverflow.jaxrs;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/test")
public class TestResource {

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response getResponse(ResponseObject ro) {
        final String json = "{\n"
                + "    \"response\": {\n"
                + "        \"description\": \"test charge\",\n"
                + "        \"email\": \"[email protected]\",\n"
                + "        \"ip_address\": \"192.123.234.546\",\n"
                + "        \"person\": {\n"
                + "            \"name\": \"Matthew\",\n"
                + "            \"address_line1\": \"42 Test St\",\n"
                + "            \"address_line2\": \"\",\n"
                + "            \"address_city\": \"Sydney\",\n"
                + "            \"address_postcode\": \"2000\",\n"
                + "            \"address_state\": \"WA\",\n"
                + "            \"address_country\": \"Australia\",\n"
                + "            \"primary\": null\n"
                + "        }\n"
                + "    }\n"
                + "}";
        return Response.created(null).entity(json).build();
    }
}

Unit Test: TestTestResource

单元测试:TestTestResource

import jersey.stackoverflow.jaxrs.ResponseWrapper;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.moxy.json.MoxyJsonConfig;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.TestProperties;
import org.junit.Test;

public class TestTestResource extends JerseyTest {

    @Test
    public void testPostReturn() throws Exception {
        final WebTarget target = target("test");
        final ResponseWrapper ro = target.request(MediaType.APPLICATION_JSON_TYPE)
                .post(Entity.entity(new ResponseWrapper()
                        , MediaType.APPLICATION_JSON_TYPE), ResponseWrapper.class);
        System.out.println(ro);

    }

    @Override
    protected Application configure() {
        enable(TestProperties.LOG_TRAFFIC);
        enable(TestProperties.DUMP_ENTITY);

        return createApp();
    }

    @Override
    protected void configureClient(ClientConfig config) {
        config.register(createMoxyJsonResolver());
    }

    public static ResourceConfig createApp() {
        // package where resource classes are
        return new ResourceConfig().
                packages("jersey.stackoverflow.jaxrs").
                register(createMoxyJsonResolver());
    }

    public static ContextResolver<MoxyJsonConfig> createMoxyJsonResolver() {
        final MoxyJsonConfig moxyJsonConfig = new MoxyJsonConfig();
        Map<String, String> namespacePrefixMapper = new HashMap<String, String>(1);
        namespacePrefixMapper.put("http://www.w3.org/2001/XMLSchema-instance", "xsi");
        moxyJsonConfig.setNamespacePrefixMapper(namespacePrefixMapper).setNamespaceSeparator(':');
        return moxyJsonConfig.resolver();
    }
}

Dependencies in pom.xml

pom.xml 中的依赖

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey</groupId>
            <artifactId>jersey-bom</artifactId>
            <version>2.13</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-grizzly2-http</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.test-framework.providers</groupId>
        <artifactId>jersey-test-framework-provider-bundle</artifactId>
        <type>pom</type>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-moxy</artifactId>
    </dependency> 
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.9</version>
        <scope>test</scope>
    </dependency> 
</dependencies>

Result: Just using toString

结果:仅使用 toString

ResponseWrapper{
  response=ResponseObject{
    description=test charge
    [email protected]
    ip_address=192.123.234.546
    person=Person{
      name=Matthew
      address_line1=42 Test St
      address_line2=
      address_city=Sydney
      address_postcode=2000
      address_state=WA
      address_country=Australia
      primary=null
    }
  }
}