Question

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:

  1. Be a primitive type;

  2. Have a constructor that accepts a single String argument;

  3. 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

  4. 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 vs firstName=John and lastName=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 a Boss, you now have to provide a EmployeeFirstName and a BossFirstName. 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?

Was it helpful?

Solution

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:

The annotation that may be used to inject custom JAX-RS "parameter aggregator" value object into a resource class field, property or resource method parameter. The JAX-RS runtime will instantiate the object and inject all it's fields and properties annotated with either one of the @XxxParam annotation (@PathParam, @FormParam ...) or the @Context annotation. For the POJO classes same instantiation and injection rules apply as in case of instantiation and injection of request-scoped root resource classes.

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

OTHER TIPS

For complex object models, you may want to consider using JSON or XML binding instead of URL-encoded string to pass your objects to your resource call so you can rely on JAXB framework? The Jersey Client library is compatible with JAXB and can handle all the marshaling transparently for you if you annotate your classes @XmlElementRoot.

For documentation, XSDs are a good starting point if you choose the XML binding. Other REST documentation tools like enunciate can take the automatic generation to the next level.

What about special handler which transforms object to e.g. json - kryo if you would prefer performance? You got couple options

Look also at persistence ignorance.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top