Find values from list with key value pair - java

I want to find the key value pair from a list. I want to put the values into a parameter from another method. I have a deserialzied map that contains the list called "InfoFields" here is my json string:
{
"operation": "get-id",
"payload": {
"ApplicationContext": {
"Context": "JORDFEIL",
"SenderId": "xxx",
"subContext": ""
},
"supportIssue": {
"InfoFields": [
{
"Key": "key1",
"Value": "value1"
},
{
"Key": "key2",
"Value": "value2"
},
{
"Key": "key3",
"Value": "value3"
}
],
}
},
"type": "~:CustomerInquiry",
}
Here is my wrapper class aswell
public class WebskjemaModel {
public class ApplicationContext {
public String Context;
public String SenderId;
public String subContext;
}
public String operation;
public Payload payload;
public String type;
public class InfoFields {
public String Key;
public String Value;
}
public class Payload {
public ApplicationContext ApplicationContext;
public SupportIssue supportIssue;
}
public class SupportIssue {
public List<InfoFields> InfoFields;
public String assignId;
public String businessObjectType;
public String comment;
public String contactDate;
public String contactName;
public String customerName;
public String customerNo;
public String docClass;
public String format;
public String objectDescription;
public String objectId;
public String subject;
}
public static WebskjemaModel parse(String json) {
return (WebskjemaModel) System.JSON.deserialize(json, WebskjemaModel.class);
}
}
I have created a map that contains the deserialzed object, now i want to map the fields for a single case. Here is what i have tried, but i cant seem to get the values from the key and from the value:
public with sharing class WebskjemaCaseCreator {
#TestVisible
private Map<Id, Case> cases { get; set; }
#TestVisible
private Map<Id, WebskjemaModel> webskjemaModels = new Map<Id, WebskjemaModel>();
public WebskjemaCaseCreator(Map<Id, Case> cases) {
this.cases = cases;
deserializeJson();
mapFields();
}
private void deserializeJson() {
for (Id caseId : cases.keySet()) {
Case c = cases.get(caseId);
WebskjemaModel model = WebskjemaModel.parse(c.Webskjemablob__c);
webskjemaModels.put(caseId, model);
}
}
private void mapFields() {
for (Id caseId : cases.keySet()) {
Case c = cases.get(caseId);
WebskjemaModel model = webskjemaModels.get(caseId);
}
}
private void mapFieldsForSingleCase(Case c, WebskjemaModel model) {
String context = model.payload.ApplicationContext.Context;
List<WebskjemaModel.InfoFields> myinfoFields = model.payload.supportIssue.InfoFields;
for (WebskjemaModel.InfoFields fields : myinfoFields) {
mapInfoField(c, context, fields.get(key), fields.get(value));
}
// TODO: Find WebskjemaModel inforfields and loop
// for (list of infofields for this model only){
// TODO: call method mapInfoField
// }
}
private void mapInfoField(Case c, String context, String infoFieldKey, String infoFieldValue) {
WebskjemaMapping__mdt[] webskjemarecords = [
SELECT CaseField__c, Context__c, JsonField__c, IfsField__c
FROM WebskjemaMapping__mdt
];
// TODO: Find Case field from custom meta data type mapping, based on context and infoFielfKey
// TODO: Put value from inforFieldValue into Case field
}
}

Related

Deserialization using Jackson Json where one of the keys is dynamic

