Constructing POJO out of JSON string with dynamic fields using Gson - java

I'm consuming a web service in my application that will return a list of ID's associated with a name. An example would look like this:
{
"6502": "News",
"6503": "Sports",
"6505": "Opinion",
"6501": "Arts",
"6506": "The Statement"
}
How would I construct a POJO for Gson to deserialize to when all of the fields are dynamic?

How about deserializing into a map?
Gson gson = new Gson();
Type mapType = new TypeToken<Map<String, String>>() {}.getType();
String json = "{'6502':'News','6503':'Sports','6505':'Opinion','6501':'Arts','6506':'The Statement'}";
Map<String, String> map = gson.fromJson(json, mapType);
Using a map sounds reasonable for me (as Java is statically typed). Even if this could work (maybe using JavaCompiler) - accessing the object would not probably be much different from accessing a map.

I don't know Gson that well but I suspect that's not possible. You'd have to know which fields are possible beforehand, although the fields might not be in the Json and thus be null.
You might be able to create classes at runtime by parsing the Json string, but I don't know whether that would be worth the hassle.
If everything is dynamic your best bet would be to deserialize the Json string to maps of strings or arrays etc. like other Json libraries do (I don't know whether Gson can do this as well, but the classes you need are commonly called JSONObject and JSONArray).
So your Json string above would then result in a Map<String, String>.

Related

Variable Names In JSON List Followed By Object Details

I've got a curious JSON to work with that I need to be able to map to a Java object. The environment I'm working in doesn't have access to Guava's Multimap (if that even is a solution), and I've considered being able to extend some sort of base class with a variable class name (if that is even possible), but I'm out of my depth on this one.
What sort of Java object allows lists of objects with unique, varying references to the same object class?
Here's a sample of the JSON I'm working with, I've confirmed it's a valid JSON via JSON formatter:
{
"apple1":{
"orchard":"green groves orchard",
"zipcode": 34567,
"speciesId": 12345,
"applePickedNumber": 6437896,
"knownProducts":{
"green grove apple butter":{
"productId":"ABC123456789",
"manufacturer":"red barn cannery",
"shipper":"hermes shipping"
}
}
},
"apple2":{
"orchard":"fair pastures orchard",
"zipcode": 34567,
"internalSpeciesId": 10001,
"speciesId": 23456,
"applePickedNumber": 145,
"knownProducts":{}
}
}
Thanks in advance for your help!
I think that the answer is probably Object[] and Map<String,Object>. But if you are going to map your JSON to types like that, then you should probably abandon the idea of mapping, and just use the JSONObject and JSONArray types.
Mappings only really work if the JSON conforms to a fixed "schema" with fixed attribute names. You can't map JSON to POJO classes if the attribute names keep changing.
Example when using Jackson. Define other attributes in Object class
ObjectMapper objectMapper = new ObjectMapper();
TypeReference<HashMap<String, Object>> typeRef
= new TypeReference<>() {
};
HashMap<String, Object> result = objectMapper.readValue(json, typeRef);

How to jsonify a object with new values?

I have some object with different atributes' types: String,Float,LocalDate and so on. To turn this object into a json String, I use (com.google.gson.Gson)
gson.toJson(object);
But now I want to add a String to it:
{
"warning" : "old",
--Jsonified Object--
}
How can I add specific key-values data into a object without doing boilerplate code or creating a new object that has a new attribute plus the old ones?
You can use com.google.gson.JsonObject class to add extra fields.
JsonObject jsonObject = (JsonObject)gson.toJsonTree(object, YourObjects.class);
jsonObject.addProperty("warning" , "old"); // add required extra fields
String json = gson.toJson(jsonObject); // create son string
The easiest way to do this without creating a new class or modify the current is to work with maps. Of course it still needs some boilerplate, but you can create a method where you do all this.
With Gson starting from the already generated json you can create a map, modify this map and then create the json again.
Gson gson = new Gson();
Map<String, Object> map = gson.fromJson(json, new TypeToken<Map<String, Object>>(){}.getType());
// here you process the map, e.g. put or remove keys
map.put("warning", "old");
String json = gson.toJson(myMap);
If you do not want to start from the created JSON I recomend to transform your object in a map with jackson object mapper and then process the map and create the json. You should use another library like jackson because Gson does not provice a way to transform a object to a map.

Convert Json to a java object

What is the way to generate a Java object with get and set methods?
You should write a java bean with properties maching the JSON key's, from that point since you already have a reader its a simple as
YourObject obj = gson.fromJson(br, YourObject.class);
UPDATE
With respect to your comment, when you don't want or can't create a bean it usually boils down to parsing JSON to map. GSON (afaik) doesn't have a built-in for this, but its not hard to build a method that will traverse GSON's objects. You have an example in this blog
http://itsmyviewofthings.blogspot.it/2013/04/jsonconverter-code-that-converts-json.html
As you seem to be open to alternatives, take a look at Jackson as well (the two libs are the de-facto standard in JAVA).
With jackson you don't have to create a bean to support deserialization, e.g.
String json = "{\"id\":\"masterslave\"}";
Map<String,String> map = new HashMap<String,String>();
ObjectMapper mapper = new ObjectMapper();
//convert JSON string to Map
map = mapper.readValue(json,
new TypeReference<HashMap<String,String>>(){});
http://www.jsonschema2pojo.org/
That link helps generate the Java object format based on the GSON you feed in. Just make sure you set the settings exactly as you need it. As always, it's not a good idea to just copy-paste generated code, but it might be of help.

Serialization and Deserialization of generic Map for Java and external use

I have a Map<String, Object> which I am using as a mapping for a JSON document, however want to create and maintain Java type information at the same time as retaining the structure of the document.
I'm attempting to use Jackson to create the document and it seems to work fine but I'm seeing something strange when attempting to deserialize it. A very simple serialization example:
final ObjectMapper mapper = new ObjectMapper().enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE, JsonTypeInfo.As.EXTERNAL_PROPERTY);
final Map<String, Object> map = Maps.newHashMap();
map.put("test", new Date());
final String ser = mapper.writeValueAsString(map);
final Map<String, Object> deser = mapper.readValue(ser, new TypeReference<HashMap<String, Object>>(){});
System.err.println(deser.get("test").getClass());
Gives the serialized form {"test":1410721662084,"#class":"java.util.Date"} which seems fine but when deserializing returns the type of "test" to be Long.
If I change the type serialization to use WRAPPER_ARRAY rather than EXTERNAL_PROPERTY then the type of "test" is correctly returned as Date, but doing this alters the structure of the JSON document so is not something I'm allowed to do. How do I retain the structure of the document as well as allow deserialization back to the correct types?
This is against Jackson 2.4.2.
Deserialization with maps is always tricky as maps don't preserve type information, which makes Jackson resort to #class and that not something you usually want. Instead, you can create a simple class:
public class TestClass {
private Date test;
//getters and setters omitted
}
This class has concrete structure and JSON will serialize it as
{ "test" : 1410721662084}
which is much cleaner and type-safe representation of your object. Then you just need to pass TestClass.class to readValue() method and your test attribute will be magically converted to proper type (Date)

