Create JSON object in Java8 using com.google.code.gson - java

I am trying to create a JSON Object using com.google.code.jso in JAVA 8. I have a list of objects and i am iterating through them. The object is as:
public class MyObject {
private String name, status, cause, id;
public String getName() {
return name;
}
public String getStatus() {
return status;
}
public String getCause() {
return cause;
}
public String getId() {
return id;
}
}
I have a list of above objects and i am trying to convert them to JSON using the below (the relevant code):
import com.google.gson.JsonObject;
JsonObject status = new JsonObject();
for (MyObject obj : objectLists){
status.add(obj.getId(),
new JsonObject()
.add("Name: ", obj.getName())
.add("Status: ", obj.getStatus())
.add("Cause: ", obj.getCause())
);
}
I was hoping to get a JSON of the following form:
{
"0 (this is the id i get from myObject.getId())": {
"name": The name i get from myObject.getName(),
"Status": The status from myobject.getStatus(),
"cause": The status from myobject.getCause()
},
"1": {
"name": "myname",
"Status": "mystatus",
"cause": "cause"
}
}
So I have 2 question.
I am getting an error in creating the Json object. Wrong 2nd
argument type. Found: 'java.lang.String', required:
'com.google.gson.JsonElement' I understand that i have to change
the second parameter but i could not find in the docs how to do
that.
How can i pretty print this.
Thanks

You used wrong method:
JsonObject.addProperty(), not JsonObject.add()
JsonObject.add(String, JsonElement) - adds nested json element to your object:
{
"root": {
"nested": {}
}
}
JsonObject.addProperty(String, String) - adds property to your object (it may be any primitive or String):
{
"root": {
"property": "some string"
}
}

Why not using this instead.
Gson.toJson(obj);

You should wrap your strings in JsonPrimitive objects, for example:
new JsonObject().add("Name: ", new JsonPrimitive(obj.getName()));
To enable pretty printing, you have to use GsonBuilder.setPrettyPrinting():
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println(gson.toJson(obj));

Related

What's the best way to handle JSON API responses using GSON?

I'm working on a project that communicates with an API using JSON. This is my first attempt at JSON and I've been away from java for a few/several years, so please bear with me.
Here is an idea of what the data looks like:
String 1:
[{
"apicall1":
[{
"thisField":"thisFieldData",
"thatField":"thatFieldData",
"anotherField":"anotherFieldData"
}]
}]
String 2:
[{
"apicall2":
[{
"thatField":"thatFieldData",
"someFieldsAreTheSame":"someFieldsAreTheSameData",
"otherFieldsAreNotTheSame":"otherFieldsAreNotTheSame"
}]
}]
As you can see from my data example, the API returns a JSON string that contains the api used. The array inside contains the data. The API's have a lot of data fields in common but they are unrelated beyond that.
EDIT: There are dozens of these API's types that will need to be handled.
What I am trying to do is create a response class that accepts all of the JSON strings and returns an object containing the appropriate data.
For Example:
Gson gson = new Gson(); //Custom TypeAdapter goes here if needed.
Response apicall2 = gson.fromJson(apicall2String, Response.class);
System.out.println(apicall2.thatField); //Prints thatFieldData
System.out.println(apicall2.someFieldsAreTheSame); //Prints someFieldsAreTheSameData
System.out.println(apicall2.otherFieldsAreNotTheSame); //Prints otherFieldsAreNotTheSameData
This is where I am lost. Here is what I have so far. I think I need to use a TypeAdapter here but haven't been able to figure how to apply that to my case.
public class Response { //Change to TypeAdapter possibly?
}
public class apicall1 {
String thisField;
String thatField;
String anotherField;
}
public class apicall2 {
String thatField;
String someFieldsAreTheSame;
String otherFieldsAreNotTheSame;
}
You can use Gson's TypeToken class to deserialize json into object. Below is an example:
JSON:
[{ "apicall1":
[{
"thisField":"thisFieldData",
"thatField":"thatFieldData",
"anotherField":"anotherFieldData"
}]
}]
Model:
class Response{
private List<Result> apicall1;
class Result{
private String thisField;
private String thatField;
private String anotherField;
public String getThisField() {
return thisField;
}
public void setThisField(String thisField) {
this.thisField = thisField;
}
public String getThatField() {
return thatField;
}
public void setThatField(String thatField) {
this.thatField = thatField;
}
public String getAnotherField() {
return anotherField;
}
public void setAnotherField(String anotherField) {
this.anotherField = anotherField;
}
}
public List<Result> getApicall1() {
return apicall1;
}
public void setApicall1(List<Result> apicall1) {
this.apicall1 = apicall1;
}
}
Converter:
public static void main(String[] args) {
String response = "[{ \"apicall1\": [{ \"thisField\":\"thisFieldData\", \"thatField\":\"thatFieldData\", \"anotherField\":\"anotherFieldData\" }]}]";
Gson gson = new Gson();
List<Response> responses = gson.fromJson(response, new TypeToken<List<Response>>(){}.getType());
System.out.println(responses.get(0).getApicall1().get(0).getThisField());
}
I don't know if you want both adapters in one class. Might not be the best OOP design.
To achieve it you would need to do something like so:
public class DoublyTypeAdapter implements JsonDeserializer<ApiCallTypeParent>
{
Gson gson = new Gson();
#Override
public ApiCallTypeParent deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext)
throws JsonParseException {
JsonObject json = jsonElement.getAsJsonObject();
ApiCallTypeParent desrializeIntoMe;
// Detect which type to implement
if(apiTypeOne(type) {
desrializeIntoMe = new TypeOne();
} else {
desrializeIntoMe = new TypeTwo();
}
for (Map.Entry<String, JsonElement> entry : json.entrySet())
{
switch(entry.getKey()){
case "thisField":
desrializeIntoMe.setThisField(entry.getValue().getAsString());
break;
......
default: // We don't care
break;
}
}
return desrializeIntoMe ;
}
}

