I am new to JSON and GSON, and I am taking a JSON feed from an input stream, and put it into an array list of custom objects. The JSON feed contains a single object, which contains an array of more objects. It looks something like this:
{ "container":[
{"item_1":"item one"},
{"item_2":"item two"},
{"item_3":"item three"}
]}
I am currently using a TypeToken with a Map to obtain the container object along with the list of objects as an array list of custom objects. Like so:
InputStreamReader input = new InputStreamReader(connection.getInputStream());
Type listType = new TypeToken<Map<String, ArrayList<Item>>>(){}.getType();
Gson gson = new GsonBuilder().create();
Map<String, ArrayList<Item>> treeMap = gson.fromJson(input, listType);
ArrayList<Item> objects = treeMap.get("container");
input.close();
I would like to know if there is a way to skip the step of creating a Map<String, ArrayList<Item>>, and go directly from the input stream to an ArrayList<Item> using GSON. Just to consolidate my code, creating a map seems like an unnecessary step.
One option is to define a wrapper type which has a container property, and then deserialize the JSON to that type instead of to a Map.
public static class Wrapper {
public List<Item> container;
}
Wrapper wrapper = gson.fromJson(input, Wrapper.class);
List<Item> objects = wrapper.container;
Related
i have list of masters that have two fields that are name and rating and after serialization to array node i need to add one more field to each object
for example i have json
[{"masterName":"Bruce","rating":30},{"masterName":"Tom","rating":25}]
and i have list of servisec in json format that look like that
[{"masterName":"Bruce","services":["hair coloring","massage"]},{"masterName":"Tom","services":["hair coloring","haircut"]}]
i need it to looks something like that
[{"masterName":"Bruce","rating":30,"services":"hair coloring,massage"},{"masterName":"Tom","rating":25,"services":"hair coloring, haircut"}]
How can do it by using jackson?
I would approach it this way. Since you want to use Jackson.
First of all, I would extend the Master class by adding the services (which seems to be an array with Strings).
So the class would look something like this:
public class Master
{
private String masterName;
private int rating;
private List<String> services = new ArrayList<>(); // THE NEW PART
// Whatever you have else in your class
}
Then you could get your JSON array, I am supposing that it comes as a String for simplicity. Serialize this array in an array with Master objects and then you can add the services as said above.
e.g.
String yourJsonString = "[{\"masterName\":\"Bruce\",\"rating\":30},{\"masterName\":\"Tom\",\"rating\":25}]";
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
List<Master> theListOfMasters = new ArrayList<>();
// Read them and put them in an Array
Master[] mastersPlainArr = mapper.readValue(yourJsonString, Master[].class);
theListOfMasters = new ArrayList(Arrays.asList(mastersPlainArr));
// then you can get your masters and edit them..
theListOfMasters.get(0).getServices.add("A NEW SERVICE...");
// And so on...
// Then you can turn them in a JSON array again:
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(theListOfMasters);
I am using GSON and would like to have it convert multiple lists to JSON - that will be one object - is there any way to do this without manipulating the lists or using a new data structure?
List<String> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
list1.populate();
list2.populate();
Gson gson = new GsonBuilder().create();
gson.toJson(list1, list2);// ----> THIS IS WHAT I WANT
I want the result to be something like this - pseudocode JSON
first result of first list to correlate with first result of second list
{
list1[element1]: list2[element1],
list1[element2]: list2[element2],
list1[element3]: list2[element3].....
}
What's wrong with modification of the list in memory?
list1.populate();
list2.populate();
list1.addAll(list2);
Gson gson = new GsonBuilder().create();
gson.toJson(list1);
Obviously populate isn't a method of lists, but you can only convert single objects to JSON
If order is at all important, you have to find a way to populate a singular list containing the data in the order you need
my json object starts with an object, then contains an array of the object I want { "myObjectArray":[ {....} , {....} , {....} ] }, I have made the model file for the object represented in {....} , how do I get this generic collection code to not assume my root element is an array without making a new nested object file
This is what I currently have,
Type listType = new TypeToken<List<T>>() {
}.getType();
List<T> yourClassList = new Gson().fromJson(jsonArray, listType);
but this assumes that my json object is constructed like this [{....}, {....}, {....}] instead of the way I detailed above
Therefore, parsing returns a JsonSyntaxException
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2
Without creating a pointless model object that contains one variable "myObjectArray" which contains a List of myObject , how would I modify a GSON builder to accomodate?
(I am using android so I can't use a lot of the Oracle JVM reflection methods, including ParameterizedTypeImpl)
using
GsonBuilder builder = new GsonBuilder();
mGson = builder.enableComplexMapKeySerialization().create();
listType = new TypeToken<Map<String, List<T>>>() {}.getType();
parsedGSON = mGson.fromJson(reader, listType);
is the answer
GSON creates a LinkedTreeMap object
I have JSON like this:
{"foos":[{"id":1}, {"id":2}]}
I can turn it into List<Foo> pretty simply with GSON, like this:
Type t = new TypeToken<List<Foo>>(){}.getType();
JsonObject resp = new Gson().fromJson(
new JsonParser().parse(json).getAsJsonObject().get("foos",t);
But let's assume that I also have another JSON, where the name of the array and type changes
{"bars":[{"id":3},{"id":9}]}
Of course I could just swap the "foos" parameter for "bars", but if it's possible, I'd like my software to do it for me.
Is there a way to extract the name of the array child with the GSON library?
I'm not sure if I understood what you want correctly, but aren't you referring to the use of generics? I mean you could write a method that returns you a List of your relevant class? Something along the lines of
Type type = new TypeToken<List<MyClass>>() {}.getType();
List<MyClass> myObjects = getMyObjects(new JsonParser().parse(json).getAsJsonObject().get("foos"), type);
public static List<T> getMyObjects(String jsonString, Type type) {
Gson gson = new Gson();
List<T> myList = gson.fromJson(jsonString, type);
return myList;
}
Looking at your JSON examples, I assume that the name of the list element can change, but not the content of the list. If this is correct, you could parse your JSON response just like this:
Type mapType = new TypeToken<Map<String, List<Foo>>>() {}.getType();
Map<String, List<Foo>> map = gson.fromJson(jsonString, mapType);
And then you can access the name of the list with:
String listName = map.keySet().iterator().next();
If the content of the list could also change, things get a bit more complicated...
I' m developing an Android REST client. We use JSON as data exchange format, so I use a Jackson parser. I get different Json responses from the server like simple arrays:
{"user_id":"332","user_role":"1"}
or something else. All these stuff I parse to LinkedHashMap<String, Object> and everything works perfectly but when I got this response from the server:
[ { "user_id":"352",
"user_role":"expert",
"name":"Test 12-18",
"description":"Test" },
{ "user_id":"263",
"user_role":"novice lab",
"name":"Tom's Desk",
"description":"Desk"}
]
I got null: {} after parsing.Here is my code where i use Jackson:
ObjectMapper mapParametersToJSON = new ObjectMapper();
String serverResponseBody = responseFromServer.getBody();
LinkedHashMap<String, Object> resultofOperation = new LinkedHashMap<String,
Object>();
TypeReference<LinkedHashMap<String,Object>> genericTypeReferenceInformation = new
TypeReference<LinkedHashMap<String,Object>>() {};
try {
resultofOperation = mapParametersToJSON.readValue(serverResponseBody,
genericTypeReferenceInformation);
So, why Jackson failed to parse this? How can I fix this?
Others have suggested the problem, but solutions are bit incomplete. If you need to deal with JSON Objects and Arrays, you can either bind to java.lang.Object, check the type:
Object stuff = objectMapper.readValue(json, Object.class);
and you will get either List or Map (specifically, ArrayList or LinkedHashMap, by default; these defaults can be changed).
Or you can do JSON trees with JsonNode:
JsonNode root = objectMapper.readTree(json);
if (root.isObject()) { // JSON Object
} else if (root.isArray()) { ...
}
latter is often more convenient.
One nice thing is that you can still create regular POJOs out of these, for example:
if (root.isObject()) {
MyObject ob = objectMapper.treeToValue(MyObject.class);
}
// or with Object, use objectMapper.convertValue(ob, MyObject.class)
so you can even have different handling for different types; go back and forth different representations.
The first JSON in your question is a map, or an object. The second is an array. You're not parsing an array, you're parsing a map.
You need to do something like this:
List<MyClass> myObjects = mapper.readValue(jsonInput, new TypeReference<List<MyClass>>(){});
Almost identical question with answer here.
In JSON the {"key": "value"} is Object and the ["this", "that"] is Array.
So, in case when you're receiving the array of objects you should use something like List<Map<Key, Value>>.
You are facing an error, because [] construction can't be translated into Map reference, only in List or array.
I would recommend do it something in this way:
ObjectMapper objectMapper = new ObjectMapper();
List<Map<String,String>> parsedResult = objectMapper.reader(CollectionType.construct(LinkedList.class, MapType.construct(LinkedHashMap.class, SimpleType.construct(String.class), SimpleType.construct(String.class)))).readValue(serverResponseBody);
//if you need the one result map
Map<String, String> resultMap = new LinkedHashMap<String, String>();
for (Map<String, String> map: parsedResult){
resultMap.putAll(map);
}