Custom Conversion from Java Object to JSON Object - java

I have the following code
Gson gson = new Gson();
String json = gson.toJson(criteria.list()); // list is passed by Hibernate
The result would be something like this:
{creationTime:0, enabled:true, id:1, loginDuration:0, online:false, userName:someone}
I would like to add new attribute (DT_RowId which has the same value as id) within the JSON response. The end result should be like this:
{creationTime:0, enabled:true, id:1, loginDuration:0, online:false, userName:someone, DT_RowId=1}
UPDATED
I created a field with #Transient annotation on the entity in order to solve this issue.
...
#Transient
private long DT_RowId;
public void setId(long id) {
this.id = id;
this.DT_RowId=id;
}
...
However the setId function was never been called. Can someone enlighten me on this ?

GSON won't call your getters and setters. It accesses member vars directly via reflection. To accomplish what you are trying to do, you will need to use a GSON custom serializer/deserializer. The GSON docs on custom serializers/deserializers provide some examples for how to do this.
Here is a working example with a passing JUnit test that demonstrates how to do it:
Entity.java
public class Entity {
protected long creationTime;
protected boolean enabled;
protected long id;
protected long loginDuration;
protected boolean online;
protected String userName;
protected long DT_RowId;
}
EntityJsonSerializer.java
import java.lang.reflect.Type;
import com.google.gson.*;
public class EntityJsonSerializer implements JsonSerializer<Entity> {
#Override
public JsonElement serialize(Entity entity, Type typeOfSrc, JsonSerializationContext context) {
entity.DT_RowId = entity.id;
Gson gson = new Gson();
return gson.toJsonTree(entity);
}
}
JSONTest.java
import static org.junit.Assert.*;
import org.junit.Test;
import com.google.gson.*;
public class JSONTest {
#Test
public final void testSerializeWithDTRowId() {
Entity entity = new Entity();
entity.creationTime = 0;
entity.enabled = true;
entity.id = 1;
entity.loginDuration = 0;
entity.online = false;
entity.userName = "someone";
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Entity.class, new EntityJsonSerializer());
Gson gson = builder.create();
String json = gson.toJson(entity);
String expectedJson = "{\"creationTime\":0,\"enabled\":true,\"id\":1,\"loginDuration\":0,\"online\":false,\"userName\":\"someone\",\"DT_RowId\":1}";
assertEquals(expectedJson, json);
}
}

Related

Gson - Nested Object inside a CustomObject - java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to java.util.List

