Currently I'm trying to write a site that interacts with a public API using Feign and Spring.
I'm having trouble deciding how to handle the object mapping for deeply nested JSON.
Ex:
[
{
"type": "console",
"category": "Console",
"result_count": 1,
"shown_count": 1,
"result": [
{
"name": "Nintendo Switch",
"id": "nintendo-switch",
"platform": {
"name": "Nintendo",
"category": "nintendo",
"type": "platform"
},
"image": {
"url": "https://encrypted-tbn1.gstatic.com/shopping?q=tbn:ANd9GcRqJYIheMDjTE9WAHjMSW4bjh7OplS7Bep9CdsBBLWMwGdXim7xOG4&usqp=CAc",
"height": 409,
"width": 631
},
"min_price": 205,
"variations": [
{
"items": [
{
"hex_code": "#696969",
"name": "Gray",
"id": "space-gray",
"type": "color"
},
{
"hex_code": "#C0C0C0",
"name": "Silver",
"id": "silver",
"type": "color"
}
],
"name": "Color",
"type": "color"
},
{
"items": [
{
"name": "Nintendo",
"id": "nintendo",
"type": "platform"
}
],
"name": "Platform",
"type": "platform"
}
]
}
]
}
]
As of now, I have a single Java file with a class for each object in the JSON, and I've considered having the Object mapper just put everything into a HashMap. Is there a more elegant way to do this?
public class SearchResults {
private List<SearchResult> products;
private int resultCount;
private String type;
}
class SearchResult {
private String name;
private String slug;
private Image image;
}
class Image {
private String URL;
private String height;
private String width;
}
Based on the json file provided i have designed the classes and also provided the code to parse the json file to java
public class Console{
String type;
String category;
int result_count;
int show_count;
Result [] result;
}
public class Result{
String name;
String id;
Platform platform;
Image image;
int mini_price;
Variation [] variations;
}
public class Platform{
String name;
String category;
String type;
}
public class Image{
String url;
int height;
int width;
}
public class Variation{
String name;
String type;
Item [] items;
}
public class Item{
String hex_code;
String name;
String id;
String type;
}
code to parse:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
Console[] consoles = objectMapper.readValue(ResourceUtils.getFile("path of json file"), Console[].class);
logger.info("Continents -> {}",(Object)continents);
for(Console console:consoles) {
//read the data accordingly
}
Related
How can I use MapStruct to create a mapper that maps a list (my source) to a object with a list (destination)?
My source classes looks like this:
class SourceB {
private String name;
private String lastname;
}
class SourceA {
private Integer id;
private List<SourceB> bs;
}
so I need to transform it to this:
class DestinationA {
private Integer id;
private DestinationAB bs;
}
class DestinationAB {
private List<DestinationB> b;
}
class DestinationB {
private String name;
private String lastname;
}
Expected sample json:
source:
{
"id": 1,
"bs": [
{
"name": "name1",
"lastname": "last1"
},
{
"name": "name2",
"lastname": "last2"
}
]
}
destination:
{
"id": 1,
"bs": {
"b": [
{
"name": "name1",
"lastname": "last1"
},
{
"name": "name2",
"lastname": "last2"
}
]
}
}
It's quite simple. Just put #Mapping annotation with specified source and destination on top of the mapping method.
#Mapper
public interface SourceMapper {
#Mapping(source = "bs", target = "bs.b")
DestinationA sourceAToDestinationA(SourceA sourceA);
}
I have a Json list using object with children
{
"id":"154",
"name":"peter",
"children": [
{
"id":"122",
"name": "mick",
"children":[]
},
{
"id":"123",
"name": "mick",
"children":[]
}
]
}
Here is the class of my object:
public class person{
private String id;
private String name;
private List<person> children;
//getters and setters
}
When I try to deserialize this object, I have the following error
Can not deserialize instance of person out of START_ARRAY token
What should I do ?
The JSON contains an array of persons.
Your class a List of person.
Either change the JSON like #Naveed Yadav suggested or change the class to
public class Person{
private String id;
private String name;
private Person[] children;
//getters and setters
}
(BTW the class name should be upper case in Java)
Fix syntax errors in your JSON body and you'll be in a good shape:
{
"id":"154",
"name":"peter",
"children": [
{
"id":"122",
"name": "mick",
"children":[], <== Excess comma
} <== Missing comma
{
"id":"123",
"name": "mick",
"children":[], <== Excess comma
}
]
}
Valid one:
{
"id": "154",
"name": "peter",
"children": [{
"id": "122",
"name": "mick",
"children": []
},
{
"id": "123",
"name": "mick",
"children": []
}
]
}
You need to change your POJO declaration like below:-
public class person{
private String id;
private String name;
private List<Children> children;
//getters and setters
private class Children{
private String id;
private String name;
private String[] children;
}
{
"id":"154",
"name":"peter",
"children":
{
"id":"122",
"name": "mick",
"children":[],
}
{
"id":"123",
"name": "mick",
"children":[],
}
}
I have the following JSON structure:
{
"status": "Completed",
"notes": null,
"members": {
"0": {
"year": "2",
"details": {
"id": "14899975",
"anotherId": "11013306"
},
"aName": "Fred",
"amounts": {
"First": 589.48,
"Second": 1000,
"Third": 339.48
}
},
"1": {
"year": "2",
"details": {
"id": "14899976",
"anotherId": "11013306"
},
"aName": "George",
"amounts": {
"First": 222.22,
"Second": 2000,
"Third": 22.22
}
},
"2": {
"year": 1,
"details": {
"id": "14899976",
"anotherId": "11013306"
},
"aName": "Albert",
"amounts": {
"First": 333.33,
"Second": 3000,
"Third": 33.33
},
}
}
}
I am using Spring RESTTemplate and JacksonMapping2HttpMessageConverter, and the following structures to receive the result of parsing the above JSON structure:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Response {
private String status;
private String notes;
private Map<String,Struct1> quotes;
}
#JsonIgnoreProperties(ignoreUnknown = true)
class Struct1 {
private int year;
private Struct2 details;
private String aName;
private Struct3 amounts;
}
#JsonIgnoreProperties(ignoreUnknown = true)
class Struct2 {
private String id;
private String anotherId;
}
#JsonIgnoreProperties(ignoreUnknown = true)
class Struct3 {
private float First;
private float Second;
private float Third;
}
All of these also have appropriate setters and getters for all fields.
My problem is that the number values in Struct3 are not filled in. I've tried making them float, Float, String, and BigDecimal, and the result is either null or 0.0.
I've tried putting a breakpoint in the setter for the first field, hoping
What am I missing? Can the capital letters in the JSON be causing a problem, do I need alternate field names?
It turned out to be the capital letters at the beginning of the field names; I added annotations like #JsonProperty("First") on the line before the getter of the field, and renamed the field to first, and now it's working.
How to send nested JSON input to Restful web service (using Java)?
eg. JSON input
{
"item1": [
{
"name": "name1",
"value": "value1",
"subitems": [
{
"sname": "sname1",
"svalue": "svalue1"
},
{
"sname": "sname2",
"svalue": "svalue2"
}
],
"attributes": [
{
"length": 25,
"height": 25,
"width": 30
},
{
"length": 35,
"height": 35,
"width": 40
}
]
}
]
}
You can create a class to map you json like this :
public class item {
private String name;
private String value;
private List<SubItem> subitems;
private List<Attribute> attributes;
// add here getters, setters and constructor
}
public class SubItem{
private String name;
private String svalue;
//add here getters, setters and constructor
}
public class Attribute{
private Integer length;
private Integer height;
private Integer width;
//add here getters, setters and constructor
}
I'm trying to use Gson to parse this JSON:
{
"status": "status",
"lang": "lang",
"guid": "guid",
"name": "name",
"tags": "tags",
"address": "address",
"description": "description",
"size": "M",
"url": "http:\/\/",
"email": "mymail#mysite.com",
"fax": "",
"tel": "000 000 00 00",
"total_votes": "0",
"total_value": "0",
"rate": 5,
"open2424": "0",
"category_main_name": "category_main_name",
"category_name": "category_name",
"category_main_name2": "category_main_name2",
"category_name2": "category_name2",
"category_main_name3": "category_main_name3",
"category_name3": "category_name3",
"park_type": "park_type",
"park_handicap": "0",
"park_free": "1",
"park_description": "",
"datemodinfo": "2012-12-15 18:18:05",
"sponsor": "2",
"sponsorstart": "2012-12-16 13:38:51",
"sponsorend": "2013-12-16 13:38:51",
"zip": "zip",
"town": "town",
"area": "area",
"latitude": "latitude",
"longitude": "longitude",
"distance_info": {
"distance": 10,
"unit": "unit"
},
"image": "image",
"url": "url",
"open": "1",
"openinghours": [{
"schedules": {
"day0": {
"periods": [{
"from": "09:00",
"to": "12:30"
},
{
"from": "14:00",
"to": "18:00"
}],
"date": "2013-08-12"
},
"day1": {
"periods": [{
"from": "09:00",
"to": "12:30"
},
{
"from": "14:00",
"to": "18:00"
}],
"date": "2013-08-13"
},
"day2": {
"periods": [{
"from": "09:00",
"to": "12:30"
},
{
"from": "14:00",
"to": "18:00"
}],
"date": "2013-08-14"
},
"day3": {
"periods": [{
"from": "09:00",
"to": "12:30"
},
{
"from": "14:00",
"to": "18:00"
}],
"date": "2013-08-15"
},
"day4": {
"periods": [{
"from": "09:00",
"to": "12:30"
},
{
"from": "14:00",
"to": "18:00"
}],
"date": "2013-08-16"
},
"day5": {
"date": "2013-08-17"
},
"day6": {
"date": "2013-08-18"
}
},
"title": "title"
}]
}
I parse the JSON with this code:
Gson gson = new Gson();
new GsonBuilder().serializeNulls().create();
Reader reader = new InputStreamReader(source);
response = gson.fromJson(reader, ResponseShow.class);
This is my ResponseShow class:
public class ResponseShow {
#SerializedName("status")
public String status;
#SerializedName("lang")
public String lang;
#SerializedName("guid")
public String guid;
#SerializedName("name")
public String name;
#SerializedName("tags")
public String tags;
#SerializedName("address")
public String address;
#SerializedName("description")
public String description;
#SerializedName("size")
public String size;
#SerializedName("url")
public String url;
#SerializedName("email")
public String email;
#SerializedName("fax")
public String fax;
#SerializedName("tel")
public String tel;
#SerializedName("total_votes")
public String total_votes;
#SerializedName("total_values")
public String total_values;
#SerializedName("rate")
public String rate;
#SerializedName("open2424")
public String open2424;
#SerializedName("category_main_name")
public String category_main_name;
#SerializedName("category_name")
public String category_name;
#SerializedName("category_main_name2")
public String category_main_name2;
#SerializedName("category_name2")
public String category_name2;
#SerializedName("category_main_name3")
public String category_main_name3;
#SerializedName("category_name3")
public String category_name3;
#SerializedName("park_type")
public String park_type;
#SerializedName("park_handicap")
public String park_handicap;
#SerializedName("park_free")
public String park_free;
#SerializedName("park_description")
public String park_description;
#SerializedName("datemodinfo")
public String datemodinfo;
#SerializedName("sponsor")
public String sponsor;
#SerializedName("sponsorstart")
public String sponsorstart;
#SerializedName("sponsorend")
public String sponsorend;
#SerializedName("town")
public String town;
#SerializedName("area")
public String area;
#SerializedName("latitude")
public String latitude;
#SerializedName("longitude")
public String longitude;
#SerializedName("distance_info")
public Map<String, String> distance_info = new HashMap<String, String>();
#SerializedName("zip")
public String zip;
#SerializedName("image")
public String image;
#SerializedName("ligoo_url")
public String ligoo_url;
#SerializedName("open")
public int open;
public List<openinghours> openinghours;
#SerializedName("query")
public String query;
}
This is my openinghours class:
public class openinghours {
public List<schedules> schedules;
#SerializedName("title")
public String title;
}
This is my Schedules class:
public class schedules {
public List<day0> day0;
public List<day1> day1;
public List<day2> day2;
public List<day3> day3;
public List<day4> day4;
public List<day5> day5;
public List<day6> day6;
}
And my day0 class:
public class day0 {
#SerializedName("date")
public String date;
public List<periods> periods;
}
The problem is that I get the following error while trying to parse day0:
Error: java.lang.IllegalStateException: Expected BEGIN_ARRAY goal was BEGIN_OBJECT at line 1 column 2414
Your problem is in the class openinghours (which btw should be in uppercase!). There, you're trying to parse the field "schedules" into a List, and as you can see in your JSON, it's not a List, but an object (it's surrounded by { }).
Concretely, the "schedules" field looks like:
"schedules": {
"day0": {
...
},
"day1": {
...
},
...
}
So, the fastest solution for you would be just to replace the type of the attribute schedules in your openinghours class by:
public schedules schedules;
Because the JSON field "schedules" is an object that contains several fields day0, day1, etc... And that's exactly what your class schedules is... So, this should work for you!
Anyway, the best solution is to use a Map this in your openinghours class:
public Map<String, Day> schedules;
This is the best option because this is exactly what the JSON field "schedules" represents... Moreover, this way you can have only one class Day instead of many classes day0, day1, etc... which makes much much more sense!
Try to replace
public class openinghours {
public List<schedules> schedules;
#SerializedName("title")
public String title;
}
//by
public class openinghours {
public schedules schedules;
#SerializedName("title")
public String title;
}
You might define a class for your distance_info():
class DistanceInfo{
private int distance;
private unit;
}
//change
#SerializedName("distance_info")
public Map<String, String> distance_info = new HashMap<String, String>();
//to
#SerializedName("distance_info")
public DistanceInfo distance_info;