I'm using Jersey 1.x here and I have a @POST
method that requires sending over a deeply nested, complex object. I'm not sure of all my options, but it seems like a lot are described in this documentation:
In general the Java type of the method parameter may:
Be a primitive type;
Have a constructor that accepts a single String argument;
Have a static method named valueOf or fromString that accepts a single String argument (see, for example, Integer.valueOf(String) and java.util.UUID.fromString(String)); or
Be List, Set or SortedSet, where T satisfies 2 or 3 above. The resulting collection is read-only.
Ideally, I wish that I could define a method like this:
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Path("complexObject")
public void complexObject(@FormParam("complexObject") ComplexObject complexObject) throws Exception {
But I guess I can only do that if my object satisfies the requirements above (which in my case, it does not). To me it seems that I have a choice.
Option 1: Implement fromString
Implement item #3 above.
Option 2: Pass in the complexObject
in pieces
Break up the complexObject
into pieces so the parameters become this:
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Path("complexObject")
public void complexObject(@FormParam("piece1") LessComplexPiece lessComplexPiece1,
@FormParam("piece2") LessComplexPiece lessComplexPiece2,
@FormParam("piece3") LessComplexPiece lessComplexPiece3) throws Exception {
This may not be enough if LessComplexPiece
does not satisfy the requirements above. I'm wondering what the best option is here. What do people usually do in this situation? Here are the pros and cons I can think of:
Cons of Implement fromString
- Have to maintain a custom deserializer. Every time the class is modified, this deserializer may break. There's more risk for bugs in general.
- It will probably be impossible to generate documentation that describes the pieces of the complex object. I'll have to write that by hand.
- For each piece of the complex object, I'll have to write my own casting and validation logic.
- I'm not sure what the post data would look like. But, this may make it very difficult for someone to call the API from a web page form. If the resource accepted primitives, it would be easy. EG:
complexObject=seralizedString
vsfirstName=John
andlastName=Smith
- You may not be able to modify the class for various reasons (thankfully, this is not a limitation for me)
Pros of Implementing fromString
- This could avoid a method with a ton of parameters. This will make the API less intimidating to use.
- This argument is at the level of abstraction I want to work at in the body of my method:
- I won't have to combine the pieces together by hand (well technically I will, it'll just have to be in the deserializer method)
- The deserializer can be a library that automates the process (XStream, gensen, etc.) and save me a lot of time. This can mitigate the bug risk.
- You may run into "namespace" clashes if you flatten the object to send over pieces. For example, imagine sending over an
Employee
. If he has aBoss
, you now have to provide aEmployeeFirstName
and aBossFirstName
. If you were just deserializing an object, you could nest the data appropriately and not have to include context in your parameter names.
So which option should I choose? Is there a 3rd option I'm not aware of?
I know that this question is old but in case anybody has this problem there is new better solution since JAX-RS 2.0. Solution is @BeanParam. Due to documentation:
If you are looking for extended explanation on how this works please look at article I've found: http://java.dzone.com/articles/new-jax-rs-20-%E2%80%93-beanparam