I am fairly new to Jackson. I am trying to map the following json to a POJO using Jackson for deserialization.
{
"data": [
{
"customerName": "abc",
"varaible_Key1": {
"p1": "text data",
"p2": "textarea data",
........
}
},
{
"customerName": "bbc",
"varaible_Key2": {
"p1": "text",
"p2": "textarea"
......
}
},
{
"customerName": "xyz",
"varaible_Key3": {
"p1": "xyz text",
"p2": "xyz textarea"
......
}
}
///////more customername / variable_keys
]
}
The problem I am facing is with dynamic / variable keys in the json.
I have tried using #JsonAnySetter in the POJO as shown below.
public class Foo {
#JsonProperty("customerName")
private String name;
private Map<String, DataObject> properties;
#JsonAnyGetter
public Map<String, DataObject> getProperties() {
return properties;
}
#JsonAnySetter
public void add(String key, DataObject value) {
properties.put(key, value);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
where DataObject contains the fields like p1,p2 and so on.
public class DataObject {
#JsonProperty("p1")
private String firstValue;
#JsonProperty("p2")
private String secondValue;
#JsonProperty("p3")
private String thirdValue;
#JsonProperty("p4")
private String fourthValue;
public String getFirstValue() {
return firstValue;
}
public void setFirstValue(String firstValue) {
this.firstValue = firstValue;
}
public String getSecondValue() {
return secondValue;
}
public void setSecondValue(String secondValue) {
this.secondValue = secondValue;
}
public String getThirdValue() {
return thirdValue;
}
public void setThirdValue(String thirdValue) {
this.thirdValue = thirdValue;
}
public String getFourthValue() {
return fourthValue;
}
public void setFourthValue(String fourthValue) {
this.fourthValue = fourthValue;
}
}
I keep getting the below error. Any help on this is appreciated.
com.fasterxml.jackson.databind.JsonMappingException: N/A (through
reference chain:
com.epic.customer.dto.DataField["data"]->java.util.ArrayList[0]-> com.epic.customer.dto.Foo["varaible_Key1"])
at
com.fasterxml.jackson.databind.deser.SettableAnyProperty._throwAsIOE(SettableAnyProperty.java:214)
at
com.fasterxml.jackson.databind.deser.SettableAnyProperty.set(SettableAnyProperty.java:179)
at
com.fasterxml.jackson.databind.deser.SettableAnyProperty.deserializeAndSet(SettableAnyProperty.java:134)
at
com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1539)
at
com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:293)
at
com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
at
com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:285)
at
com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:244)
at
com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:27)
at
com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:127)
at
com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:287)
at
com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
at
com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
You just need to create 2 setters, for specific property:
class Foo {
private DataObject dataObject;
public DataObject getDataObject() {
return dataObject;
}
public void setVaraible_Key1(DataObject dataObject) {
this.dataObject = dataObject;
}
public void setVaraible_Key2(DataObject dataObject) {
this.dataObject = dataObject;
}
}
Further usages refers here.
I think you have to give it a hint on the type of object you want back:
ObjectMapper mapper = new ObjectMapper();
Map<String, DataObject> test = mapper.readValue("Insert Data in here", mapper.getTypeFactory().constructMapLikeType(HashMap.class, String.class, DataObject.class));

[Spring]: Request mapping nested Json with array inside it

I have a requestbody as,
{
"first": "0",
"second": "3",
"third": {
"Types": ["AAA"],
"Name": "XXXX"
}
}
i cannot map this to request mapping using spring. I tried with below but it did not work.
public class requestMap {
private Integer skip;
private Integer take;
private Map<String, String[]> keywords;
public Integer getSkip() {
return skip;
}
public void setSkip(Integer skip) {
this.skip = skip;
}
public Integer getTake() {
return take;
}
public void setTake(Integer take) {
this.take = take;
}
public Map<String, String[]> getKeywords() {
return keywords;
}
public void setKeywords(Keywords keywords) {
this.keywords = (Map<String, String[]>) keywords;
}
}
How can i map the request body?
EDIT
Case sensitive key in Json.
this should be the correct model.
public class jsonObject
{
private Keywords keywords;
private String take;
private String skip;
public Keywords getKeywords ()
{
return keywords;
}
public void setKeywords (Keywords keywords)
{
this.keywords = keywords;
}
public String getTake ()
{
return take;
}
public void setTake (String take)
{
this.take = take;
}
public String getSkip ()
{
return skip;
}
public void setSkip (String skip)
{
this.skip = skip;
}
#Override
public String toString()
{
return "ClassPojo [keywords = "+keywords+", take = "+take+", skip = "+skip+"]";
}
}
//keywords class
public class Keywords
{
private String name;
private String[] types;
public String getName ()
{
return name;
}
public void setName (String name)
{
this.name = name;
}
public String[] getTypes ()
{
return types;
}
public void setTypes (String[] types)
{
this.types = types;
}
#Override
public String toString()
{
return "ClassPojo [name = "+name+", types = "+types+"]";
}
}
Change String[] to Object in your map because keywords can have an array or a String instead of only arrays, for example name pair has a String value (and cannot mapped as an array) and types has an array value .
So it would be:
private Map<String, Object> keywords;
Otherwise, the best option is create an object wich wrappes keyword, annotate with json property, so your properties start with Upper case:
class Keywords {
#JsonProperty("Types")
List<String> types;
#JsonProperty("Name")
String name;
}
And then used it instead of the map.
If you are able to change the json your keywords pairs-values could be an array:
"keywords": {
"types": ["P-A01"],
"name": ["XXXX"]
}
Then you'll be able to use the keywords map like your example:
Map<String, String[]> keywords;
And of course, you should know that the key name will have an array of lenth 1.

