【问题标题】:Spring Resttemplate: Parsing using @JsonIgnore causes values to be nullSpring Resttemplate:使用@JsonIgnore 解析导致值为空
【发布时间】:2017-11-09 00:30:05
【问题描述】:

所以,我正在使用 Spring Boot 1.5.3 并尝试使用以下 Json 的一部分 - 即 AccountIdUsername- (实际上,它是从 SAP Netweaver 实例获取的 oData v2 接口)使用 restTemplate.exchange 进入一个类:

{  
   "d":{  
      "__metadata":{  
         "id":"...",
         "uri":"...",
         "type":"...."
      },
      "AccountID":"0100000001",
      "Username":"test@test.com",
      "Partners":{  
         "__deferred":{  
            "uri":"Navigationproperty"
         }
      }
   }
}

我的班级是这样设置的,因为一开始我只想获取帐户 ID 和名称:

@JsonIgnoreProperties(ignoreUnknown = true)
public class PortalAccount implements Serializable{

    public PortalAccount() {
    }

    @JsonProperty("AccountID")
    public String accountID;

    @JsonProperty("Username")
    public String username;

    public String getPortalAccountID() {
        return accountID;
    }

    public void setPortalAccountID(String portalAccountID) {
        this.accountID = portalAccountID;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public String toString() {
        return "Account{" +
                "accountID='" + accountID + '\'' +
                ", username='" + username +'\'' +
                '}';
    }
}

这是我尝试称呼它的方式:

        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders httpHeaders = this.createHeaders();
        ResponseEntity<String> response;
        response  = restTemplate.exchange(uri,HttpMethod.GET,new HttpEntity<Object>(httpHeaders),String.class);
        ObjectMapper mapper = new ObjectMapper();

        PortalAccount acc = mapper.readValue(response.getBody(), PortalAccount.class);

我首先尝试像在文档中一样使用ResponseEntity&lt;PortalAccount&gt; 直接解析它,但这只会导致一个空类(accountid = null,username = null),所以我尝试使用上述方法使用ResponseEntity&lt;String&gt; 看看什么我只是将响应解析为字符串表示形式。这样,我可以确保正确返回上面的 json,它就是这样。所以,这些值肯定存在,它必须是解析的问题,但遗憾的是我没有解决这个问题。

希望你能帮帮我!

编辑:正如一个答案提到的,getForObject 可能有效,但这会给我带来其他问题,因为我必须使用基本身份验证,所以它不是真的可行。我还尝试了大小写问题,命名变量 accountID 或 AccountID ,但没有成功。

【问题讨论】:

  • 我的猜测是,问题是 JSON 中包含 AccountId 和 Username 的对象“d”。这实际上将转换为一个名为“d”的类,其中包含字符串“AccountId”和“Username”。出于测试目的,请尝试将您的类命名为“d”而不是 PortalAccount。
  • 另外,在 PortalAccount 类上尝试@JsonTypeName("d")
  • 所以,是的,getBody() 包含我添加到问题中的 json。现在我尝试将类更改为“d”,这会导致相同的行为。另外,我尝试将 JsonTypeName("d") 添加到 d-Class 和重新重构的 PortalAccount-Class 中,但没有成功:/
  • 好的,所以我可能弄错了,您必须将“d”包装在另一个类中,以便您拥有一个包含“d”类型作为属性的类,就像现在一样。同样,出于测试目的。

标签: java json spring-boot jackson resttemplate


【解决方案1】:

因此,Christian Zieglers 的评论和回答部分正确。

您需要确保可以从检索到的 Json 映射您的类结构。

所以,为了让它工作,最简单的方法是,而不是创建一个包装对象:

  1. 删除您的 @JsonIgnoreProperties 注释。我们将使用对象映射器来做到这一点。

  2. 然后,将 Jacksons @JsonRootName 属性添加到您的类 PortalAccount 并将值设置为 d。你的班级现在应该只有一个注解:

@JsonRootName(value = "d") 像这样:

@JsonRootName(value = "d")
public class PortalAccount implements Serializable{
    public PortalAccount() {
    }

    @JsonProperty("AccountID")
    public String accountID;

    @JsonProperty("Username")
    public String username;

    ...
}

现在,当您调用它时,您必须将 Objectmapper(假设为 jackson 2)设置为 Unwrap 您的 rootElement(并忽略未知属性),如下所示:

objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

所以你的整个通话看起来像这样:

RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = this.createHeaders();
ResponseEntity<String> response;
response  = restTemplate.exchange(uri,HttpMethod.GET,new HttpEntity<Object>(httpHeaders),String.class);
ObjectMapper mapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

PortalAccount acc = mapper.readValue(response.getBody(), PortalAccount.class);

这里重要的是,如上所述,@JsonRootName 属性,因为没有它,UNWRAP_ROOT_VALUE 功能将无法工作。

希望这会有所帮助!

【讨论】:

    【解决方案2】:

    问题是,根据您的 JSON,ObjectMapper 需要一个包含“d”类型属性的类,该属性包含两个名为“AccountId”和“Username”的属性。

    所以,你基本上只需要解析对象“d”的内容。

    Parsing a subset of JSON in Java using Jackson 描述了它是如何完成的。

    【讨论】:

    • 感谢您的帮助!我认为我们在这里走对了路。刚刚接受了另一个答案,因为它有一个完整的示例,并且恕我直言,使用 JsonRootName 比创建包装类更优雅。
    • 确实如此。我不知道@JsonRootName。非常好!
    【解决方案3】:

    您可以尝试使用 getForObject 方法代替交换。

    这是一个例子:

    @JsonIgnoreProperties(ignoreUnknown = true) 
    
    public class Page { 
    
        private String name; 
        private String about; 
        private String phone; 
        private String website; 
    
        public String getName() { 
            return name; 
        } 
    
        public String getAbout() { 
            return about; 
        } 
    
        public String getPhone() { 
            return phone; 
        } 
    
        public String getWebsite() { 
            return website; 
        } 
    
    }  
    
    
    RestTemplate restTemplate = new RestTemplate();
    Page page = restTemplate.getForObject("http://graph.facebook.com/pivotalsoftware", Page.class);
    System.out.println("Name:    " + page.getName());
    System.out.println("About:   " + page.getAbout());
    System.out.println("Phone:   " + page.getPhone());
    System.out.println("Website: " + page.getWebsite());
    

    【讨论】:

    • 很遗憾我不能,因为我需要基本身份验证,这让我遇到了其他问题。 (老实说,我还没有找到一个使用 get/postforobject 和 basi auth 的工作示例)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多