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

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.

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.

How to understand annotation in java And How to implement my annotation in java?

What I have known are:
annotation was added in java 5
annotation can be using in method, class, and property
annotation can work in RUNTIME, CLASS, SOURCE( I don't know how to work with CLASS and SOURCE, and their's features)
annotation with retention which is RUNTIME can be implement when java program is running.
And I want to implement a annotation to have follows features:
ensure class only being allowed to create a instance
ensure methods only being allowed to access method in the class
it is like as friend in c++
it is same as public and private , but more dynamicall, like
#MyAnnotation(allowMethods={xxx.doSomething})
public void getValue(){}
the getValues method only can be accessed in the instance self and xxx.doSomething() method
What should I do and learn in next?
And Where can I learn about these?
I think you might be misunderstanding something there. Annotations are descriptive elements, not parts of your program. You can write as many annotations as you want, and people who use your code will still be able to ignore them.
That said, an annotation that enforces a policy (as yours does) can actually be implemented, either at compile or at runtime, but you need an external mechanism to help you. I can think of 3:
Annotation processing lets you interact with the compiler and process annotations by generating code or by omitting compiler errors. Unfortunately, I don't think it will work for your case, as you want to protect your annotated type from instantiation, and that means the call site doesn't actually have an annotation. Annotation processing only gives you access to the actual code pieces that have annotations, not to those that refer to them.
AspectJ allows you to write policy enforcement aspects and omit compiler errors, based on static pointcuts. The problem here is that static pointcuts have very limited semantics, so while you could forbid the instantiation of your class altogether, or from certain packages, you could not limit the your class instantiations to 1.
The third way, and probably the only sane way is that you use a container like Spring or Guice and configure your class as singleton. As long as you only retrieve your class from the container, it will never create a second instance.
Finally: If you want to limit the number of instantiations of your class, you can always use a classic Singleton pattern approach.

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! :)

Is there a #NonNullByDefault annotation in IDEA?

Eclipse has the #NonNullByDefault annotation, which treats all values as #NonNull unless you explicitly annotate them as #Nullable.
Is there an equivalent option in IntelliJ IDEA, or do you have to always use #Nonnull?
Idea version 14 will include support for the JSR 305 "#TypeQualifierDefault" annotation, which allows the user to create a custom annotation, to be used on a package declaration in a package-info.java file, that specifies that everything in that package (not just parameters, but method return values, local variables, etc.) will be implicitly annotated as not allowing null values.
Unfortunately, this doesn't (currently) recursively affect subpackages, so each subpackage has to have a package-info.java file too, declaring that subpackage to use the annotation.
See here for details and an example of use:
http://youtrack.jetbrains.com/issue/IDEA-125281
Note that this is already implemented in Early Access Program (EAP) builds.
No, it is currently not supported by IDEA.
As a proof, see lena's link about the open feature request to allow 'NotNull' as the default element behavior for a given class or package.
Maybe a similar feature will be become standard with JSR-305, which may include the #ParametersAreNonnullByDefault annotation and also the opposite annotation #ParametersAreNullableByDefault. Note that in contrast to #NonNullByDefault, return values are not covered by those two annotations. So, you still had to annotate the return value explicitely.
All that doesn't change the current state, though. Neither has JSR-305 become a standard, nor does IDEA implement it.

JAX-RS - Can two classes have the same #Path identifier?

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.

Categories

Resources