retrofit gson converter for nested json with different objects

I've JSON structure like follows -
{
"status": true,
"message": "Registration Complete.",
"data": {
"user": {
"username": "user88",
"email": "user#domain.com",
"created_on": "1426171225",
"last_login": null,
"active": "1",
"first_name": "User",
"last_name": "",
"company": null,
"phone": null,
"sign_up_mode": "GOOGLE_PLUS"
}
}
}
Above format is common . Only data key can hold different types of information like user, product, invoice etc.
I want to keep status, message and data keys same in every rest response. data will be treated according to status and message will be displayed to user.
So basically, above format is desired in all apis. Only information inside data key will be different each time.
And I've setup a following class and set it up as gson converter - MyResponse.java
public class MyResponse<T> implements Serializable{
private boolean status ;
private String message ;
private T data;
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
Deserializer.java
class Deserializer<T> implements JsonDeserializer<T>{
#Override
public T deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException{
JsonElement content = je.getAsJsonObject();
// Deserialize it. You use a new instance of Gson to avoid infinite recursion to this deserializer
return new Gson().fromJson(content, type);
}
}
And used it as follows -
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
gsonBuilder.registerTypeAdapter(MyResponse.class, new Deserializer<MyResponse>());
...... ..... ....
restBuilder.setConverter(new GsonConverter(gsonBuilder.create()));
Service interface is as follows -
#POST("/register")
public void test1(#Body MeUser meUser, Callback<MyResponse<MeUser>> apiResponseCallback);
#POST("/other")
public void test2(Callback<MyResponse<Product>> apiResponseCallback);
Problem
I can access status and message fields from inside callback. But information inside data key is not parsed and model like MeUser and Product always returns as empty.
If I change json structure to following above code works perfectly -
{
"status": true,
"message": "Registration Complete.",
"data": {
"username": "user88",
"email": "user#domain.com",
"created_on": "1426171225",
"last_login": null,
"active": "1",
"first_name": "User",
"last_name": "",
"company": null,
"phone": null,
"sign_up_mode": "GOOGLE_PLUS"
}
}
How can I have it worked with specifying separate key inside data object and parse it successfully ?
If I can suggest to change something in json is that you have to add at one new field that defines the type of data, so json should look like below:
{
"status": true,
"message": "Registration Complete.",
"dataType" : "user",
"data": {
"username": "user88",
"email": "user#domain.com",
"created_on": "1426171225",
"last_login": null,
"active": "1",
"first_name": "User",
"last_name": "",
"company": null,
"phone": null,
"sign_up_mode": "GOOGLE_PLUS"
}
}
The MyResponse class has to have new filed DataType so it should look like below:
public class MyResponse<T> implements Serializable{
private boolean status ;
private String message ;
private DataType dataType ;
private T data;
public DataType getDataType() {
return dataType;
}
//... other getters and setters
}
The DataType is an enum which defines type of data. You have to pass Data.class as param in constructor. For all data types you have to create new classes. DataType enum should look like below:
public enum DataType {
#SerializedName("user")
USER(MeUser.class),
#SerializedName("product")
Product(Product.class),
//other types in the same way, the important think is that
//the SerializedName value should be the same as dataType value from json
;
Type type;
DataType(Type type) {
this.type = type;
}
public Type getType(){
return type;
}
}
The desarializator for Json should looks like below:
public class DeserializerJson implements JsonDeserializer<MyResponse> {
#Override
public MyResponse deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
throws JsonParseException {
JsonObject content = je.getAsJsonObject();
MyResponse message = new Gson().fromJson(je, type);
JsonElement data = content.get("data");
message.setData(new Gson().fromJson(data, message.getDataType().getType()));
return message;
}
}
And when you create RestAdapter, in the line where you register Deserializator, you should use this :
.registerTypeAdapter(MyResponse.class, new DeserializerJson())
Other classes (types of data) you define like standard POJO for Gson in separated classes.
Your issue is because the data attribute is defined as T which you expect to be of types MeUser, Product, etc, but is actually of an object which has inner attribute like user. To resolve this, you need to introduce another level of classes which has the required attributes user, product, invoice etc. This can be easily achieved using static inner classes.
public class MeUser{
private User user;
public static class User{
private String username;
//add other attributes of the User class
}
}
Might be a little bit off-topic, but what happens if the inner object contains a Date property? My TypeAdapter looks like this:
.registerTypeAdapter(Date.class, new DateDeserializer())
.registerTypeAdapter(GenericNotificationResponse.class, new NotificationDeserializer())
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss")
.create();
But due to the parsing which is done by this : message.setData(new Gson().fromJson(data, message.getDataType().getType()));
It will throw an error whenever it will try to deserialize the Date property. Is there a quick fix for this?
EDIT: Marked the answer as accepted, definitely :) it helped me fix my issue. But now there's this problem with the date deserializer.

Java Gson serialize json into an object

I have the following Item class:
public class Item {
public Object item;
}
I am inserting a JSON into this object using GSON.
tmp =
{
"_id": {
"$oid": "5076371389d22e8906000000"
},
"item": {
"values": [
{
"value1": [
4958,
3787,
344
],
"value2": [
4,
13,
23
]
}
],
"name": "item1"
}
}
Java bit:
Item item = new Item();
Gson g = new Gson();
it = g.fromJson(tmp.toString(), Item.class);
it.item becomes a StringMap type (http://code.google.com/p/google-gson/source/browse/trunk/gson/src/main/java/com/google/gson/internal/StringMap.java?r=1131)
I now need to access the sub-objects within this object.
I can use the overridden toString function this type has which prints all objects within this object. But how would I be able to navigate through it?
P.S. The reason I put everything into an object datatype not a structured class is that the JSON structure varies each time, so I can't really have a class schema.
Any suggestions?
You should create an object structure that reflects the JSON instead (since this is what you're trying to do anyway). For your example, you could use this:
public class MyObject {
private Item item;
private String _id;
// getters, setters, etc.
}
public class Item {
private List<Value> values;
private String name;
// getters, setters, etc.
}
public class Value {
private List<Integer> values1;
private List<Integer> values2;
// getters, setters, etc.
}
Then pass MyObject.class to Gson:
MyObject myObj = g.fromJson(tmp.toString(), MyObject.class);
You can get the lists in values like so:
List<Integer> values1 = myObj.getItem().getValues().get(0).getValues1();
List<Integer> values2 = myObj.getItem().getValues().get(0).getValues2();
Try that and see if it works.
Also, you should check out my answer to a similar question here, specifically the part at the end about how to write an object structure for Gson based on some JSON object.
You can always create a constructor for the custom object that uses reflection and takes the StringMap
public MyObject(StringMap sm){
Iterator it = sm.entrySet().iterator();
while(it.hasNext()){
Entry pairs = (Entry)it.next();
Class<?> c = this.getClass();
try {
Field value = c.getDeclaredField((String) pairs.getKey());
value.set(this, pairs.getValue());
} catch (Exception e) {
e.printStackTrace();
}
}
}

Gson json getting the result

I have a json string like this:
{
"d": {
"results": [
{
"__metadata": {
"uri": "http://localhost:2000",
"key_fields": "Accountnum",
"rows_affected": 0,
"last_autoinc": 0
},
"Accountnum": "9999999",
"workphone": null,
"name": "Smith",
"address": "33 Main St",
"city": "Anytown",
"state": "FL",
"zip": "33333",
}
]
}
}
and I tried to deserialize it according to diffrent questions here on stackoverflow, but I can't get it right.
Here is what I did I created a class, I only need the accountnum and name.
public class Result {
#SerializedName("Accountnum")
public String accountnumStr;
#SerializedName("name")
public String nameStr;
}
I have a string with the json myresult.
Gson gson = new Gson();
Result result = gson.fromJson(myresult,Result.class);
myName.setText(result.nameStr);
I receive an empty string.
Thanks
Since there is a object holding the result object your trying to create, you have make the result class an inner class. You're Result class would have to look like this:
public class ResultParent {
public class Result {
#SerializedName("Accountnum")
public String accountnumStr;
#SerializedName("name")
public String nameStr;
}
}
If you visualize your JSON in terms of class objects then it will be no problem at all. Imagine that your root object contains a property named "d" of type "D". And type "D" contains a list of "results" of another type "Result". The result contains its properties as above. Here's the picture of it:
class RootObj {
D d;
}
class D {
List<Result> results;
}
class Result {
#SerializedName("Accountnum")
public String accountnumStr;
#SerializedName("name")
public String nameStr;
}
To get the objects from a JSON, you would do the following:
Gson g = new Gson();
RootObj ro = g.fromJson(jsonString, RootObj.class);

Help me to parse this kind of json for android

I have this type of json from api:
[
{
"id": "12",
"name": "elo2",
"status": "ok",
"vulumes": [
{
"id": 17592,
"name": "vol1",
"status": "ok"
}
]
},
{
"id": "13",
"name": "elo",
"status": "ok",
"vulumes": [
{
"id": "17596",
"name": "vol2",
"status": "ok"
}
]
}
]
ID 12 and 13 its shelf, volumes is a part of shelf with id 17592 and 17596
I cannot to parse it with json, i trying to use gson or json, but i can't understand how to get sime block, for e.g. block with id 12 for parse info about shelf and existing volumes at this shelf.
Can you help me? In other apis i can see named objects vith k/v, but there is nothing.
With Gson, here's one simple approach you could take. This demonstrates a Java data structure that matches the JSON example, along with how to deserialize and serialize it using Gson.
public class Foo
{
public static void main(String[] args) throws Exception
{
Gson gson = new Gson();
Type thingsType = new TypeToken<List<Thing>>() {}.getType();
List<Thing> things = gson.fromJson(new FileReader("input.json"), thingsType);
System.out.println(gson.toJson(things));
}
}
class Thing
{
String id;
String name;
String status;
List<Vulume> vulumes;
}
class Vulume
{
String id;
String name;
String status;
}
Since the attributes of the two object types are almost identical, then maybe the intention was that there be only one object type, with a reference to a collection of objects of the same type. Here's what that would look like.
public class Foo
{
public static void main(String[] args) throws Exception
{
Gson gson = new Gson();
Type thingsType = new TypeToken<List<Vulume>>() {}.getType();
List<Vulume> things = gson.fromJson(new FileReader("input.json"), thingsType);
System.out.println(gson.toJson(things));
}
}
class Vulume
{
String id;
String name;
String status;
List<Vulume> vulumes;
}

Categories