JSONArray to list of objects - java

I have JSONArray where each element in the array is a json with 5 fields.
I would like to map this JSONArray to a list on Class objects. Each Class object has exact same fields as the json element, plus 3 additional Class fields that I would like to set to null when the object is mapped from the json element.
I tried:
JSONObject jsn = SomeJsonWith2Keys
JSONArray jsn_a = (JSONArray) jsn.get("response");
List<MyClass> tags = (List<MyClass>) objectMapper.readValue(jsn_a.toString(), MyClass.class)
But this is throwing an exception
Cannot deserialize instance of x.x.x.x.MyClass out of START_ARRAY token
The array size is large and I am trying to not do mapping in a loop if possible.
I would appreciate any suggestion on how to do the mapping to the class while setting the 3 additional fields to null
Thank you

You need to specify the type as a List rather than MyClass. You can't do this by just saying List.class, but Jackson provides a com.fasterxml.jackson.core.type.TypeReference class that allows you to supply the fact that you want a list of a specific type.
So assuming your objectmapper is a jackson one you can do the following.
List<MyClass> tags = mapper.readValue(jsn_a.toString(), new TypeReference<List<MyClass>>() {});
If you're OK using an array instead of a list you can specify the array type.
MyClass[] tags = mapper.readValue(jsn_a.toString(), MyClass[].class);

Related

How to set an ArrayList Type dynamically using the class name?

Using the Gson library, I convert a JSON string to an ArrayList Object by following code:
posts = gson.fromJson(json, new TypeToken<List<Post>>(){}.getType());
and I use the following code for convert a json to a class objec:
obj = gson.fromJson(json, Class.forName(fullClassName));
You see in the second code that I used reflection to specify the type of class;
but for the first code, I don't know how to specify the type of list using reflection.
What do I do?!
So, from what I understand you need to deserialize list of objects but type isn't known on compile time but you are providing it dynamically?
You probably want to use something like that for your type:
TypeToken.getParameterized(List.class, Class.forName("foo.bar.MyDynamicType"))
This will create same type as
new TypeToken<List<MyDynamicType>>(){}.getType()

Why type of left hand side ignored - Jackson deserialisation

I have a POJO like this
class POJO {
Map<Integer, Integer> map;
//Getter and Setter for map here
}
And I have a json (list of POJO)
[
{
"200": 10
},
{
"20": 100,
"30": 400
}
]
During Jackson deserialization if I do
String s = ... //s has the above json
List<POJO> pojoList = mapper.readValue(s, new TypeReference<List<POJO>>() {});
System.out.println(pojoList.get(0).getMap().get(20)); //prints 100
then there is no problem
But if I use generic List like
List<POJO> pojoList = mapper.readValue(s, List.class);
then in the System.out.println it throws ClassCastException
java.util.LinkedHashMap cannot be cast to mycode.model.POJO
I understand that if I just tell Jackson List it deserializes each object as Map and not as type POJO. So when I try to access pojoList.get(0).getMap() it throws exception
(Note: Printing pojoList.get(0) gives no problem and prints {"200":10})
My question is why didn't it throw exception during deserialization itself. Did the type of object on LHS ignored?
Thanks..
My question is why didn't it throw exception during deserialization
itself. Did the type of object on LHS ignored?
You have a misunderstanding of how Java works. The runtime evaluation of these two statements
List<POJO> pojoList = mapper.readValue(s, List.class);
mapper.readValue(s, List.class);
is exactly the same. In other words, an assigned variable plays no role at runtime. At compile time, all it's good for is potentially providing context for generics and poly expressions.
When you invoke your
mapper.readValue(s, List.class);
you're telling Jackson to deserialize the JSON into a List. That's it. You give it no other information. There's absolutely no way for Jackson to guess that you meant a list of POJO or anything else. As such, Jackson guesses and uses its own defaults. For JSON objects, that default is LinkedHashMap.
What's more, List.class evaluates to Class<List> and therefore the return type of your readValue is the raw List type. When working with raw types, generics are erased. You therefore don't get a compilation error, but you should have a warning about unchecked conversions.
You should read
What is a raw type and why shouldn't we use it?
On the other hand, this
List<POJO> pojoList = mapper.readValue(s, new TypeReference<List<POJO>>() {});
works because you are giving Jackson ALL the information it needs to properly deserialize the JSON. It's a List (a JSON array) of POJO elements (JSON objects).
This, however, has its own problems. The return type (ie. compile time) of readValue is inferred from the context (that I mentioned earlier) and bound to List<POJO> since that is the type of the expression you're assigning the result to. The TypeReference provides no type information for the generics here. Because of this, you can do something like
List<String> stringList = mapper.readValue(s, new TypeReference<List<POJO>>() {});
and it will compile without error. At runtime though, everything will probably break.

Deserialize JSON in Java by inferring/embedding object type

