How can I send the Object class to server with Jackson? - java

I have a Message class like this:
class Message {
#JsonProperty("content")
Object content;
}
where the content attribute can be a User, a Post, or a String
and I have to send this object to the server and cast the content to the right class.
I'm using Jackson annotations to serialize the JSON, but when I try to cast the content, an error appears, because the attribute content arrives in the server like a LinkedHashMap object.
The error is:
ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/MegaRadarSocial].[Resteasy]] (http-localhost-127.0.0.1-8080-1) Servlet.service() for servlet Resteasy threw exception: org.jboss.resteasy.spi.UnhandledException: java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to br.com.megaradar.megaradarsocial.model.User
I would like a help to casting...
Thanks

As you control both ends (server and client), you could try Genson library http://code.google.com/p/genson/. One of its features allows you to serialize to json and type information, this enables you to deserialize back to the right type.
Genson genson = new Genson.Builder().setWithClassMetadata(true).create();
json = genson.serialize(yourMessage);
// then deserialize it back
Message message = genson.deserialize(json, Message .class);
The serialized json will look like : {"content": {"#class":"package.path.Message", ...the object values...}}
You can even define aliases for the serialized classes
new Genson.Builder().addAlias("message", Message.class)
Important: Note that you need to use the same configuration of genson on both sides. So enable type information with setWithClassMetadata and if you use aliases, you must define the same on the client side.

What you need is #JsonTypeInfo annotation, like so:
class Message {
#JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY property="type")
#JsonProperty("content")
Object content;
}
(you can see http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html for examples)
which would add property "type" with class name as value (there are many alternative ways as well) when serializing, and using that when deserializing.

Thank you for all the answers. But I found another way to convert my Object to any type I want.
I'm using the method convertValue from the ObjectMapper object. Then, I can simulate the casting.
Thanks again

Related

Jackson Deserialize To Concrete Class Based On Type

I have what I believe should be a simple use case.
I would like to serialize a POJO with type metadata (preferably a simple name I come up with, not the fully qualified class/package name), and later have Jackson deserialize the JSON back into the concrete class it came from by using this metadata. There is no inheritance hierarchy among classes being serialized and deserialized.
My scenario is I have a service which accepts multiple file types. For each file uploaded, the client can retrieve JSON data whose structure and type depends on the file it came from. Thus when I retrieve JSON from the service, it's not known what the concrete class is to deserialize to. I would like Jackson to figure this out based on metadata which it supplies.
For example, I'd like to be able to do this:
String json = ... // get JSON from the service
Object obj = mapper.readValue(json, Object.class) // concrete class is not known
System.out.println(obj.getClass()) // I want this to be MyConcreteClass.class
There is no inheritance hierarchy among JSON types returned.
I don't want to reveal package names or other internal service
details/structure.
I have control over Jackson's serialization process
Relevant question: Can jackson determine root object type to deserialize to when json includes type property?
Thank you so much for your help!
This can be achieved using Jackson's JavaType:
String className = "class.name.from.json.service";
JavaType dtoType = TypeFactory.defaultInstance().constructFromCanonical(className);
Object dto = new ObjectMapper().readValue(InputStream, dtoType);
assert dto.getClass().equals(dtoType.getRawClass());

Instantiate generic based on property file setting

I'm building a data driven test system. I have done this before in XML but json is giving me some interesting issues.
For each request and response type json, I have a setting in my script where I specify a pojo type. This type is instantiated to a class object thats passed to jackson to marshal the json into a usable pojo. so its like this:
"responseType": "java.util.List",
eventually gets pumped to
Class<?> reponseType = null;
try {
if (d.shouldPass) {
reponseType = Class.forName(d.responseType);
}
} catch (ClassNotFoundException e) {
throw new RequestResponseTypeInvalid(testName);
}
and I have usable class info to use in jackson. My problem is I need to do this:
"responseType": "java.util.List<foo>",
otherwise complex json types parse as hashmaps instead of pojo's. I suppose I can get creative and put something in to go from hashmap to pojo if I need to but I was wondering if there was any straight forward way to do this.
I suppose another way is to implement a factory class where I could say list_foo in the property file and have the factory class map that to an actual class object. That wouldn't be very hard but not as easy as just using the property.
thanks
You can't do this in the way that you're hoping, I'm afraid. Generics are a compile-time thing only, and can't be used in this way at runtime, because of type erasure.
The best you could do would be to have some list_foo properties, and map these explicitly to List<Foo> and so in in your code. But you can't do it by reflection.