I googled and saw many question and answers but none of it are helping me. Here is the issue. I have a Class
public class ResponseData {
public static transient final int SUCCESS = 1;
public static transient final int FAILED = 0;
public String id;
public int status;
public Object data;
// Constructor, Getters and Setters
}
I'm using ResponseData as the common return object for my server and the server has many APIs. In one of the API, it is setting the data parameter to ArrayList. Then converting as json using Gson (2.8.0).
And then sending back to caller. (It's not HTTP)
public class MyServerClass {
private final Gson gson;
public MyServerClass() {
GsonBuilder builder = new GsonBuilder();
gson = builder.serializeNulls().create();
}
public String someAPI() {
ResponseData responseData = new Response("myid", ResponseData.SUCCESS, Arrays.asList("Some string value", ArrayList<MyCustomObject>, "Some other Value"));
String json = gson.toJson(response)
}
}
And the MyCustomClass is a plain POJO class with some set of attributes.
public class MyCustomClass {
private String name;
private String id;
private String createdTime;
//Constructor, Getters & Setters
}
At the receiving side I have below code.
private Gson gson = null;
GsonBuilder builder = new GsonBuilder();
gson = builder.create();
///
ResponseData response = gson.fromJson(eventData, ResponseData.class);
ArrayList list = (ArrayList) respone.getData();
String val = (String) list.get(0);
List rwData = (List) list.get(1);
for(List<List<String>> entry: rwData) { // Exception is thrown Here. How to get it as List?
//Coverting Data
}
Exception is thrown when trying to get the data as List<List<String>>. How to convert the json string properly here? I cannot use the MyCustomClass at my client layer. That's why trying list
Exception occured:com.google.gson.internal.LinkedTreeMap cannot be cast to java.util.List
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to java.util.List

#jsonIgnore annotation is not working

I am using #JsonIgnore property to ignore some attributes in pojo, but these fields are not ignore in json response after parsing json using Gson library please help.
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
#JsonIgnoreProperties(ignoreUnknown=true)
public class RideInvite extends RideInviteOld implements Serializable
{
private static final long serialVersionUID = -3729010679180341959L;
private double newFare = -1;
#JsonIgnore
private long prefPickupDropId;
#JsonIgnore
private String pickupLandmark;
#JsonIgnore
private String dropLandmark;
}
using following code to parse
GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();
jsonText = gson.toJson(msgObject);
Response after parsing
{"newFare":-1.0,"prefPickupDropId":2,"savePickupDropPoints":false,"pickupDropBasedOnTraffic":true,"allowFareChange":true}
here prefPickupDropId and savePickupDropPoints are json ignored but still value attribute is present in json text
I can not use #Expose for fields because my project is build in such away that ignoring fields which are not required json ignore and same pojos are using for preparing http response. This was working fine earlier but recently I am facing this issue
thanks in advance
Approach1:
Instead of using com.fasterxml.jackson.annotation.JsonIgnore you should use
com.google.gson.annotations.Expose to achieve your requirement.
Here is working code snippet -
import java.io.Serializable;
import com.google.gson.annotations.Expose;
public class RideRecord implements Serializable {
#Expose
private double newFare = -1;
private long prefPickupDropId;
private String pickupLandmark;
private String dropLandmark;
public RideRecord(double newFare, long prefPickupDropId, String pickupLandmark, String dropLandmark) {
super();
this.newFare = newFare;
this.prefPickupDropId = prefPickupDropId;
this.pickupLandmark = pickupLandmark;
this.dropLandmark = dropLandmark;
}
}
use the following code to parse:
RideRecord msgObject = new RideRecord(-1.0, 2, "sfo", "powell bart station");
GsonBuilder builder = new GsonBuilder();
builder.excludeFieldsWithoutExposeAnnotation();
Gson gson = builder.create();
String jsonText = gson.toJson(msgObject);
System.out.println(jsonText);
It will give output:
{"newFare":-1.0}
because only newFare is the field which is exposed.
you can play with the #Expose attribute to meet your requirements.
Approach2:
If you don't want to use #Expose then also you can achieve your
requirement by just creating Gson object as below -
RideRecord msgObject = new RideRecord(-1.0, 2, "sfo", "powell bart station");
GsonBuilder builder = new GsonBuilder();
builder.addSerializationExclusionStrategy(new ExclusionStrategy() {
#Override
public boolean shouldSkipField(FieldAttributes fieldAttributes) {
return fieldAttributes.getName().equals("prefPickupDropId") || fieldAttributes.getName().equals("pickupLandmark") || fieldAttributes.getName().equals("dropLandmark");
}
#Override
public boolean shouldSkipClass(Class<?> arg0) {
// TODO Auto-generated method stub
return false;
}
});
Gson gson = builder.create();
String jsonText = gson.toJson(msgObject);
System.out.println(jsonText);
In this case also you will get the same output :
{"newFare":-1.0}
You're using Jackson with GSON and those are too separate frameworks.
One of the approaches is to initialize Gson to exclude fields that do not have the expose annotation.
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
Then mark every field you need to use with the #Expose annotation:
ex:
class MyClass {
#Expose public String name;
}

Serialization error using Gson

I am using the following code for serialization:
public class JsonTransformer implements ResponseTransformer {
private Gson gson = new Gson();
#Override
public String render(Object model) {
GsonBuilder gsonBuilder = new GsonBuilder();
return gson.toJson(model);
}
}
I get error:
java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: com.soul.seeker.models.Post. Forgot to register a type adapter?
How do I serialize a list a return it in the below code?
get("/data_on_page_load", "application/json", (Request request, Response response) -> {
List<Post> list = Post.findAll();
return list;
}, new JsonTransformer());
pojo class:
public class Post extends Model{
private String title;
private String details;
private String username;
private String userImage;
private String url;
private List categories;
//Getters and Setters removed for brevity
}
update:
When I tried to use it the below way:
public class JsonTransformer implements ResponseTransformer {
private Gson gson = new Gson();
#Override
public String render(Object model) {
GsonBuilder gsonBuilder = new GsonBuilder();
gson = gsonBuilder.registerTypeAdapterFactory(new ClassTypeAdapterFactory()).create();
return gson.toJson(model);
}
}
public class ClassTypeAdapterFactory implements TypeAdapterFactory {
#Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
if(!Class.class.isAssignableFrom(typeToken.getRawType())) {
return null;
}
return (TypeAdapter<T>) new ClassTypeAdapter();
}
}
it returns unnecessary information in json object when I pass it back to client side:
Array[2]
0:Object
attributes:Object
cachedChildren:Object
cachedParents:Object
compositeKeyPersisted:false
dirtyAttributeNames:Array[0]
errors:Object
frozen:false
manageTime:true
metaModelLocal:Object
modelRegistryLocal:Object
__proto__:
Object1:Object
length:2
__proto__:Array[0]
It makes sense that ClassTypeAdapter is where I have modify the code to return proper list object as json and exclude irrelevant information, but I am still new to serialization.

Gson json unable to get the result

