Deserialize with Dependency Injection - java

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.

Related

Salesforce External API not deserializing

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...

Java mapping JSON with POJO using jackson

I want to create this JSON using jakson annotated POJOS. The issue I have when I create a new class without #JsonProperty annotation to represent the last {"id":"123ccc","role":"dddd"}, it by default take the class name and create something like "customer":{"id": "123ccc","role":"dddd"}.
The JSON Structure I indent to build
{
"relatedParty": [
{
"contact": [
{
"mediumType": "xxx",
"characteristic": {
"city": "xxx",
"country": "xxx"
}
},
{
"mediumType": "yyy",
"characteristic": {
"emailAddress": "yyy#yy.yyy"
}
}
],
"role": "ccc",
"fullName": "ccc"
},
{
"id": "123ccc",
"role": "dddd"
}
]
}
The JSON I'm receiving from the below code.
{
"relatedParty": [
{
"contact": [
{
"mediumType": "xxx",
"characteristic": {
"city": "xxx",
"country": "xxx"
}
},
{
"mediumType": "yyy",
"characteristic": {
"emailAddress": "yyy#yy.yyy"
}
}
],
"role": "ccc",
"fullName": "ccc"
},
"customer" : {
"id": "123ccc",
"role": "dddd"
}
]
}
What would be a workaround to get the exact JSON format as the image. Current Implementation is below.
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
public class RelatedParty {
#JsonProperty(value = "contact")
private List<Contact> contact;
#JsonProperty(value = "role")
private String role;
#JsonProperty(value = "fullName")
private String fullName;
private Customer customer;
public List<Contact> getContact() {
return contact;
}
public void setContact(List<Contact> contact) {
this.contact = contact;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
public class Customer {
#JsonProperty(value = "id")
private String id;
#JsonProperty(value = "role")
private String role;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
You need to create additional and different POJO classes to model your JSON correctly. Basically, JSON arrays will be handle in Java lists, and JSON objects will be handled in Java classes.
Starting from the inside (most nested level) of the JSON, and working our way out:
NOTE: getters and setters not shown here
Characteristic.java
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Characteristic {
#JsonProperty("city")
private String city;
#JsonProperty("country")
private String country;
#JsonProperty("emailAddress")
private String emailAddress;
}
Contact.java (contains our characteristics):
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Contact {
#JsonProperty("mediumType")
private String mediumType;
#JsonProperty("characteristic")
private Characteristic characteristic;
}
The above two classes handle the innermost objects. If we remove them from your target JSON, that leaves the following:
{
"relatedParty": [{
"contact": [...],
"role": "ccc",
"fullName": "ccc"
}, {
"role": "dddd",
"id": "123ccc"
}]
}
Note that the contact field is a JSON array, not an object - so we do not create a Java Contact class (which would be for a JSON object).
To handle the above I create two more classes:
RelatedPartyInner.java (contains a list of contacts)
#JsonInclude(JsonInclude.Include.NON_NULL)
public class RelatedParty_ {
#JsonProperty("contact")
private List<Contact> contact = null;
#JsonProperty("role")
private String role;
#JsonProperty("fullName")
private String fullName;
#JsonProperty("id")
private String id;
}
RelatedParty.java (wraps everything in an outer object):
#JsonInclude(JsonInclude.Include.NON_NULL)
public class RelatedParty {
#JsonProperty("relatedParty")
private List<RelatedPartyInner> relatedParty = null;
}
To test this I create the following data:
Characteristic chr1 = new Characteristic();
chr1.setCity("xxx");
chr1.setCountry("xxx");
Characteristic chr2 = new Characteristic();
chr2.setEmailAddress("yyy#yy.yyy");
Contact con1 = new Contact();
con1.setMediumType("xxx");
con1.setCharacteristic(chr1);
Contact con2 = new Contact();
con2.setMediumType("yyy");
con2.setCharacteristic(chr2);
List<Contact> cons = new ArrayList<>();
cons.add(con1);
cons.add(con2);
RelatedPartyInner rpi1 = new RelatedPartyInner();
rpi1.setContact(cons);
rpi1.setRole("ccc");
rpi1.setFullName("ccc");
RelatedPartyInner rpi2 = new RelatedPartyInner();
rpi2.setId("123ccc");
rpi2.setRole("dddd");
List<RelatedPartyInner> rpis = new ArrayList<>();
rpis.add(rpi1);
rpis.add(rpi2);
RelatedParty rp = new RelatedParty();
rp.setRelatedParty(rpis);
Finally, we can generate the JSON:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValue(new File("rp.json"), rp);
The resulting file contains the following:
{
"relatedParty": [{
"contact": [{
"mediumType": "xxx",
"characteristic": {
"city": "xxx",
"country": "xxx"
}
}, {
"mediumType": "yyy",
"characteristic": {
"emailAddress": "yyy#yy.yyy"
}
}],
"role": "ccc",
"fullName": "ccc"
}, {
"role": "dddd",
"id": "123ccc"
}]
}

Best Way to do Object Mapping with Nested Json

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
}

How map List to an Object with list in mapstructs

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);
}

Gson for Android

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;

Categories

Resources