Mapping JSON to Java Class using Jackson - java

I have a scenario where at run time depending upon the JSON values I have to convert them to choose which JAVA classes we have to use to initialize them.
Below are the two JSON examples
JSON Example1:
{
"parentVal1" : "parent Val 1",
"parentVal2" : "parent val 2",
"childVal1" : "child Val 1",
"childVal2" : {
"childPropVal1" : "child prop 1",
"grandChild" : {
"maleGrandChildVal1" : "male grand child 1",
"maleGrandChildVal2" : "male grand child 2"
}
}
}
JSON Example2:
{
"parentVal1" : "parent Val 1",
"parentVal2" : "parent val 2",
"childVal1" : "child Val 1",
"childVal2" : {
"childPropVal1" : "child prop 1",
"grandChild" : {
"femaleGrandChildVal1" : "female grand child 1",
"femaleGrandChildVal2" : "female grand child 2"
}
}
}
Now, corresponding JAVA classes which I made and class diagram are
public class Parent{
private String parentVal1;
private String parentVal2;
//getters and setters
}
public class Child extends{
private String childVal1;
private ChildProperty childVal2;
//getters and setters
}
public class ChildProperty{
private String childPropVal1;
private GrandChildAbstract grandChild;
//getters and setters
}
public class GrandChildAbstract{
}
public class MaleGrandChild extends GrandChildAbstract{
private String maleGrandChildVal1;
private String maleGrandChildVal2;
//setters and getters
}
public class FemaleGrandChild extends GrandChildAbstract{
private String femaleGrandChildVal1;
private String femaleGrandChildVal2;
//setters and getters
}
The problem is on the runtime I will get a JSON and have to decide whether it belongs to MaleGrandChild or FemaleGrandChild depending upon the ChildProperty.childPropVal1 that I get from JSON.
Can anyone help me are there any way which could initialize the ChildProperty.grandChild property with the respective FemaleGrandChild or MaleGrandChild object.
I am using Jackson for conversion from JSON to JAVA.

Did you read about polymorphic deserialization with Jackson? http://wiki.fasterxml.com/JacksonPolymorphicDeserialization.
Usually you provide the type using JsonTypeInfo. That allows Jackson to understand how to map a specific object.
If you can't really do any manipulation on the JSON (if not sourced by you, for example), you can write a custom mapper (not straightforward) or you can those properties to a simple Map, and let another part of your application deal with the type.

Related

Gson - deserialize unknown classes

Lets say I have a group of classes A,B,C:
public class A:
int number;
public class B:
int number;
String address;
public class C:
int orderNumber;
How can i deserialize a Json string which contains only these classes, but in an unknown order (using Gson, in Java)? For example:
{//A
"number" : 3
}
//C
{
"orderNumber": 10
}
//B
{
"number" : 5
"address" : "New York"
}
//C
{
"orderNumber": 1
}
Thank you very much!
Answer by pirho is clean and easy if, like he said, your classes are simple as you've provided. But if that isn't the case, you can write your own deserializer.
public class PayloadJsonDeserializer implements JsonDeserializer {
#Override
public Object deserialize(JsonElement elm, Type type, JsonDeserializationContext context) throws JsonParseException {
// create java objects based on the properties in the json object
JsonPrimitive orderNumber = elm.getAsJsonObject().getAsJsonPrimitive("orderNumber");
if(!orderNumber.isJsonNull()) {
return new C(orderNumber.getAsInt());
}
return null;
}
}
Register your custom deserializer with Gson.
GsonBuilder gsonBuilder = new GsonBuilder()
.registerTypeAdapter(PayloadJson.class, new PayloadJsonDeserializer());
Gson gson = gsonBuilder.create();
Use it to deserialize your json.
gson.fromJson(jsonString, PayloadJson[].class);
This is not a generic or anyway a great strategy to do this in general if you have more complex classes with more fields.
But if the classes you want to deserialize are as simple as you provide as an example then create a class having all these fields
#Getter
public class Z {
private Integer orderNumber;
private Integer number;
private String address;
}
You will get a list of Zs and depending on which of the field are null or not null you can -if needed - later construct A, B or C from Z.
If classes to deserialize are more complex you anyway need to create some kind of a mechanism that determines what is the class to parse and to return. It could be like user1516873 suggested in the comment
Collection<Map<String,String>>
so for each item you would need to determine by what fields are present in that map to what class - A,B or C - item would be constructed.

