getting values from a Gson object into a HashMap - java

I have the following json String:
"{\"rates\":{\"CAD\":1.5601,\"HKD\":8.4781,\"ISK\":156.1,\"PHP\":55.709,\"DKK\":7.4642,\"HUF\":369.36,\"CZK\":27.369,\"AUD\":1.8053,\"RON\":4.834,\"SEK\":10.9368,\"IDR\":18239.61,\"INR\":83.6004,\"BRL\":5.7349,\"RUB\":86.475,\"HRK\":7.6285,\"JPY\":117.55,\"THB\":36.111,\"CHF\":1.0564,\"SGD\":1.5689,\"PLN\":4.5815,\"BGN\":1.9558,\"TRY\":7.2925,\"CNY\":7.7653,\"NOK\":11.2685,\"NZD\":1.8547,\"ZAR\":19.6619,\"USD\":1.0936,\"MXN\":26.4097,\"ILS\":3.9015,\"GBP\":0.8846,\"KRW\":1346.48,\"MYR\":4.7654},\"base\":\"EUR\",\"date\":\"2020-04-01\"}"
it's a list of rates with the matching rate values, these have been retrieved from here.
What I want to do, is to deserialize the string into an object, that I've already created
package com.example.android.myrates.core.json;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class JsonLatestStructure {
#SerializedName("rates")
#Expose
private JsonRatesStructure rates;
#SerializedName("base")
#Expose
private String base;
#SerializedName("date")
#Expose
private String date;
public JsonRatesStructure getRates() {
return rates;
}
public void setRates(JsonRatesStructure rates) {
this.rates = rates;
}
public String getBase() {
return base;
}
public void setBase(String base) {
this.base = base;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
I currently have a method that creates a new Gson object, and I want to be able to get all the rate names and matching rate values into a hashmap.
JsonLatestStructure jsonData = new Gson().fromJson(rateListPresenter.getLatestRateList(), JsonLatestStructure.class);
Thanks in advance!
UPDATE:
I accomplished what I wanted by doing this:
JsonLatestStructure jsonData = new Gson().fromJson(rateListPresenter.getLatestRateList(), JsonLatestStructure.class);
Map<String, Double> rateListItems = jsonData.getRates();

Try below it will return all dynamic key and value list
JSONObject data = jsonResponse.getJSONObject("rates");// here response is server response
Iterator keys = data.keys();
while(keys.hasNext()) {
// loop to get the dynamic key
String key = (String)keys.next(); // it returns a key ;ile CAD, HKD etc...
// get the value of the dynamic key
int value = data.getInt(key); // it returns a value like 1.5601,8.4781 etc...
}

Related

Deserializing Enum, which contains Map

my enum:
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum Currency {
USD("USD", "United States Dollar"),
EUR("EUR", "Euro"),
BGP("BGP", "British Pound"),
AUD("AUD", "Australian Dollar"),
CAD("CAD", "Canadian Dollar");
private final String shortName;
private final String fullName;
private Map<Enum, Double> rates;
Currency(String shortName, String fullName) {
this.shortName = shortName;
this.fullName = fullName;
this.rates = new HashMap<>();
}
public String getShortName() {
return shortName;
}
public String getFullName() {
return fullName;
}
public Map<Enum, Double> getRates() {
return rates;
}
}
Postman response I get from another rest api:
{
"shortName": "EUR",
"fullName": "Euro",
"rates": {
"AUD": 1.62,
"CAD": 1.47,
"USD": 1.11,
"BGP": 0.86,
"EUR": 1.0
}
}
Title pretty much sums up what I need. Any ideas how to serialize the postman response in my code, so i have enum as a result, which contains all properties, including "rates" map?
Thanks in advance.
You need to create a static factory method annotated with com.fasterxml.jackson.annotation.JsonCreator annotation. In case when whole JSON Object represents enum, Jackson automatically converts it to Map, so this method should have signature like below:
#JsonCreator
public static Currency from(Map<String, Object> value)
Below showcase provides complete implementation:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./src/main/resources/test.json");
ObjectMapper mapper = new ObjectMapper();
Currency currency = mapper.readValue(jsonFile, Currency.class);
System.out.println(currency + " => " + currency.getRates());
}
}
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
enum Currency {
USD("USD", "United States Dollar"),
EUR("EUR", "Euro"),
BGP("BGP", "British Pound"),
AUD("AUD", "Australian Dollar"),
CAD("CAD", "Canadian Dollar");
private final String shortName;
private final String fullName;
private Map<Enum, Double> rates;
Currency(String shortName, String fullName) {
this.shortName = shortName;
this.fullName = fullName;
this.rates = Collections.emptyMap();
}
public String getShortName() {
return shortName;
}
public String getFullName() {
return fullName;
}
public Map<Enum, Double> getRates() {
return rates;
}
public static Currency fromShortName(String value) {
for (Currency currency : values()) {
if (currency.getShortName().equals(value)) {
return currency;
}
}
throw new IllegalArgumentException(value + " is not found!");
}
#JsonCreator
public static Currency from(Map<String, Object> value) {
String shortName = value.getOrDefault("shortName", "").toString();
Currency currency = fromShortName(shortName);
Map<String, Double> rates = (Map<String, Double>) value.getOrDefault("rates", Collections.emptyMap());
Map<Enum, Double> newRates = new HashMap<>(9);
rates.forEach((k, v) -> {
newRates.put(Currency.fromShortName(k), v);
});
currency.rates = Collections.unmodifiableMap(newRates);
return currency;
}
}
Above code prints:
EUR => {EUR=1.0, AUD=1.62, CAD=1.47, USD=1.11, BGP=0.86}
Warning
enum should be an Immutable object and keeping rates Map inside is not a good idea. You should definitely try to remove it from enum. In multi thread environment you need to guarantee that this Map will not be change during the read. So, in implementation I do not change already used Map but create new every time.

