I'm currently working on a project which allows users to book (via the web) the use of a chosen resource for a given period of time. In this program I am trying to keep with Spring's philosophy (and the general best practice) of programming to interfaces and as such I try to use interfaces anywhere where functionality is repeated among concrete classes.
One interface I have created is called a BookableResourceController which specifies the methods needed by a controller to handle the minimum required functionality for any type of resource to be booked. I also make use of a second interface, BookableResource, which identifies which objects model a resource that is allowed to be booked through the application.
The problem I am currently running into is that a few of the methods defined by BookableResourceController use the #RequestBody mapping to convert a JSON object into a method parameter, and since Jackson can only convert JSON into "SimpleType" objects, I receive an error if I specify the input parameter to be a BookableResource.
#RequestMapping(value="/delete.html", method = RequestMethod.POST)
public ModelAndView processDeleteResource(
#RequestBody BookableResource resource);
Can not construct instance of
org.codehaus.jackson.map.type.SimpleType,
problem: abstract types can only be
instantiated with additional type
information
From what I can tell this error means that I will need to define a specific implementation of BookableResource, meaning I will most likely need to exclude these methods from the interface even though any controller that is to be used for this purpose will require those methods.
What I am asking is if anyone knows a way to define an interface as the object that is expected from an #RequestBody mapping using JSON, or does anyone have any suggestions of how to structure my contoller interface in order to include these methods?
Cheers
I'm not sure it would work, but you can try to make it generic:
public interface BookableResourceController<R extends BookableResource> {
#RequestMapping(value="/delete.html", method = RequestMethod.POST)
public ModelAndView processDeleteResource(#RequestBody R resource);
}
Additional way to go that can be used is to annotate interface with Jackson annotation:
#JsonDeserialize(as=BookableResourceImp.class)
(possibly using mix-in annotations if one does not want to add it directly in interface class)
EDIT: Another possibility is to use SimpleModule method addAbstractTypeMapping() to specify implementation type. This avoids linkage from interface to implementation, and may (or may not) be more convenient way to register this aspect.
Related
I have the following class hierarchy for Coupon and Deals platform am developing::
Promotion - abstract
- Coupon
- Sale
- Deal
(Coupon, Sale and Deal inherit from Promotion. Promotion has a string attribute called type and an abstract method that initializes the the type attributes of the subclasses to a string value. For instance the type in coupon gets the value "Coupon" etc...)
For each subclass, I have a DAO and Service classes like CouponDAO, CouponService, etc.
In the front-end users can create Coupon or Sale or a Deal through Angular 2 interface so I decided to have the following controllers:
PromotionController - abstract
- CouponController
- SaleController
- DealController
(CouponController, SaleController, DealController inherit from PromotionController )
The PromotionController will contain all the common CRUD functions common to all subclasses and in the specific controllers I will handle specific operations meant for those classes.
A) The issue am facing now is how to instantiate the correct object coming from the client side. For instance when a user submit a Coupon or a Sale or a Deal how do I instantiate the right object. For instance in the PromotionController I have a function like this::
#RequestMapping(value=CREATE_PROMO, method=RequestMethod.POST)
public ResponseEntity<?> create(#RequestBody Promotion promotion){
promotionService.save(promotion);
return new ResponseEntity<>("", HttpStatus.OK);
}
Promotion which is abstract is the argument of the function. Should I use the factory pattern and the **type** attribute to create the right object?
For instance if the type="Coupon" then I create Coupon object, if it is "Sale" then I create the Sale object
B) Since the controller uses the Services objects it means that I have to declare all the three services objects in the PromotionController. Because after instantiating the right object, I need to call its corresponding service to do the job. In the method above I have promotionService which I think should be replaced with the right service of subclass
C) I am looking for how to handle REST APIs that deals with subclasses in the real world like the situation I have described above
D) I was thinking of making it easy for myself by copying all the CRUD operations to their specific controllers but it seems that will be repetitive code.
I think there is a better way that can be done.
I have also tried if I can find an open source project that deals with this situations but it seems all the projects I found use one class and not inheritance. Their REST/APIs don't handle inheritance situations
In my view, keep your endpoints simple. From a REST API standpoint, create individual or only one controller and use the following patterns after the controller layer. From what I have seen, it is always better to keep REST endpoints away from inheritance/reuse and apply it later after receiving and validating the requests.
To instantiate service/helper layer from controllers, use factory method pattern:
https://en.wikipedia.org/wiki/Factory_method_pattern
Create a PromotionServiceFactory which returns the PromotionService implementation depending upon the promotion type.
In controller, invoke corresponding method of promotion service using the factory. The factories still accept arguments of type Promotion.
#RequestMapping(value=CREATE_COUPON, method=RequestMethod.POST)
public ResponseEntity<?> create(#RequestBody Promotion promotion){
//helper if adding one more helper layer. The factory invocation is then //transferred to the helper layer
PromotionService couponService = promotionServiceFactory.get(PROMOTYPES.COUPON);
couponService.save(promotion);
return new ResponseEntity<>("", HttpStatus.OK);
}
From your questions, it seems like that there are common CRUD/other methods for different promotion types. This is a good candidate of the template pattern in the service layer if some of the steps/sub-tasks are same for every promotion and the others vary. Otherwise, you could just store the common CRUD methods by creating an abstract promotion service.
https://en.wikipedia.org/wiki/Template_method_pattern
Create an abstract promotion service with the primary method and implementations of common CRUD methods. Create individual implementations of other promotion service types with respective varying methods.
I think you can handle this in two ways depending upon the logic.
If you want to keep everything Separate then create a difference endpoints for coupon/deal/sale. That way every endpoint will call its controller and so on.
2) If you think code is same that you can use abstract factory pattern to instantiate the correct service and DAO object.
It all depends on your business requirement, I would prefer the second way if code logic is almost same. One controller per inheritance, so that in future if hierarchy increases you do not need to create multiple classes until required.
to answer you (A), I think you could use requestObject.instanceOf() method, to tell the correct subclass type, then handle with correct handler.
I want to write an annotation like #ResponseBody, use it on class such way that it can work on every method. So I want to know how to implement.
How a class level annotation applies to all methods, is not specific to #ResponseBody annotation, it is applicable to all such annotations, #Transactional for instance. When compiling code with annotations, the compiler runs the corresponding annotation processor (which has shown interest in that specific annotation). The annotation processor generally uses reflection to inspect the elements being compiled. Processor may simply run checks on the code snippets/methods, modify them, or generate new code before the final compilation. And this might include modification of all methods of that class as well. Refer http://mkyong.com/java/java-custom-annotations-example for an example of implementing custom annotations on class level.
Coming to #ResponseBody:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ResponseBody.html states that as of spring version 4.0 #ResponseBody annotation can also be added on the type level in which case it is inherited and does not need to be added on the method level.
How #ResponseBody works:
If you annotate a method (or the encapsulating class) with #ResponseBody, spring will try to convert method's return value and write it to the http response automatically.
Depending on your configuration, spring has a list of HttpMessageConverters registered in the background. A HttpMessageConverter's responsibility is to convert the method return value to a HTTP response body, depending on a predefined mime type.
Every time an issued request is hitting a #ResponseBody annotation, spring loops through all registered HttpMessageConverters seeking for the first that fits the given mime type and class and then uses it for the actual conversion.
I'm doing a very simple thing that should just work, IMO. I've got a resource like:
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("{nodeType}/{uuid}")
public Object getResourceInfo(#PathParam("nodeType") String nodeType,
#PathParam("uuid") String uuid,
#Context SecurityContext authority) { ...
Note I'm returning type Object. This is because depending on the call (here depending on the nodeType argument) I want to return a different concrete class (which will always be #XmlRootElement) and have that get marshalled out into the response.
However, this does not work. I get exception like:
Exception Description: A descriptor for class com.mycompany.XmlElementTypeInstance was not found in the project. For JAXB, if the JAXBContext was bootstrapped using TypeMappingInfo[] you must call a marshal method that accepts TypeMappingInfo as an input parameter.
If I change Object to a single subclass, it works. But I want it to be able to handle any subclass, XmlElementTypeInstance, XmlElementTypeInstance2, etcetc.
I tried making a common interface from which all of the XmlElementTypeInstance subclasses derive, but then I only get those properties in the interface, not the extra properties in the subclasses. Playing with #XmlElementRef and adding all possible properties to the common interface is extremely ugly and can't work quite correctly to generate the JSON I want, so please don't suggest that. =)
Is there any way to do this? It seems like simple, basic, necessary functionality... any other REST framework I've used, no problem...
The solution it turns out is simple (had to read the JSR instead of the actual Jersey docs, however!)
Instead of returning Object, returning Response (section 3.3.3 of JSR 339) with the object set as the entity forces the implementation to pick an appropriate MessageBody{Writer,Reader} at runtime.
return Response.ok().entity(<the object>).build();
Lost way too much time on this. Hope it helps someone later. =/
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 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?
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
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.
Let's say we have controllers with URL mappings like movie/{id}-{title}, actor/{id}-{name}, etc. These mappings identify some objects in our app, mostly entities - we can say it's a RESTful service.
I'm looking for a solution as to where I should put methods responsible for creation of those URIs. I think that creating them in multiple JSP files and some other places (redirection, etc.) is redundant.
First, what I thought about was creating some interface with method public URI getURI() that classes that will be used in controllers will implement. But, in my opinion, that would involve too much into entity - I prefer entities just to represent data and contain only methods to change state.
My second idea was to create a URIService with overloaded methods like URI getURI(Movie m) and URI getURI(Actor a), but there will be a problem with the choice of overloading method at compile time. For example, in EL in JSP that wouldn't work well, as the solution would be naming methods differently.
I don't want to reinvent the wheel, so maybe you know or use some solution to that problem?
How enterprisey do you want the solution to be? (I'm just half kidding)
Here's a solution: Have a service that has a method like URI getURI(Object o). This method will check if the object passed belongs to a class with an annotation that specifies the URI path. Example annotation:
public #interface PathTemplate {String value();}
Example class with the annotation:
#PathTemplate("/movie/{title}-{id}")
public class Movie {
private int id;private String title;
// getters and setters too
}
Now, the getURI method will see that the parameter object's class has a PathTemplate annotation and will interpolate the parameters using bean introspection. Voila! Expandable and relatively decoupled URI generation.