Cannot deserialize instance of java.lang.String out of START_ARRAY token: - java

Hi Everyone i want to call my api from lambda but when i am passing the request i got this error "Cannot deserialize instance of java.lang.String out of START_ARRAY token"
This is the POJO but here only List aids is not deserializing when passing request from Lambda
#Data
#Builder
#ToString
public class BulkFetchRequest {
#JsonProperty("merchId")
private String merchId;
#JsonProperty("markId")
private String markId;
#JsonProperty("aids")
private List<String> aids;
}
This is my request format:
{
"merchId": "2077759361",
"markId" : "44571",
"aids": ["B096BK8GW", "B09B7S84X", "B07N7QPZD", "B09GG2LPL" , "B09M41GVR"]
}

Related

Unable to convert a json array into java list

I have the following Json string:
String jsonString = "[
{
"nameOnCard": "Test T",
"active": true,
"declineReason": null
},
{
"nameOnCard": "TestT",
"active": false,
"declineReason": "payment_stolen"
}
]";
The string is contained in an object called ApiResponse in a field called data. E.g.
APIResponse apiResponse = APIResponse.builder()
.data(jsonString)
.build();
I am trying to map the contents of the string into a list of PaymentObject.
The payment object looks like this:
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class PaymentObject {
private String declineReason;
private String nameOnCard;
private String active;
}
I am using the following to convert the String into a List<PaymentObject> by the following:
List<PaymentObject> paymentObjectDTOs = mapper.convertValue(apiResponse.getData(), new TypeReference<>() {});
where mapper is ObjectMapper from Jackson 2.13.2.2.
But I am getting the following error:
Cannot deserialize value of type `java.util.ArrayList<com.abc.PaymentObject>` from String value (token `JsonToken.VALUE_STRING`)
at [Source: UNKNOWN; byte offset: #UNKNOWN]
I can't see what's going wrong.
You're missing the referenced type. This will work:
List<PaymentObject> paymentObjectDTOs =mapper.readValue(apiResponse.getData(), new TypeReference<List<PaymentObject>>(){});
But make sure you've all the getters and setters methods on the PaymentObject class, as well as the default constructor.

Issue with serializing JSON from a rest call

Newbie developer here. I am trying to make a call to a public API. The API receives the name of a drink as a string and returns information and recipe for that name. The response from the API looks like this:
{
"drinks":[
{
"id": ...
"name": ...
"recipe": ...
"category": ...
"alcoholic": ...
... many other fields ...
},
{
...
}
...
]
}
I am only interested in name, recipe and category. I have a domain class for this purpose that looks like this
#Data
#NoArgsConstructor
#AllArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class Drink {
#JsonProperty("name")
private String name;
#JsonProperty("category")
private String category;
#JsonProperty("recipe")
private String recipe;
}
I also implemented a client to call the endpoint using restTemplate. Here is the call that client makes:
ResponseEntity<List<Drink>> response = restTemplate.exchange(
url,
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<Drink>>() {
});
My goal is to call the API, get the response and only the fields that I want and store it in a list of Drink. However when I try to run the app locally and make a call I am getting this error:
Caused by: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.util.ArrayList<Drink>` from Object value (token `JsonToken.START_OBJECT`); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.util.ArrayList<Drink>` from Object value (token `JsonToken.START_OBJECT`)
When I use ResponseEntity<String> instead, it works but returns the whole json as a string, which does not seem like a good approach. How can I get this approach to work?
The problem is mismatch between json structure and object structure. The object you deserialize into must represent correctly the json. It's an object with a field drinks, which is an array of objects(drinks in your case). Correct java class would be:
public class Wrapper {
private List<Drink> drinks;
//getters and setters
#Override
public String toString() {
return "Wrapper{" +
"drinks=" + drinks +
'}';
}
}
Other option would be to write custom deserializer, which can extract drinks from the tree before deserializing directly into a list.]
Edit: Added toString() override for debugging purposes.

Map nested json to a pojo with raw json value