Jackson: Parsing an object with an array of objects

I'm working on a project where I'm integrating with a 3rd party service that returns a JSON response. I am using Jackson to deserialize the response into a Java POJO. The response is an object that has a few simple fields that Jackson is able to easily parse. However the response also contains an array with a single entry that is also an object. When Jackson attempts to deserialize it I get the top level object containing a list with the single entry in the list, however all of the fields for the single entry in the list are null. Any idea what I'm doing wrong here?
UPDATE: after setting FAIL_ON_UNKNOWN_PROPERTIES to true, I am getting the following stack trace. Still not sure why it is having issues with the wrapped "RecurringDetail" object in the array.
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "RecurringDetail" (class com.adyen.www.models.RecurringDetail), not marked as ignorable (19 known properties: "variant", "contractTypes", "tokenDetails", "aliasType", "name", "creationDate", "firstPspReference", "elv", "card", "additionalData", "shopperName", "socialSecurityNumber", "billingAddress", "bank", "recurringDetailReference", "paymentMethodVariant", "alias", "acquirer", "acquirerAccount"])
at [Source: response.json; line: 5, column: 33] (through reference chain: com.adyen.www.models.RecurringDetailsResult["details"]->java.util.ArrayList[0]->com.adyen.www.models.RecurringDetail["RecurringDetail"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:62)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:834)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1094)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1470)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1448)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:282)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:287)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:259)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:26)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:499)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:101)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:276)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2759)
JSON
{
"creationDate": "2017-01-26T23:11:20+01:00",
"details": [
{
"RecurringDetail": {
"acquirer": "TestPmmAcquirer",
"acquirerAccount": "TestPmmAcquirerAccount",
"additionalData": {
"cardBin": "440000"
},
"alias": "B133243153928547",
"aliasType": "Default",
"card": {
"expiryMonth": "8",
"expiryYear": "2018",
"holderName": "Steve HAll",
"number": "0008"
},
"contractTypes": [
"RECURRING"
],
"creationDate": "2017-01-26T23:11:20+01:00",
"firstPspReference": "8524854686798738",
"paymentMethodVariant": "visadebit",
"recurringDetailReference": "8414854686802111",
"variant": "visa"
}
}
],
"invalidOneclickContracts": "false",
"lastKnownShopperEmail": "someones#email.com",
"shopperReference": "xggZcGauSSG5jP+akIlijQ=="
}
Unit Test
public class RecurringDetailResultTest {
public static ObjectMapper mapper = new ObjectMapper()
{
private static final long serialVersionUID = -174113593500315394L;
{
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
configure(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS, true);
setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
};
#Test
public void testParseRecurringDetailResulte() throws IOException {
RecurringDetailsResult result = mapper.readValue(new File("response.json"), new TypeReference<RecurringDetailsResult>(){});
if (result.getDetails() != null && !result.getDetails().isEmpty()) {
RecurringDetail detail = result.getDetails().get(0);
if (StringUtils.isEmpty(detail.getRecurringDetailReference())) {
fail("Recurring detail does not contain any information.");
}
} else {
fail("No result details returned.");
}
}
}
Model (Root object)
public class RecurringDetailsResult
implements java.io.Serializable {
private static final long serialVersionUID = 5297684963950973136L;
private Date creationDate;
private String shopperReference;
private List<RecurringDetail> details;
private String lastKnownShopperEmail;
#JsonGetter("creationDate")
public Date getCreationDate ( ) {
return this.creationDate;
}
#JsonSetter("creationDate")
public void setCreationDate (Date value) {
this.creationDate = value;
}
#JsonGetter("shopperReference")
public String getShopperReference ( ) {
return this.shopperReference;
}
#JsonSetter("shopperReference")
public void setShopperReference (String value) {
this.shopperReference = value;
}
#JsonGetter("details")
public List<RecurringDetail> getDetails ( ) {
return this.details;
}
#JsonSetter("details")
public void setDetails (List<RecurringDetail> value) {
this.details = value;
}
#JsonGetter("lastKnownShopperEmail")
public String getLastKnownShopperEmail ( ) {
return this.lastKnownShopperEmail;
}
#JsonSetter("lastKnownShopperEmail")
public void setLastKnownShopperEmail (String value) {
this.lastKnownShopperEmail = value;
}
}
Model (the object in the array, all of the fields of this guy are null when Jackson deserializes the JSON)
public class RecurringDetail
implements java.io.Serializable {
private static final long serialVersionUID = 5302883242997268343L;
private String name;
private Date creationDate;
private Card card;
private ELV elv;
private Address billingAddress;
private String additionalData;
private Name shopperName;
private String socialSecurityNumber;
private String recurringDetailReference;
private BankAccount bank;
private String alias;
private String aliasType;
private TokenDetails tokenDetails;
private String variant;
private String paymentMethodVariant;
private String firstPspReference;
private List<String> contractTypes;
private String acquirer;
private String acquirerAccount;
#JsonGetter("name")
public String getName ( ) {
return this.name;
}
#JsonSetter("name")
public void setName (String value) {
this.name = value;
}
#JsonGetter("creationDate")
public Date getCreationDate ( ) {
return this.creationDate;
}
#JsonSetter("creationDate")
public void setCreationDate (Date value) {
this.creationDate = value;
}
#JsonGetter("card")
public Card getCard ( ) {
return this.card;
}
#JsonSetter("card")
public void setCard (Card value) {
this.card = value;
}
#JsonGetter("elv")
public ELV getElv ( ) {
return this.elv;
}
#JsonSetter("elv")
public void setElv (ELV value) {
this.elv = value;
}
#JsonGetter("billingAddress")
public Address getBillingAddress ( ) {
return this.billingAddress;
}
#JsonSetter("billingAddress")
public void setBillingAddress (Address value) {
this.billingAddress = value;
}
#JsonGetter("additionalData")
public String getAdditionalData ( ) {
return this.additionalData;
}
#JsonSetter("additionalData")
public void setAdditionalData (String value) {
this.additionalData = value;
}
#JsonGetter("shopperName")
public Name getShopperName ( ) {
return this.shopperName;
}
#JsonSetter("shopperName")
public void setShopperName (Name value) {
this.shopperName = value;
}
#JsonGetter("socialSecurityNumber")
public String getSocialSecurityNumber ( ) {
return this.socialSecurityNumber;
}
#JsonSetter("socialSecurityNumber")
public void setSocialSecurityNumber (String value) {
this.socialSecurityNumber = value;
}
#JsonGetter("recurringDetailReference")
public String getRecurringDetailReference ( ) {
return this.recurringDetailReference;
}
#JsonSetter("recurringDetailReference")
public void setRecurringDetailReference (String value) {
this.recurringDetailReference = value;
}
#JsonGetter("bank")
public BankAccount getBank ( ) {
return this.bank;
}
#JsonSetter("bank")
public void setBank (BankAccount value) {
this.bank = value;
}
#JsonGetter("alias")
public String getAlias ( ) {
return this.alias;
}
#JsonSetter("alias")
public void setAlias (String value) {
this.alias = value;
}
#JsonGetter("aliasType")
public String getAliasType ( ) {
return this.aliasType;
}
#JsonSetter("aliasType")
public void setAliasType (String value) {
this.aliasType = value;
}
#JsonGetter("tokenDetails")
public TokenDetails getTokenDetails ( ) {
return this.tokenDetails;
}
#JsonSetter("tokenDetails")
public void setTokenDetails (TokenDetails value) {
this.tokenDetails = value;
}
#JsonGetter("variant")
public String getVariant ( ) {
return this.variant;
}
#JsonSetter("variant")
public void setVariant (String value) {
this.variant = value;
}
#JsonGetter("paymentMethodVariant")
public String getPaymentMethodVariant ( ) {
return this.paymentMethodVariant;
}
#JsonSetter("paymentMethodVariant")
public void setPaymentMethodVariant (String value) {
this.paymentMethodVariant = value;
}
#JsonGetter("firstPspReference")
public String getFirstPspReference ( ) {
return this.firstPspReference;
}
#JsonSetter("firstPspReference")
public void setFirstPspReference (String value) {
this.firstPspReference = value;
}
#JsonGetter("contractTypes")
public List<String> getContractTypes ( ) {
return this.contractTypes;
}
#JsonSetter("contractTypes")
public void setContractTypes (List<String> value) {
this.contractTypes = value;
}
#JsonGetter("acquirer")
public String getAcquirer ( ) {
return this.acquirer;
}
#JsonSetter("acquirer")
public void setAcquirer (String value) {
this.acquirer = value;
}
#JsonGetter("acquirerAccount")
public String getAcquirerAccount ( ) {
return this.acquirerAccount;
}
#JsonSetter("acquirerAccount")
public void setAcquirerAccount (String value) {
this.acquirerAccount = value;
}
}
The easiest thing I can think to do is to make your java objects look like your Json. Because this Json has a wrapped inner object but not the outer object you would have to have a similar wrapping in java. It isn't elegant but works.
public class RecurringDetailsResult implements java.io.Serializable {
private Date creationDate;
private String shopperReference;
private List<RecurringDetailWrapper> details;
private String lastKnownShopperEmail;
// getters and setters here. No need for any #JsonGetter or #JsonSetter annotations
}
#JsonRootName("RecurringDetail")
public class RecurringDetailWrapper {
#JsonProperty("RecurringDetail")
RecurringDetail recurringDetail;
public RecurringDetail getRecurringDetail() {
return recurringDetail;
}
public void setRecurringDetail(RecurringDetail recurringDetail) {
this.recurringDetail = recurringDetail;
}
}
public class RecurringDetail implements java.io.Serializable {
private static final long serialVersionUID = 5302883242997268343L;
private String name;
private Date creationDate;
private Card card;
private AdditionalData additionalData;
private String socialSecurityNumber;
private String recurringDetailReference;
private String alias;
private String aliasType;
private String variant;
private String paymentMethodVariant;
private String firstPspReference;
private List<String> contractTypes;
private String acquirer;
private String acquirerAccount;
public class AdditionalData {
String cardBin;
public String getCardBin() {
return cardBin;
}
public void setCardBin(String cardBin) {
this.cardBin = cardBin;
}
}
// getters and setters here. No need for any #JsonGetter or #JsonSetter annotations
}
Then in your unit test:
#Test
public void testParseRecurringDetailResulte() throws IOException {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("ID41901838.json");
ObjectReader objectReader = mapper.readerFor(RecurringDetailsResult.class);
RecurringDetailsResult result = objectReader.readValue(inputStream);
if (result.getDetails() != null && !result.getDetails().isEmpty()) {
RecurringDetailWrapper detail = result.getDetails().get(0);
if (StringUtils.isEmpty(detail.getRecurringDetail().getRecurringDetailReference())) {
fail("Recurring detail does not contain any information.");
}
} else {
fail("No result details returned.");
}
}
I posted the full working code here:
https://github.com/teacurran/java-experiments/tree/master/stackoverflow-sandbox/src/main/java/com/wirelust/stackoverflowsandbox/ID41901838
It seems your current structure will work for the response JSON as below (an extra named layer is removed)
{
"creationDate": "2017-01-26T23:11:20+01:00",
"details": [
{
"acquirer": "TestPmmAcquirer",
"acquirerAccount": "TestPmmAcquirerAccount",
"additionalData": {
"cardBin": "440000"
},
"alias": "B133243153928547",
"aliasType": "Default",
"card": {
"expiryMonth": "8",
"expiryYear": "2018",
"holderName": "Steve HAll",
"number": "0008"
},
"contractTypes": [
"RECURRING"
],
"creationDate": "2017-01-26T23:11:20+01:00",
"firstPspReference": "8524854686798738",
"paymentMethodVariant": "visadebit",
"recurringDetailReference": "8414854686802111",
"variant": "visa"
}
],
"invalidOneclickContracts": "false",
"lastKnownShopperEmail": "someones#email.com",
"shopperReference": "xggZcGauSSG5jP+akIlijQ=="
}
For named object maybe you can try something like
public class RecurringDetailsResult
implements java.io.Serializable {
private static final long serialVersionUID = 5297684963950973136L;
private Date creationDate;
private String shopperReference;
private List<Map<String,RecurringDetail>> details;
private String lastKnownShopperEmail;
#JsonGetter("creationDate")
public Date getCreationDate ( ) {
return this.creationDate;
}
#JsonSetter("creationDate")
public void setCreationDate (Date value) {
this.creationDate = value;
}
#JsonGetter("shopperReference")
public String getShopperReference ( ) {
return this.shopperReference;
}
#JsonSetter("shopperReference")
public void setShopperReference (String value) {
this.shopperReference = value;
}
#JsonGetter("details")
public List<Map<String, RecurringDetail>> getDetails ( ) {
return this.details;
}
#JsonSetter("details")
public void setDetails (List<Map<String, RecurringDetail>> value) {
this.details = value;
}
#JsonGetter("lastKnownShopperEmail")
public String getLastKnownShopperEmail ( ) {
return this.lastKnownShopperEmail;
}
#JsonSetter("lastKnownShopperEmail")
public void setLastKnownShopperEmail (String value) {
this.lastKnownShopperEmail = value;
}
}

Android java/gson serialization List<MyObject> produces null,null,null

I have following classes:
public class MyProperty
{
public String Key;
public String Value;
}
public class MyModel
{
public String Name;
public List<MyProperty> Properties;
}
When I try to serialize an object of type MyObject like this:
MyModel m = new MyModel(){{
Name="aaaa";
Properties = new ArrayList<MyProperty>();
}};
m.Properties = new ArrayList<MyProperty>();
m.Properties.add(new MyProperty() {{ Key="a"; Value="1"; }});
m.Properties.add(new MyProperty() {{ Key="b"; Value="11"; }});
m.Properties.add(new MyProperty() {{ Key="c"; Value="111"; }});
String json1 = g.toJson(m, MyModel.class);
I'm getting following result:
{"Name":"aaaa","Properties":[null,null,null]}
Why is the list of properties serialized to list of null's when the source objects are definitely not null?
Deserialization of a string
{"Name":"aaaa","Properties":[{"Key":"a","Value":"1" etc }]}
works fine.
The problem you're likely hitting is polymorphism - you're model says that the Properties are of type "MyProperty" but your code fragment uses "SyncProperty". There are some gotchas to doing this with Gson - have a look at the discussion here: How to handle deserializing with polymorphism?
I will tell you why this code has the output you are looking for and not the code you have in question.
Code
import java.util.ArrayList;
import com.google.gson.Gson;
public class TestOneDrive {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyModel model = new MyModel();
model.setName("someName");
ArrayList<MyProperty> myProperties = new ArrayList<>();
for (int i = 0; i < 5; i++) {
MyProperty myProperty = new MyProperty();
myProperty.setKey("Key_" + i);
myProperty.setValue("Value_" + i);
myProperties.add(myProperty);
}
model.setProperties(myProperties);
String result = (new Gson()).toJson(model);
System.out.println("" + result);
}
}
class MyProperty {
public String Key;
public String Value;
public String getKey() {
return Key;
}
public void setKey(String key) {
Key = key;
}
public String getValue() {
return Value;
}
public void setValue(String value) {
Value = value;
}
}
class MyModel {
public String Name;
public ArrayList<MyProperty> Properties;
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public ArrayList<MyProperty> getProperties() {
return Properties;
}
public void setProperties(ArrayList<MyProperty> properties) {
Properties = properties;
}
}
Output
{
"Name": "someName",
"Properties": [
{
"Key": "Key_0",
"Value": "Value_0"
},
{
"Key": "Key_1",
"Value": "Value_1"
},
{
"Key": "Key_2",
"Value": "Value_2"
},
{
"Key": "Key_3",
"Value": "Value_3"
},
{
"Key": "Key_4",
"Value": "Value_4"
}
]
}

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.

Categories

Resources