Get value from dynamic json in Android

I want to parse this following dynamic JSON
{
"lowfares": {
"2017-07-30": {
"price": "1208.00",
"tax": "946.00",
"totalprice": "2154.00"
},
"2017-07-31": {
"price": "1208.00",
"tax": "946.00",
"totalprice": "2154.00"
}
}
}
This is my class contains price, tax, and totalprice
public class PriceModel {
#SerializedName("price")
private String price;
#SerializedName("tax")
private String tax;
#SerializedName("totalprice")
private String totalprice;
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getTax() {
return tax;
}
public void setTax(String tax) {
this.tax = tax;
}
public String getTotalPrice() {
return totalprice;
}
public void setTotalPrice(String totalPrice) {
this.totalprice = totalPrice;
}
}
This is my class to contain hashmap to store the response
public class ResponseModel {
#SerializedName("prices")
#Expose
private Map<String,PriceModel> priceModelMap;
public Map<String, PriceModel> getPriceModelMap() {
return priceModelMap;
}
public void setPriceModelMap(Map<String, PriceModel> priceModelMap) {
this.priceModelMap = priceModelMap;
}
}
in API interface, this is how I get the response
#GET("getprice/{start}/{end}/1/2")
Call<ResponseModel> getResponse(#Path("start") String start, #Path("end") String end);
and in MainActivity, I execute like this
Call call = apiInterface.getResponse("CRB","IMY");
call.enqueue(new Callback() {
#Override
public void onResponse(Call call, Response response) {
Log.d("TAG",response.code()+" ");
Log.d("TAG","REsponse: "+response.body());
ResponseModel responseModel = (ResponseModel) response.body();
Log.d("TAG","REsponse: "+responseModel.getPriceModelMap());
Map<String, PriceModel> priceModelMap = responseModel.getPriceModelMap();
for (Map.Entry<String,PriceModel> entry : priceModelMap.entrySet()){
String key = entry.getKey();
PriceModel priceModel = entry.getValue();
System.out.println("KEY: "+key+" value: "+priceModel.getPrice());
}
}
#Override
public void onFailure(Call call, Throwable t) {
call.cancel();
}
});
I want to get price, tax, totalprice. But using my method, I tried getPrice method give null value.
How can I get the date and the values from that JSON? Thanks
So in the end I decided not to use retrofit as I couldnt find a way to parse the json as I wanted.
What I did to parse that dynamic json response
private HashMap<String,JSONObject> getLowfaresJson(JSONObject data){
HashMap<String,JSONObject> result = new HashMap<>();
try {
JSONObject lowfareJson = data.getJSONObject("lowfares");
Iterator keys = lowfareJson.keys();
while ((keys.hasNext())){
//Getting dynamic key from json
String currentDynamicKey = (String) keys.next();
//Getting dynamic value from json
JSONObject currentDynamicValue = lowfareJson.getJSONObject(currentDynamicKey);
result.put(currentDynamicKey,currentDynamicValue);
}
} catch (JSONException e) {
e.printStackTrace();
}
return result;
}
that method will return hashmap from dynamic json response. Hope this will help someone
You can simply gson.
Import in your project.
dependencies {
compile 'com.google.code.gson:gson:2.8.1'
}
public class TestModel {
private String name;
private int age;
private String position;
}
Use:
String strModel ="Staff{name='john', age=35, position='Developer'}"
Gson gson = new Gson();
TestModel testModel = gson.fromJson(strModel, TestModel .class);
Read more:Samples

How to replace a Date that I add to an ArrayList

ArrayList member = new ArrayList();
member.add(new Member("V0001","Amy","0000-0000-0000","012-3456789","01-01-2014","01-01- 2015"));
private String memberId=V0001;
private String memberName=Amy;
private String icNo = 0000-0000-0000;
private String hpNo = 012-3456789;
private String joiningDate = 01-01-2014;
private String expiredDate = 01-01-2015;
System.out.printf("\nEnter New Expired Date: ");
String expiredDate =inputS12.nextLine();
member.get(inputS12).set(6,"expiredDate"); // This is the problem
The problem now is, I can enter the new expired date which is ("01-01-2016") that I want, but the new expired date did not change to 01-01-2016, it still remains 01-01-2015.
Can anyone help me solve this problem?
with your code
member.get(index);
will return you a Member object.
If you have a public setter for expiredDate
you should be able to do
member.get(index).setExpiredDate (new Date ());
To make this work better I recommend you to also do
ArrayList <Member> member = new ArrayList <Member> ();
Full code:
ArrayList member = new ArrayList();
member.add(new Member("V0001","Amy","0000-0000-0000","012-3456789","01-01-2014","01-01-2015"));
System.out.printf("\nEnter New Expired Date: ");
String expiredDate =inputS12.nextLine();
Member m=(Member)member.get(0);//First you need to get the object
m.setExpiredDate(expiredDate);
member.set(0,m);
If you use java, I hope following codes will get done the job you want.
Your Member class should be like this:
package stackoverflow;
public class Member {
private String memberId;
private String memberName;
private String icNo;
private String hpNo;
private String joiningDate;
private String expireDate;
///Setters
public void setMemberId(String memberId) {
this.memberId = memberId;
}
public void setMemberName(String memberName) {
this.memberName = memberName;
}
public void setIcNo(String icNo) {
this.icNo = icNo;
}
public void setHpNo(String hpNo) {
this.hpNo = hpNo;
}
public void setJoiningDate(String joiningDate) {
this.joiningDate = joiningDate;
}
public void setExpireDate(String expireDate) {
this.expireDate = expireDate;
}
////Getters
public String getMemberId() {
return memberId;
}
public String getMemberName() {
return memberName;
}
public String getIcNo() {
return icNo;
}
public String getHpNo() {
return hpNo;
}
public String getJoiningDate() {
return joiningDate;
}
public String getExpireDate() {
return expireDate;
}
}
Following code will show you how your job get done.
package stackoverflow;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
**//Create ArrayList to hold the list of members**
ArrayList<Member> memberList = new ArrayList();
**//Create new member**
Member member = new Member();
**//Adding new member's info**
member.setMemberId("V0001");
member.setMemberName("Amy");
member.setIcNo("0000-0000-0000");
member.setHpNo("012-3456789");
member.setJoiningDate("01-01-2014");
member.setExpireDate("01-01-2015");
**//Adding newly created member to memberList**
memberList.add(member);
**//Checking expire date before you change it.
//here you should know the index of the member object which you
//want to update or view values of it .Here in case its 0**
System.out.println(((Member) memberList.get(0)).getExpireDate());
//
**//Adding new expire date to the member need to do the following steps.**
String newExpireDate = "01-01-2016";
**//Getting Object you want to update value and updat it**
((Member) memberList.get(0)).setExpireDate(newExpireDate);
**//Checking the values after updating the expire date.**
System.out.println(((Member) memberList.get(0)).getExpireDate());
}
}

