Jackson mapping JSON to Java POJO - MismatchedInstanceException - java

I´m using spring rest template and want to parse the JSON response into the corresponding java POJO. I get every time a MismatchedInputException - Cannot deserialized instance of out of start array token.
I´ve looked at several questions relating to jackson but didn´t find the suitable solution.
I´m not sure if my POJO structure is correct.
First the related JSON:
{
"days":[
[
{
"day":"2019-04-29",
"time":"08:00-09:30",
"room":"room1",
"name":"lecture1",
"lecturer":"prof1",
"eventId":332713,
"modified":false
}
],
[
],
[
],
[
{
"day":"2019-05-02",
"time":"08:00-10:15",
"room":"room2",
"name":"lecture2",
"lecturer":"prof2",
"eventId":332714,
"modified":false
},
{
"day":"2019-05-02",
"time":"10:45-13:00",
"room":"room3",
"name":"lecture3",
"lecturer":"prof3",
"eventId":332721,
"modified":false
}
],
[
],
[
],
[
]
]
}
POJO Structure:
public class Main{
ArrayList<Day> days = new ArrayList<>();
public ArrayList<Day> getDays() {
return days;
}
public void setDays(ArrayList<Day> days) {
this.days = days;
}
public class Day {
private String day;
private String time;
private String room;
private String name;
private String lecturer;
private Integer eventId;
private Boolean modified;
public Day() {
}
// Getter and setter of Day Object
}
}
Rest-Template Method in API Object:
public String getInfoByEventsPeriods(String eventIDs) {
String url = APIURL + "/info?from="2019-04-29"&to="2019-05-03"&eventId=" + eventIDs;
return rest.getForObject(url, String.class);
}
Processing with ObjectMapper in Main Object:
public Main getLectures(String eventIDs) throws IOException {
API api = new API();
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(api.getInfoByEventsPeriods(eventIDs), Main.class);
}

Yes, you'r right,the wrong type is used while deserializing.
I'm not sure exactly, but your days array contains another arrays with day objects, but in your structure ArrayList consists of objects day, not array of them.
Correct JSON would be:
{
"days":[
{
"day":"2019-04-29",
"time":"08:00-09:30",
"room":"room1",
"name":"lecture1",
"lecturer":"prof1",
"eventId":332713,
"modified":false
},
{
"day":"2019-05-02",
"time":"08:00-10:15",
"room":"room2",
"name":"lecture2",
"lecturer":"prof2",
"eventId":332714,
"modified":false
},
......
]
}
So, change response structure or pojo object depending on what needs to be fixed.
If you need to modify POJO, your ArrayList must contains List of days.

Can you have your POJO like below. I tried to deserialize with your JSON and I was able to deserialize successfully.
class Day {
private String day;
private String time;
private String room;
private String name;
private String lecturer;
private Integer eventId;
private Boolean modified;
public void setDay(String day) {
this.day = day;
}
public void setTime(String time) {
this.time = time;
}
public void setRoom(String room) {
this.room = room;
}
public void setName(String name) {
this.name = name;
}
public void setLecturer(String lecturer) {
this.lecturer = lecturer;
}
public void setEventId(Integer eventId) {
this.eventId = eventId;
}
public void setModified(Boolean modified) {
this.modified = modified;
}
}
class Main{
private List<List<Day>> days;
public void setDays(List<List<Day>> days) {
this.days = days;
}
}

Related

JSON serialize to a different value

I have the below json which im serializing
{
"name":"John",
"switch":"1"
},
{
"name":"Jim",
"switch":"0"
}
I want to serialize it to a differnt name So I had to do it like below
class Data {
private String name;
private String flag;
#JsonProperty("flag")
public byte getFlag() {
return flag;
}
#JsonProperty("switch")
public void setSwitch(String s) {
this.flag = flag;
}
}
So that I get it converted as below
{
"name":"John",
"flag":"1"
},
{
"name":"Jim",
"flag":"0"
}
Now I wanted to map the numic values to Y and N for 1 and 0 respectively. Can I acheive that ?
Im expecting my final string to be like this
{
"name":"John",
"switch":"Y"
},
{
"name":"Jim",
"switch":"N"
}
I agree with #Gaël J, but still if you want to go ahead this code change might help you to convert that 1/0 to Y/N.
public class Application {
#ToString
static class Input {
#JsonProperty("name")
private String name;
#JsonProperty("switch")
private String flag;
#JsonProperty("name")
public void setName(String name){
this.name = name;
}
#JsonProperty("switch")
public void setSwitch(String s) {
for(SwitchMap valuePair : SwitchMap.values()){
if(valuePair.getValue().equals(s)){
this.flag = valuePair.name();
}
}
}
}
public static void main(String[] args) throws JsonProcessingException {
String json = "{\n" +
"\"name\":\"John\",\n" +
"\"switch\":\"1\"\n" +
"}";
ObjectMapper mapper = new ObjectMapper();
Input in = mapper.readValue(json, Input.class);
System.out.println(mapper.writeValueAsString(in));
}
}
define an enum with the mapping
#Getter
public enum SwitchMap {
Y("1"),
N("0");
private final String value;
private SwitchMap(String value){
this.value = value;
}
}