json jackson inner collection deserialize as LinkedHashMap instead of MyObject

I have the following object structure, on which I can't do any modification (this is a library and I don't have sources) :
class Foo {
List bars; // with no generics (but this is a List<Bar>)
Baz baz;
}
class Bar {
Fiz fiz;
Buz buz;
}
class Baz {
int toto;
}
class Fiz {
String titi;
}
class Buz {
String tata;
}
And the following json :
{
"bars" : [
{
"fiz" : {
"titi" : "Hello"
},
"buz" : {
"tata" : "World"
}
},
{
"fiz" : {
"titi" : "Hola"
},
"buz" : {
"tata" : "El Mundo"
}
}
],
"baz" : {
"toto" : 42
}
}
I try to deserialize the json with the following code :
ObjectMapper mapper = new ObjectMapper();
// ... use the visibilityChecker because objects are immutable (no setter)
mapper.readValue(json, Foo.class);
I retrieve a List of LinkedHashMap instead of a List of Bar. I've check all others posts on the subject on stackoverflow, but each time, the list is at the top level so it is quite easy. I tried to use mixin without success, i tried with enableDefaultTyping but i got an error...
How can i do this ? I repeat I cannot modify the class files, add annotations, add intermediary objects, ... everything is in a library.
EDIT 21/12/2016 :
I tried with Mixin :
abstract class FooMixin {
#JsonProperty("bars")
#JsonDeserialize(contentAs = Bar.class)
List bars;
}
abstract class BarMixin {
#JsonProperty("fiz") Fiz fiz;
#JsonProperty("buz") Buz buz;
}
mapper.addMixin(Foo.class, FooMixin.class);
mapper.addMixin(Bar.class, BarMixin.class);
But got the same result (LinkedHashMap)...
Even if you don't control library code, you can still use mix-in annotations:
http://www.cowtowncoder.com/blog/archives/2009/08/entry_305.html
which is the way to go. One possibility here is to "mix in":
#JsonDeserialize(contentAs=Bar.class)
to augment type information; this needs to be before List-valued field or setter-method used to assign it.

How can I create a JSON object given a schema and object

I have an object that I'd like to generate a JSON object for.
Currently I have an object that is wrapped by another object, a ResourceObject.
This resource object only has a subset of the exposed variables on the top level object.
I use this resource object to generate the json by annotating it. This is to keep the original object cleaner as it's used in other places in the code. However, maintaining this filtering code increases complexity and is mostly boilerplate code.
Ideally, I'd like to pass the object and the expected schema to do the filtering for me, but I don't see anything like that available. I'm hoping my search criteria is just not correct.
Example Class1
Class1 {
private String name = "C1";
private String version = "1.0";
public String getName() {
return name;
}
public String getVersion() {
return version;
}
}
Example Resource class
ResourceClass1 {
private Class1 class1;
ResourceClass1 (Class1 c1) {
class1 = c1;
}
public String getName() {
return class1.getName();
}
}
Example Schema
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Class1",
"type" : "object",
"properties" : {
"name" : {
"type" : "string"
},
}
}
Right now, getting the JSON from the Resource class gives me something to the affect of:
{
"properties" : {
"name" : "C1"
},
}
Is there a package which would get me the same json by passing in only the schema and java object?

Using Gson to parse Json array and object with no name

