Parse JSON Object in ajax to Custom Object with JsonDeserializer - java

I have serialized the Object of TestDetail Class to Json using gson.
TestDetail Class--
public class TestDetail implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name="test_details_id")
private int testDetailsId;
#Column(name="test_exists_cc")
private byte testExistsCc;
#Column(name="test_name")
private String testName;
#Column(name="test_package")
private String testPackage;
#Column(name="test_automated_on")
private Date testAutomationDate;
//bi-directional many-to-one association to VariableDetail
#OneToMany(mappedBy="testDetail", fetch=FetchType.EAGER)
private Set<VariableDetail> variableDetails;
My Servlet Code is ---
String productSelected = request.getParameter("productSelected");
ProductDetailDAO productDetailDAO = new ProductDetailDAOImpl();
ProductDetail productDetail = productDetailDAO.getProductByName(productSelected);
Set<TestDetail> testDetailSet = productDetail.getTestDetails();
productDetailDAO.closeEntityManager();
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(TestDetail.class, new TestDetailJsonSerializer());
Gson gson = builder.create();
String json = gson.toJson(testDetailSet);
//gson.fromJson(json, TestDetail.class);
System.out.println(json);
response.getWriter().write(json);
On printing the json output in consol I am getting this -
["com.amadeus.automatepckg.db.entities.TestDetail#18e4593","com.amadeus.automatepckg.db.entities.TestDetail#38a3ca","com.amadeus.automatepckg.db.entities.TestDetail#a6bcec","com.amadeus.automatepckg.db.entities.TestDetail#115a56d","com.amadeus.automatepckg.db.entities.TestDetail#89583a","com.amadeus.automatepckg.db.entities.TestDetail#6aa01a","com.amadeus.automatepckg.db.entities.TestDetail#bd5fa1","com.amadeus.automatepckg.db.entities.TestDetail#fe8ee7","com.amadeus.automatepckg.db.entities.TestDetail#7d6ca2","com.amadeus.automatepckg.db.entities.TestDetail#30c6ca","com.amadeus.automatepckg.db.entities.TestDetail#4b0a55","com.amadeus.automatepckg.db.entities.TestDetail#e89bed","com.amadeus.automatepckg.db.entities.TestDetail#10924b1","com.amadeus.automatepckg.db.entities.TestDetail#12a15d3","com.amadeus.automatepckg.db.entities.TestDetail#12c1685","com.amadeus.automatepckg.db.entities.TestDetail#1281b8c","com.amadeus.automatepckg.db.entities.TestDetail#939339","com.amadeus.automatepckg.db.entities.TestDetail#15343c2","com.amadeus.automatepckg.db.entities.TestDetail#75324a","com.amadeus.automatepckg.db.entities.TestDetail#1b9fc6","com.amadeus.automatepckg.db.entities.TestDetail#19699dd","com.amadeus.automatepckg.db.entities.TestDetail#147f26f","com.amadeus.automatepckg.db.entities.TestDetail#1f28508","com.amadeus.automatepckg.db.entities.TestDetail#a5de12","com.amadeus.automatepckg.db.entities.TestDetail#d5cfd6","com.amadeus.automatepckg.db.entities.TestDetail#18587ac","com.amadeus.automatepckg.db.entities.TestDetail#7c0a2c","com.amadeus.automatepckg.db.entities.TestDetail#16d9fe1","com.amadeus.automatepckg.db.entities.TestDetail#17fd935","com.amadeus.automatepckg.db.entities.TestDetail#6d6c90","com.amadeus.automatepckg.db.entities.TestDetail#17a765c","com.amadeus.automatepckg.db.entities.TestDetail#8d5581","com.amadeus.automatepckg.db.entities.TestDetail#102ab48","com.amadeus.automatepckg.db.entities.TestDetail#1402894","com.amadeus.automatepckg.db.entities.TestDetail#179eb02","com.amadeus.automatepckg.db.entities.TestDetail#35449e","com.amadeus.automatepckg.db.entities.TestDetail#8bed1c","com.amadeus.automatepckg.db.entities.TestDetail#1b72911","com.amadeus.automatepckg.db.entities.TestDetail#196a464","com.amadeus.automatepckg.db.entities.TestDetail#28b522","com.amadeus.automatepckg.db.entities.TestDetail#4dbd0f","com.amadeus.automatepckg.db.entities.TestDetail#ff7853","com.amadeus.automatepckg.db.entities.TestDetail#2ff65","com.amadeus.automatepckg.db.entities.TestDetail#6f03ec","com.amadeus.automatepckg.db.entities.TestDetail#976b5b","com.amadeus.automatepckg.db.entities.TestDetail#3cee0d","com.amadeus.automatepckg.db.entities.TestDetail#d150be","com.amadeus.automatepckg.db.entities.TestDetail#154e92c","com.amadeus.automatepckg.db.entities.TestDetail#bed71","com.amadeus.automatepckg.db.entities.TestDetail#fc0795","com.amadeus.automatepckg.db.entities.TestDetail#f0ce45","com.amadeus.automatepckg.db.entities.TestDetail#111a20c","com.amadeus.automatepckg.db.entities.TestDetail#b1a201","com.amadeus.automatepckg.db.entities.TestDetail#176323e","com.amadeus.automatepckg.db.entities.TestDetail#1987899","com.amadeus.automatepckg.db.entities.TestDetail#4f96a0","com.amadeus.automatepckg.db.entities.TestDetail#1fb14e","com.amadeus.automatepckg.db.entities.TestDetail#dc907a","com.amadeus.automatepckg.db.entities.TestDetail#6727f0","com.amadeus.automatepckg.db.entities.TestDetail#57e44e","com.amadeus.automatepckg.db.entities.TestDetail#91630f","com.amadeus.automatepckg.db.entities.TestDetail#cd504e","com.amadeus.automatepckg.db.entities.TestDetail#3b0790","com.amadeus.automatepckg.db.entities.TestDetail#1fee2b4","com.amadeus.automatepckg.db.entities.TestDetail#1e95777","com.amadeus.automatepckg.db.entities.TestDetail#3496c9","com.amadeus.automatepckg.db.entities.TestDetail#560854"]
Custom Serializer -
import java.lang.reflect.Type;
import com.amadeus.automatepckg.db.entities.TestDetail;
import com.google.gson.*;
public class TestDetailJsonSerializer implements JsonSerializer<TestDetail> {
#Override
public JsonElement serialize(TestDetail entity, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(entity.toString());
}
}
custom DeSerializer - TestDetailJsonSerializer
import java.lang.reflect.Type;
import com.amadeus.automatepckg.db.entities.TestDetail;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
public class TestDetailJonsDeSerializer implements JsonDeserializer<TestDetail> {
#Override
public TestDetail deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return new TestDetail();
}
}
ajax function in jsp
$.ajax({
url: 'GetTestDetailsForProduct',
data: 'productSelected='+$("#productSelectBox").val(),
type: 'get',
dataType:'json',
success: function(result){
$(result).each(function(index,element){
alert(element); // showing object address same as console output
alert(element.testPackage); // showing undefined in alert
});
// $('#availableTests').val(jsonTestDetails);
}
Now I want to access the member variables of TestDetail from the ajax response , for this how can I parse the JSON Object back to TestDetail Object.

Replace
return new JsonPrimitive(entity.toString());
with
return new JsonPrimitive(entity);
updated:
You are right, it's a primitive presentation and it cant take object.
But still your code is building json object using String representations of entity objects, which by defaul is like 'com.package.Class#18e4593'. Thats obvious nonsense, and you need provide Object to json formatter instead of its toString() result.
And why just not use gson.toJson(obj)?

Related

Nested inner class being ignored in OSGI?

I'm using gson to bind some json to a pojo. When I don't use OSGI, everything binds perfectly, so I am feeling like a class type is getting ignored completely due to some classloader issue because the nested collection is null after parsing.
I have an abstract generic class that does the binding within a separate bundle:
public <T> T deserialize(String jsonString, Class<T> clazz) {
GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();
return gson.fromJson(jsonString, clazz);
}
This approach works without OSGI, but when I use OSGI, it only binds the top-level elements that exist within the T class, but not the nested inner class.
To better illustrate "top-level" elements, the title and description are deserialized into the POJO correctly, but theThings is null. Do I need to somehow embed that nested subtype into the generic?
This is the class signature that contains the deserialize method.
public abstract class MyAbstractClass<T>
{
"title": "my awesome title",
"description": "all the awesome things",
"theThings": [
{
"thing": "coolThing1",
"association-type": "thing"
},
{
"thing": "coolThing2",
"association-type": "thing"
}
]
}
POJO Class that JSON Binds To:
package things;
import java.io.Serializable;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class ThingsPOJO implements Serializable
{
#SerializedName("title")
#Expose
public String title = "";
#SerializedName("description")
#Expose
public String description = "";
#SerializedName("theThings")
#Expose
public List<TheThing> theThings = null;
private class TheThing implements Serializable
{
#SerializedName("thing")
#Expose
public String thing = "";
#SerializedName("association-type")
#Expose
public String associationType = "";
}
}

want to map a json object unto a java object

I am using a certain API which have a json output as below. I have parsed it to String.
the json output as string: {"result":{"number":"INC0022500"}}.
As you can see it has nested object for key result.
my snippet which i am using to map the above json unto a object.
Gson gson = new Gson();
EspIncidentTrial staff = gson.fromJson(json, EspIncidentTrial.class);
ESPIncidentTrial class:
import javax.persistence.Embeddable;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonProperty;
#Embeddable
#JsonIgnoreProperties(ignoreUnknown = true)
public class EspIncidentTrial {
#JsonProperty("result")
private ResultTrial result;
public ResultTrial getResult() {
return result;
}
public void setResult(ResultTrial result) {
this.result = result;
}
}
For the nested object i created another class ResultTrial. Below is the body.
ResultTrial class:
import javax.persistence.Embeddable;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonProperty;
#Embeddable
#JsonIgnoreProperties(ignoreUnknown = true)
public class ResultTrial {
#JsonProperty("number")
private String incidentId;
public String getIncidentId() {
return incidentId;
}
public void setIncidentId(String incidentId) {
this.incidentId = incidentId;
}
}
What happens now is, in EspIncidentTrial class, object result is getting mapped. However, inside ResultTrial class, no mapping is being done.
I tried treating the key result in the json object as String, but the threw the below error, which was expected though.
The error occured while parsing the JSON. com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 12 path $.result
Please help!
Here you are mixing gson and Jackson.
You are using annoations of Jackson, but using GSON's method to deserailze it.
Use Jackson's objectMapper to deserialize.
E.g.:
ObjectMapper mapper = new ObjectMapper();
EspIncidentTrial staff = mapper.readValue(json, EspIncidentTrial.class);
you can try this....
String searchdata="{\"userPojo\":{\"userid\":1156}}";
JSONObject jsonObject=new JSONObject(searchdata);
SummaryPojo summaryPojo=new SummaryPojo();
if(searchdata.contains("userPojo"))
{
String jsonstring=jsonObject.getString("userPojo");
Gson gson = new Gson();
UserPojo userPojo = gson.fromJson(searchdata, UserPojo.class);
summaryPojo.setUserPojo(userPojo);
}

Gson: Instantiate Interface from Json String

I'm using Gson to deserialize some json string (actually it's jwt) passed in by http header. The json contains:
[
{"authority":"a1"},
{"authority":"a2"},
{"authority":"a3"},
.
.
.
{"authority":"a4"},
]
in JsonElement.
And I'd like the above part to be deserialized into the field (in some class):
Set<GrantedAuthority> authorities
Where GrantedAuthority is an interface from Spring, it has an implementation SimpleGrantedAuthority. SimpleGrantedAuthority has a constructor that takes a string:
public SimpleGrantedAuthority(String au) {this.au = au}
I need Gson to know the implementation class of interface GrantedAuthority in order to deserialize the json. I was trying:
public class GrantedAuthorityInstanceCreator implements InstanceCreator<GrantedAuthority> {
#Override
public GrantedAuthority createInstance(Type type) {
// no such constructor
GrantedAuthority ga = new SimpleGrantedAuthority();
return ga;
}
}
But since SimpleGrantedAuthority has no no-arg constructor, I need to provide an argument to the constructor. How can I achieve this?
InstanceCreator won't work. According to gson-user-guide. you have 3 options:
Option 1: Use Gson's parser API (low-level streaming parser or the DOM parser JsonParser) to parse the array elements and then use Gson.fromJson() on each of the array elements.This is the preferred approach. Here is an example that demonstrates how to do this.
Option 2: Register a type adapter for Collection.class that looks at each of the array members and maps them to appropriate objects. The disadvantage of this approach is that it will screw up deserialization of other collection types in Gson.
Option 3: Register a type adapter for MyCollectionMemberType and use fromJson with Collection
This approach is practical only if the array appears as a top-level element or if you can change the field type holding the collection to be of type Collection.
You said
And I'd like the above part to be deserialized into the field (in some class):
So, assume the "some class" is MyClass, and authorities is one field of MyClass for your json string (and there's other fields in MyClass). Below is an example code using method "Option 3":
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.util.Set;
public class Test2 {
public static void main(String[] args) throws Exception {
String json = "{ authorities: [\n" +
" {\"authority\":\"a1\"},\n" +
" {\"authority\":\"a2\"},\n" +
" {\"authority\":\"a3\"},\n" +
" {\"authority\":\"a4\"}\n" +
"]}";
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeHierarchyAdapter(GrantedAuthority.class, new GrantedAuthorityTypeAdaptor());
Gson gson = gsonBuilder.create();
MyClass obj1 = gson.fromJson(json, MyClass.class);
for (GrantedAuthority au : obj1.authorities) {
SimpleGrantedAuthority sgau = (SimpleGrantedAuthority) au;
System.out.println(sgau.authority);
}
}
}
class MyClass {
Set<GrantedAuthority> authorities;
// other fields
}
interface GrantedAuthority {
}
class SimpleGrantedAuthority implements GrantedAuthority {
final String authority;
public SimpleGrantedAuthority(String au) {
this.authority = au;
}
}
class GrantedAuthorityTypeAdaptor extends TypeAdapter<GrantedAuthority> {
#Override
public void write(JsonWriter out, GrantedAuthority value) throws IOException {
new Gson().getAdapter(SimpleGrantedAuthority.class).write(out, (SimpleGrantedAuthority) value);
}
#Override
public GrantedAuthority read(JsonReader in) throws IOException {
return new Gson().getAdapter(SimpleGrantedAuthority.class).read(in);
}
}
The approach is to use SimpleGrantedAuthorityAdaptor as an adaptor for GrantedAuthority.
In order not to mess up other code, the GsonBuilder should be used only here. You should create a new GsonBuilder in your other code.

JSON Formatting with Jersey, Jackson, & json.org/java Parser using Curl Command

Using Java 6, Tomcat 7, Jersey 1.15, Jackson 2.0.6 (from FasterXml maven repo), & www.json.org parser, I am trying to
pretty print the JSON String so it will look indented by the curl -X GET command line.
I created a simple web service which has the following architecture:
My POJOs (model classes):
Family.java
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Family {
private String father;
private String mother;
private List<Children> children;
// Getter & Setters
}
Children.java
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Children {
private String name;
private String age;
private String gender;
// Getters & Setters
}
Using a Utility Class, I decided to hard code the POJOs as follows:
public class FamilyUtil {
public static Family getFamily() {
Family family = new Family();
family.setFather("Joe");
family.setMother("Jennifer");
Children child = new Children();
child.setName("Jimmy");
child.setAge("12");
child.setGender("male");
List<Children> children = new ArrayList<Children>();
children.add(child);
family.setChildren(children);
return family;
}
}
My web service:
import java.io.IOException;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jettison.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import com.myapp.controller.myappController;
import com.myapp.resource.output.HostingSegmentOutput;
import com.myapp.util.FamilyUtil;
#Path("")
public class MyWebService {
#GET
#Produces(MediaType.APPLICATION_JSON)
public static String getFamily() throws IOException,
JsonGenerationException,
JsonMappingException,
JSONException,
org.json.JSONException {
ObjectMapper mapper = new ObjectMapper();
String uglyJsonString = mapper.writeValueAsString(FamilyUtil.getFamily());
System.out.println(uglyJsonString);
JSONTokener tokener = new JSONTokener(uglyJsonString);
JSONObject finalResult = new JSONObject(tokener);
return finalResult.toString(4);
}
}
When I run this using:
curl -X GET http://localhost:8080/mywebservice
I get this in my Eclipse's console:
{"father":"Joe","mother":"Jennifer","children":[{"name":"Jimmy","age":"12","gender":"male"}]}
But from the curl command on the command line (this response is more important):
"{\n \"mother\": \"Jennifer\",\n \"children\": [{\n \"age\": \"12\",\n \"name\": \"Jimmy\",\n \"gender\": \"male\"\n }],\n \"father\": \"Joe\"\n}"
This is adding newline escape sequences and placing double quotes (but not indenting like it should it does have 4 spaces after the new line but its all in one line).
Would appreciate it if someone could point me in the right direction.
What I believe is happening is your currently configured message body reader is taking your String returned from your method, and escaping it properly so that it is a valid JSON string (since json doesn't let newlines inside of string constants).
Here's what you do... I'm assuming that you are using Jackson's included Message Body Writers. (e.g. JacksonJsonProvider)
You create a #Provider that sets up an ObjectMapper instance with Pretty Printing enabled like so:
#Provider
public class JacksonObjectMapperProvider implements ContextResolver<ObjectMapper> {
/**
* {#inheritDoc}
*/
#Override
public ObjectMapper getContext(final Class<?> type) {
final ObjectMapper toReturn = new ObjectMapper();
toReturn.enable(SerializationFeature.INDENT_OUTPUT); // This is the important setting
toReturn.disable(MapperFeature.USE_ANNOTATIONS); // I have this one on but it's probably for other resources in the container testing it in, I don't know if you'd need it.
return toReturn;
}
}
You then have your Resource return the resolved Family object instead of trying to transform it to Json... let the Message Body Writer do that... i.e.
public class MyWebService {
#GET
#Produces(MediaType.APPLICATION_JSON)
public Family getFamily()
return FamilyUtil.getFamily()
}
}
and Voila:
$ curl http://<server>/<ctx-root>/<path>
{
"father" : "Joe",
"mother" : "Jennifer",
"children" : [ {
"name" : "Jimmy",
"age" : "12",
"gender" : "male"
} ]
}
Now I glossed over getting the Provider and MessageBodyReader registered with your JAX-RS Application configuration, but that could vary greatly depending upon if you're using Jersey's servlet, using a custom Application, using Guice, or any number of other ways of setting up your JAX-RS stack.
Just use GSON library
This is an example for Jersey
normal Gson:
Gson gson = new Gson();
String json = gson.toJson(obj);
System.out.println(json);
the JSON output is display as compact mode like following :
{"data1":100,"data2":"hello","list":["String 1","String 2","String 3"]}
To enable pretty print, you should use GsonBuilder return a Gson object :
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(obj);
System.out.println(json);
Output will like this:
{
"data1": 100,
"data2": "hello",
"list": [
"String 1",
"String 2",
"String 3"
]
}
Full example from mkyong
package com.mkyong.core;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class GsonExample {
public static void main(String[] args) {
DataObject obj = new DataObject();
// Gson gson = new Gson();
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(obj);
System.out.println(json);
}
}

Gson not parsing Class variable

I am using Gson and I have an object that one of its fields is a Class
class A {
…
private Class aClass;
… }
When I parse the instance to Json using default Gson object aClass comes empty.
Any idea why?
You need custom type adapter. Here is example:
package com.sopovs.moradanen;
import java.lang.reflect.Type;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
public class GsonClassTest {
public static void main(String[] args) {
Gson gson = new GsonBuilder()
.registerTypeAdapter(Class.class, new ClassTypeAdapter())
.setPrettyPrinting()
.create();
String json = gson.toJson(new Foo());
System.out.println(json);
Foo fromJson = gson.fromJson(json, Foo.class);
System.out.println(fromJson.boo.getName());
}
public static class ClassTypeAdapter implements JsonSerializer<Class<?>>, JsonDeserializer<Class<?>> {
#Override
public JsonElement serialize(Class<?> src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.getName());
}
#Override
public Class<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
try {
return Class.forName(json.getAsString());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
public static class Foo {
Class<?> boo = String.class;
}
}
The output of this code is:
{
"boo": "java.lang.String"
}
java.lang.String
When I parse the instance to Json using default Gson object aClass comes empty.
Any idea why?
In a comment in issue 340, a Gson project manager explains:
Serializing types is actually somewhat of a security problem, so we don't want to support it by default. A malicious .json file could cause your application to load classes that it wouldn't otherwise; depending on your class path loading certain classes could DoS your application.
But it's quite straightforward to write a type adapter to support this in your own app.
Of course, since serialization is not the same as deserialization, I don't understand how this is an explanation for the disabled serialization, unless the unmentioned notion is to in a sense "balance" the default behaviors of serialization with deserialization.

Categories

Resources