JSON parse error: Can not construct instance of class - java

Unable to map json string with java object, getting error JSON parse error: Can not construct instance of com.test.CPInput$Evc$Uni
error:
{
"timestamp": 1502270576300,
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.http.converter.HttpMessageNotReadableException",
"message": "**JSON parse error: Can not construct instance of com.test.CPInput$Evc$Uni: can only instantiate non-static inner class by using default, no-argument constructor; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.test.CPInput$Evc$Uni: can only instantiate non-static inner class by using default, no-argument constructor at [Source: java.io.PushbackInputStream#edc246; line: 20, column: 9] (through reference chain: com.test.CPInput["evc"]->com.test.CPInput$Evc["uni"]->java.util.ArrayList[0]**)",
"path": "/demo/addCustomer"
}
json
{
"customerId": "abcdef",
"customerSegment": {
"customerType": "customer type",
"customerSubtype": "subtype",
"industry": "industry",
"subIndustry": "subindustry",
"specialPopulation": " spl population"
},
"evc": {
"evcId": "evcid",
"action": "PR",
"serviceId": "assigned prod id",
"previousValues": {
"previousName":"evcId",
"previousValue":"EVC id - OLD"
},
"uni": [
{
"type": "uniA",
"uniId": "uni id",
"siteId": "sidt id",
"tspCode": "tsp code",
"elocId": "e loc id",
"siteClli": "site clli",
"uniAction": "PR",
"previousValues": {
"previousName":"evcId",
"previousValue":"EVC id - OLD"
}
},
{
"type": "uniZ",
"siteId": "sidt id",
"tspCode": "tsp code",
"elocId": "e loc id",
"siteClli": "site clli",
"uniAction": "PR",
"previousValues": {
"previousName":"evcId",
"previousValue":"EVC id - OLD"
}
}
]
},
"solutionType": "EPL",
"source": "Orion"
}
CPInput.java
public class CPInput {
private String customerId;
private CustomerSegment customerSegment;
private Evc evc;
private String solutionType;
private String source;
public CPInput() {
super();
}
public class CustomerSegment{
private String customerType;
private String customerSubtype;
private String industry;
private String subIndustry;
private String specialPopulation;
//getter setter
}
public class Evc{
private String evcId;
private String action;
private String serviceId;
private PreviousValues previousValues;
private List<CPInput.Evc.Uni> uni=new ArrayList<CPInput.Evc.Uni>();
//getter setter
public class PreviousValues{
private String previousName;
private String previousValue;
//getter setter
}
public class Uni{
private String type;
private String uniId;
private String siteId;
private String tspCode;
private String elocId;
private String siteClli;
private String uniAction;
private PreviousValues previousValues;
//getter setter
public class PreviousValues{
private String previousName;
private String previousValue;
//getter setter
}
//getter setter
}
DemoController.java
#RestController
#SpringBootApplication(scanBasePackages = {"com.test"})
#RequestMapping(value = "/demo")
public class DemoController {
#RequestMapping(method = RequestMethod.POST, value = "/addCustomer")
public CPOutput addCustomer(#RequestBody CPInput input) {
System.out.println(input);
return null;
}
}

Try to use static inner classes for: CustomerSegment, Evc, PreviousValues and Uni.
I always use static inner classes, and I don't have any problem like that.

Related

How to create Java classes using the reusable json attributes in Jackson?

I need to convert below JSON to Java classes
Here is the JSON
{
"browserName": "chrome",
"env": "test",
"envUrls1": {
"qatesta": {
"fName": "test",
"lName": "test",
"email": "3242342",
"password": "passTestaa"
},
"qatestb": {
"fName": "test",
"lName": "test",
"email": "3242342",
"password": "passTestaa"
},
"qatestc": {
"fName": "test",
"lName": "test",
"email": "3242342",
"password": "passTestaa"
}
}
}
Using above JSON body I able to creates below classes.
1.
public class JsonConfMainObj {
private String browserName;
private String env;
private EnvUrls1 envUrls1;
}
2.
public class EnvUrls1 {
private Qatesta qatesta;
private Qatestb qatestb;
private Qatestc qatestc;
}
3. In each above 'Qatesta', 'Qatestb' and 'Qatestc' Java Classes Contains the below-repeated values
public class Qatestx{
private String fname;
private String lname;
private String email;
private String password;
}
But I need to avoid repeating the above attributes in each class and move them to common Class and map to 'Qatesta', 'Qatestb', and 'Qatestc'.
like below
public class Qatesta{
private Common com;
}
public class Qatestb{
private Common com;
}
public class Qatestc{
private Common com;
}
public class Common{
private String fname;
private String lname;
private String email;
private String password;
}
Is there a way to do this?
You Can use only One class and give the different variable assigned for that class for eg in EnvUrls1 give class Qatest assigned 3 different values
1.
public class JsonConfMainObj {
private String browserName;
private String env;
private EnvUrls1 envUrls1;
}
2.
public class EnvUrls1 {
private Qatest qatesta;
private Qatest qatestb;
private Qatest qatestc;
}
public class Qatest{
private String fname;
private String lname;
private String email;
private String password;
}

Nested JSON objects from Spring RestClient and Jackson

I have a rest client that will be getting JSON back from an endpoint. I would like to just get what is in the data[].
{
"responseStatus": "SUCCESS",
"responseDetails": {
"limit": 1000,
"offset": 0,
"size": 2,
"total": 2
},
"data": [
{
"id": "00P000000001M01",
"name__v": "Foo",
"status__v": [
"active__v"
],
"abbreviation__c": "F170053",
"internal_name__c": "Foo",
"therapeutic_area__c": [
"neurology__c"
],
"external_id__v": "84",
"generic_name__c": "Foo",
"scientific_name__c": null
},
{
"id": "00P000000001N01",
"name__v": "Bar",
"status__v": [
"active__v"
],
"abbreviation__c": "B333334",
"internal_name__c": "Bar",
"therapeutic_area__c": [
"bone_muscle_joint__c"
],
"external_id__v": "101",
"generic_name__c": "Bar",
"scientific_name__c": null
}
]
}
Because I will make other calls which will return different fields in the data[], I wanted to map each type to a POJO so I used #JSONProperty
#JsonIgnoreProperties(ignoreUnknown = true)
public class Product extends VBase{
private String fNumber;
private String genericName;
private String scientificName;
private String therapeuticArea;
public String getFNumber() {
return fNumber;
}
#JsonProperty("abbreviation__c")
private void unpackFNumber(Map<String,Object> abbreviation__c){
fNumber = ((Map<String,Object>)abbreviation__c.get("data")).get("abbreviation__c").toString();
}
public void setLyNumber(String fNumber) {
this.fNumber = fNumber;
}
public String getGenericName() {
return genericName;
}
#JsonProperty("generic_name__c")
private void unpackGenericName(Map<String,Object> generic_name__c){
genericName = ((Map<String,Object>)generic_name__c.get("data")).get("generic_name__c").toString();
}
public String getScientificName() {
return scientificName;
}
#JsonProperty("scientific_name__c")
private void unpackScientificName(Map<String,Object>sName){
scientificName = ((Map<String,Object>)sName.get("data")).get("scientific_name__c").toString();
}
public String getTherapeuticArea() {
return therapeuticArea;
}
#JsonProperty("therapeutic_area__c")
private void unpackTheraputicArea(Map<String,Object>tArea){
therapeuticArea=((Map<String,Object>)tArea.get("data")).get("therapeutic_area__c").toString();
}
}
I have tried various ways of just getting the data[].
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
RestTemplate restTemplate = new RestTemplate(clientHttpReq);
ResponseEntity<Product[]> response = restTemplate.exchange(url, HttpMethod.GET, request,Product[].class);
//ResponseEntity<Product[]> response = restTemplate.postForEntity(url,request,Product[].class ,parmMap);
What I have been trying to avoid is making a ResponseDetail POJO with a Data[] as a field. I know it will work but because the fields in the data[] will change based on the endpoint.
Can I use a wrapper class with a List to represent the data[] as all of the POJO will extend VBase?
Here is the exception:
Exception in thread "main" org.springframework.web.client.RestClientException: Error while extracting response for type [class [Lcom.lilly.models.Product;] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `com.lilly.models.Product[]` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `com.lilly.models.Product[]` out of START_OBJECT token
at [Source: (PushbackInputStream); line: 1, column: 1]
Declaring a POJO class as below code, and then you can get data property from the POJO.
#Data
public class Example {
private String responseStatus;
private ResponseDetails responseDetails;
private List<Data> data;
#lombok.Data
public static class ResponseDetails {
private int limit;
private int offset;
private int size;
private int total;
}
#lombok.Data
public static class Data {
private String id;
private String name__v;
private String abbreviation__c;
private String internal_name__c;
private String external_id__v;
private String generic_name__c;
private Object scientific_name__c;
private List<String> status__v;
private List<String> therapeutic_area__c;
}
#lombok.Data
#JsonIgnoreProperties(ignoreUnknown = true)
public static class Product {
#JsonProperty("name__v")
private String fNumber;
#JsonProperty("generic_name__c")
private String genericName;
#JsonProperty("scientific_name__c")
private String scientificName;
#JsonProperty("therapeutic_area__c")
private List<String> therapeuticArea;
}
public static void main(String[] args) {
String jsonResult = "{\"responseStatus\":\"SUCCESS\",\"responseDetails\":{\"limit\":1000,\"offset\":0,\"size\":2,\"total\":2},\"data\":[{\"id\":\"00P000000001M01\",\"name__v\":\"Foo\",\"status__v\":[\"active__v\"],\"abbreviation__c\":\"F170053\",\"internal_name__c\":\"Foo\",\"therapeutic_area__c\":[\"neurology__c\"],\"external_id__v\":\"84\",\"generic_name__c\":\"Foo\",\"scientific_name__c\":null},{\"id\":\"00P000000001N01\",\"name__v\":\"Bar\",\"status__v\":[\"active__v\"],\"abbreviation__c\":\"B333334\",\"internal_name__c\":\"Bar\",\"therapeutic_area__c\":[\"bone_muscle_joint__c\"],\"external_id__v\":\"101\",\"generic_name__c\":\"Bar\",\"scientific_name__c\":null}]}";
ObjectMapper objectMapper = new ObjectMapper();
try {
Example example = objectMapper.readValue(jsonResult, new TypeReference<Example>() {
});
//you can get data[] via example.getData()
System.out.println(objectMapper.writeValueAsString(example.getData()));
List<Product> products = objectMapper.readValue(objectMapper.writeValueAsString(example.getData()), new TypeReference<List<Product>>() {
});
//you can also parse data[] as List<Product>
System.out.println(JSONObject.toJSONString(products));
} catch (IOException e) {
e.printStackTrace();
}
}
}

JsonMappingException: no single-String constructor/factory method

[This is not a duplicate of Can not instantiate value of type from JSON String; no single-String constructor/factory method: that is a far simpler POJO and JSON. The solution in my case was different as well.]
The JSON I want to parse and create a POJO from:
{
"test_mode": true,
"balance": 1005,
"batch_id": 99,
"cost": 1,
"num_messages": 1,
"message": {
"num_parts": 1,
"sender": "EXAMPL",
"content": "Some text"
},
"receipt_url": "",
"custom": "",
"messages": [{
"id": 1,
"recipient": 911234567890
}],
"status": "success"
}
If the response happens to be an error, it looks like:
{
"errors": [{
"code": 80,
"message": "Invalid template"
}],
"status": "failure"
}
Here's the POJO I have defined:
#Data
#Accessors(chain = true)
public class SmsResponse {
#JsonProperty(value = "test_mode")
private boolean testMode;
private int balance;
#JsonProperty(value = "batch_id")
private int batchId;
private int cost;
#JsonProperty(value = "num_messages")
private int numMessages;
private Message message;
#JsonProperty(value = "receipt_url")
private String receiptUrl;
private String custom;
private List<SentMessage> messages;
private String status;
private List<Error> errors;
#Data
#Accessors(chain = true)
public static class Message {
#JsonProperty(value = "num_parts")
private int numParts;
private String sender;
private String content;
}
#Data
#Accessors(chain = true)
public static class SentMessage {
private int id;
private long recipient;
}
#Data
#Accessors(chain = true)
public static class Error {
private int code;
private String message;
}
}
The annotations #Data (tells Lombok to automatically generate getters, setters, toString() and hashCode() methods for the class) and #Accessors (tells Lombok to generate the setters in such a way that they can be chained) are from Project Lombok.
Seems like a straightforward setup, but every time I run:
objectMapper.convertValue(response, SmsResponse.class);
I get the error message:
Can not instantiate value of type [simple type, class com.example.json.SmsResponse]
from String value ... ; no single-String constructor/factory method
Why do I need a single-string constructor for SmsResponse, and if so, which string do I accept in it?
To parse and map a JSON String with ObjectMapper you need to use the readValue method:
objectMapper.readValue(response, SmsResponse.class);

Creating a listview from a nested JSON

I have a JSON file that I fetch from the internet which contains schedule data for a TV channel. Nested within that file, alongside lots of metadata, is info about each broadcast (i.e. each programme) and below is a sample of that file:
For ease of understanding, I recommend this visual representation of the below JSON instead (click on the Viewer tab on the JSON viewer).
{
"schedule": {
"service": {
"type": "tv",
"key": "bbcnews",
"title": "BBC News Channel"
},
"day": {
"date": "2013-11-15",
"has_next": 1,
"has_previous": 1,
"broadcasts": [
{
"is_repeat": false, <=== This is the 1st broadcast programme
"is_blanked": false,
"pid": "p01ks4z3",
"start": "2013-11-15T03:45:00Z",
"end": "2013-11-15T04:00:00Z",
"duration": 900,
"programme": {
"type": "episode",
"pid": "b03hdhhp",
"position": null,
"title": "15/11/2013",
"short_synopsis": "All the latest sports news and results from around the globe.",
"media_type": "audio_video",
"duration": 900,
"display_titles": {
"title": "Sport Today",
"subtitle": "15/11/2013"
},
"first_broadcast_date": "2013-11-15T03:45:00Z",
"ownership": {
"service": {
"type": "tv",
"id": "bbc_news24",
"key": "bbcnews",
"title": "BBC News Channel"
}
},
"programme": {
"type": "brand",
"pid": "b0121xvw",
"title": "Sport Today",
"position": null,
"expected_child_count": null,
"first_broadcast_date": "2011-06-13T02:45:00+01:00",
"ownership": {
"service": {
"type": "tv",
"id": "bbc_news24",
"key": "bbcnews",
"title": "BBC News Channel"
}
}
},
"is_available_mediaset_pc_sd": false,
"is_legacy_media": false
}
},
{
"is_repeat": false, <=== This is the 2nd broadcast programme
"is_blanked": false,
"pid": "p01ks4z4",
"start": "2013-11-15T04:00:00Z",
"end": "2013-11-15T04:30:00Z",
"duration": 1800,
"programme": {
"type": "episode",
"pid": "b03hdhhs",
"position": null,
"title": "15/11/2013",
"short_synopsis": "Twenty-four hours a day, the latest national and international stories as they break.",
"media_type": "audio_video",
"duration": 1800,
"display_titles": {
"title": "BBC News",
"subtitle": "15/11/2013"
},
"first_broadcast_date": "2013-11-15T04:00:00Z",
"ownership": {
"service": {
"type": "tv",
"id": "bbc_news24",
"key": "bbcnews",
"title": "BBC News Channel"
}
},
"programme": {
"type": "brand",
"pid": "b006mgyl",
"title": "BBC News",
"position": null,
"expected_child_count": null,
"first_broadcast_date": "2006-11-01T13:00:00Z",
"ownership": {
"service": {
"type": "tv",
"id": "bbc_news24",
"key": "bbcnews",
"title": "BBC News Channel"
}
}
},
"is_available_mediaset_pc_sd": false,
"is_legacy_media": false
}
}
]
}
}
}
Using the answer to this question on StackOverflow, I created a Javabean class like so:
private class ScheduleData {
private Schedule schedule;
// create getter & setter
public static class Schedule {
private Service service;
private Day day;
// create getter & setter
}
public static class Service {
private String type;
private String key;
private String title;
// create getter & setter
}
public static class Day {
private String date;
private String has_next;
private String has_previous;
private Broadcasts broadcasts;
// create getter & setter
}
public static class Broadcasts {
private String is_repeat;
private String is_blanked;
private String pid;
private String time;
private String end;
private String duration;
private OuterProgramme programme;
// create getter & setter
}
public static class OuterProgramme {
private String type;
private String pid;
private String position;
private String title;
private String short_synopsis;
private String media_type;
private String duration;
private String first_broadcast_date;
private DisplayTitles display_titles;
private Ownership ownership;
private InnerProgramme programme;
// create getter & setter
}
public static class DisplayTitles {
private String title;
private String subtitle;
// create getter & setter
}
public static class Ownership {
private Service service;
// create getter & setter
}
public static class Service {
private String type;
private String id;
private String key;
private String title;
// create getter & setter
}
public static class InnerProgramme {
private String type;
private String pid;
private String title;
private String position;
private String expected_child_count;
private String first_broadcast_date;
private Ownership ownership;
private String is_available_mediaset_pc_sd;
private String is_legacy_media;
// create getter & setter
}
}
In my activity file, how do I loop through each broadcast node of the fetched JSON and retrieve programme data such as short_synopsis or display_titles and pass these into a custom listview display?
1) Define root Json Wrapper class ScheduleData.java
public class ScheduleData {
private Schedule schedule;
public Schedule getSchedule() {
return schedule;
}
}
2) Define its properties as seperate public classes:
2.a) Schedule.java
public class Schedule {
private Service service;
private Day day;
// TODO: create other getters & setters if you need
public Day getDay() {
return day;
}
}
2.b) Service.java
public class Service {
private String type;
private String id;
private String key;
private String title;
// TODO: create getters & setters if you need
}
2.c) Day.java
public class Day {
private String date;
private int has_next;
private int has_previous;
private Broadcast[] broadcasts;
// TODO: create other getters & setters if you need
public Broadcast[] getBroadcasts() {
return broadcasts;
}
}
2.d) Broadcast.java
public class Broadcast {
private boolean is_repeat;
private boolean is_blanked;
private String pid;
private String start;
private String end;
private int duration;
private Programme programme;
// TODO: create other getters & setters if you need
public Programme getProgramme() {
return programme;
}
}
2.e) Programme.java
public class Programme {
private String type;
private String pid;
private String position;
private String title;
private String short_synopsis;
private String media_type;
private int duration;
private String first_broadcast_date;
private DisplayTitle display_titles;
private Ownership ownership;
private Programme programme;
// TODO: create other getters & setters if you need
public String getShort_synopsis() {
return short_synopsis;
}
public DisplayTitle getDisplay_titles() {
return display_titles;
}
}
2.f) DisplayTitle.java
public class DisplayTitle {
private String title;
private String subtitle;
// create getter & setter
}
2.g) Ownership.java
public class Ownership {
private Service service;
// create getter & setter
}
3) Define an AsyncTask and call json service. Get result as stream and set its value to a ScheduleData instance using gson library. (I assume you know how to call json service on android, but if you don't it is a 5 min googling issue.)
HttpEntity getResponseEntity = getResponse.getEntity();
InputStream source = getResponseEntity.getContent();
Gson gson = new Gson();
Reader reader = new InputStreamReader(source);
ScheduleData scheduleData = gson.fromJson(reader, ScheduleData.class);
4) Now you have a ScheduleData instance. It is filled by service's json response.
Schedule schedule = scheduleData.getSchedule();
Day day = schedule.getDay();
Broadcast[] broadCastArr = day.getBroadcasts();
// TODO: use your broadCastArr in an adapter

What should be my class structure to parse JSON in GSON

I have the following JSON data:
{
"response": {},
"errorMessage": {
"error": [
{
"errorId": 260003,
"domain": "ads",
"subdomain": "asd",
"severity": "asd",
"category": "asd",
"message": "asdsa asd ad",
"errorName": "UnAuthorized"
}
]
}
}
Currently I have the following class structure:
public class JSONCollection
private Response response;
private ErrorMessage error;
public class Response
private String collectionId;
private String url;
public class ErrorMessage
private List<ErrorValues> error;
public class ErrorValues
private String errorId;
private String domain;
private String subdomain;
private String severity;
private String category;
private String message;
private String errorName;
I have setters/get set for all private variables
But when I do a JSONCollection cJson = gson.fromJson(JSONValue,JSONCollection.class); I get cJson as a null.
How to get it right?
I used this tool shown by #JigarJoshi to generate my schema.
The only difference I found is I had to change the class name from ErrorValues to Error

Categories