This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Parsing JSON to Java POJO's using GSON
I'm trying to map this JSON to a POJO with GSON:
{
"get_lists": [
{
"Solution": [
{
"A05": "Herhalingsbezoek vereist"
},
{
"A03": "Melding met oh verholpen"
}
]
},
{
"Problem": [
{
"R07B": "Aandrijving"
},
{
"R07C": "Coating"
}
]
}
]
}
However, both the keys and values inside of the solution and problem can vary, and I haven't had to deal with this before.
If your keys don't vary too much you can make a class having all the desired fields ?
If not you have those solutions :
use a custom Deserializer.
decode as a raw collection : here's an example very similar to your problem.
deserialize your solutions using HashMap<String, String>[] :
public class ListItem {
public HashMap<String, String>[] Solution;
public HashMap<String, String>[] Problem;
}
public class Message {
public ListItem[] get_lists;
}
That's a little heavy but it avoids the use of custom deserializer.
According to me Given Structure represents below POJO
class OuterObject
{
private List<MyObject> getLists;
}
private class MyObject
{
private List<MyKeyValuePair> myList;
}
private class MyKeyValuePair
{
private String key;
private String value;
}
May this help
Related
I am trying to parse the incoming Json (given below) to Java object using Gson. The Json request seems to be a valid one, but I am getting the following exception while parsing it.
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_ARRAY at line 5 column 19 path $.metadata.
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:226) ~[gson-2.8.5.jar:?]
at com.google.gson.Gson.fromJson(Gson.java:927) ~[gson-2.8.5.jar:?]
Incoming Json request :
{
"metadata": {
"salesId": "123",
"promoCode": "2010",
"items": [
{
"0": {
"productCode": "1234",
"total": 169900
},
"1": {
"productCode": "4567",
"total": 19900
}
}
]
}
}
Parsing logic :
protected <T extends GenericModel> Optional<T> convertFromJson(final String json, final Class<T> clazz) {
if (StringUtils.isEmpty(json)) {
return Optional.empty();
}
return Optional.of(new Gson().fromJson(json, clazz));
}
Java class :
public class Metadata {
private String salesId;
private String promoCode;
private ArrayList<Object> items = new ArrayList<Object>();
public String getSalesId() {
return salesId;
}
public void setSalesId(String salesId) {
this.salesId = salesId;
}
public String getPromoCode() {
return promoCode;
}
public void setPromoCode(String promoCode) {
this.promoCode = promoCode;
}
public ArrayList<Object> getItems() {
return items;
}
public void setItems(ArrayList<Object> items) {
this.items = items;
}
#Override
public String toString() {
return "Metadata{" +
"salesId=" + getSalesId() +
"promoCode=" + getPromoCode() +
"items=" + getItems() +
'}';
}
}
Please note that Metadata.java is an inner class.
Have been trying to resolve the issue, but no luck. Could anyone let me know how to solve it? TIA.
I'd guess the problem is with the items object in the json you are trying to deserialize.
In the Metadata class items is an ArrayList<Object> but that doesn't tell gson how to deserialize it.
Instead you should try creating another POJO for Item and then making the items an ArrayList<Item>. Something like this: Gson and deserializing an array of objects with arrays in it
You could check if items is the problem by commenting out that attribute and sending in just the salesId and promoCode.
I found out the issue and thought I'l post it here incase someone comes across the same issue. I cleaned the project and rebuild again and it worked fine. The issue was not with the code afterall. I read it on a thread regarding gson libraries and tried it. And it worked for me.
As your json has all data in metadata attribute, I created a new POJO having metadata field.
class ParentMetadata {
private Metadata metadata;
// getters and setters
}
And then parsed json to POJO using below code:
ParentMetadata parentMetadata = new Gson().fromJson(jsonStr, ParentMetadata.class);
This works fine for me.
Also, as items is of type ArrayList<Object>, during debugging I could see items are deserialized as List of LinkedTreeMap.
The JSON I'm parsing looks like this:
{ "version": 1
"data": {
"1001": {
"id": 1001,
"name": "herp",
"into": [
"3111": "we"
]
},
"1032": {
"id": 1002,
"name": "derp",
"into": [
"36": "w",
"12341: "c"
],
"tags": [
"hi there"
],
"cost" {
"even": 15
}
},
"1603": {
"id": 1003,
"name": "her",
"into": [
"37": "dll",
"58": "eow",
"32145": "3a"
],
"cost" {
"highest": 325
"lowest": 100
}
},
.... Even more data
}
The Json that is within "data" goes on for a while and does not have a set endpoint. I have no control over the Json, I'm just trying to read it. Unfortunately, with my class code I'm unable to get it to work. When I make a retrofit call the information inside "data" is empty.
I've tried many iterations of implementing this, including using a deserializer and restructuring my POJO code. This is the current state of my Data class:
public class Data {
private Map<String, Item> itemData;
// Relevant Getters, Setters and Constructors //
}
For my Item Class, the main issue is that the JSON Content isn't set, it can vary at times. As you can see above the values inside "into" vary and sometimes the amount of things within item changes as well such as "tags" or "cost":
public class Item {
private int id;
private String name;
private String group;
private String description;
private Map<String, String> into;
private List<String> tags;
private Map<String, Integer> cost;
// Relevant Getters, Setters and Constructors //
When I use this code my data class is empty, I don't see any errors in the log so I can't seem to figure out why the GSON isn't working with this.
In case you wanted to see how I construct my RestClient, here it is:
RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint(ROOT)
.setClient(new OkClient(new OkHttpClient()))
.setLogLevel(RestAdapter.LogLevel.FULL);
RestAdapter restAdapter = builder.build();
REST_CLIENT = restAdapter.create(DataApi.class);
I know that my Rest Query works because I can get the content within "version" but everything inside data is null.
I am officially a dumb scrub and completely looked over the easiest possible fix and should have my account and developer title revoked.
This is all I should have done:
public class ItemGroup {
private String version;
private Map<String,Item> data;
//...Man i'm so dumb...
}
AS REFERENCE FOR THE FUTURE. The reason why this works is because the JSON is in this format { { } { } { } }. Which means you have 3 objects of objects, as opposed to { [ ] [ ] [ ] } which is 3 objects of a list. What I had done was treat { { } { } { } } as { { { } { } { } } }. Which is not correct. By using a map which is basically a collection of pairs, we are able to imitate the { { } { } { } } with a Map.
Map Object { {Key-Pair Object} {Key-Pair Object} {Key-Pair Object} }
Just a quick idea for your Pojos:
Not sure if this will work. Maybe write a custom deserializer.
public class YourResponse {
int version;
Data data;
class Data {
Subdata subData;
}
class Subdata {
private int id;
private String name;
private ArrayList<Into> into;
private ArrayList<String> tags;
//...
}
class Into {
// "3111": "we"
private String into;
}
}
I have this JSON data, and I was wondering how I might convert this data to a Java POJO object:
"progression": {
"64693": [
{
"1": 1
}
],
"64717": [
{
"1": 4
}
]
},
I was thinking it can't be:
public class Progression{
private List<64693> 64693;
private List<64717> 64717;
public List<64693> get64693(){
return this.64693;
}
public void set64693(List<64693> 64693){
this.64693 = 64693;
}
public List<64717> get64717(){
return this.64717;
}
public void set64717(List<64717> 64717){
this.64717 = 64717;
}
}
I'm very familiar with Java, so I know I can do a #JsonProperty instead of the actual numbers, but just wondering if there were any other choices.
Thanks!
_ug had the right suggestion:
... object consider naming 64693 to like DataType64693 and adding the
#JsonProperty("64693") annotation
That worked fine. And BTW, I am using the Jackson 2.0 JSON processor.
I was wondering if it possible to convert Statics Classes with Jackson instead Doing a parser by myself. For Example I have the next Static Class:
public static class SQL {
public enum Table {
CREATE,
ALTER
}
public enum Database {
CREATE
}
}
And I want to convert to next Json String
{
"SQL" :
{
"Table":
{"CREATE": "CREATE", "ALTER": "ALTER"},
{"CREATE": "CREATE"}
}
}
This is because I can use this class in Java to create great strings, and I want a similar functionality in Javascript Side.
I tried to use
new ObjectMapper.writeValuesToString(SQL);
However, this is impossible since it only converts an instantiated Object
You can achieve something like you want by using Reflection. You can add simply method to your SQL class, which can return Map.
public static Map<String, ?> toJsonMap() {
Map<String, Object> map = new HashMap<String, Object>();
Class<?>[] declaredClasses = SQL.class.getDeclaredClasses();
for (Class<?> clazz : declaredClasses) {
if (clazz.isEnum()) {
map.put(clazz.getSimpleName(), clazz.getEnumConstants());
} else {
// ...
}
}
return Collections.singletonMap(SQL.class.getSimpleName(), map);
}
Simple usage:
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(SQL.toJsonMap()));
Above program prints:
{
"SQL" : {
"Database" : [ "CREATE" ],
"Table" : [ "CREATE", "ALTER" ]
}
}
I can't seem to figure this out. I've looked at a couple SO posts (here, and here), and my situation is just a little different.
I'm not sure if I have to register a new TypeToken or what. But my JSON object looks like this:
{
"id": 6,
"error": "0",
"dates": {
34234 : "2011-01-01" // I want to parse the date into a string.
87474 : "2011-08-09" // The first values are all unique.
. //this can be any number of entries.
.
.
74857 : "2011-09-22"
}
}
I've created both of my objects like this:
public class Response {
public Integer id;
public String error;
public DateList dates;
}
Separate file:
public class DateList {
public List<Map<Integer, String>> dateString;
}
I'm not sure how to tweek it to get it right. Documentation doesn't seem to help... And the other examples I've seen are parsing a custom object, not a string type.
Thanks!
I tried it in this form:
The Json
{
"id": 6,
"error": "0",
"dates": {
"34234" : "2011-01-01"
"87474" : "2011-08-09"
"74857" : "2011-09-22"
}
}
And the Response.java
public class Response {
public Integer id;
public String error;
public Map<Integer, String> dates;
}
At least that seemed to work out of the box.