Java can't deserialize JSON

I'm getting an error trying to deserialize what I believe is a valid JSON string:
String json = "{\"email\":\"testing#example.com\",\"password\":\"12345\"}";
// FlexJSON deserializer
JSONDeserializer<Signin> deserializer = new JSONDeserializer<Signin>();
// Deserialize into a Signin POJO.
Signin signin = deserializer.deserialize(json);
When I run this code, I get:
java.util.HashMap cannot be cast to com.myapp.server.Signin
java.lang.ClassCastException: java.util.HashMap cannot be cast to com.myapp.server.Signin
at com.myapp.server.SigninService.doPost(SigninService.java:39)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
... rest of stack trace omitted for brevity
Is my JSON malformed? It's almost as if the JSON is somehow "bad" and FlexJSON is treating it like a HashMap...
Looking at the documentation, the problem is that your json doesn't declare its class. This means that you explicitly need to supply a Class object to the deserializer, as in Java generics are only compile time, not runtime.
To quote from the documentation:
We need to replace the type information we just dropped when we instantiate the deserializer. To do that we'll pass the class we want to use into to flexjson.JSONDeserializer.deserialize(String, Class) method like so:
Hero hero = new JSONDeserializer<Hero>().deserialize( jsonHarvey, Hero.class );
So use:
Signin signin = deserializer.deserialize(json, Signin.class);
This library you're using seems like it's not supported really.
Seems it's not changed since 2010. I would try using something else.
I have used this one for example without any issues.
http://code.google.com/p/google-gson/downloads/list

Restlet response type

How can I return Restlet response in desired format?
I am using the method:
#Get ("json")
public Address sendResponse(){
Address add = getAddress();
return add;
}
Right now I have to explicitly convert java object to a json string as a response to browser. Can't it be taken care by Restlet framework itself?
Spring MVC's Restful implementation can do it. I am looking similar implementation in Restlet too.
In fact, there are two ways to do that with Restlet:
the explicit one using JSON representations. The JSONRepresentation if you use objects from org.json or the JacksonRepresentation if you want JSON / Object mapping. You can find below an example:
#Get ("json")
public Representation sendResponse(){
Address add = getAddress();
return new JacksonRepresentation<Address>(address);
}
the implicit one using converter. In this case, it's the code you gave. You must have in your classpath an appropriate converter such as the one provided by the org.restlet.ext.jackson extension. It will detect that a JSON content needs to be returned and implicitly convert your Address object to a JSON content.
Just for hint, the json media specified in the GET annotation tells Restlet to use the associated method to handle the request when application/json is defined for conneg (content negociation) with the accept header.
Hope it helps you.
Thierry
Try setting the response type to application/json instead of just json. Normally, you need to specify the correct MIME type. As you say, if you set the MIME type correctly, other frameworks will do the conversion automatically.

apache camel and jackson

I'm trying out apache-camel, and I've set up a basic route that calls an http service via http4 component, transforms the result via unmarshal().json(JsonLibrary.Jackson), and then prints out part of the response in a bean component.
The problem I'm having is that it blows up at runtime when it gets to the json unmarhsaller:
No type converter available to convert from type: java.util.HashMap to the required type: com.xxx.MyType
The response is of this format:
{"data":[{"x":"y"},{"x":"z"}]}
And my object model is like:
#lombok.Data
class Response {
private List<Elem> data;
}
#lombok.Data
class Elem {
private String x;
}
So it would appear that the unmarshaller thinks the response is a hash map, whereas I want it to unmarshal into an object structure. Is there a way to get it to do what I want?
Found the answer, posting in case anyone else runs into this. The route builder should be setup like:
from("direct:start").to("http4://...").unmarshal().json(JsonLibrary.Jackson,com.xxx.Response)
.to("bean:com.xxx.MyResponseEchoer")
I.e. pass the class type to the json method.

Categories