Search code examples
javajsonspring-bootjacksonresttemplate

Spring Resttemplate: Parsing using @JsonIgnore causes values to be null


So, I am using Spring Boot 1.5.3 and am trying to a part of the following Json - - namely AccountId and Username- (actually, it is an oData v2 interface getting from a SAP Netweaver instance) into a class using restTemplate.exchange:

{  
   "d":{  
      "__metadata":{  
         "id":"...",
         "uri":"...",
         "type":"...."
      },
      "AccountID":"0100000001",
      "Username":"[email protected]",
      "Partners":{  
         "__deferred":{  
            "uri":"Navigationproperty"
         }
      }
   }
}

My class is set up like this, because for a start I only want to get the account id and name:

@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 +'\'' +
                '}';
    }
}

and here's the way I try to call it:

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

I first tried to parse it directly like in the docs using ResponseEntity<PortalAccount>, but this just lead to an empty class (accountid = null, username = null), So i tried the way above using ResponseEntity<String> to see what I get when just parsing the response into the string representation. That way, I could make sure the json above is correctly returned, which it is.So, the values are definitely there, it has to be a matter of parsing, but I sadly don't get my way around this problem.

I hope you could help me out here!

edit: As one answer mentions, getForObject might work, but this leads for me to other problems, as I have to use basic authentication, so its not really viable.I also tried casing-issues, naming the Variables accountID or AccountID, which did not work out.


Solution

  • So, Christian Zieglers Comments and Answer is partially right.

    You need to make sure your Class Structure can be mapped from the retrieved Json.

    So, to make it work, the imho easiest way woud be, instead of creating a wrapper object:

    1. Remove your @JsonIgnoreProperties Annotation. We'll do this with the object mapper.

    2. Then, Add Jacksons @JsonRootName Property to your class PortalAccount and set the value to d. Your class now should only have this one annotation:

    @JsonRootName(value = "d") like this:

    @JsonRootName(value = "d")
    public class PortalAccount implements Serializable{
        public PortalAccount() {
        }
    
        @JsonProperty("AccountID")
        public String accountID;
    
        @JsonProperty("Username")
        public String username;
    
        ...
    }
    

    Now, when you call it, you have to set your Objectmapper (assuming jackson 2) to Unwrap your rootElement (and to ignore unknown properties) like this:

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

    So your whole call would look like this:

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

    Important thing here is, as stated above, the @JsonRootName Property, because without it, the UNWRAP_ROOT_VALUE feature would not work.

    Hope this helps!