Reputation: 1787
While developing spring REST Client, appear a problem:
{
"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?
Upvotes: 4
Views: 23157
Reputation: 351
You can also use the JsonPath library to navigate through json:
String json = restTemplate.exchange(URL_GET,HttpMethod.GET,request, String.class);
DocumentContext document = JsonPath.parse(content, json);
List<User> users = document.read("$.return.*", new TypeRef<List<User>>() {});
Upvotes: 4
Reputation: 12024
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();
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!
Upvotes: 5
Reputation: 64
You can use the annotation @JsonRootName to specify the root element in your response. So try this:
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonRootName(value ="result")
public class User {
public User(){
}
private boolean admin;
....
}
Upvotes: 2