Unable to parse JSON with Jackson (mapping doesn't work)

I am trying to use Jackson to parse sample json as demonstrated below. However, I the parsing doesn't work (fails without any exceptions - as I get an empty string for event.getAccountId(); What could I be doing wrong?
Thanks!
ObjectMapper om = new ObjectMapper();
String json = "{\"_procurementEvent\" : [{ \"accountId\" : \"3243234\",\"procurementType\" : \"view\"," +
"\"_procurementSubType\" : \"Standard Connector\",\"_quantity\" : \"4\", \"_pricePerMonth\" : \"100.00\"" +
",\"_annualPrice\" : \"1200.00\"}]}";
ProcurementEvent event = om.readValue(json, ProcurementEvent.class);
event.getAccountId(); // returns null
#JsonIgnoreProperties(ignoreUnknown = true)
private static class ProcurementEvent {
private String _accountId;
private String _procurementType;
private String _quantity;
private String _pricePerMonth;
private String _annualPrice;
#JsonProperty("accountId")
public String getAccountId() {
return _accountId;
}
public void setAccountId(String accountId) {
_accountId = accountId;
}
#JsonProperty("procurementType")
public String getProcurementType() {
return _procurementType;
}
public void setProcurementType(String procurementType) {
_procurementType = procurementType;
}
#JsonProperty("_quantity")
public String getQuantity() {
return _quantity;
}
public void setQuantity(String quantity) {
_quantity = quantity;
}
#JsonProperty("_pricePerMonth")
public String getPricePerMonth() {
return _pricePerMonth;
}
public void setPricePerMonth(String pricePerMonth) {
_pricePerMonth = pricePerMonth;
}
#JsonProperty("_annualPrice")
public String getAnnualPrice() {
return _annualPrice;
}
public void setAnnualPrice(String annualPrice) {
_annualPrice = annualPrice;
}
}
In the question, try the following approach:
class ProcurementEvents {
private List<ProcurementEvent> _procurementEvent; // + annotations like #JsonIgnoreProperties, getters/ setters, etc.
}
// json from your example
ProcurementEvents events = om.readValue(json, ProcurementEvents.class);
events.get(0).getAccountId();

UnrecognizedPropertyException: Unrecognized field "sections"

I'm using Jackson as part of a spring boot app. I am turning JSON into Java, and I am getting this error. I did some research, but I still don't understand what is going wrong or how to fix it.
Here is the JSON fragment:
"dataBlock": {
"sections": [
{
"info": "",
"prompt": "",
"name": "First Section",
"sequence": 0,
"fields": [],
"gatingConditions": [],
"guid": "480d160c-c34f-4022-97b0-e8a1f28c49ae",
"id": -2
}
],
"prompt": "",
"id": -1,
"name": ""
}
So my Java object for this "dataBlock" element:
public class DataBlockObject {
private int id;
private String prompt;
private String name;
private List<SectionObject> sections;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getPrompt() {
return prompt;
}
public void setPrompt(String prompt) {
this.prompt = prompt;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<SectionObject> getSections() {
return sections;
}
public void setSections(List<SectionObject> sections) {
this.sections = sections;
}
}
And the Section object is this:
public class SectionObject {
private int id;
private String name;
private String prompt;
private String info;
private int sequence;
private List<FieldObject> fields;
private List<GatingConditionObject> gatingConditions;
private String guid;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPrompt() {
return prompt;
}
public void setPrompt(String prompt) {
this.prompt = prompt;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public int getSequence() {
return sequence;
}
public void setSequence(int sequence) {
this.sequence = sequence;
}
public List<FieldObject> getFields() {
return fields;
}
public void setFields(List<FieldObject> fields) {
this.fields = fields;
}
public List<GatingConditionObject> getGatingConditions() {
return gatingConditions;
}
public void setGatingConditions(List<GatingConditionObject> gatingConditions) {
this.gatingConditions = gatingConditions;
}
public String getGuid() {
return guid;
}
public void setGuid(String guid) {
this.guid = guid;
}
}
So it seems to me that Jackson would make a DataBlockObject, map the obvious elemenets, and create an array that I have clearly marked as a List named sections. -- just like the JSON shows.
Now the error is:
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "sections" (class com.gridunity.workflow.bean.json.SectionObject), not marked as ignorable (8 known properties: "gatingConditions", "sequence", "prompt", "fields", "id", "info", "guid", "name"])
Now according to that error it would seem that one of my 8 elements should be named "sections" - But that's not one of my elements. It clearly has a problem with my List of Sections, but I cant figure out what it is.
Can someone explain WHY this is happening, especially sence it looks like I have my structure correct, and how to fix this. I have seen this on other posts:
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
But that seems incredibly wrong as I know all of my properties.
It looks like the JSON itself has another sections field in one or more of the dataBlock.sections items. If you don't have control over the construction of the JSON object, you'll need to add a #JsonIgnoreProperties annotation on the SectionObject class so that when the JSON object has fields that aren't specified in the POJO, it won't throw an error during deserialization.
#JsonIgnoreProperties(ignoreUnknown = true)
public class SectionObject {
// class members and methods here
}

Parsing nested JSON containing both Objects and single values

I have what I believe is called nested JSON and I want to use Jackson to deserialize into objects. Is it possible to automatically parse the child objects into Java Objects as well if a Program class had for example objects of the type TrackedEntity and ProgramStage (see JSON code) ? Alternatively would it be possible to simply parse the "id" of the respective objects and put them in Strings in the Program objects?
JSON Example is as follows:
{
programs:
[
{
"id": "IpHINAT79UW",
"created": "2013-03-04T10:41:07.494+0000",
"trackedEntity":
{
"id": "cyl5vuJ5ETQ",
"name": "Person"
},
"programStages":
[
{
"id": "A03MvHHogjR",
},
{
"id": "ZzYYXq4EJie",
},
{
"id": "AREMvHHogjR",
},
{
"id": "ZzYYXq4fJie",
}
]
},
{
"id": "IGRINAT79UW",
"created": "2013-03-04T10:41:07.494+0000",
"trackedEntity":
{
"id": "cyl5vuJ5ETQ",
"name": "Person"
},
"programStages":
[
{
"id": "A03MvHHogjR",
},
{
"id": "ZzYYXq4fJie",
},
{
"id": "A01MvHHogjR",
},
{
"id": "ZzGYXq4fJie",
}
]
}
]
}
One approach is simply to create POJOs for the various entities.
If you assume the following for TrackEntity
class TrackedEntity {
private final String id;
private final String name;
#JsonCreator
TrackedEntity(
#JsonProperty("id") final String id,
#JsonProperty("name") final String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
}
Then the following may be suitable for ProgramStage:
class ProgramStage {
private final String id;
#JsonCreator
ProgramStage(#JsonProperty("id") final String id) {
this.id = id;
}
public String getId() {
return id;
}
}
The Program class is slightly trickier since it must parse som kind of zoned date. I have used the Java 8 ZonedDateTime in this example with a custom formatter. You can also use JSR 310 module as described in this answer.
class Program {
private static final DateTimeFormatter FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSxx");
private final ZonedDateTime created;
private final String id;
private final List<ProgramStage> programStages;
private final TrackedEntity trackedEntity;
#JsonCreator
public static Program of(
#JsonProperty("id") final String id,
#JsonProperty("created") final String created,
#JsonProperty("trackedEntity") final TrackedEntity trackedEntity,
#JsonProperty("programStages") final List<ProgramStage> programStages) {
return new Program(
id,
ZonedDateTime.parse(created, FORMATTER),
trackedEntity,
programStages);
}
public Program(
final String id,
final ZonedDateTime created,
final TrackedEntity trackedEntity,
final List<ProgramStage> programStages) {
this.id = id;
this.created = created;
this.trackedEntity = trackedEntity;
this.programStages = programStages;
}
public ZonedDateTime getCreated() {
return created;
}
public String getId() {
return id;
}
public List<ProgramStage> getProgramStages() {
return programStages;
}
public TrackedEntity getTrackedEntity() {
return trackedEntity;
}
}
Finally, to fix the outer programs entity the following can be used:
class Programs {
private final List<Program> programs;
#JsonCreator
Programs(#JsonProperty("programs") final List<Program> programs) {
this.programs = programs;
}
public List<Program> getPrograms() {
return programs;
}
}
To use the whole thing, simply instantiate an ObjectMapper and use the readValue method like this:
final Programs programs = new ObjectMapper().readValue(json, Programs.class);
Yes. You should be fine. Crate a data structure which represents your data:
public class Container
{
public List<ProgramInfo> programs {get;set;}
}
public class ProgramInfo
{
public string id{get; set;}
public DateTime created{get;set;}
public TrackEntity trrack{get;set;}
}
public class TrackEntity
{
public string id{get;set;}
public string name{get;set;}
}
//Then call the deserialise or serialize
Container container = new JavaScriptSerializer().Deserialize<Container>(yourString);
public class TrackedEntity
{
public string id { get; set; }
public string name { get; set; }
}
public class ProgramStage
{
public string id { get; set; }
}
public class Program
{
public string id { get; set; }
public string created { get; set; }
public TrackedEntity trackedEntity { get; set; }
public List<ProgramStage> programStages { get; set; }
}
public class RootObject
{
public List<Program> programs { get; set; }
}
//Then call the deserialise or serialize
var container = new JavaScriptSerializer().Deserialize<RootObject>(inputjson);
hope it works for you.

Binding json, that has a list, with an object using Jackson

Given I have the following json:
{
"Company": {
"name": "cookieltd",
"type": "food",
"franchise_location": [
{
"location_type": "town",
"address_1": "5street"
},
{
"location_type": "village",
"address_1": "2road"
}
]
}
}
How can it be binded to the following object classes using Jackson?:
1) Company class
public class Company
{
String name, type;
List<Location> franchise_location = new ArrayList<Location>();
[getters and setters]
}
2) Location class
public class Location
{
String location_type, address_1;
[getters and setters]
}
I have done:
String content = [json above];
ObjectReader reader = mapper.reader(Company.class).withRootName("Company"); //read after the root name
Company company = reader.readValue(content);
but I am getting:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "franchise_location"
As far as I can tell, you are simply missing an appropriately named getter for the field franchise_location. It should be
public List<Location> getFranchise_location() {
return franchise_location;
}
(and the setter)
public void setFranchise_location(List<Location> franchise_location) {
this.franchise_location = franchise_location;
}
Alternatively, you can annotate your current getter or field with
#JsonProperty("franchise_location")
private List<Location> franchiseLocation = ...;
which helps to map JSON element names that don't really work with Java field name conventions.
The following works for me
public static void main(String[] args) throws Exception {
String json = "{ \"Company\": { \"name\": \"cookieltd\", \"type\": \"food\", \"franchise_location\": [ { \"location_type\": \"town\", \"address_1\": \"5street\" }, { \"location_type\": \"village\", \"address_1\": \"2road\" } ] } }";
ObjectMapper mapper = new ObjectMapper();
ObjectReader reader = mapper.reader(Company.class).withRootName(
"Company"); // read after the root name
Company company = reader.readValue(json);
System.out.println(company.getFranchise_location().get(0).getAddress_1());
}
public static class Company {
private String name;
private String type;
private List<Location> franchise_location = new ArrayList<Location>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<Location> getFranchise_location() {
return franchise_location;
}
public void setFranchise_location(List<Location> franchise_location) {
this.franchise_location = franchise_location;
}
}
public static class Location {
private String location_type;
private String address_1;
public String getLocation_type() {
return location_type;
}
public void setLocation_type(String location_type) {
this.location_type = location_type;
}
public String getAddress_1() {
return address_1;
}
public void setAddress_1(String address_1) {
this.address_1 = address_1;
}
}
and prints
5street
my solution for JSON is always GSON, you can do some research on that, as long as you have the correct structure of class according to the JSON, it can automatically transfer from JSON to object:
Company company = gson.fromJson(json, Company.class);
GSON is so smart to do the convertion thing!
enjoy GSON !

Categories

Resources