I have a necessity to deserialize a JSON message into a generic object/interface and not to a specific type.
I went throught this post Interfaces and #RequestBody and tried to implement the same.
But again it failed with the same error
Can not construct instance of XXXXX, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
When the control reaches the method, the object is constructed as a linked hash map.
What might have gone wrong? Am I approaching the solution rightly?
Related
I'm trying to develop a Jax-RS POST resource, reported here below:
#Path("testJson")
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response testJson(Float firstValue, Float secondValue, String thirdValue) {
LOG.info(" firstValue: " + firstValue);
LOG.info(" secondValue: " + secondValue);
LOG.info(" thirdValue: " + thirdValue);
return Response.ok().build();
}
However, i get the following error:
RESTEASY002305: Failed executing POST /aliments/testJson: org.jboss.resteasy.spi.ReaderException: javax.ws.rs.ProcessingException: RESTEASY008200: JSON Binding deserialization error
Searching around, I understood that for a POST method that accepts a JSON, you need to give to it only one parameter, which is in fact the entire JSON message.
My questions are:
Why can't I put two or more parameters? Is that because the Json represents the body part of the message and I can have only one body? Can you explain it better to me please?
I can create a DTO that contains my parameters and use this DTO as one and only parameter for my POST method, but is this the best practice? Doing so, I will have a DTO for each POST method, which actually acts as a Wrapper.
Is there anything I'm missing?
Thank you a lot for your time,
Have a nice day.
Why can't I put two or more parameters? Is that because the Json represents the body part of the message and I can have only one body? Can you explain it better to me please?
JAX-RS allows for one "entity" parameter. This parameter represents the entire request entity. It is determined to be the entity parameter by not having any annotations1. If you want the raw entity, you can use an InputStream parameter. If you want a POJO, you can do so. How the conversion works is with the use of MessageBodyReaders. The reader will be chosen based on the Content-Type header and the parameter type. The framwork comes with some standard readers for easiliy convertable types. For example String, InputStream, byte[]. The reader will get passed the entity stream and it will need to convert the stream to the parameter type. You can read more about "Entity Providers" here.
If you want to use a common media type like JSON, there are libraries that handle JSON/POJO conversion, and from that library, a reader can be made. For JSON, a common librabry is Jackson, and there is a Jackson MessageBodyReader that is provided by the Jackson team.
I can create a DTO that contains my parameters and use this DTO as one and only parameter for my POST method, but is this the best practice? Doing so, I will have a DTO for each POST method, which actually acts as a Wrapper.
Yes, this is very common practice. Get used to it with these type of frameworks.
Is there anything I'm missing?
I don't know, you tell me.
1. Some special annotation are allowed like #Valid for bean validation.
I would like to send Json to the server, and we do that with Newtonsoft's Json.NET1. The json may contain type information ("$type" = ...). This type info may point to an unknown type. Said object would typically be contained in a property of type object.
What I would like to do:
Convert the part of the unknown type to a JObject
Preserve somehow the type information, so I can send the same json back to the client at a later point as it was passed to the server.
What I've tried so far
By replacing the SerializationBinder on the JsonSerializer, I can force Json.NET to deserialize the json contained into a JObject. This is almost what I would like to have, alas the $type property is lost.
In the binder returning a type that points to an object that would work in harmony with a custom JsonConverter which would gobble up the offending object such that upon write it would faithfully recreate the json as it was encountered. However, when you hit the $type info, no converters will be called anymore, apparently we are then in a different branch of the json.NET code
One can handle a serialization error, try to read from the reader the offending part, then one could create a JOBject manually and annotate the type information.
1) More specific - the built of it that is contained in the RavenDB.Abstractions, but hopefully they have not diverged too much.
We're in a process of switching from Json.NET to ServiceStack.Text and I came across an issue with serialization of polymorphic collections.
In JSON.NET I used to create a custom JsonCreationConverter and overriding the Create() method to select the type I want to create - as outlined here:
http://dotnetbyexample.blogspot.co.uk/2012/02/json-deserialization-with-jsonnet-class.html
The collection in question is List<ItemBase> which can contain FlightItem or CarHireItem objects.
This is my version of the Create() method for JSON.NET:
protected override ItemBase Create(Type objectType, JObject jsonObject)
{
var itemType = jsonObject["Type"].ToString();
switch (itemType)
{
case "flight":
return new FlightItem();
case "carhire":
return new CarHireItem();
default:
return null;
}
}
Is that possible with ServiceStack?
Serialization and deserialization in ServiceStack for polymorphic collections works, however, it appends the object type to the JSON output, e.g.
"__type" : "TestProject.Model.FlightItem, TestProject"
This means that I need to supply the type when posting JSON and I'm not too keen on having the .NET type visible for anyone within the API calls.
Any suggestions? If it's possible to do this in a different way, can you point me to some examples?
Firstly, Interfaces or abstract types in DTOs are a bad idea.
You're now in the strange position where you're trying to support polymorphic types in DTOs, but don't want to provide JSON Serializer-specific info? The reason why you need bespoke code to support polymorphic DTO's is because it's impossible to tell what concrete type should be used based on the wire format, hence why ServiceStack emits the __type property for this purpose.
To avoid these hacks, and have it work equally well in all JSON Serializers, you're better off "flattening" your polymorphic types into a single "flat" DTO and send that across the wire instead. Once you're back in C# you can use code to project it into the ideal types.
ServiceStack does provide some JsConfig<ItemBase>.RawDeserializeFn that will let you do something similar, see the CustomSerializerTests for an example. There's also the JsConfig<ItemBase>.OnDeserializedFn hook that can potentially help, but it's dependent on whether ItemBase contains a complete property list of both concrete types.
I'm trying to use AutoBean on the server and client to send and receive json data through AppEngines channel API. I don't want to store this data in the datastore. I already have a Proxy for this object that I use for the RequestFactoryServlet (which underneath just uses AutoBean anyways), so this should be doable. Instead of writing up a new Proxy for the object that exactly duplicates the Proxy for the RequestFactoryServlet, I'd like to just use the proxy that I use for the RequestFactoryServlet. The only problem is that I get an error while compiling that comes from my AutoBeanFactory.
Invoking generator
com.google.web.bindery.autobean.gwt.rebind.AutoBeanFactoryGenerator
[ERROR] The com.wmba.wmbaapp.shared.ObjectProxy parameterization is not simple, but the obj method does not provide a
delegate
So I'm not really sure what to do here. It seems like before I added the client side in, it's able to serialize the object into JSON just fine, but for some reason it doesn't like this. It sounds like it wants a delegate from me, but I can't find anything on this from the internet.
Anyone have any ideas?
Note: I also tried the same thing with EntityProxy (which is the base of the RequestFactory framework from what I read on the AutoBean page, but I get the same error).
The issue is that EntityProxy defines the stableId method which is not a getter (name doesn't start with get). That makes it a not simple bean, for which AutoBeans require a real bean instance to be wrapped in the created AutoBean (the delegate, passed as an argument of the type of the AutoBean –ObjectProxy in your case– to your obj method of the AutoBeanFactory).
In other words, AutoBeans expects your obj method to be of the form:
AutoBean<ObjectProxy> obj(ObjectProxy toWrap);
The simplest solution is to not try to reuse the entity proxy with AutoBeans.
You might be able to make it work though by annotating your AutoBeanFactory with:
#Category(EntityProxyCategory.class)
You might have to add #NoWrap(EntityProxyId.class) too, see http://code.google.com/p/google-web-toolkit/source/browse/trunk/user/src/com/google/web/bindery/requestfactory/vm/InProcessRequestFactory.java
It turned out for me that I had a property setter that had an empty parameter list in my Ojbect interface. It didn't have anything to do with the factory, except for the interface the factory was trying to create a proxy for:
interface Factory {
AutoBeans<MyObject> createObject();
}
interface MyObject {
String getProperty();
void setProperty();
}
A bone-headed mistake but held me up with this precise compiler error. Adding the Category annotation as mentioned in the previous answer identified the faulty property setter.
I'm POSTing a JSON request to a Spring 3.0 controller. The method signature is...
#RequestMapping(value="/add", method=RequestMethod.POST)
public #ResponseBody Map<String, ? extends Object> add(#RequestBody Entry)
The JSON looks like this...
{"user":"1"}
The Entry object has one attribute of type User.
When a request is submitted this error is thrown,
org.codehaus.jackson.map.JsonMappingException: Can not construct instance of com.x.y.z.Entry, problem: no suitable creator method found
I'm guessing the error is due to the fact that user on Entry is of type User rather than String ("1" is being passed in on the JSON).
Is there a way of taking the "1" coming in and using it to create a real User object (by looking it up in the database in this case)?
Does Entry have a parameterless constructor?
That's your first place to look. Normally errors of this nature occur because the code is looking for a parameterless constructor to create Entry with.
Your idea, that is to create User as the real user is fine, but it should be done after this method is called, in some other layer or something. You wanna keep things simple by not interfering with the marshalling of the json. You can add onto this with another layer.