Spring Resttemplate:使用@JsonIgnore 解析导致值为空

Posted

技术标签:

【中文标题】Spring Resttemplate:使用@JsonIgnore 解析导致值为空【英文标题】:Spring Resttemplate: Parsing using @JsonIgnore causes values to be null 【发布时间】: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”类型作为属性的类,就像现在一样。同样,出于测试目的。 【参考方案1】:

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

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

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

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

    然后,将 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 的工作示例)。

以上是关于Spring Resttemplate:使用@JsonIgnore 解析导致值为空的主要内容,如果未能解决你的问题,请参考以下文章

Spring Cloud Commons教程Spring RestTemplate作为负载平衡器客户端

Spring RestTemplate 超时

spring RestTemplate提交json格式数据

Spring RestTemplate作为负载平衡器客户端

Spring RestTemplate作为负载平衡器客户端

Spring RestTemplate作为负载平衡器客户端