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;
Related
I am relativly new to salesforce and apex programming. Recently I am assigned to get data from an external api. I am receiving an object which also has another object inside the main object. the data I am suppose to receive is as follows
{
"Product_Catagories": [{
"id": "8ad08aef8534de220185400383d82def",
"name": "Product One",
"description": "Desc One",
"region": "",
"category": "Main Products",
"ProductFamily": "Main",
"RelatedProducts": "POC-B0000001",
"productfeatures": []
}, {
"id": "8ad0887e8534de2701853fff5a9b22ee",
"name": "Product Two",
"description": "Desc Two",
"region": "",
"category": "Main Products",
"ProductFamily": "Main",
"RelatedProducts": "POC-B0000002",
"productfeatures": []
}, {
"id": "8ad08aef8534de2201853ffe48fc08f6",
"name": "Product Three",
"description": "Desc Three",
"region": "",
"category": "Main Products",
"ProductFamily": "Main",
"RelatedProducts": "POC-B0000003",
"productfeatures": []
}]
}
but i am getting
Product_Catagories:[category=null, description=null, id=null, name=null, productFamily=null, productfeatures=null, region=null, relatedProducts=null]
I have defined classes in apex code but the object is coming as empty. No data is showing. The code I am using is as follows
public class POCGetCategories {
public static List<Product_Catagories> getPOCCats(){
return new List<Product_Catagories>{getPOCProducts()};
}
public class Product_Catagories {
public String id;
public String name;
public String description;
public String region;
public String category;
public String productFamily;
public String relatedProducts;
public POCProductfeature productfeatures;
}
public class POCProductfeature {
public String id;
public String name;
public String code;
public String status;
public String description;
}
private static Product_Catagories getPOCProducts(){
Product_Catagories cats = new Product_Catagories();
Http h = new Http();
String method = 'GET';
String url = 'https://externalapi';
HttpRequest req = new HttpRequest();
req.setEndpoint(url);
req.setMethod(method);
req.setTimeout(120000);
req.setHeader('Content-Type', 'application/jsson');
req.setHeader('subscription-Key','db163fc326d***');
HttpResponse res = h.send(req);
cats = (Product_Catagories)System.JSON.deserialize(res.getBody(), Product_Catagories.class);
system.debug('Data: ' + cats);
return cats;
}
}
The main response object is an object with a "Product_Catagories" key that contains an array of individual categories. The features key in each category is a list as well. Your model should look something like this:
public class ProductCatagoriesResponse {
public List<Product_Catagory> Product_Catagories;
}
public class Product_Catagory {
public String id;
public String name;
public String description;
public String region;
public String category;
public String productFamily;
public String relatedProducts;
public List<POCProductfeature> productfeatures;
}
...
ProductCatagoriesResponse cats = (ProductCatagoriesResponse)System.JSON.deserialize(res.getBody(), ProductCatagoriesResponse.class);
Also, it's spelled "category." But I'm assuming that's their typo and you just have to deal with it...
I have a nested Json object and I want to deserialize it into the Account object.
Json example:
{
"status": "OK",
"output": {
"accountNum": ".....",
"customerType": ".....",
"homeNumber": ".....",
"homeIndicator": ".....",
"eligible": true,
"startDate": "2017-01-01",
"contactDetails": {
"firstName": ".....",
"lastName": ".....",
"addressStreet": ".....",
},
"indicators": [
"ind1",
"ind2",
],
"employees": [
{
"name": ".....",
"email": ".....",
"model": ".....",
"program": [
{
"name": ".....",
"date": "....."
},
{
"name": ".....",
"date": "....."
}
],
"type": ".....",
"indicators": [
"....."
],
"customer": false
}
],
}
}
Since it’s a nested Json I am using the following method to do that:
ObjectMapper mapper = new ObjectMapper();
Flux<Timed<XXXDto >> mergedMonos = Flux.fromIterable(jsonList).flatMapSequential(Function.identity());
mergedMonos.map(timed -> mapper.valueToTree(timed.get())).collectList().subscribe(System.out::print);
#Component
public class XXXDto {
#Autowired
private Account account;
#JsonProperty("output")
private void unpackOutput(Map<String, Object> output) {
//Account a1 = new Account();
// this.account.setAccountNum is null
output.get("accountNum");
The problem is that I want to store the "accountNum" in the Account object but during the deserialization the inject Account is null.
I can create an instance in unpackOutput method but I would to see if there is another option via injection.
Any advice will be appreciated.
Thank you
I was able to deserialise the example input using these classes and this code.
First of all, here is the formatted input:
{
"status":"OK",
"output":{
"accountNum":".....",
"customerType":".....",
"homeNumber":".....",
"homeIndicator":".....",
"eligible":true,
"startDate":"2017-01-01",
"contactDetails":{
"firstName":".....",
"lastName":".....",
"addressStreet":"....."
},
"indicators":[
"ind1",
"ind2"
],
"employees":[
{
"name":".....",
"email":".....",
"model":".....",
"program":[
{
"name":".....",
"date":"....."
},
{
"name":".....",
"date":"....."
}
],
"type":".....",
"indicators":[
"....."
],
"customer":false
}
]
}
}
These are the classes I used:
public class ContactDetails{
public String firstName;
public String lastName;
public String addressStreet;
}
public class Program{
public String name;
public String date;
}
public class Employee{
public String name;
public String email;
public String model;
public List<Program> program;
public String type;
public List<String> indicators;
public boolean customer;
}
public class Output{
public String accountNum;
public String customerType;
public String homeNumber;
public String homeIndicator;
public boolean eligible;
public String startDate;
public ContactDetails contactDetails;
public List<String> indicators;
public List<Employee> employees;
}
public class Root{
public String status;
public Output output;
}
And this is the code I used to deserialise:
ObjectMapper objectMapper = new ObjectMapper();
Root root = objectMapper.readValue(input2, Root.class);
It was pretty simple so Im wondering if I missed something.
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
}
I was working around with JSON files that I could use in my program. However, I was a bit confused on how to use the library. For example, this is the following JSON file I am trying to parse here:
{
"shoes": [
{
"shoeName": "Shoe",
"shoePrice": "120",
"brand": "Shoe",
"typeOfShoes": "Running",
"style": "Cool",
"Color": [
"Blue",
"Green",
"Pink"
],
"Sizes": [
"W5/M3.5",
"W5.5/M4"
],
"Description": "The Shoe SE features sleek lines and a sheer upper that combine classic Air Max elements into a lightweight, comfortable and versatile icon. Together with its smart toe-down profile and extra lift, the shoe offers an ever-bigger expression..",
"shipping": "0",
"tax": "0",
"sub-total": "0",
"review": "4.5",
"images": [
"https://c.static-nike.com/a/images/t_PDP_864_v1/f_auto,b_rgb:f5f5f5/ds8ojj70wtpthbzadaft/air-max-dia-se-shoe-WCG8t5.jpg",
"https://c.static-nike.com/a/images/t_PDP_864_v1/f_auto,b_rgb:f5f5f5,q_80/n5txnsyb21v5zhruxfer/air-max-dia-se-shoe-WCG8t5.jpg"
],
"totalUsers": "60",
"totalRaffles": "80",
"clientID_Paypal": "",
"clientSecret_Paypal": "",
"isSold": "false"
},
{
"shoeName": "Empty Shoe",
"shoePrice": "",
"brand": "",
"typeOfShoes": "",
"style": "",
"Color": [
],
"Sizes": [
],
"Description": "",
"shipping": "",
"tax": "",
"sub-total": "",
"review": "",
"images": [
],
"totalUsers": "",
"totalRaffles": "",
"clientID_Paypal": "",
"clientSecret_Paypal": "",
"isSold": "false"
},
{
"shoeName": "Empty Shoe1",
"shoePrice": "",
"brand": "",
"typeOfShoes": "",
"style": "",
"Color": [
],
"Sizes": [
],
"Description": "",
"shipping": "",
"tax": "",
"sub-total": "",
"review": "",
"images": [
],
"totalUsers": "",
"totalRaffles": "",
"clientID_Paypal": "",
"clientSecret_Paypal": "",
"isSold": "false"
}
]
}
The JSON file is thoroughly simple. Inside, there is an array of objects called "shoes" which each have their own shoeName, shoePrice, brand, etc. However, how would I be able to create an array "Shoe" objects by retrieving each of the values in the JSON file?
My Shoe.java:
import java.awt.Image;
public class Shoe {
public int shoePrice;
public int shipping;
public int tax;
public int subtotal;
public int totalUsers;
public double review;
public int totalRaffles;
public int rafflesBought;
public String shoeName;
public String style;
public String typeOfShoes;
public String brand;
public Image[] images;
public String name;
public String description;
public String[] colors;
public String[] sizes;
public boolean isSold;
public Shoe(int shoePrice, int shipping, int tax, int subtotal, double review,
int totalRaffles, int rafflesBought,
String shoeName, String style, String typeOfShoes, String brand,
Image[] images,
String description, String[] colors, String[] sizes,
boolean isSold) {
this.shoePrice = shoePrice;
this.shipping = shipping;
this.tax = tax;
this.subtotal = subtotal;
this.review = review;
this.totalRaffles = totalRaffles;
this.rafflesBought = rafflesBought;
this.sizes = sizes;
this.shoeName = shoeName;
this.style = style;
this.typeOfShoes = typeOfShoes;
this.images = images;
this.description = description;
this.colors = colors;
this.isSold = isSold;
this.brand = brand;
}
}
What I have tried:
I have tried to define a Shoe array and tried initializing it using a for loop to retrive the values, make a Shoe, and add it to the array, however, I am confused on how you would be able to program this.
Use a library like GSON to convert JSON to Object.
In pom.xml, add dependency to GSON:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
Since your JSON returns String even for integers and doubles, this is the suitable definition for your Shoe Class.
public class Shoe
{
public String shoeName;
public String shoePrice;
public String brand;
public String typeOfShoes;
public String style;
public String[] Color;
public String[] Sizes;
public String Description;
public String shipping;
public String tax;
public String subtotal;
public String review;
public String[] images;
public String totalUsers;
public String totalRaffles;
public String clientID_Paypal;
public String clientSecret_Paypal;
public boolean isSold;
}
Since 'shoes" is the parent level object, you need to define it as well
public class Shoes
{
private List<Shoe> shoes;
public List<Shoe> getShoes()
{
return shoes;
}
public void setShoes(List<Shoe> shoes)
{
this.shoes = shoes;
}
}
Assume jsonData is the JSON input as String, below code would convert JSON string to "Shoes" object which contain List
Gson gson = new Gson();
Type dataType = (new TypeToken<Shoes>()
{
}).getType();
Shoes shoeList = gson.fromJson(jsonData, dataType);
for(Shoe e: shoeList.getShoes()) {
System.out.println(e);
}
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.