Cannot deserialize instance of POJO out of START_ARRAY token - spring

I'm using merriam webster API and for some words, i get this error. I tried to see the difference between words and found that some of them are missing a property, in this case It's app-shortdef, which is a POJO class that i've created.
As I said, It only occurs on words that misses this property. Is there a way to just ignore these words?
Word that doens't work
"meta": {
"id": "car park",
"uuid": "c54c3476-f520-457e-97db-355b4fad1a0f",
"src": "learners",
"section": "alpha",
"target": {
"tuuid": "f675a703-73a4-4ba0-bab2-b516be9c9d5a",
"tsrc": "collegiate"
},
"stems": [
"car park",
"car parks"
],
"app-shortdef": [],
"offensive": false
},
Word that works
"meta": {
"id": "ball:2",
"uuid": "908a56c8-aa20-440d-bd0c-735d956ff1f4",
"src": "learners",
"section": "alpha",
"target": {
"tuuid": "be866f14-c794-4dee-bc3b-aee0002daaaa",
"tsrc": "collegiate"
},
"stems": [
"ball",
"balled",
"balling",
"balls"
],
"app-shortdef": {
"hw": "ball:2",
"fl": "verb",
"def": [
"{bc} to form (something) into a ball"
]
},
"offensive": false
},
As you can see, the difference is that app-shortdef is empty in the first one. Here is my POJO structure:
Dicionario
package com.ankitoword.entity;
public class Dicionario {
private Meta meta;
public Meta getMeta() {
return meta;
}
public void setMeta(Meta meta) {
this.meta = meta;
}
}
Meta
public class Meta {
private String id;
#JsonProperty(value="app-shortdef")
private AppShortDef appShortdef;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public AppShortDef getAppShortdef() {
return appShortdef;
}
public void setAppShortdef(AppShortDef appShortdef) {
this.appShortdef = appShortdef;
}
}
App
public class AppShortDef {
public String hw;
public String fl;
public String[] def;
public String getHw() {
String[] split = hw.split(":");
return split[0];
}
public void setHw(String hw) {
this.hw = hw;
}
public String getFl() {
return fl;
}
public void setFl(String fl) {
this.fl = fl;
}
public String[] getDef() {
return def;
}
public void setDef(String[] def) {
this.def = def;
}
}
Full Error
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Nov 26 19:24:58 BRT 2020
There was an unexpected error (type=Internal Server Error, status=500).
JSON decoding error: Cannot deserialize instance of `com.ankitoword.entity.AppShortDef` out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `com.ankitoword.entity.AppShortDef` out of START_ARRAY token at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: com.ankitoword.entity.Dicionario["meta"]->com.ankitoword.entity.Meta["app-shortdef"])
org.springframework.core.codec.DecodingException: JSON decoding error: Cannot deserialize instance of `com.ankitoword.entity.AppShortDef` out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `com.ankitoword.entity.AppShortDef` out of START_ARRAY token
at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: com.ankitoword.entity.Dicionario["meta"]->com.ankitoword.entity.Meta["app-shortdef"])
at org.springframework.http.codec.json.AbstractJackson2Decoder.processException(AbstractJackson2Decoder.java:215)
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
Service Class
The error occurs on the collectList() line.
public List<Dicionario> getWords(String palavra) {
// OMono permite tratar o retorno quando a requisição finalizar sem bloquear o método.
Flux<Dicionario> fluxDicionario = this.webClient
.get()
.uri(builder -> builder.path("/"+palavra).queryParam("key", APIKey).build())
.retrieve() //Retorna o response-spec
.bodyToFlux(Dicionario.class);
List<Dicionario> dicionarios = new ArrayList<>();
dicionarios = fluxDicionario.collectList().block();
return dicionarios;
}
#Edit
I've fixed this problem accepting a Object as a parameter, then checking if It's a array list, meaning It's the empty array and can't be converted.
public void setAppShortDef(Object object) {
if (object instanceof ArrayList){
//
} else {
ObjectMapper mapper = new ObjectMapper();
AppShortDef appShortDef = mapper.convertValue(object, AppShortDef.class);
this.appShortDef = appShortDef;
}
}
I Have another problem now, I can get a response that doesn't contain any of my properties. Ex:
[
"testified",
"the last\/final word",
"testify for",
"Lakewood",
"foreword",
"headword",
"lakewood",
"sent word",
"swearword",
"testament",
"testamentary",
"testaments",
"tested",
"tester",
"testers",
"testier",
"testosterone",
"the f-word",
"the final word",
"true to her word"
]