Jackson Can not deserialize empty array

Im reading the Facebook Insights and trying to get Jackson to map the JSON to Object. If all the data comes in without empty, i have it working. But Im having a problem trying to deserialize empty array of key value. Even after trying this post: How to prevent null values inside a Map and null fields inside a bean from getting serialized through Jackson it did not resolve the problem :(
This is the JSON :
{"data":[{"id":"492640667465465\/insights\/page_fans_country\/lifetime","name":"page_fans_country","period":"lifetime","values":[{"value":{"MY":26315,"ID":311,"SG":77,"NP":63,"MM":56,"PH":51,"GB":44,"US":44,"KR":36,"TH":36,"IN":34,"BD":24,"PK":22,"BN":22,"AU":15,"TW":14,"VN":12,"KH":11,"YE":11,"CA":10,"JP":10,"EG":8,"ZA":7,"SA":6,"ES":6,"HK":6,"FR":6,"IT":5,"IL":5,"IR":5,"NG":5,"LK":5,"BR":5,"IQ":4,"AF":4,"AE":4,"GT":4,"RO":4,"LR":4,"RU":4,"PS":4,"DE":4,"CN":4,"LY":3,"JO":3},"end_time":"2014-08-02T07:00:00+0000"},{"value":{"MY":26326,"ID":315,"SG":77,"NP":63,"MM":56,"PH":54,"GB":44,"US":43,"TH":38,"KR":36,"IN":33,"BD":23,"BN":22,"PK":21,"AU":16,"TW":14,"VN":12,"KH":11,"YE":11,"CA":10,"JP":10,"EG":8,"ZA":7,"SA":7,"ES":6,"HK":6,"FR":6,"IT":5,"IL":5,"IR":5,"NG":5,"LK":5,"BR":5,"IQ":4,"RU":4,"CN":4,"GT":4,"RO":4,"LR":4,"AF":4,"PS":4,"DE":4,"AE":4,"LY":3,"CH":3},"end_time":"2014-08-03T07:00:00+0000"},{"value":{"MY":26338,"ID":312,"SG":79,"NP":63,"MM":55,"PH":52,"US":45,"GB":44,"TH":39,"KR":34,"IN":32,"BD":24,"BN":22,"PK":21,"AU":16,"TW":14,"KH":12,"VN":12,"CA":11,"YE":11,"JP":10,"EG":8,"ZA":7,"SA":7,"ES":6,"HK":6,"FR":6,"IT":5,"CN":5,"IR":5,"NG":5,"LK":5,"BR":5,"IL":5,"IQ":4,"AF":4,"AE":4,"GT":4,"RO":4,"LR":4,"RU":4,"PS":4,"DE":4,"NZ":3,"TR":3},"end_time":"2014-08-04T07:00:00+0000"}],"title":"Lifetime Likes by Country","description":"Lifetime: Aggregated Facebook location data, sorted by country, about the people who like your Page. (Unique Users)"},{"id":"492640667465465\/insights\/page_storytellers_by_country\/day","name":"page_storytellers_by_country","period":"day","values":[{"value":[],"end_time":"2014-08-02T07:00:00+0000"},{"value":[],"end_time":"2014-08-03T07:00:00+0000"},{"value":[],"end_time":"2014-08-04T07:00:00+0000"}],"title":"Daily Country: People Talking About This","description":"Daily: The number of People Talking About the Page by user country (Unique Users)"},{"id":"492640667465465\/insights\/page_storytellers_by_country\/week","name":"page_storytellers_by_country","period":"week","values":[{"value":{"MY":136,"IN":3,"ID":2,"BD":1,"US":1,"TN":1,"AU":1},"end_time":"2014-08-02T07:00:00+0000"},{"value":{"MY":131,"IN":3,"US":1,"TN":1,"AU":1,"ID":1},"end_time":"2014-08-03T07:00:00+0000"},{"value":{"MY":118,"IN":2,"KH":1,"TR":1,"US":1,"TN":1,"AR":1,"AU":1},"end_time":"2014-08-04T07:00:00+0000"}],"title":"Weekly Country: People Talking About This","description":"Weekly: The number of People Talking About the Page by user country (Unique Users)"},{"id":"492640667465465\/insights\/page_storytellers_by_country\/days_28","name":"page_storytellers_by_country","period":"days_28","values":[{"value":{"MY":492,"IN":5,"ID":3,"AU":2,"SG":2,"ZA":2,"US":2,"GB":2,"RO":1,"PH":1,"NP":1,"BD":1,"JO":1,"PS":1,"TN":1,"IR":1,"CA":1,"CN":1,"KR":1},"end_time":"2014-08-02T07:00:00+0000"},{"value":{"MY":499,"IN":5,"ID":3,"GB":2,"SG":2,"ZA":2,"US":2,"RO":1,"PH":1,"NP":1,"BD":1,"AU":1,"CN":1,"KR":1,"TN":1,"IR":1,"CA":1,"JO":1},"end_time":"2014-08-03T07:00:00+0000"},{"value":{"MY":501,"IN":4,"ID":3,"SG":2,"ZA":2,"US":2,"GB":2,"AU":1,"RO":1,"PH":1,"NP":1,"JO":1,"AR":1,"KR":1,"BD":1,"TR":1,"IR":1,"CA":1,"CN":1,"KH":1,"TN":1},"end_time":"2014-08-04T07:00:00+0000"}],"title":"28 Days Country: People Talking About This","description":"28 Days: The number of People Talking About the Page by user country (Unique Users)"}],"paging":{"previous":"https:\/\/graph.facebook.com\/v2.0\/492640667465465\/insights?since=1406649169&until=1406908369","next":"https:\/\/graph.facebook.com\/v2.0\/492640667465465\/insights?since=1407167569&until=1407426769"}}
My current code does not like this at all --> "value":[]
And the follwing is my Object:
import java.util.Date;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
public class Insights {
private Data[] data;
private Paging paging;
public Data[] getData() {
return data;
}
public void setData(Data[] data) {
this.data = data;
}
public Paging getPaging() {
return paging;
}
public void setPaging(Paging paging) {
this.paging = paging;
}
/**
* inner class for Data
* #author pohsoon.yap
*
*/
public static class Data {
private String id;
private String name;
private String period;
private Values[] values;
private String title;
private String description;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPeriod() {
return period;
}
public void setPeriod(String period) {
this.period = period;
}
public Values[] getValues() {
return values;
}
public void setValues(Values[] values) {
this.values = values;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
/**
* inner class for Values
* #author pohsoon.yap
*
*/
public static class Values {
// if "value":[] then this will break
private Map<String, Integer> Value;
private String end_time;
public Map<String, Integer> getValue() {
return Value;
}
public void setValue(Map<String, Integer> value) {
Value = value;
}
public String getEnd_time() {
return end_time;
}
public void setEnd_time(String end_time) {
this.end_time = end_time;
}
}
}
public static class Paging {
private String previous;
private String next;
public String getPrevious() {
return previous;
}
public void setPrevious(String previous) {
this.previous = previous;
}
public String getNext() {
return next;
}
public void setNext(String next) {
this.next = next;
}
}
}
My code snippet as follows:
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
List<Insights> insightList = new ArrayList();
String insightStr = "";
try {
for (Operation operation : mq.getOperationList()){
String apiEndPoint = this.facebookGraphApiUrl + operation.getApi();
apiEndPoint = apiEndPoint.replace("{pageid}", mq.getFacebookPage().getPageId());
uri = new URI(apiEndPoint);
insightStr = facebook.getApi().restOperations().getForObject(uri, String.class);
Insights insights = mapper.readValue(insightStr, Insights.class);
The full stack trace:
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.LinkedHashMap out of START_ARRAY token
at [Source: java.io.StringReader#625a80df; line: 1, column: 1603] (through reference chain: com.social.facebook.model.Insights["data"]->com.social.facebook.model.Data["values"]->com.social.facebook.model.Values["value"])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:599)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:593)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:306)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:26)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:375)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:98)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:308)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:147)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:18)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:375)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:98)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:308)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:147)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:18)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:375)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:98)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:308)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2796)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1942)
As explained by others, you are trying to map JSON Array into Java Map, something that is not allowed by default.
But it may be possible to allow empty JSON Array to map to java.util.Map. by enabling DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT:
objectMapper.enable(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT);
this at least works in case of a POJO type; I do not recall if this works for other Java types that usually take JSON Object.
The value field in your model is declared as Map while the corresponding JSON property can be either an empty array or a key-value map. Jackson cannot assign an empty array to a map field.
Assuming that you wish to solve the problem on the client side, you can modify the setValue method to accept a generic Object and then verify whether it is a map or an array (actually List since Jackson deserialize arrays as Java collections). Here is an example:
public class JacksonArrayAsMap {
public static class Bean {
private Map<String, Object> value;
public void setValue(Object value) {
if (value instanceof Map) {
this.value = (Map<String, Object>) value;
} else if (value instanceof List && ((List) value).size() == 0){
this.value = Collections.EMPTY_MAP;
} else {
throw new IllegalArgumentException("Invalid value: " + value);
}
}
#Override
public String toString() {
return "Bean{" +
"value=" + value +
'}';
}
}
public static void main(String[] args) throws IOException {
final String json1 = "{\"value\":{}}";
final String json2 = "{\"value\":[]}";
final String json3 = "{\"value\":{\"a\":\"b\"}}";
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.readValue(json1, Bean.class));
System.out.println(mapper.readValue(json2, Bean.class));
System.out.println(mapper.readValue(json3, Bean.class));
}
}
Output:
Bean{value={}}
Bean{value={}}
Bean{value={a=b}}

deserialize a json array using gson

I'm deserializing a json object like this:
class Offer
{
private Category category;
private String description;
private String discount;
private Date expiration;
private Date published;
private String rescinded_at;
private String title;
private Date valid_from;
private Date valid_to;
private String id;
private Business business;
private Location location;
private Long distance;
public String getDescription() {
return String.format("[Offer: description=%2$s]", description);
}
#Override
public String toString()
{
return String.format(
"[Offer: category=%1$s, description=%2$s, discount=%3$s, expiration=%4$s, published=%5$s, rescinded_at=%6$s, title=%7$s, valid_from=%8$s, valid_to=%9$s, id=%10$s, business=%11$s, location=%12$s, distance=%13$s]",
category, description, discount, expiration, published, rescinded_at, title, valid_from, valid_to, id,
business, location, distance);
}
}
As you can see, whenever there's a nested object I just refer to a class that has a toString() method for that particular nested json object. My question is: when the json object contains an array, which in my case just looks something like this:
"draws":[
"Hair Cut",
"Blow Dry",
"Blow Dry Treatment"
]
...how do I use format.toString() to deserialize this array and then put it in my Offer toString()?
Let's clarify the meaning of two terms.
Serialize: To convert an object to a sequence of bytes.
Deserialize: To parse (serialized data) so as to reconstruct the original object.
So #LuxuryMode, when you said "deserialize", did you mean "serialize"?
Assuming this is the case...
Note that your toString implementation does not currently properly generate a JSON object or array, or anything else that is valid JSON.
I recommend not using toString or any other hand-written implementation to serialize objects to JSON (or to XML or to bytes). If possible, use an API like Gson or Jackson (or XStream or the Java Serialization API).
The following example serializes a single Offer object.
// output:
// {
// "category":
// {
// "name":"category_1",
// "type":1
// },
// "description":"description_1",
// "discount":"discount_1",
// "expiration":
// {
// "value":123
// },
// "published":
// {
// "value":456
// },
// "rescinded_at":"rescinded_at_1",
// "title":"title_1",
// "valid_from":
// {
// "value":789
// },
// "valid_to":
// {
// "value":987
// },
// "id":"id_1",
// "business":
// {
// "name":"business_name_1",
// "opening_date":
// {
// "value":654
// }
// },
// "location":
// {
// "latitude":111,
// "longitude":222
// },
// "distance":333
//}
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class Foo
{
public static void main(String[] args)
{
Offer offer = new Offer(
new Category("category_1", 1),
"description_1",
"discount_1",
new Date(123),
new Date(456),
"rescinded_at_1",
"title_1",
new Date(789),
new Date(987),
"id_1",
new Business("business_name_1", new Date(654)),
new Location(111, 222),
new Long(333));
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
Gson gson = gsonBuilder.create();
String offerJson = gson.toJson(offer);
System.out.println(offerJson);
}
}
class Offer
{
private Category category;
private String description;
private String discount;
private Date expiration;
private Date published;
private String rescindedAt;
private String title;
private Date validFrom;
private Date validTo;
private String id;
private Business business;
private Location location;
private Long distance;
Offer(Category category,
String description,
String discount,
Date expiration,
Date published,
String rescindedAt,
String title,
Date validFrom,
Date validTo,
String id,
Business business,
Location location,
Long distance)
{
this.category = category;
this.description = description;
this.discount = discount;
this.expiration = expiration;
this.published = published;
this.rescindedAt = rescindedAt;
this.title = title;
this.validFrom = validFrom;
this.validTo = validTo;
this.id = id;
this.business = business;
this.location = location;
this.distance = distance;
}
}
class Category
{
private String name;
private int type;
Category(String name, int type)
{
this.name = name;
this.type = type;
}
}
class Date
{
private long value;
Date(long value)
{
this.value = value;
}
}
class Business
{
private String name;
private Date openingDate;
Business(String name, Date openingDate)
{
this.name = name;
this.openingDate = openingDate;
}
}
class Location
{
private int latitude;
private int longitude;
Location(int latitude, int longitude)
{
this.latitude = latitude;
this.longitude = longitude;
}
}
This next example takes the JSON output from the previous example, and deserializes it back into a Java Offer object. You can add toString and/or equals implementations to verify that all of the attributes are populated as expected, but note that the toString method is not used by Gson during deserialization or serialization.
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
Gson gson = gsonBuilder.create();
String offerJson = gson.toJson(offer);
Offer offerDeserialized = gson.fromJson(offerJson, Offer.class);
To serialize an array of Offer objects is similarly simple.
Offer offer1 = new Offer(
new Category("category_1", 1),
"description_1",
"discount_1",
new Date(123),
new Date(456),
"rescinded_at_1",
"title_1",
new Date(789),
new Date(987),
"id_1",
new Business("business_name_1", new Date(654)),
new Location(111, 222),
new Long(333));
Offer offer2 = new Offer(
new Category("category_2", 2),
"description_2",
"discount_2",
new Date(234),
new Date(567),
"rescinded_at_2",
"title_2",
new Date(890),
new Date(876),
"id_2",
new Business("business_name_2", new Date(543)),
new Location(444, 555),
new Long(666));
Offer[] offers = new Offer[] {offer1, offer2};
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
Gson gson = gsonBuilder.create();
String offersJson = gson.toJson(offers);
System.out.println(offersJson);
This final example takes the JSON array output from the previous example and deserializes it back into an array of Offer objects.
Offer[] offersDeserialized = gson.fromJson(offersJson, Offer[].class);

Categories

Resources