How do I serialize a JSON object?

I have the following JSON string.
{"portfolio":"HEXGENFUND","transSrlNo":"1","transCode":"BUY","investReason":"009","inflowOutflow":"I","transDate":"2012-09-01","tradeDate":"2012-09-01","tradeDateUpto":"2012-09-01","tradeTime":"15:46:36","investCategory":"FVTPL","custodian":"DEUTSCHE","holdType":"HOLD","securityType":"INV","security":"9.45SBAI160326","assetClass":"NCD","issuer":"SBAI","marketType":"LIM","tradePriceType":"R","requisitionType":"MS","priceFrom":"343490934332","priceTo":"343490934332","marketPrice":"343490934332","averagePrice":"343490934332","price":"343490934332","quantity":"234","grossAmtTcy":"80376878633688","exchRate":"1","grossAmtPcy":80376878633688,"grossIntTcy":"992.42","grossIntPcy":992.42,"netAmountTcy":80376878634680.42,"netAmountPcy":80376878634680.42,"acquCostTcy":80376878633688,"acquCostPcy":80376878633688,"yieldType":"N","purchaseYield":"0","marketYield":"0","ytm":"-80.07453968","mduration":"0","currPerNav":"0","desiredPerNav":"0","currHolding":"0","noofDays":"0","realGlPcy":0,"realGlTcy":"0","nowLater":"N","isAllocable":"false","acquCostReval":0,"acquCostHisTcy":80376878633688,"acquCostHisPcy":0,"exIntTcy":0,"exIntPcy":0,"accrIntReval":0,"accrIntTcy":0,"accrIntPcy":0,"grossAodTcy":0,"grossAodPcy":0,"grossAodReval":0,"bankAccAmtAcy":80376878634680.42,"bankAccAmtPcy":80376878634680.42,"taxAmountTcy":0,"unrelAmortTcy":0,"unrelAmortPcy":0,"unrelGlTcy":0,"unrelGlPcy":0,"realGlHisTcy":0,"realGlHisPcy":0,"tradeFeesTcy":0,"tradeFeesPcy":0}
I have a POJO for the above.
How do I deserialize this to a Object?
You can use gson library like this to convert above JSON string to HashMap:
Gson gson = new Gson(); // get a new Gson instance
// define a Type for Map<String, String>
Type type = new TypeToken<Map<String, String>>(){}.getType();
// convert JSON string to a Map<String, String> instance
Map<String, String> map = gson.fromJson(jsonStr, type);
EDIT (Based your Edited question): For converting JSON to your POJO object
You can convert JSON string to your custom POJO using gson like this:
// assuming your POJO is of type MyClass
MyClass instance = gson.fromJson(jsonStr, MyClass.class);
If you want to generate the matching java class for the above json string, going with a json generator would be the best solution since the data has many fields.
You may check http://www.jsonschema2pojo.org/
Just paste your json, select JSON as source type and you will have a Jackson compatible annotated java class.
Thake a look at this library tutorial: jackson
String myJson = new org.codehaus.jackson.map.ObjectMapper.writeValueAsString(myObject);
There are some JSON libraries that may helps you.
For example, Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object
You can create JSON object by using libraries like gson or JsonOrg. You can take a lokk at the following links for libraries and implementations
https://sites.google.com/site/gson/gson-user-guide
http://code.google.com/p/google-gson/
http://json.org/java/

Categories