Please i have a json response String like this:
{"result":{"id":21456,"name":"3mm nail","type":"2" }}
and this is my code:
class rootObj{
List<Result> result;
}
public class Result {
#SerializedName("id")
public String idItem;
#SerializedName("name")
public String name;
}
public static void main(String[] args) throws Exception {
Gson gson = new Gson();
Result result = gson.fromJson(json,Result.class);
System.out.println(result.name);
}
But the result is null :(
Thx in advance.
So.. This code is what i was aiming:
class ResultData{
private Result result;
public class Result {
private String id;
private String name;
}
}
...
Gson gson = new Gson();
ResultData resultData = new Gson().fromJson(json, ResultData.class);
System.out.println(resultData.result.id);
System.out.println(resultData.result.name);
Thx to BalusC gave me the idea about it.
Java - Gson parsing nested within nested
In your JSON string your result property is an Object not an Array. So to make it work with your two Java classes (rootObj and Result) you need to add [brackets] around your {braces}
Original
{"result":{"id":21456,"name":"3mm nail","type":"2" }}
New
{"result":[{"id":21456,"name":"3mm nail","type":"2" }]}
This code works for me:
import static org.junit.Assert.assertEquals;
import java.util.List;
import org.junit.Test;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
public class TestGson {
private static final String NAME = "3mm nail";
#Test
public void testList() {
final String json = "{\"result\":[{\"id\":21456,\"name\":\"" + NAME + "\",\"type\":\"2\" }]}";
Gson gson = new Gson();
ListWrapper wrapper = gson.fromJson(json, ListWrapper.class);
assertEquals(NAME, wrapper.result.get(0).name);
}
static class ListWrapper {
List<Result> result;
}
static class ObjectWrapper {
Result result;
}
static class Result {
#SerializedName("id")
public int idItem;
#SerializedName("name")
public String name;
}
}
refer this ..It explaining how to parse the json without using the GSON

How to expose a method using GSon?

Using Play Framework, I serialize my models via GSON. I specify which fields are exposed and which aren't.
This works great but I'd also like to #expose method too. Of course, this is too simple.
How can I do it ?
Thanks for your help !
public class Account extends Model {
#Expose
public String username;
#Expose
public String email;
public String password;
#Expose // Of course, this don't work
public String getEncodedPassword() {
// ...
}
}
The best solution I came with this problem was to make a dedicated serializer :
public class AccountSerializer implements JsonSerializer<Account> {
#Override
public JsonElement serialize(Account account, Type type, JsonSerializationContext context) {
JsonObject root = new JsonObject();
root.addProperty("id", account.id);
root.addProperty("email", account.email);
root.addProperty("encodedPassword", account.getEncodedPassword());
return root;
}
}
And to use it like this in my view:
GsonBuilder gson = new GsonBuilder();
gson.registerTypeAdapter(Account.class, new AccountSerializer());
Gson parser = gson.create();
renderJSON(parser.toJson(json));
But having #Expose working for a method would be great: it would avoid making a serializer just for showing methods!
Check out Gson on Fire: https://github.com/julman99/gson-fire
It's a library I made that extends Gson to handle cases like exposing method, results Post-serialization, Post-deserialization and many other things that I've needed over time with Gson.
This library is used in production in our company Contactive (http://goo.gl/yueXZ3), on both Android and the Java Backend
Gson's #Expose seem to only be supported on fields. There is an issue registered on this: #Expose should be used with methods.
Couple different options based on Cyril's answer:
Custom serializer with a shortcut:
public static class Sample
{
String firstName = "John";
String lastName = "Doe";
public String getFullName()
{
return firstName + " " + lastName;
}
}
public static class SampleSerializer implements JsonSerializer<Sample>
{
public JsonElement serialize(Sample src, Type typeOfSrc, JsonSerializationContext context)
{
JsonObject tree = (JsonObject)new Gson().toJsonTree(src);
tree.addProperty("fullName", src.getFullName());
return tree;
}
}
public static void main(String[] args) throws Exception
{
GsonBuilder gson = new GsonBuilder();
gson.registerTypeAdapter(Sample.class, new SampleSerializer());
Gson parser = gson.create();
System.out.println(parser.toJson(new Sample()));
}
-OR-
Annotation based serializer
public static class Sample
{
String firstName = "John";
String lastName = "Doe";
#ExposeMethod
public String getFullName()
{
return firstName + " " + lastName;
}
}
public static class MethodSerializer implements JsonSerializer<Object>
{
public JsonElement serialize(Object src, Type typeOfSrc, JsonSerializationContext context)
{
Gson gson = new Gson();
JsonObject tree = (JsonObject)gson.toJsonTree(src);
try
{
PropertyDescriptor[] properties = Introspector.getBeanInfo(src.getClass()).getPropertyDescriptors();
for (PropertyDescriptor property : properties)
{
if (property.getReadMethod().getAnnotation(ExposeMethod.class) != null)
{
Object result = property.getReadMethod().invoke(src, (Object[])null);
tree.add(property.getName(), gson.toJsonTree(result));
}
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
return tree;
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD) //can use in method only.
public static #interface ExposeMethod {}
public static void main(String[] args) throws Exception
{
GsonBuilder gson = new GsonBuilder();
gson.registerTypeAdapter(Sample.class, new MethodSerializer());
Gson parser = gson.create();
System.out.println(parser.toJson(new Sample()));
}

Categories