I know there are many JSON with GSON questions but none of them relate to me directly. My JSON is formatted differently.
I have a JSON data I want to parse using GSON which looks like the following:
[
{
"foo":"1",
"bar":[ { "_id":"bar1"} ],
"too":["mall", "park"]
}
]
And I have the model Classes:
ItemArray Class
public class ItemArray
{
List<Item> itemArray;
//Get set here
}
Item Class
public class Item
{
String foo;
List<Bar> bar;
List<String> too;
//Get set here
}
Bar Class
public class Bar
{
String id;
//Get set here
}
Heres the question. Is the JSON in the correct format? If so, are the model classes in the correct format?
If not, please shove me in the right direction. Thank you in advance!
PS. I can modify the JSON data format if need be.
According to your json, you should simply have :
public class ItemArray extends List<Item> {
}
if you want to keep you java class and change your json it should be :
{
itemArray: [
{
"foo":"1",
"bar":[ { "_id":"bar1"} ],
"too":["mall", "park"]
}
]
}
Oh, and there is a mismatch with the id and _id for Bar :
public class Bar
{
String _id;
//Get set here
}
You could also use an annotation to change the field's name during Json de/serialization.
And last but not least, consider typing your values better. Don't see any data as strings if they are not, you will not a lot of processing in java code to convert things. For instance :
"foo" : 1,
and see foo as an int data member, not a String.
Some times we get JsonArray [ {..} , {..} ] as a response (without 'itemArray' name like yours)
In that case you can use following code
Type fooType = new TypeToken<ArrayList<Item>>() {}.getType();
List<Item> array = new Gson().fromJson(response, fooType);
find more about this Official doc - Gson Array-Examples
If you have a JsonArray like [ {..} , {..} ] you can do this with Gson:
Item[] items = gson.fromJson(json, Item[].class);
To check Json is valid use this tool http://jsonlint.com/
Class Bar(
private String _id;
//create getter/setters
{
public class Item
{
String foo;
List<Bar> bar;
List<String> too;
//Get set here
}
//this is also fine
public class ItemList
{
List<Item> itemArray;
//Get set here
}
you named of list of items "itemArray", but in your json you have not named the corresponding array of items "itemArray".
So make it itemArray, The problem is not in your json, it is valid. Problem is in its representation for Gson,
Gson map keys of json on the variables of object (i.e Java POJO) with same name.
If the name of your list is Class is
List<Item> itemArray;
then the corresponding json array name should also be itemArray, take a look blow
{
itemArray: [
{
"foo":"1",
"bar":[ { "_id":"bar1"} ],
"too":["mall", "park"]
}
]
}
so you can convert json into object like that
Reader reader = new InputStreamReader(IOUtils.toInputStream(json_string));
ItemList itemList = json.toObject(reader, ItemList.class);
Take a look into blow reference for more details
https://stackoverflow.com/questions/13625206/how-to-parse-the-result-in-java/13625567#13625567

Deserializing JSON strings using GSON in Android

This might be a bit long so please bear with me..
I'm working on a project in Android. I have a JSON string that i need to deserialize into objects representing the JSON structure, the JSON string is something like below:
{"parents":[
{"parent":{
"id":1,
"name":"Sam",
"childs":[
{
"child":{
"id":1,
"name":"Alice",
"books":[
{
"book":{
"id":1,
"name":"Alice in Wonderland"
}
}
]
}
}
]
}
}
]}
Note that for arrays there are repeating values (i.e. many parent and many child) i just put one line here to make it short.
With this i created classes to accomodate the structure:
public class Containers{
private List<Parent> parents;
//setter and getter..
}
public static class Parent extends CommonItem {
private List<Child> childs;
//setter and getter..
}
public static class Child extends CommonItem {
private List<Book> books;
//setter and getter..
}
public class CommonItem{
private int id;
private String name;
//setter and getter
}
Note that i'd created a common class to accommodate the repeating attributes.
Below is how i parse them using GSON:
Gson gson = new Gson();
Containers parents = gson.fromJson(jsonString, Containers.class);
After parsing (there're no error) i try to retrieve the objects. The number of object count in the parents list is correct (i.e. there are 5 parents in the JSON string, and there are 5 Parent objects in the parents List). However, all their attributes are not there, and the child tree are missing as well.
I'd tried numerous configuration, including remove the extended class and put all the id and name in the respective classes but the result is still the same.
Anyone can give me any pointer that where did i go wrong?
Thanx a bunch!
Your JSON and Java class mismatch.
Lets read
{"parents":[
{"parent":{
"id":1,
"name":"Sam",
"childs":[
{
"child":{
"id":1,
"name":"Alice",
"books":[
{
"book":{
"id":1,
"name":"Alice in Wonderland"
}
}
]
}
}
]
}
}
]}
Your top object has a List of class that has parents as it's attribute. Your Java class Container has parents attribute. Good.
Now this list parents is a List of objects that has parent attribute. Does your Parent object has parent attribute? No.
Go further down, each Parent has id, name, and a List of objects as childs (children, should be) attribute that has child attribute, does your Child class has it? No.
Similarly, goes for books.
Did you try your classes on JSON like
{"parents":[
{
"id":1,
"name":"Sam",
"childs":[
{
"id":1,
"name":"Alice",
"books":[
{
"id":1,
"name":"Alice in Wonderland"
}
]
}
]
}
]}

Categories

Resources