I am serializing a Map<String, Object> into JSON using Jackson.
Later when I deserialize it, all objects that are not of primitive type get converted to LinkedHashMap's instead of the class that they originally belonged to.
Is there any way to deserialize JSON into a map so that the nested objects are of correct type?
Use constructCollectionType of Typefactory with ArrayList as the CollectionClass & your POJO class as the second argument and read the "List" value using ObjectMapper. Like this:
List<T> list;
ObjectMapper om = new ObjectMapper();
TypeFactory t = TypeFactory.defaultInstance();
list = om.readValue(json, t.constructCollectionType(ArrayList.class,POJO_clazz));
Hope this helps!

Dynamically entering class literal as method argument at runtime

I have an application which makes use of an external library (Jackson), and the method I need requires a class literal as an argument. So if I wish to parse my JSON string into a User object:
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(new File("user.json"), User.class);
Now, I wish to use this method dynamically (i.e. parse different JSON strings using the same line of code). For example:
String json1 = "{"type":"jacket",...}";
String json2 = "{"type":"sweater",...}";
Object object = mapper.readValue(json1/json2, ???);
//returns a Jacket object OR Sweater object based on the "type" key
//i.e. use Jacket.class as the 2nd argument if "type" is "jacket"
//OR Sweater.class if "type" is "sweater"
//After getting the deserialized object,
//if object is Jacket, cast as a Jacket
//if object is Sweater, cast as a Sweater
Of course, the JSON string in question can be for any class, so I can't simply hard-code an if-else loop. I've looked at custom serializers, but frankly am quite lost at what it's talking about, and would like some help in how I can go about this.
In summary, I need some way to first define a class literal from a String, and then cast the resulting Object into the specific class (but my focus is on getting readValue to work dynamically).
Looks like you need a mapping somewhere between JSON type variable and Java class type.
Generally result should be something like this map:
Map<String, Class<? extends YourSupertype>> map = new HashMap<>();
map.put("sweater", Sweater.class);
map.put("jacket", Jacket.class);
Just store possible clothing types somewhere in a file, then do something like:
String clothingType = nextEntryFromFile();
String className = constructClassNameFromClothingType(clothingType);
map.put(clothingType, Class.forName(className));
Since version 1.5 Jackson supports Polymorphic Type Handling, check here http://www.cowtowncoder.com/blog/archives/2010/03/entry_372.html
there are examples on how to correctly handle deserialization in those cases.

How to convert JAVA Object to JSON Efficiently..?

I am using Mule. I have a JAVA Object that is populated from my internal Class..It is actually a HashMap<String,Object>. Object can be anything..another HashMap, OR List etc ..Now i have to convert it into JSON (and removing all those keys that have value as NULL)..
When i use a given Mule Transformer , ObjectToJSON, it is converting into appropriate JSON..but not able to remove NULL value..And i could not find any properties to set in Custom-transformer that will remove NULL values..!!
So then, i wrote a custom transformer, that uses the net.sf.json-lib library and i am able to remove NULL values.
But in one of my JAVA Object , i have a HashMap<Integer,String> and since in JSON Object , Integer cannot be keys, net.sf.json library is giving an Exception :
Exception stack is:
1. JSON keys must be strings. (java.lang.ClassCastException)
net.sf.json.JSONObject:1120 (null)
2. java.lang.ClassCastException: JSON keys must be strings. (net.sf.json.JSONException)
net.sf.json.JSONObject:1160 (null)
3. java.lang.ClassCastException: JSON keys must be strings. (net.sf.json.JSONException). Message payload is of type: HashMap (org.mule.api.transformer.TransformerMessagingException)
and so it is unable to convert it into JSON..
So what is most viable option..??
I would recommend you to try gson it worked like a magic for me.
Collections Examples
Gson gson = new Gson();
Collection<Integer> ints = Lists.immutableList(1,2,3,4,5);
(Serialization)
String json = gson.toJson(ints); ==> json is [1,2,3,4,5]
(Deserialization)
Type collectionType = new TypeToken<Collection<Integer>>(){}.getType();
Collection<Integer> ints2 = gson.fromJson(json, collectionType);
ints2 is same as ints
Here is an example of how to write a custom serializer for JodaTime DateTime class.
private class DateTimeSerializer implements JsonSerializer<DateTime> {
public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.toString());
}
}
Have you looked at Gson?
http://sites.google.com/site/gson/gson-user-guide#TOC-Null-Object-Support
From http://www.ietf.org/rfc/rfc4627.txt
An object structure is represented as a pair of curly brackets surrounding zero or more name/value pairs (or members). A name is a string.
I would suggest to modify your initial Java structure to use String as key type.
However with Jackson library you can create fancier solutions:
Use a custom deserializer Deserializing non-string map keys with Jackson
Use a Tree Model instead of your own Java POJO http://wiki.fasterxml.com/JacksonInFiveMinutes

Categories

Resources