I have a nested json pojo where the nested part of json is tagged with #JsonRawValue. I am trying it to map with rest template, but I am getting the error
JSON parse error: Cannot deserialize instance of java.lang.String out of START_OBJECT token;
The nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException.
This is what my response object looks like:
import com.fasterxml.jackson.annotation.JsonRawValue;
public class ResponseDTO {
private String Id;
private String text;
#JsonRawValue
private String explanation;
//getters and setters;
}
where explanation is a json mapped to a string. This works fine with postman, swagger, and I see the explanation as json in the response.
But when I am testing it using Rest Template:
ResponseEntity<ResponseDTO> resonseEntity = restTemplate.exchange(URI, HttpMethod.POST, requestEntity, ResponseDTO.class);
I see this exception:
org.springframework.web.client.RestClientException: Error while extracting
response for type [class com.**.ResponseDTO] and content type
[application/json;charset=utf-8]; nested exception is
org.springframework.http.converter.HttpMessageNotReadableException: JSON
parse error: Cannot deserialize instance of java.lang.String out of
START_OBJECT token; nested exception is
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot
deserialize instance of java.lang.String out of START_OBJECT token
at [Source: (PushbackInputStream); line: 1, column: 604] (through
reference chain: com.****.ResponseDTO["explanation"])
Jackson is telling you that it can't insert an Object (in the error log) inside a String.
The #JsonRawValue is used during serialization of objects to JSON format. It is a way to indicate that the String field is to be sent as-is. In other words, the purpose is to tell Jackson that the String is a valid JSON and should be sent without escaping or quoting.
What you can do instead is provide Jackson with a custom method for it to set the field value. Using JsonNode as the argument will force Jackson to pass the "raw" value. From there you can get the string representation:
public class ResponseDTO {
private String Id;
private String text;
private String explanation;
//getters and setters;
#JsonProperty("explanation")
private void unpackExplanation(JsonNode explanation) {
this.explanation = explanation.toString();
}
}

Java Spring JSON parse error: Cannot deserialize instance out of START_ARRAY token

I have a method with a restTemplate call like this:
restTemplate.getForObject(apiUrl ,Someclass.class);
Someclass.class:
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class Imp implements Serializable {
#JsonProperty("Id")
private String Id;
#JsonProperty("ReportId")
private String ReportId;
#JsonProperty("Title")
private String Title;
#JsonProperty("Name")
private String Name;
#JsonProperty("Uri")
private String Uri;
}
The API returns an array, and the error i'm receiving is:
org.springframework.web.client.RestClientException: Error while extracting response for type [class ...] and content type [application/json;charset=utf-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of com... out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of com... out of START_ARRAY token
Which restTempalte method shoud i use to get proper api response?, or where is the problem?.thanks!
You said the API returns an array.
But your line of code restTemplate.getForObject(apiUrl ,Someclass.class);
will work only for a single Someclass object.
You should use new ParameterizedTypeReference<List<Someclass.class>> along with the exchange method.
Refer to the below link
Get list of JSON objects with Spring RestTemplate

RestTemplate: Can not deserialize instance of OBJECT out of START_OBJECT token

I'm trying out the RestTemplate stuff from spring. I'm trying to read in this JSON data: JSON Data. The data is a a key value pair in which the key is "geonames" and the value is an array of "geoname" objects.
I have a Geoname class to handle the input. This class also has getters and setters in it. I then have an app class that just runs a main method to invoke a RestTemplate object:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Geoname {
private String name;
private long lat;
private long lng;
private String countrycode;
}
App.java
public class App
{
public static void main( String[] args )
{
String jsonUrl = "http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo";
RestTemplate template = new RestTemplate();
ResponseEntity<Geoname[]> entity = template.getForEntity(jsonUrl, Geoname[].class);
List<Geoname> data = Arrays.asList(entity.getBody());
System.out.print("Success!");
}
}
This is my error output:
Exception in thread "main" org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Can not deserialize instance of com.declan.Geoname[] out of START_OBJECT token
at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream#54fc3ac5; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of com.declan.Geoname[] out of START_OBJECT token
at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream#54fc3ac5; line: 1, column: 1]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:208)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:200)
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:96)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:812)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:796)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:576)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:529)
at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:261)
at com.declan.App.main(App.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of com.declan.Geoname[] out of START_OBJECT token
at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream#54fc3ac5; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:835)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:831)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.handleNonArray(ObjectArrayDeserializer.java:232)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:139)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:17)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3560)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2660)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:205)
... 13 more
I've tried this setup, i've tried using getForObject like on the spring documentation, I've tried searching here on stackoverflow and using the common answer of mapping to a list. I've even tried creating a Geonames class that contained just an array or Geoname objects but that didn't work either...Same error all the time. Perhaps, I'm not reading the Json correctly but if someone could lend me a pair of eyes I'd be grateful. :D
Cheers!
EDIT
Okay, I now have this new class and it now makes the GET request for the JSON data. However, after a debug, the ResponseEntity body has the array set to null. Do I need to instantiate the array in Geonames manually?
#JsonIgnoreProperties(ignoreUnknown = true)
public class Geonames {
#JsonProperty("geonames")
Geoname[] geonames;
public void setGeonames(Geonames[] geonames) {
this.geonames = geonames;
}
public void getGeonames() {
return geonames;
}
}
Resolved. Turns out that the null was because the JSON link had a max hits per hour limit. By creating my own account on the site, the api gave me my own limits. So the response body then populated with data.

Categories

Resources