Search code examples
javaspringpojoresttemplate

How RestTemplate parse response


While developing spring REST Client, appear a problem:

  1. I have next json:


{
 "return": [
 {
    "admin": false,
    "alias": "",
    "email": "",
    "emailId": {"value": 0},
    "groups": [],
    "id": {"value": 1},
    "locked": false,
    "loggedInCount": 0,
    "master": true,
    "sms": "",
    "smsId": {"value": 0},
    "type": "POWER",
    "username": "NGCP"
 },
 {
    "admin": false,
    "alias": "",
    "email": "",
    "emailId": {"value": 0},
    "groups": [{"value": 2}],
    "id": {"value": 3},
    "locked": false,
    "loggedInCount": 0,
    "master": false,
    "sms": "",
    "smsId": {"value": 0},
    "type": "POWER",
    "username": "POLICY"
 }
        ]
}

Model class to save User:

@JsonIgnoreProperties(ignoreUnknown = true)
public class User {

   public User(){

   }

   private boolean admin;

   private String alias;

   private String email;

   private String emailId;

   private ArrayList<String> groups;

   private String id;

   private boolean locked;

   private int loggedInCount;

   private boolean master;

   private String sms;

   private String smsId;

   private String type;

   private String userName;

//getter and setters
}

Now I'm using "RestTemplate" to get result.

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<User[]> response = restTemplate.exchange(URL_GET,HttpMethod.GET,request, User[].class);

And get error. I know that is because main key is "result" but can I specify from where should restTemplate parse this JSON?

And it's possible to indicate on fileds liks "emailId" to get direct value? some templates?


Solution

    1. As of the "main key is result":

      a. I would create a wrapper class for the actual payload if you deal with just one of this kind of web service:

      public class Return{
          // Class property cannot be called "return" because it is Java reserved name.
          @JsonProperty("return")
          private User[] array;
          .... getter and setter
      }
      

      b. If you deal with multiple webservices where actual payload is in "return" field I would create a generic wrapper class :

      public class Return<T>{
          // Class property cannot be called "return" because it is Java reserved name.
          @JsonProperty("return")
          private T[] array;
          .... getter and setter
      }
      

      Call to RestRemplate:

      ResponseEntity<Return<User>> response = restTemplate.exchange(URL_GET, 
              HttpMethod.GET, request, new ParameterizedTypeReference<Return<User>>(){});
      User[] usersArray = response2.getBody().getArray();
      
    2. As of the property value in JSON attribute called "value" I would create two custom JsonDeserializer(s): one for single value and one for array of values and annotate each property with @JsonDeserialize where it applies:

      Single value deserializer:

      public class StringValueDeserializer  extends JsonDeserializer<String>{
      
          @Override
          public String deserialize(JsonParser parser, DeserializationContext ctxt)
                  throws IOException, JsonProcessingException {
              ObjectCodec codec = parser.getCodec();
              TreeNode node = codec.readTree(parser);
              JsonNode value = (JsonNode)node.get("value");
      
              if (value != null){
                  return value.asText();
              }
              return null;
          }
      }
      

      Array of values derializer:

      public class StringArrayValueDeserializer  extends JsonDeserializer<List<String>>{
      
          @Override
          public List<String> deserialize(JsonParser parser, DeserializationContext ctxt)
              throws IOException, JsonProcessingException {
      
              List<String> ret = new ArrayList<>();
      
              ObjectCodec codec = parser.getCodec();
              TreeNode node = codec.readTree(parser);
      
              if (node.isArray()){
                  for (JsonNode n : (ArrayNode)node){
                      JsonNode value = n.get("value");
                      if (value != null){
                          ret.add(value.asText());
                      }
                  }
              }
              return ret;
          }
      }
      

      Here you are new User.class:

      public class User {
      
          private boolean admin;
      
          private String alias;
      
          private String email;
      
          @JsonDeserialize(using = StringValueDeserializer.class)
          private String emailId;
      
          @JsonDeserialize(using = StringArrayValueDeserializer.class)
          private ArrayList<String> groups;
      
          @JsonDeserialize(using = StringValueDeserializer.class)
          private String id;
      
          private boolean locked;
      
          private int loggedInCount;
      
          private boolean master;
      
          private String sms;
      
          @JsonDeserialize(using = StringValueDeserializer.class)
          private String smsId;
      
          private String type;
      
          private String username;
          .... getter and setter
      }
      

    Good luck!