Related

Parsing nested json received from an api to objects in spring boot

I am creating a spring boot application which receives some JSON data from a 3rd party api. The JSON data has so many nested objects.I want to map them as Java objects. Below is the code I wrote for getting the api response.
public ResponseEntity<MovieSearchResultsDto> getMovies(String searchText, String countryCode) {
logger.info("GetMovies Service started");
String url = prepareUrl(searchText,countryCode);
HttpHeaders header = new HttpHeaders();
prepareHeader(header);
HttpEntity<String> requestEntity = new HttpEntity<String>(header);
try {
logger.info("Calling the API for movie info");
responseEntity = restClient.exchange(url,
HttpMethod.GET,
requestEntity,
MovieSearchResultsDto.class);
}catch (Exception e) {
logger.error("Exception occured while calling the API "+ e);
if(responseEntity.getStatusCodeValue() != 200) {
}
}
logger.info("GetMovies Service Ended");
return responseEntity;
}
And the JSON response looks like
{
"results": [
{
"id": ******,
"picture": "url",
"name": "Titanic",
"locations": [
{
"icon": "url",
"display_name": "Amazon Instant Video",
"name": "AmazonInstantVideoIVAGB",
"id": "***",
"url": "url"
}
],
"provider": "iva",
"weight": 0,
"external_ids": {
"iva_rating": null,
"imdb": {
"url": "url",
"id": "tt0046435"
},
"tmdb": {
"url": "url",
"id": "id"
},
"wiki_data": {
"url": "url",
"id": "id"
},
"iva": null,
"gracenote": null,
"rotten_tomatoes": null,
"facebook": null
}
}
] }
What I have done is , I created a class MovieSearchResultsDto and include a list as its data member with getters and setters.
private List<MoviesDto> results = new ArrayList<>();
And created MoviesDto class as below
public class MoviesDto {
private String id;
private String name;
private String picture;
#JsonInclude(value = Include.NON_EMPTY)
private List<MovieLocation> locations = new ArrayList<MovieLocation>();
#JsonInclude(value = Include.NON_EMPTY)
private List<ExternalIds> external_ids = new ArrayList<ExternalIds>();
public MoviesDto() {
}
//getters and setters
}
class MovieLocation{
private String icon;
private String id;
private String display_name;
private String name;
private String url;
public MovieLocation() {
}
//getters and setters
}
class ExternalIds{
private IdAndUrl imdb;
private IdAndUrl tmdb;
private IdAndUrl wiki_data;
public ExternalIds() {
}
//getters and setters
}
class IdAndUrl{
private String url;
private String id;
public IdAndUrl() {
}
//getters and setters
}
But it shows error while parsing.
Exception occured while calling the API org.springframework.web.client.RestClientException: Error while extracting response for type [class com.prebeesh1427.MovieNameServiceProvider.dto.MovieSearchResultsDto] and content type [application/json]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.util.ArrayList<com.prebeesh1427.MovieNameServiceProvider.dto.ExternalIds>` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList<com.prebeesh1427.MovieNameServiceProvider.dto.ExternalIds>` out of START_OBJECT token
at [Source: (PushbackInputStream); line: 1, column: 1054] (through reference chain: com.prebeesh1427.MovieNameServiceProvider.dto.MovieSearchResultsDto["results"]->java.util.ArrayList[0]->com.prebeesh1427.MovieNameServiceProvider.dto.MoviesDto["external_ids"])
I am a newbie to this area. Kindly help me not just only to resolve this issue but to understand the concept of these parsing techniques too.
Thanks in advance

Spring Boot - Get Data from DB and store it in list and parse it to JSON using jackson

