I have a RESTful Web service, using Drop Wizard 0.8.5 with Jersey 2.21. I have a resource class with is annotated with:
#Path("/mysite/somepath")
This class contains various methods, such as #GETs, #PUTS, etc., all working just fine.
Now, I have another resource class that is annotated with #Path("/mysite"). Within this resource class I have a need to add a few methods annotated with paths such as the following:
#Path("/somepath/dothis")
#Path("/somepath/dothat")
The resource classes all register just fine. However, when I make a call to the second class I get a 404, as it appears Jersey is looking for these methods in my first class. Is there a way to resolve this issue, other than changing my #Path annotations to avoid this naming conflict?
Jersey presumes each class has unique #Path expression associated with it. If you want to use the same #Path variable to two different resources, you either use two different path names, or you can combine the two classes into one class.
Related
I would like to know if it is possible to make Spring MVC work like Stripes when resolving controller classes.
Normally I can annotate a controller with a #RequestMapping in order to map it to its URL.
However my boss asked for a convention-over-configuration mechanism derived from Stripes, which we are progressively abandoning after years of employment.
You see, Stripes Actions are scanned in classpath under packages that contain stripes.action in their name. Each subpackage is a virtual directory and ultimately a class named SomethingAction will map to url Something.action.
Whan I need to do is as follows:
com.example.product.web.controllers.secure.admin.UserController mapping to /secure/admin/user
com.example.something.different.from.before.web.controllers.pub.WelcomeController mapping to /pub/welcome
Basically I'd like to make Spring MVC automagically map controllers according to their full class name instead of using #RequestMapping on every controller.
Important! I don't need exactly that naming convention (web.controllers) if Spring MVC has already a naming convention. I simply need one.
I have found no clue so far.
Thanks
ControllerClassNameHandlerMapping does it out-of-box what you are looking forward to.
Simply set the base package as com.example.product.web.controllers and the sub-packages would be mapped as path for you. To quote from API docs
Specify a base package like "com.mycompany.myapp" to include subpackages within that base package as path elements, e.g. generating the path "/mymodule/buyform" for the class name "com.mycompany.myapp.mymodule.BuyForm". Subpackage hierarchies are represented as individual path elements, e.g. "/mymodule/mysubmodule/buyform" for the class name "com.mycompany.myapp.mymodule.mysubmodule.BuyForm".
Do note that it is constrained to have only single base package. Incase there are different package hierarchies to scan, the behaviour of ControllerClassNameHandlerMapping has to be customized accordingly.
Is it possible to load the value for the #PATH annotation from configuration (web.xml, etc) for a given class?
#Path(<value loaded from config>)
public class myRestService {
...
Independent of JAX-RS: Annotations in Java are compile time constants so they can't be changed at runtime.
I don't know your use case but possible ways to change the values of the annotations are:
Replacing variables before compilation, e.g. through a maven plugin.
Adding the #Path annotations dynamically like described here.
Using one generic ResourceClass mapped to /* which decides which subresource should be returned.
No comment if one of these approaches makes sense as I don't know why you want to change them. As the URI names a resource I don't see any reason to change it. See also: Cool URIs don't change
Update: JAX_RS_SPEC-60 requests "A Dynamic way to register JAX-RS resources (not based on annotations)".
According to JAX-RS specification (here), there is no standard way to do this, I think.
I'm currently refactoring a (former) monster of a method in a Spring-MVC controller. The method basically does the following things:
Digs up a few identifiers from the request
Gets an XML representation for a product identified by them from a cache
Uses an XSL stylesheet to produce a PDF (which it then stores to a cache and adds the key it can be found with to the Model).
I've been able to remove almost all duplicated logic by making a Product enum which contains all the other product specific things, but the locations of the XSL stylesheets are problematic. Previously they were configured as org.springframework.core.io.Resource-type properties of the controller bean, but now that the product specific things are in the enum, I would either need to map them somehow to the enum constants or find another solution for locating them.
I think it would be best to have the XSL as part of the enum since there's a 1-to-1 relationship between them, but there's no way to inject the resource there. Using the class loader to load the resource to the enum manually would work in tests, but would be problematic in production environment since the stylesheet files are not in the classpath there. Plus I wouldn't like to make the enum depend on any Spring stuff.
Any ideas on how to tackle this problem without making the enum and the controller too tightly coupled?
In the end I made the enum an inner class of the controller and added an abstract method called getXsl to it. The implementing enum constants now return the related Resource directly. I didn't have to change anything else since the Resource beans were already static.
For the sake of my own education, I wanted to build a simple Dependency Injection framework that functions similar to the way Google's Guice does. So that when a class is loaded, it pre-populates annotated fields with data from a factory class.
I am using Reflections to scan all my factory classes at compile time and save those classes in a static list so that when it comes time to load my classes, I have a reference to my factories that I can then scan methods and return the appropriate data.
Where i'm stuck at is how to pre-populate my classes annotated fields without actually doing any of the work in the actual class. In other words, when a class is loaded, I need to be able to determine if any of the fields are annotated with a specific annotation, and if they are, retrieve the value from the factory class.
Is there some way of performing reflection on a class right before it is loaded, pre-populate specific fields and then return an instance of that class to be used?
I could extend all of my classes that require dependency injection with a base class that does all of this work, but I figure there must be a better way so that I can simply use an #Inject (or whatever annotation I decide to use to say that this field requires DI) and "magically" all the work is done.
The way that Guice approaches this is that it will only populate the fields of an instance that was itself created by Guice1. The injector, after creating the instance, can use the Reflection API to look at the fields of the Class and inspect their annotations with Field.getDeclaredAnnotations().
This is also the reason why, when you want to inject into a static field, you need to use Binder.requestStaticInjection() to populate the static fields.
Guice does not simply scan your code for annotations; all injections recurse from an explicit request (e.g. requestStaticInjection(), Injector.getInstance(), etc). Now often that initial, explicit request will have been made in some library code.
For example, if you're using guice-servlet you let Guice create the instances of your servlet by using the serve().with() calls. But if you didn't do that, and instead left your servlet config in your web.xml, Guice would not inject into your servlet.
1 - You can also request explicit injection using Binder.requestInjection().
I have a webapp that redirects to a particular URI: let's say /service/library. In another bundle, I have a jaxrs server that listens for /service in the URI, and defines some beans to handle the request. There are quite a few beans there already, and one of the classes is already implemented to handle requests for /service/library. I am trying to create a new class that also handles requests for /service/library, but with a different absolute URI path, for example: /service/library/mynewlibrary. My question is, is it possible to define the same #Path identifier in two classes, or must they be unique, in other words, will I need to use a URI like /service/mylibrary for my new class implementation instead of implementing a second class that also uses the same #Path identifier? I am pretty new to JAX-RS, so I hope my question makes sense!
Thanks!
It's possible to have two #Path annotations that match the URI. In your case, if servlet-mapping is service, you may have #Path("/library") and #Path("library/mynewlibrary").
When request arrives, the matching paths are sorted in descending order, so the second class should be called, when a request with /service/library/mynewlibrary arrives.
It's most certainly possible to have two methods with the same #Path annotation, e.g., if they're distinguished by other means (such as HTTP method or #Consumes annotation). The #Path on a class acts as a default/root for the #Paths on the class's methods. Moreover, it's not a problem at all if you've got one path that is “within” another; JAX-RS specifies that the most specific match possible is used. (I prefer to not do it that way, instead having the “outer” class return a reference to the “inner” class on a suitable partial match, so that every path has a traceable route to responsibility that definitely leads to a single class. That requires a fairly different way of arranging the #Path annotations though.)
But if you've ended up with two methods that can serve the same incoming request, you've got a clash and the JAX-RS implementation will be free to pick which one to use (in an implementation-dependent manner). That's probably not what you want, as computers tend to make bad decisions when given a free choice.
You can achieve your goal to have /service/library/mynewlibrary using below configuration.
In your existing class you have /service/library configured at class level so you can configure /service at class level in new class you are adding and then at method level configure /library/mynewlibrary.
This way it will not have same path for both classes and your goal is also achieved. I tried this and it works.