jjzjj

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

coder 2024-04-01 原文

第一次在应用程序中实现 JAX-RS 客户端 API,在存储响应数据时遇到了一些小问题,响应数据以 JSON 的形式返回Java BEAN。请参阅下面的代码片段,它们展示了我到目前为止是如何实现它的。

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

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

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

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

"response": {
        "description": "test charge",
        "email": "testing@example.com",
        "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
        }
    }

为什么会发生这种情况?

更新 [下面的响应 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

属于 ResponseObject 类的 Person 对象

@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

最佳答案

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

结构如下

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

这是你的类(class)

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

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

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

public class ResponseWrapper {
    private ResponseObject response;
}

这将使解码成功

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

完成测试

响应对象

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  }";
    }
}

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    }";
    }
}

响应包装器

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}";
    } 
}

测试资源

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\": \"testing@example.com\",\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();
    }
}

单元测试: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();
    }
}

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>

结果:仅使用 toString

ResponseWrapper{
  response=ResponseObject{
    description=test charge
    email=testing@example.com
    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
    }
  }
}

关于java - JAX-RS 响应对象将对象字段显示为 NULL 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26675967/

有关java - JAX-RS 响应对象将对象字段显示为 NULL 值的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  3. ruby-on-rails - Rails 编辑表单不显示嵌套项 - 2

    我得到了一个包含嵌套链接的表单。编辑时链接字段为空的问题。这是我的表格:Editingkategori{:action=>'update',:id=>@konkurrancer.id})do|f|%>'Trackingurl',:style=>'width:500;'%>'Editkonkurrence'%>|我的konkurrencer模型:has_one:link我的链接模型:classLink我的konkurrancer编辑操作:defedit@konkurrancer=Konkurrancer.find(params[:id])@konkurrancer.link_attrib

  4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  5. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  6. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  7. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  8. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  9. ruby-on-rails - 使用 Sublime Text 3 突出显示 HTML 背景语法中的 ERB? - 2

    所以我在关注Railscast,我注意到在html.erb文件中,ruby代码有一个微弱的背景高亮效果,以区别于其他代码HTML文档。我知道Ryan使用TextMate。我正在使用SublimeText3。我怎样才能达到同样的效果?谢谢! 最佳答案 为SublimeText安装ERB包。假设您安装了SublimeText包管理器*,只需点击cmd+shift+P即可获得命令菜单,然后键入installpackage并选择PackageControl:InstallPackage获取包管理器菜单。在该菜单中,键入ERB并在看到包时选择

  10. ruby-on-rails - 未在 Ruby 中初始化的对象 - 2

    我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调

随机推荐