I'm trying to get data from multiple tables and put it in Array List of class, and then convert it to JSON Object.
But when i'm trying to parse it to json using Jackson Object Mapper all the lists are converted as below
Using ObjectMapper().writeValueAsString for deserialization from class objects to json
```{
"College": [
{
"institution": [
{
"instId": "T34",
"Country": "India",
"Code": "T33"
},
{
"instId": "T22",
"Country": "India",
"Code": "T22"
}
],
"Rating": [
{
"star": "4"
"comments": "good"
},
{
"star": "2"
"comments": "ok"
},
}
]
}```
But i want the result as below
{
"College": [
{
"institution": [
{
"instId": "T34",
"Country": "India",
"Code": "T33"
}
],
"Rating": [
{
"star": "4"
"comments": "good"
}
]
},
{
"institution": [
{
"instId": "T22",
"Country": "India",
"Code": "T22"
}
],
"Rating": [
{
"star": "2"
"comments": "ok"
}
]
}
]
}
The above is just an example.
Please help in getting the desired output.
Below are the class files used.
public class AllCollege{
List<College> college = new ArrayList<>();
public List<College> getCollege() {
return college;
}
public void setCollege(List<College> college) {
this.college = college;
}
}
public class College{
private List<Institution> institution = new ArrayList<>();
private List<Rating> rating = new ArrayList<>();
public List<Institution> getInstitution() {
return institution;
}
public void setInstitution(List<Institution> institution) {
this.institution = institution;
}
public List<Rating> getRating() {
return rating;
}
public void setRating(List<Rating> rating) {
this.rating = rating;
}
}
public class Institution {
private String instId;
private String country;
private String code;
public String getInstId() {
return instId;
}
public void setInstId(String instId) {
this.instId = instId;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
public class Rating {
private String star;
private String comments;
public String getStar() {
return star;
}
public void setStar(String star) {
this.star = star;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
}
Below is where the data from tables is set into ArrayList and then converted to json string.
session = sessionFactory.openSession();
String sql = "from institution";
Query<InstDto> query = session.createQuery(sql);
List<Institution> configdtoList =query.list();
College alc = new College();
alc.setInstitution(configdtoList);
.
.
.
similarly Rating table.
List<College> clist = new new ArrayList<>();
clist.add(alc);
AllCollege ac = new AllCollege();
ac.setCollege(clist);
String responseJson = new ObjectMapper().writeValueAsString(ac)
class structure as below it will help you to parse:
public class Sample {
#JsonProperty("College")
private List<College> college;
}
public class College {
private List<Institution> institution;
#JsonProperty("Rating")
private List<Rating> rating;
}
public class Rating {
private String comments;
private String star;
}
public class Institution {
#JsonProperty("Code")
private String code;
#JsonProperty("Country")
private String country;
private String instId;
}
I have created an HashMap contains the List<AllCollege> as value and then used json parser which worked as expected.

Cannot deserialize instance

I have a problem. I am using Spring Boot and sqlite3 DB. I tried to send data to the DB.
When I sent data to the DB I have this error:
{
"timestamp": "2019-02-12T12:39:40.413+0000",
"status": 400,
"error": "Bad Request",
"message": "JSON parse error: Cannot deserialize instance of `com.dar.darkozmetika.models.CategoryModel` out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `com.dar.darkozmetika.models.CategoryModel` out of START_ARRAY token\n at [Source: (PushbackInputStream); line: 1, column: 1]",
"path": "/api/cateogry/dar"
}
This is my controller:
RestController
#RequestMapping("api/cateogry/dar")
public class CategoryController {
#Autowired
private CategoryRepository categoryRepository;
#GetMapping
private List<CategoryModel> getAllCategory (){
System.out.println("sadad");
System.out.println("sadad" + this.categoryRepository.findAll());
return this.categoryRepository.findAll();
}
#PostMapping
#ResponseStatus(HttpStatus.OK)
public void create(#RequestBody CategoryModel bike) {
categoryRepository.save(bike);
}
#GetMapping("/{id}")
public CategoryModel getSpecificCategory(#PathVariable("id") long id) {
return null;//categoryRepository.getOne(id);
}
}
This is my model:
#Entity
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class CategoryModel {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String categoryName;
private String categoryDescription;
private String imagePath;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCategoryName() {
return categoryName;
}
I sent this data from Postman:
[
{
"id": 2,
"categoryName": "dsds",
"categoryDescription": "sdsd",
"imagePath": "Jsdsds"
}
]
Very interesting, I can get data from the DB without problems. This is return form my DB.
[
{
"id": 1,
"categoryName": "jeff#bikes.com",
"categoryDescription": "Globo MTB 29 Full Suspension",
"imagePath": "Jeff Miller"
}
]
Your request is not ok, you are sending an array of CategoryModel and the POST api/cateogry/dar receives just a CategoryModel. You should send just:
{
"id": 2,
"categoryName": "dsds",
"categoryDescription": "sdsd",
"imagePath": "Jsdsds"
}

Spring doesn't consume a RESTful Web Service but deserialises the corresponding string properly, why?

I'm trying to consume a RESTful Web Service with Spring and my reference code is the one in this guide. The service that I'm interrogating returns JSON like the following:
{ "id": 1,
"content": [
{ "dependencies": [
{ "parent": 0, "child": 1, "type": "PUNCT" },
{ "parent": 0, "child": 2, "type": "NPADVMOD" },
{ "parent": 0, "child": 3, "type": "PUNCT" } ],
"tokens": [
{ "ent": "", "index": 0, "lemma": "hello", "pos": "INTJ", "tag": "UH", "text": "Hello" },
{ "ent": "", "index": 1, "lemma": ",", "pos": "PUNCT", "tag": ",", "text": "," },
{ "ent": "PERSON", "index": 2, "lemma": "world", "pos": "PROPN", "tag": "NNP", "text": "World" },
{ "ent": "", "index": 3, "lemma": "!", "pos": "PUNCT", "tag": ".", "text": "!" } ]
} ]
}
I have created the following objects (all their methods are omitted for brevity):
#JsonIgnoreProperties(ignoreUnknown = true)
public class Token {
private String ent;
private int index;
private String lemma;
private String pos;
private String tag;
private String text;
}
#JsonIgnoreProperties(ignoreUnknown = true)
public class Dependency {
private int parent;
private String type;
private int child;
}
#JsonIgnoreProperties(ignoreUnknown = true)
public class Content {
private List<Token> tokens;
private List<Dependency> dependencies;
}
#JsonIgnoreProperties(ignoreUnknown = true)
public class Message {
private long id;
private List<Content> content;
}
With the following code, I can successfully deserialise a Message object:
#RequestMapping("/message")
public String message() {
return "{\"content\": [{\"dependencies\": [{\"child\": 1,\"type\": \"PUNCT\",\"parent\": 0},{\"child\": 2,\"type\": \"NPADVMOD\",\"parent\": 0},{\"child\": 3,\"type\": \"PUNCT\",\"parent\": 0}],\"tokens\": [{\"index\": 0,\"text\": \"Hello\",\"tag\": \"UH\",\"lemma\": \"hello\",\"pos\": \"INTJ\",\"ent\": \"\"},{\"index\": 1,\"text\": \",\",\"tag\": \",\",\"lemma\": \",\",\"pos\": \"PUNCT\",\"ent\": \"\"},{\"index\": 2,\"text\": \"World\",\"tag\": \"NNP\",\"lemma\": \"world\",\"pos\": \"PROPN\",\"ent\": \"PERSON\"},{\"index\": 3,\"text\": \"!\",\"tag\": \".\",\"lemma\": \"!\",\"pos\": \"PUNCT\",\"ent\": \"\"}]}],\"id\": 1}";
}
#RequestMapping("/decode")
public Boolean decode() {
RestTemplate restTemplate = new RestTemplate();
Message response = restTemplate.getForObject("http://localhost:8080/message", Message.class);
logger.info("I got: {}", response);
return Boolean.TRUE;
}
as I can see in the log:
17:26:34.609 [qtp990226843-17] INFO a.c.j.controllers.ExampleController - Message[content = [Content[dependencies = [Dependency[child = 1, parent = 0, type = PUNCT], Dependency[child = 2, parent = 0, type = NPADVMOD], Dependency[child = 3, parent = 0, type = PUNCT]], tokens = [Token[ent = , index = 0, lemma = hello, pos = INTJ, tag = UH, text = Hello], Token[ent = , index = 1, lemma = ,, pos = PUNCT, tag = ,, text = ,], Token[ent = PERSON, index = 2, lemma = world, pos = PROPN, tag = NNP, text = World], Token[ent = , index = 3, lemma = !, pos = PUNCT, tag = ., text = !]]]], id = 1]
If I try to connect directly to the RESTful Web Service with the following code:
#RequestMapping("/remote")
public Boolean remote() {
RestTemplate restTemplate = new RestTemplate();
Map<String, String> env = System.getenv();
String host = env.getOrDefault("MY_HOST", "localhost");
String port = env.getOrDefault("MY_HOST", "7890");
String url = String.format("http://%s:%s", host, port);
String content = "Hello, World!";
URI uri = UriComponentsBuilder.fromHttpUrl(url).queryParam("content", content).build().encode().toUri();
Message response = REST_TEMPLATE.getForObject(uri, Message.class);
logger.info("I got: {}", response);
return Boolean.TRUE;
}
I observe the following error:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Fri Jun 02 16:53:42 BST 2017
There was an unexpected error (type=Internal Server Error, status=500).
org.springframework.web.util.NestedServletException: Request processing failed;
nested exception is org.springframework.web.client.RestClientException:
Could not extract response: no suitable HttpMessageConverter found for response
type [class ai.context_scout.joshi.model.Message] and content type
[text/plain;charset=utf-8]
I search online and in this site to find a solution, but I couldn't think of any keyword that led to meaningful results... any help?
Why I get this error? How to fix it?
Thanks!
PS: I just tried to implement a dumb service that connects to the remote service and returns the JSON received by that service as a String, and I modified the decode service that was already able to deserialise the JSON to get the data from the dumb service rather than the remote service and it works! I'm flabbergasted! It doesn't make sense!
Anyway, for reference, the code is as follows (please let me know if it is possible to avoid to use the dumb service):
#RequestMapping("/dumb")
public String dumb() {
Map<String, String> env = System.getenv();
String host = env.getOrDefault("SPACY_HOST", "localhost");
String port = env.getOrDefault("SPACY_HOST", "7890");
String url = String.format("http://%s:%s", host, port);
String content = "Hello, World!";
URI uri = UriComponentsBuilder.fromHttpUrl(url).queryParam("content", content).build().encode().toUri();
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject(uri, String.class);
logger.info("I got: {}", response);
return response;
}
#RequestMapping("/decode")
public Boolean decode() {
RestTemplate restTemplate = new RestTemplate();
Message response = restTemplate.getForObject("http://localhost:8080/dumb", Message.class);
logger.info("I got: {}", response);
return Boolean.TRUE;
}

Get data as a JSON format in spring boot

I want to build a request endepoints using spring boot: I have to consume restful api and convert that into another rest endpoint.
I have a json Response on www.exampleapiurl.com/details
[{
"name": "age",
"value": "Child"
},
{
"name": "recommendable",
"value": true
},
{
"name": "supported",
"value": yes
},
]
[{
"name": "age",
"value": "Adult"
},
{
"name": "recommendable",
"value": true
},
{
"name": "supported",
"value": no
},
]
I want the response to be:
[{
"age": "Child"
},
{
"recommendable": true
},
{
"supported": "yes"
},
]
[{
"age": "Adult"
},
{
"recommendable": true
},
{
"supported": "no"
},
]
For this I have a attribute class with getter and setter:
Attributes.class
#JsonIgnoreProperties(ignoreUnknown = true)
public class Attributes {
private String age;
private boolean recommendable;
private String supported;
getter and setter for these:
}
This is my service.java class
#Service
public class CService {
private static RestTemplate restTemplate;
public String url;
#Autowired
public CService(String url) {
this.url = url;
}
public Attributes getAttributes() {
HttpHeaders headers= new HttpHeaders();
headers.add("Authorization", "some value");
HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, request, Attributes.class);
return response.getBody();
}
}
And this is my controller.class
#Controller
public class CController {
private CService cService;
#Autowired
public CController(CService cService) {
this.cService = cService;
}
#RequestMapping(value="/example")
#ResponseBody
public Attributes getCAttributes() {
return cService.getAttributes(); }
}
The Authorization is successful but,
I am not getting any response for now
What you can do is create a model class to recive the response from example API
as follows.
#JsonIgnoreProperties(ignoreUnknown = true)
public class Details{
private String name;
private String value;
#JsonProperty("value")
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#JsonProperty("name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Then change your invoking RestTemplate code as follows
Details[] details = null;
//Keeps the example API's data in array.
ResponseEntity<Details[]> response = restTemplate.exchange(url, HttpMethod.GET, request, Details[].class);
details = response.getBody();
//Next step is to process this array and send the response back to your client
List<Attributes> attributes = new ArrayList<Attributes>();
Attributes attr = null;
for(Details detail : details) {
attr = new Attributes();
//set the values here
}
//returns the attributes here
attributes.toArray(new Attributes[attributes.size()]);

Resources