I have been using the jackson implementation of the json protocol in my own little project, and it has gone just fine a while now until I decided (for the first time) to serialize a stateless object.
I know that might sound weird, why would I want to send a stateless object? What I serialize is requests for a server, and this particular one conatins no fields, just code for an instruction on the server side. My model can take any ClientRequest implementation and call it's perform() method. I want it to work even though the request comes without fields.
Code looks like this:
public class GetWallInputsRequest implements ClientRequest<List<WallInput>>
{
#JsonCreator public GetWallInputsRequest()
{
}
#Override public ServerResponse<List<WallInput>> perform()
{
return new WallMessageResponse( Wall.WALL.getInputs() );
}
}
I get JsonMappingException: No serializer found for class GetWallInputsRequest.
Google does not help me, which makes me wonder if I'm just being stupid. Sadly I don't see a way out of this.
I solved it after a lot of brute force attempting different things. And by solved it I mean not figured it out but made it work. By adding the line:
#JsonAutoDetect(getterVisibility=JsonAutoDetect.Visibility.NONE)
above the class declaration it seems to work out. Why this is necessary I don't know, but now It sends an empty json string instead of crashing.
The documentation says
Value that indicates that no access modifiers are auto-detectable: this can be used to explicitly disable auto-detection for specified types.
Since your class doesn't include any explicit notations to tell Jackson that there's a field or method to serialize, it determines that there is indeed nothing to look for. Without this, I presume, it's going to expect something, as suggested in the documentation quoted.
http://jackson.codehaus.org/1.9.0/javadoc/org/codehaus/jackson/annotate/JsonAutoDetect.Visibility.html
Related
Assuming there is a REST Controller with an endpoint that accepts a single object in the body:
#PostMapping("/ExampleObjects")
void mapping(#RequestBody ExampleObject object){ ....
If one would want to add the ability to accept an array under the same endpoint like this:
#PostMapping("/ExampleObjects")
void mapping(#RequestBody ExampleObject[] objects){ ....
Is there a way to implement the new functionality with the given design and without breaking existing users?
That should help you.
application.properties:
spring.jackson.deserialization.accept-single-value-as-array=true
controller:
#PostMapping("/ExampleObjects")
void mapping(#RequestBody List<ExampleObject> objects){ ....
How about having the first endpoint called "/ExampleObject" instead, seeing as it appears to be singular?
It's good practise to keep your API endpoints as simple as possible, as consistent as possible (between different endpoints in the single API), and as error-tolerant as possible.
Instead of an array, you'd want to use a generic List<ExampleObject> in any case.
You could just implement the list version of the method, call that method with a list that only contains a single instance. You'd want to think about the consistency part of the equation a little bit. What kinds of different endpoints will you be implementing in your API. Would this solution fit most of those use cases?
Go with the solution that results with the least surprises to your API users.
Currently something like Jackson is doing the parsing from HTTP request body to ExampleObject automatically for you.
You could do the parsing in your code and decide during parsing, if it is an instance of ExampleObject or ExampleObject[]. Therefore you would have one method with this signature:
#PostMapping("/ExampleObjects")
void mapping(#RequestBody String objectOrArray){
// code to parse String into ExampleObject or ExampleObject[] ...
This should handle your issue, but a better API design would be having 2 different endpoints / URLs.
I have an action I want to apply to multiple routes in my Play application. These routes perform actions on a product, and a product can have various versions. I want my API to work such that the user can specify a version explicitly (via a query parameter), and if they do not specify one we will look up the latest version from the DB for them and operate on that one. So this action needs to be able to look up the latest version of a product, but we need to know which product is being asked for. In the route's controller, this is obvious. Play calls the route controller with route parameters as arguments:
#RequireProductVersion()
public CompletionStage<Result> getProduct(String productId) {
...
}
But in our action, we only have this Play internal Context object to work with. My action looks something like this:
public class RequireProductVersion extends Action<RequireProductVersion> {
#Override
public CompletionStage<Result> call(Http.Context ctx) {
final String version = ctx.request().getQueryString("version");
// if an explicit "version" parameter was specified, verify it and use it
if (version != null) {
...
} else {
// look up the latest version for this product
final String productId = ctx.request.????getParameter("productId");
return lookupLatestProductVersion(productId).thenCompose( ... );
}
}
}
Although I have some additional validity checking in that action. Sometimes I return an error from there immediately. So we could replace this action composition solution by adding the query string parameter "version" to all the routes and adding a half dozen lines of code in each of my route controllers:
#RequireProductVersion()
public CompletionStage<Result> getProduct(String productId, #Nullable String productVersion) {
final int productVersion;
try {
productVersion = Utils.getProductVersion(productId, productVersion);
} catch (ProductVersionException e) {
return CompletableFuture.completedFuture(e.getAppropriateResult());
}
...
}
But this use case is exactly what action composition should be for, I think. It just seems that the route parameters are missing. The Context object exposed in the Action call() method has a lot of stuff in it, actually. Headers are there, query parameters are there, and even the exact path being hit is there! Even if that were not so, by the point the framework has parsed the route and determined the values of the route parameters. This must be true because if it was not, then how would it know which action to call? However, it appears that these parsed parameters are completely unavailable to us. We could parse them again ourselves from the path. But why should we have to do that? We would be parsing the path twice. Why doesn't the framework expose these values?
There's an interesting article I found that, to solve a similar problem, suggests a hack that will put a url parameter into the query string parameters map.
https://alots.wordpress.com/2014/05/01/accessing-url-parameters-as-get-parameters-in-play/
However it appears to me that this method is also basically double parsing the path anyway, although I might be misinterpreting it as I'm not very familiar with Scala. If so, I might as well just hack in logic to reparse the path in my Action.
Okay so this problem is solvable in Scala. It does not appear there is currently any way to solve it in Java due to how Play Java uses annotations for action composition (and for body parsers, which is another place I ran into this exact same problem). You would have to parse the path again yourself. However, it looks like it is quite easy to accomplish in Scala. I haven’t tested either of these and I’m not very familiar with Scala, but it looks like for Play in Scala, action composition works differently.
this gist has an example of how Play Scala action composition should support this:
https://gist.github.com/wolfendale/75e8b5e9a7ace95aa7e6d123e6c6dacd
jroper’s posts in this issue thread also demonstrate what appears to me to be the same solution:
https://github.com/playframework/playframework/issues/3378#issuecomment-54925034
If those work, the technique demonstrated in the article I linked in the original post is not at all necessary to solve this problem if you are using Scala. However, because it only requires writing some code in Scala (whereas for the technique demonstrated by wolfendale and jroper, you need to write your controller in Scala as well), it could be a useful way to solve this problem and still write most of your application in Java. I don’t know for sure. I haven’t tested it and I’m not interested in that kind of hack.
You can't, at least, not out of the box. Play doesn't provide ways to get the request params in action composition.
Basically : You have to parse yourself.
The Java language benefited much from adding enums to it; but unfortunately they don't work well when sending serialized objects between systems that have different code levels.
Example: assume that you have two systems A and B. They both start of with the same code levels, but at some point the start to see code updates at different points in time. Now assume that there is some
public enum Whatever { FIRST; }
And there are other objects that keep references to constants of that enum. Those objects are serialized and sent from A to B or vice versa. Now consider that B has a newer version of Whatever
public enum Whatever { FIRST; SECOND }
Then:
class SomethingElse implements Serializable { ...
private final Whatever theWhatever;
SomethingElse(Whatever theWhatever) {
this.theWhatever = theWhatever; ..
gets instantiated ...
SomethingElse somethin = new SomethingElse(Whatever.SECOND)
and then serialized and sent over to A (for example as result of some RMI call). Which is bad, because now there will be an error during deserialization on A: A knows the Whatever enum class, but in a version that doesn't have SECOND.
We figured this the hard way; and now I am very anxious to use enums for situations that would actually "perfect for enums"; simply because I know that I can't easily extend an existing enum later on.
Now I am wondering: are there (good) strategies to avoid such compatibility issues with enums? Or do I really have to go back to "pre-enum" times; and don't use enums, but have to rely on a solution where I use plain strings all over the place?
Update: please note that using the serialversionuid doesn't help here at all. That thing only helps you in making an incompatible change "more obvious". But the point is: I don't care why deserialization fails - because I have to avoid it to happen. And I am also not in a position to change the way we serialize our objects. We are doing RMI; and we are serializing to binary; I have no means to change that.
As #Jesper mentioned in the comments, I would recommend something like JSON for your inter-service communication. This will allow you to have more control on how unknown Enum values are handled.
For example, using the always awesome Jackson you can use the Deserialization Features READ_UNKNOWN_ENUM_VALUES_AS_NULL or READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE. Both will allow your application logic to handle unknown enum values as you see fit.
Example (straight from the Jackson doc)
enum MyEnum { A, B, #JsonEnumDefaultValue UNKNOWN }
...
final ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE);
MyEnum value = mapper.readValue("\"foo\"", MyEnum.class);
assertSame(MyEnum.UNKNOWN, value);
After going back and forth regarding different solutions, I figured a solution based on the suggestion from #GuiSim : one can build a class that contains an enum value. This class can
do custom deserialization; thus I can prevent there won't be exceptions during the deserialization process
provide simple methods like isValid() and getEnumValue(): the first one tells you if the enum deserialization actually worked; and the second one returns the deserialized enum (or throws an exception)
I'm currently using RestEasy(2.3.6) with Jackson(1.9.9) and needing to prefix my JSON arrays with '{} &&' in order to prevent JSON hijacking.
I'm new to Jackson and am having a really hard time understanding where to insert anything like this. I'm not even sure where to insert something like this to make it happen all the time, and I would like to take it one step further and be able to specify to only prefix return values that contain JSON arrays and not regular objects.
I imagine there is a class somewhere I need to subclass and override a method, and then register that class somehow. Has anyone ever done anything like this?
Jukka, the question you linked to led me to a solution. I extended JacksonJsonProvider, and overrode the writeTo() method. There are a few conditions in there and I was able to add jg.writeRaw("{}&&"); before each place it writes the value. Also, since I'm using Spring, I had to annotate my class with #Component in order for it to be found.
Also another gotcha with creating your own JsonProvider subclass is your rest methods must have #Produces('application/json') (you should always be explicit with these anyway) or else the default JsonProvider will be used.
As you could see from this question, the response that worldweather return is not quite pretty. They return array of current weather conditions (I try to understand why did they made it that way, there couldn't be more then one weather condition in a specific place, as far as I know...), so it breaks the unmarshalling via annotations,
#JsonProperty("current_condition")
private CurrentWeatherData currentWeatherData;
because Jackson actually awaits a collection or an array. Now, can I somehow to tell the unmarshaller to use the first array member, and if yes, how do I do that?
There is no such annotation. You will probably want a custom deserializer to handle this special case.
For Jackson 2.2 there will be support for separate Converters, which could work here (as they only work on Java objects). But since it is not yet released, custom deserializer is probably the way to go.