I did a get request to a external RESTful api and receive as response a json object with this structure:
{
"data": {
"id": 1,
"name": "John Doe",
"email": "doe#john.com",
"urlPicture": "urlPicture.com/82819",
"address": {
"street": "My street",
"number": "29",
"city": "Nurnberg",
"country": "Germany"
}
}
}
I don't need all stuff of this response, I want only some fields to save in a database.
My POJO classes are similar to this pseudocode:
public class Data{
private User user;
// getters and setters
}
public class User{
private int id;
private String name;
private String urlPicture;
private String country;
// getters and setters
}
But, when I try to extract fields that I want, I receive null in this fields
public void testResponse(){
RestTemplate restTemplate = new RestTemplate();
Data data = new Data();
User user = new User();
Gson gson = new Gson();
String response = restTemplate.getForObject(
"https://apifrommyrequest.com/user/{id}",
String.class,
73442);
user = gson.fromJson(response, User.class);
System.out.println(user);
}
```
My output:
22:20:57.641 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP GET https://apifrommyrequest.com/user/73442
22:20:57.672 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[text/plain, application/json, application/*+json, */*]
22:20:58.243 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK
22:20:58.247 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [java.lang.String] as "application/json;charset=UTF-8"
Data(id=0, name=null, urlPicture=null, country=null)
I really don't know how to do anymore.
Try out the below code. You can't directly access the country, it is a value placed in a nested object. And also since response body returns as data you can't convert it to a User object. first, you need to convert it to a Data object.
public class User {
private int id;
private String name;
private String urlPicture;
private Address address;
// getters and setters
}
public class Address {
private String country;
// getters and setters
}
public void testResponse(){
RestTemplate restTemplate = new RestTemplate();
Data data = new Data();
User user = new User();
Gson gson = new Gson();
String response = restTemplate.getForObject(
"https://apifrommyrequest.com/user/{id}",
String.class,
73442);
data = gson.fromJson(response, Data.class);
System.out.println(data);
}
If you want, you can design your POJO like this too(to reduce nested POJOs):
public class Data {
private User data;
//getters and setters
}
public class User {
private int id;
private String name;
private String urlPicture;
private String country;
#JsonProperty("address")
private void unpackNested(Map<String,String> elements)
{
this.country = elements.get("country");
}
//getters and setters
}
Then finally deserialize on Data class
you dont really need to do the conversion from string to object, resttemplate already use jackson that do it for u , just have to
YourObject response = restTemplate.getForObject(
"https://apifrommyrequest.com/user/{id}",
YourObject.class,
73442);
then it is going to do the mapping to your pojo objects, u dont really need gson in this scenario.
Related
I am not able to deserialize nested JSON array from response JSON using Spring Rest template.
JSON response which I am consuming is as follows
[
{
"creationTime": "2023-01-13",
"code": "456",
"cid": "123",
"priority": "CRITICAL",
"reviewDate": null,
"systemCall": [
{
"creationTime": "2023-01-13",
"status": null,
"id": "787878",
"modificationTime": "2023-01-13",
"creatorId": "ABC"
},
{
"creationTime": "2023-01-14",
"status": null,
"id": "787879",
"modificationTime": "2023-01-14",
"creatorId": "DEF"
}
],
level: "1"
}
]
And My model classes as follows
public class Resolution {
private String creationTime;
private String code;
private String cid;
private String priority;
private String reviewDate
private List<SystemCallVo> systemCall;
private String level;
public Resolution(){
}
//Getters and Settrs
}
public class SystemCallVo {
private String creationTime;
private String status;
private String id;
private String modificationTime;
private String creatorId;
public SystemCallVo(){
}
//Getters and Setters
}
public class ResolutionVo extends Resolution{
public ResolutionVo(){
}
}
I am calling my endpoint using rest template as follows.
ResponseEntity<List<ResolutionVo>> response = this.restTemplateConfig.restTemplate().exchange(builder.toUriString(), HttpMethod.POST, httpEntity, new ParameterizedTypeReference<List<ResolutionVo>>() {
}, new Object[0]);
Problem is List systemCall object is always null in response received through resttemplate even though systemCall attribute is present in JSON whenever I hit endpoint through swagger.
There is a defect in RestTemplate.exchange that prevents the deserialisation of even moderately complex JSON objects.
Read the response as a String and then deserialise to List<ResolutionVo> with an com.fasterxml.jackson.databind.ObjectMapper instance as follows:
ResponseEntity<String> response = this.restTemplateConfig.restTemplate().exchange(builder.toUriString(), HttpMethod.POST, httpEntity, String.class, new Object[0]);
String body = response.getBody();
List<ResolutionVo> value = objectMapper.readValue(body, new TypeReference<List<ResolutionVo>>() {});
I think this is a related issue.
I am calling an endpoint that returns back a JSON response.
Here is sample of the JSON response:
{
"main": {
"test":{
"Date": "2022-06-06",
"Id": 1234
},
"response" :[
{
"responseTime": 100,
"redirects": 0
}
]
}
}
Here is my code to get the JSON response:
HttpEntity<String> request = new HttpEntity<>(setHeaders());
ResponseEntity<Main> response = restTemplate.exchange(endpoint, HttpMethod.GET, request, Main.class);
I want to convert the response to an entity object, with the response section being a HashMap. I tried the following but I get an error that the conversion failed
public class Main {
private Test test;
private Response response;
}
public class Test{
private Date Date;
private int Id;
}
public class Response{
private Map<String, String> responseMap;
}
Can someone help me understand what I am doing wrong?
what you are getting back is an Object containing a main object
{
"main": {
"test":{
"Date": "2022-06-06",
"Id": 1234
},
"response" :[
{
"responseTime": 100,
"redirects": 0
}
]
}
}
which means
// Can be named whatever
public class Response {
private Main main;
//constructor, getter setters
}
public class Main {
private Test test;
private ArrayList<Data> response;
//constructor, getter setters
}
public class Test {
private LocalDate date;
private int id;
//constructor, getter setters
}
public class Data {
private int responseTime;
private int redirects;
//constructor, getter setters
}
And then you call and plase the response data in the top level object
ResponseEntity<Main> response = restTemplate.exchange(endpoint, HttpMethod.GET, request, Response.class);
I am using retrofit to do the api call from my android app. But the response shows the status code 200 with ok message.
But the data for the call is return by httpClient.
So how can I handle the response data of my call.
Here the response will be
request payload
/okhttp.OkHttpClient: {"data":{"email":"foobar#gmail.com","password":"PASSWoRD121"}}
response:
okhttp.OkHttpClient: {"data":"my tokken"}
Here is my printed response will not give the above data. How can I set the token to my next calls?
response ==== Response{protocol=http/1.1, code=200, message=OK, url="http://tyhgfhfty/hfhgfh/"}
ApiService.java
#POST(ApiConstant.Login)
Call<User> LoginRequest(#Body JsonObject user);
LoginActivity:
ApiService userLoginService = retrofit.create(ApiService.class);
final JsonObject jo = new JsonObject();
jo.addProperty(ApiParameter.EMAIL, email);
jo.addProperty(ApiParameter.PASSWORD, password);
final JsonObject jobj = new JsonObject();
jobj.add(ApiParameter.DATA, jo);
userLoginService.userLogin(jobj).enqueue(new Callback<LoginRequest>(){
#Override
public void onResponse(Call<LoginRequest> call, Response<LoginRequest>response) {
System.out.println(("response ===" + response));
LoginRequest.java
public class LoginRequest {
private String email;
private String password;
public void setEmail(String email) {
this.email = email;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public String getPassword() {
return password;
}
}
When you have a json response, you can analyze or presume a json is equal a class, because Gson convertion.
In that json is containing a key data and a string my tokken.
In a class retrofit response it is equal variable named data which is from key data with type String, why String? because value my tokken is a string in that json. So you can retrieve that value later from data getter setter. Like getData();
So for {"data":"my tokken"}, your LoginResponse class only contain one field that is data with type String and the setter getter.
When you have response {"data": {"user": "xxxx", "email": "foobar#gmail.com", "lastname": "yyyyy", "gender": 1, "deviceType": 1}"}. You can analyze that key data contain a json object; a json equal a class.
So, you need a class to get accessibility to it value. Let's say it User class.
public class User {
private String user; // because the value of user in json is String
private String email;
private String lastname;
private Int gender; // because the value of gender in json is Int
private Int deviceType;
// the setter getter here
}
Last, your class response that handle the retrofit call. Let say UserResponse should be like this
public class UserResponse {
private User data;
// the variable is named data because it should be the same to the json key and the type of the variable is class `User`. Remember about the bolded text
// (variable named same is not a must, if different, you can use `SerializedName` annotation, you can read about it later)
// the setter getter here
}
I explained in simple way of my thinking, i hope you understand about it.
JSON FORMAT:
[
{
"0":
{
"cast":"",
"showname":"woh pagle",
"type":"Episodes"
},
"video":[
{
"src":"video.mp4"
},
{
"DRM":"False"
}
]
}
]
Here problem is I am getting below exception:
org.codehaus.jackson.map.JsonMappingException: Can not deserialize
instance of java.util.ArrayList out of START_OBJECT token at [Source:
java.io.StringReader#1c9ca1; line: 1, column: 55617] (through
reference chain:
com.apalya.myplex.valueobject.ThirdPartyContentDetailsArray["video"])
My pojo classes are :
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonProperty("0")
private ThirdPartySubContentDetails subContent;
#JsonProperty("video")
private List<ThirdPartySubContentVideoInfo> video;
My Sub class pojo is :
private String src;
#JsonIgnore
#JsonProperty("DRM")
private String drm;
Please help me to write a pojo for that video list.
Your json starts as an array and not as an Object. The important part to change is how the Objectmapper should generate your json. For returning a List you need to do it this way:
List<FirstJson> jsonList = mapper.readValue(json, new TypeReference<List<FirstJson>>(){});
Here is my short working test I implement locally:
public static void main(String[] args) {
String json = "[{\"0\":{\"cast\":\"\",\"showname\":\"wohpagle\",\"type\":\"Episodes\"},\"video\":[{\"src\":\"video.mp4\"},{\"DRM\":\"False\"}]}]";
ObjectMapper mapper = new ObjectMapper();
List<FirstJson> jsonList = mapper.readValue(json, new TypeReference<List<FirstJson>>(){});
System.out.println(jsonList.toString());
}
The first part of your JsonArray in Pojo.(Named it FirstJson)
public class FirstJson{
#JsonProperty("0")
private FirstJson subContent;
private String cast;
private String showname;
private String type;
#JsonProperty("video")
private List<Video> videos;
//getter/setter
And the Video Pojo:
public class Video {
private String src;
#JsonProperty("DRM")
private String drm;
//getter/setter
Just a sidenote: If you declare your pojos in the same class file, the classes should be static. public static class FirstJson
According to the JSON structure described in the question, the following should be the POJOs:
public class MainPojo
{
#JsonProperty("0")
private ThirdPartySubContentDetails subContent;
#JsonProperty("video")
private List<ThirdPartySubContentVideoInfo> video;
// Getters and Setters for subContent and video
}
class ThirdPartySubContentDetails
{
private String cast;
private String showName;
private String type;
// Getters and Setters for cast, showName and type
}
#JsonIgnoreProperties(ignoreUnknown = true)
class ThirdPartySubContentVideoInfo
{
#JsonProperty("src")
private String src;
#JsonProperty("DRM")
private String drm;
// Getters and Setters for src and drm
}
You should call the deserializer method as follows:
List<MainPojo> list = new ObjectMapper().readValue(json, new TypeReference<List<MainPojo>>(){});
I wrote an REST service to ingest metadata from post requests. I am using spring-data-elasticsearch, and I made a custom Metadata Object to deserialize Json into that looks like this:
#Document(indexName = "metadata_v1", type = "metadata")
public class Metadata {
#Id
private String id;
#Field(type = FieldType.String)
private String uuid;
#Field(type = FieldType.String)
private String userId;
#Field(type = FieldType.Date, format = DateFormat.basic_date_time)
private Date date = null;
#Field(type = FieldType.String)
private String classification;
#Field(type = FieldType.Nested)
private List<NumericKeyValue> numericKeyValue;
#Field(type = FieldType.Nested)
private List<TextKeyValue> textKeyValue;
with a bunch of getters and setters.
It works fine for all of its fields except numericKeyValue and textKeyValue Json Arrays. I couldn't send those in via post request, and realized I needed to write a deserializer. I did that for numericKeyValue, and as far as I've read, it's supposed to look like this:
public class NumericKeyValueJsonDeserializer extends JsonDeserializer<List<NumericKeyValue>>{
#Override
public List<NumericKeyValue> deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
TypeReference<List<NumericKeyValue>> typeRef = new TypeReference<List<NumericKeyValue>>(){};
ObjectMapper mapper = new ObjectMapper();
JsonNode root = jp.getCodec().readTree(jp);
String numericKeyValue = root.get("numericKeyValue").asText();
return mapper.readValue( numericKeyValue, typeRef);
}
}
And I added
#JsonDeserialize(using = NumericKeyValueJsonDeserializer.class)
to the field declaration in my Metadata class.
However, after a lot of testing, I have come to realize that the JsonNode root not only doesn't contain "numericKeyValue", but gives me a completely empty string when I invoke root.asText().
I have been using Postman to send in a post request to my endpoint
#RequestMapping(value="/metadata_v1/ingest", method=RequestMethod.POST, consumes="application/json")
public #ResponseBody Metadata createEntry(#RequestBody Metadata entry){
repository.save(entry);
return entry;
}
containing the following Json:
{
"numericKeyValue":
[
{
"key": "velocity",
"value": 55.5
},
{
"key": "angle",
"value": 90
}
]
}
My mapping looks like this:
"numericKeyValue" : {
"type" : "nested",
"properties" : {
"key" : {"type" : "string"},
"value" : {"type" : "double"}
}
}
I can show more things if needed. I think I will be fine if I can just get the JSON I send in Java somehow, perhaps as a String. I've been getting empty Strings that result in null pointer exceptions and when I tried String numericKeyValue = jp.getText() the String was just the current token of "[", which I guess at least isn't an empty String, but still doesn't help me.
Any help or advice is much appreciated.
In your case the value for numericKeyValue is an array. You should replace the following line:
String numericKeyValue = root.get("numericKeyValue").asText();
with:
if ( root.isArray() ){
// loop trough array
for (final JsonNode node : root){
String numericKeyValue = node.get("numericKeyValue").asText();
// then build the list to be returned
}
}