Replacement for <servlet-mapping> in web.xml & Spring MVC - java

Because my URLs are really complex and each of the parts between the slashes depends on the content of my database, I suppose the is not sufficient for me. I suppose I need to write some URL parser, which goes through the url parts between the slash and calls some kind of handler.
Is there a way how to write such URL parser, which would get string and return an object, representing the current request, that would replace the ? I only managed to find simple tutorials which use only the url-routing defined by web.xml.
Thanks

Spring is extremely flexible, so you can customize URL parsing. Take a look on this tutorial http://static.springsource.org/spring/docs/3.0.0.M3/spring-framework-reference/html/ch16s11.html, pay attention on DefaultAnnotationHandlerMapping and AnnotationMethodHandlerAdapter. It seems you should study how do they work and override some of the functionality.
But before you are starting, think again. Do you really need this and #RequestMapping does not satisfy you? Really, you can use path variable {myvar} into the URL pattern definition. The variables may be of different types including enums. I used this and found very convenient. You can for example create enum MyType ONE, TWO; define abstract method on enum level and override it for each element. Then you can use path variable of type MyType into the request mapping and call this method directly from the method marked with #RequesteMapping annotation.

Related

Is there a way to use Google's Custom Methods with Jersey Resources?

I was looking for a way to make my JAX-RS APIs more readable and came across with Google's Custom Methods approach:
https://cloud.google.com/apis/design/custom_methods
I was looking for this because some of my entities perform more actions than I could express with traditional HTTP verbs. Google pattern is to use a colon (:) at the end of the URI, separating the entity/collection from the desired action.
I tried to apply this pattern to a simple Jersey resource, just to test how it could be done. I've got a resource class StudentDetailsResource annotated with #Path("students/{studentId}") and a few methods also annotated with #Path.
If my method has another entity before the custom method, then all is ok. Let's say the enrol method is annotated with
#Path("subjects/{subjectId}:enroll").
The problem rises when the action is right after the Resource Class URI, because #Path uses a URI Template that prefixWithSlash all sub-resources. So if I have a dropout method, the annotation would look like #Path(":dropout"), but the URI template would become /students/{studentId}/:dropout, an this /: would break in the matching phase.
I have read about Jersey Providers and ResourceDelegates, but I couldn't find a way to replace the URI Template default action of prefixWithSlash.
The question is: how can I apply Google's custom method approach or how can I avoid the default prefixWithSlash behaviour with Jersey?
Note: I know this is a silly example and there are other ways to solve this specific case, but I have more complex cases which can benefit from the custom methods.

Jersey #PathParam at instance level vs at method level

In a Jersey class, Which is more appropriate of the two:
On an instance variable
#PathParam("service-id")
private String serviceId;
On a method argument
public Response subscribe(#PathParam("service-id") String serviceId){}
I'm using first one only because service-id is required by almost all my methods. However, a colleague of mine had a comment over this approach that ultimately Jersey classes are based on servlets and servlets should not have stateful variables.
I read about this in the JSR-311 java docs
Because injection occurs at object creation time, use of this
annotation on resource class fields and bean properties is only
supported for the default per-request resource class lifecycle.
Resource classes using other lifecycles should only use this
annotation on resource method parameters.
Since in a webapp, my Jersey class is going to follow per-request resource class lifecycle, I feel first approach is safe. Thoughts please :)
It is made safe by virtue of only allowing this annotation in request-scope (so that every request gets its own bean/resource instance and there is no shared state).
I'd probably give each method the full set of parameters, though, even if it is a bit repetitive. Makes it easier to see at a glance what is going on. That's a code style issue, though, and people can have different opinions here.
This is only coding styles issues since this code has exactly the same result.
I also prefer to define it in the method, instead of defining it in the instance.
Whatever, once compiled, the result is the same! :)

JAX-RS: Is it possible to have an externally configurable #PATH?

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.

Handling Dot (.) Parameters in Java Jersey

I want to format my REST interface as follows:
myurl.com/resources/{resourceId}
I optionally want people to be able to provide the following variations to specify return formats:
myurl.com/resources.json/{resourceId}
I am using Jersey to provide my REST services. What is the best way to handle these parameters?
Should a create a separate class with a different #PATH notation, or can I have a single class and parse out that parameter? Are there any built in annotations that might handle this, similar to #PathParam or #QueryParam?
There already is a mechanism for this (as #digitaljoel already stated) - HTTP Accept header.
Jersey doesn't have any direct support for your usecase, but there is something similar - media type mapping feature, see
http://jersey.java.net/nonav/apidocs/1.12/jersey/com/sun/jersey/api/core/ResourceConfig.html#PROPERTY_MEDIA_TYPE_MAPPINGS
and
http://jersey.java.net/nonav/apidocs/1.12/jersey/com/sun/jersey/api/core/ResourceConfig.html#getMediaTypeMappings%28%29
Unfortunately for you it handles only URLs which have this "param" at the end, but it should not be very hard to take UriConnegFilter sources (http://java.net/projects/jersey/sources/svn/content/trunk/jersey/jersey-server/src/main/java/com/sun/jersey/api/container/filter/UriConnegFilter.java?rev=5698) and modify it to suit your needs.

Spring MVC isFormSubmission() equivalent for annotations?

With Spring MVC, it's easy to express a concept like "A user is submitting the form if they use POST or if they include the 'isSubmit' parameter." You'd just extend SimpleFormController and override the isFormSubmission method.
However, Spring MVC now uses these neat annotations like #RequestMapping to handle requests. #RequestMapping has an obvious filter for whether somebody used a GET or a POST, but I don't see any inherent support for all of the useful logic SimpleFormController provided. Is it still available to me with annotations?
So, after a bit of investigation, there are in fact a couple of ways to handle this situation.
The first way is to go ahead and use a SimpleFormController with with #RequestMapping annotation at the class level. A lesser-known but pretty cool property of #RequestMapping is that it knows perfectly well how to deal with the classes that implement Spring's Controller interface. The only downside here is that I'm still using the old MVC interfaces and classes, and they're going to be deprecated in Spring 3.0.
The second way was pointed out by kgiannakakis above. Simply create a #RequestMapping method for every way that the submit can be called, and have them all just call a single submit method, either in a constructor-chaining style or with some private method. Simple and easy to understand. Thanks, kgiannakakis!
Copying from here:
Path mappings can be narrowed through parameter conditions: a sequence of
"myParam=myValue" style expressions, with a request only mapped if each such
parameter is found to have the given value. "myParam" style expressions are
also supported, with such parameters having to be present in the request
(allowed to have any value). Finally, "!myParam" style expressions indicate
that the specified parameter is not supposed to be present in the request.
You can only use the RequestMapping options to define the desired functionality. The Annotations Controller doesn't implement any interface to work with.
Here is one example of using Path mappings:
#RequestMapping(params = "formAction=APPROVE", method = RequestMethod.POST)
public String myMethod ()....
This method will only be called then for POSTs where there is a field named "formAction" with a value of "APPROVE".
The other answers listed work fine for a method annotated with #RequestMapping.
However, if you want to achieve the same thing on a method annotated with #InitBinder, you can simply do this:
#InitBinder
public void initBinder(HttpServletRequest request) {
if ("POST".equals(request.getMethod()){
//Do something
}
}

Categories

Resources