I'm new to JAX-RS and I'm trying to understand how the #Context annotation is supposed to work.
At the javadoc there is a list of six classes (Application, UriInfo, Request, HttpHeaders, SecurityContext, Providers). However I find code on the web that use the this annotation with other types, for example:
#GET
public String something(#Context HttpServletRequest req) {
}
Is there a list of supported types that can be used with this annotations? Does this list change between implementation of the standard?
I'm currently experimenting with Jersey and I'm worried that I'll write code that cannot be ported to other JAX-RS implementation.
The #Context annotation allows you to inject request/response context details into JAX-RS provider and resource classes. Injection can be performed into a class field, a bean property or a method parameter.
The following list summarizes all the types that can be injected using the #Context annotation, according to the JAX-RS 2.0 specification:
javax.ws.rs.core.Application
javax.ws.rs.core.HttpHeaders
javax.ws.rs.core.Request
javax.ws.rs.core.SecurityContext
javax.ws.rs.core.UriInfo
javax.ws.rs.core.Configuration
javax.ws.rs.container.ResourceContext
javax.ws.rs.ext.Providers
Except for Configuration and Providers, which
are injectable in both client and server-side providers, all the other types are server-side only.
The following types are available only when the application is deployed in a servlet container:
javax.servlet.HttpServletRequest
javax.servlet.HttpServletResponse
javax.servlet.ServletConfig
javax.servlet.ServletContext
JAX-RS 2.1 introduced other types that can be injected with #Context:
javax.ws.rs.sse.Sse
javax.ws.rs.sse.SseEventSink
Besides the standard types listed above, JAX-RS implementations, such as Jersey, RESTEasy and Apache CXF, might define their own types that can be injected using #Context.
Find below a quick description of each JAX-RS type available for injection:
Application: The instance of the application-supplied Application subclass can be injected into a class field or method parameter. Access to the Application subclass instance allows configuration information to be centralized in that class.
URIs and URI templates: UriInfo provides both static and dynamic, per-request information, about the components of a request URI.
Headers: HttpHeaders provides access to request header information either in map form or via strongly typed convenience methods. Response headers may be provided using the Response class.
Content negotiation and preconditions: The methods of Request allow a caller to determine the best matching representation variant and to evaluate whether the current state of the resource matches any preconditions in the request.
Security context: The SecurityContext interface provides access to information about the security context of the current request. The methods of SecurityContext provide access to the current user principal, information about roles assumed by the requester, whether the request arrived over a secure channel and the authentication scheme used.
Providers: The Providers interface allows for lookup of provider instances based on a set of search criteria. This interface is expected to be primarily of interest to provider authors wishing to use other providers functionality. It is injectable in both client and server providers.
Resource context: The ResourceContext interface provides access to instantiation and initialization of resource or subresource classes in the default per-request scope. It can be injected to help with creation and initialization, or just initialization, of instances created by an application.
Configuration: Both the client and the server runtime Configurations are available for injection in providers (client or server) and resource classes (server only).
SSE events: SseEventSink represents the incoming SSE connection and provides methods to send events. Sse provides factory methods for events and broadcasters.
This post written by Arjan Tijms suggests that future versions of JAX-RS may have a stronger integration with CDI. So #Context may be deprecated and then removed in favor of #Inject:
JAX-RS 2.2
For some reason, one that has largely been lost in time, JAX-RS uses its own dependency injection system based on #Context instead of CDI's #Inject. While JAX-RS was updated at the last moment before its initial release to have some level of support for CDI, the fact that JAX-RS resources are not CDI beans has unnecessarily hold back the spec and has caused confusion even since JAX-RS was introduced in EE 6 (2009).
This changeover to CDI could possibly happen in 2 steps; in JAX-RS 2.2 everything that can now be injected by #Context should also be injectable using #Inject and JAX-RS resources would be CDI beans by default (perhaps unless explicitly disabled). At the same time #Context would be deprecated. In JAX-RS 3.0 #Context would then be actually removed.
The riveting JAX-RS specification defines all the standard types you can inject via #Context.
But if I were you, I would just consult the specific documentation of your chosen provider to see what is available.
For example, RESTEasy provides these values via #Context. Meanwhile, Jersey provides these. Obviously there will be overlap because of the standard context values.
The #Context annotation can be used to inject 12 objects. Here is a quick summary of each of them
HttpHeaders - HTTP header valuesand parameters
UriInfo - URI query parameters and path variables
SecurityContext - Gives access to security-related data for the given HTTP request
Request - Allows precondition request processing
ServletConfig - The ServletConfig
ServletContext - The ServletContext
HttpServletRequest - The HttpServletRequest instance for the request
HttpServletResponse - The HttpServletResponse instance
Application, Configuration, and Providers -> Provide information about the JAX-RS application, configuration and providers
ResourceContext - Gives access to resource class instances
All of these instances can be injected in the resource method
#Path("/")
public class EndpointResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getAllHttpHeaders(final #Context HttpHeaders httpHeaders){
// Code here that uses httpHeaders
}
}
or as a field:
#Path("/")
public class EndpointResource {
private final #Context HttpHeaders httpHeaders;
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getAllHttpHeaders(){
// Code here that uses httpHeaders
}
}
Here is a five part series answering the question What is #Conext used for?
To extend already provided answers: JAX-RS implementations usually provide a way to access the context. For RESTEasy it's ResteasyContext. The context can be listed by
ResteasyContext.getContextDataMap()
Keys of returned map can look like:
interface javax.ws.rs.core.Request
interface javax.ws.rs.core.HttpHeaders
interface javax.ws.rs.ext.Providers
class org.jboss.resteasy.plugins.server.Cleanables
class org.jboss.resteasy.core.PostResourceMethodInvokers
class org.jboss.resteasy.core.InternalDispatcher
interface javax.ws.rs.container.ResourceInfo
interface io.vertx.core.http.HttpServerResponse
interface io.vertx.core.Context
interface org.jboss.resteasy.spi.Registry
interface org.jboss.resteasy.spi.HttpRequest
interface org.jboss.resteasy.spi.ResteasyDeployment
interface javax.ws.rs.container.ResourceContext
interface org.jboss.resteasy.spi.Dispatcher
interface io.vertx.ext.web.RoutingContext
interface io.vertx.core.http.HttpServerRequest
interface io.vertx.core.Vertx
interface javax.ws.rs.core.Configurable
interface org.jboss.resteasy.spi.ResteasyAsynchronousContext
interface javax.ws.rs.core.SecurityContext
interface javax.ws.rs.core.Configuration
interface javax.ws.rs.core.UriInfo
interface org.jboss.resteasy.spi.HttpResponse
Related
I am struggling to understand when and how to use the different interfaces.
They seem to be quite similar, with some minor differences in method names to dynamically check security roles or retrieve the Principal, but - as far as I am currently understanding - are only accessible in their specific context.
I am trying to implement fine grained authorization with specific requirements.
Mainly the roles are not stored in the tokens, but must be read from a table in the database.
Therefore I have an implementation of IdentityStore that provides a CallerPrincipal with all available roles.
The IdentityStore is used by my HttpAuthenticationMechanism implementation, which is fairly simple, thus all it does is for valid requests to call HttpMessageContext.notifyContainerAboutLogin to push the CallerPrincipal into the SecurityContext - as far as I know.
Because there are a lot of generic endpoints in the codebase with path parameters, that decide which role has to be checked I need a generic way of checking if the user is in a role depending on the value of some path segments of the requested uri.
I created a method interceptor for that, where I want to access the SecurityContext, but both interfaces have their problems here:
#Interceptor
public class RolesAllowedInterceptor {
#Context
private UriInfo uriInfo;
// this injection is always null
#Context
private javax.security.enterprise.SecurityContext securityContext;
// this injection works
#Context
private javax.ws.rs.core.SecurityContext securityContext;
#AroundInvoke
public Object validate(InvocationContext ctx) throws Exception {
... // read path param to retrieve role and check SecurityContext.isUserInRole()
}
}
The injection of javax.security.enterprise.SecurityContext does not work. I assume the reason for this is, that the interceptor is called in a JAX-RS context.
The injection of javax.ws.rs.core.SecurityContext works (my assumption in 1. is based on this). But when SecurityContext.isUserInRole(String) is called, the debugger shows, that the Principal does not have any of the groups (roles in my business context) that were assigned via my IdentityStore implementation and thus the validation incorrectly fails.
I am currently using another approach with ContainerRequestFilter to set the javax.ws.rs.core.SecurityContext explicitly, which is working fine for the interceptor, but not with the javax.annotation.security.RolesAllowed annotation. For that I shifted the invocation of my IdentityStore into the filter, because I obviously do not want to call it twice.
I am not looking for complete code examples/solutions.
I am merely trying to understand why there are different interfaces of SecurityContext, as the Java Docs do not elaborate on that.
And therefore hopefully understand how I can use RolesAllowed for static endpoints and my interceptor for generic endpoints, without the need of a ContainerRequestFilter to set the SecurityContext for the later.
--
For context: I am using Payara Micro and jakartaee-api:8.0.0
I'm trying to clear my concept about Interceptors in Java EE. I have read Java EE specification but I'm little confused about it. Please provide me some useful link or tutorial which could clear my concept. How, When, Why do we use interceptors?
Interceptors are used to implement cross-cutting concerns, such as logging, auditing, and security, from the business logic.
In Java EE 5, Interceptors were allowed only on EJBs. In Java EE 6, Interceptors became a new specification of its own, abstracted at a higher level so that it can be more generically applied to a broader set of specifications in the platform.
They intercept invocations and life-cycle events on an associated target class. Basically, an interceptor is a class whose methods are invoked when business methods on a target class are invoked, life-cycle events such as methods that create/destroy the bean occur, or an EJB timeout method occurs. The CDI specification defines a type-safe mechanism for associating interceptors to beans using interceptor bindings.
Look for a working code sample at:
https://github.com/arun-gupta/javaee7-samples/tree/master/cdi/interceptors
Java EE 7 also introduced a new #Transactional annotation in Java Transaction API. This allows you to have container-managed transactions outside an EJB. This annotation is defined as an interceptor binding and implemented by the Java EE runtime. A working sample of #Transactional is at:
https://github.com/arun-gupta/javaee7-samples/tree/master/jta/transaction-scope
Interceptors are used to add AOP capability to managed beans.
We can attach Interceptor to our class using #Interceptor annotation.
Whenever a method in our class is called, the attached Interceptor will intercept that method invocation and execute its interceptor method.
This can be achieved using #AroundInvoke annotation ( see example below ).
We can intercept life cycle events of a class ( object creation,destroy etc) using #AroundConstruct annotation.
Main difference between Interceptor and Servlet Filters is We can use Interceptor outside WebContext, but Filters are specific to Web applications.
Common uses of interceptors are logging, auditing, and profiling.
For more detailed introduction, you can read this article.
https://abhirockzz.wordpress.com/2015/01/03/java-ee-interceptors/
I like this definition: Interceptors are components that intercept calls to EJB methods. They can be used for auditing and logging as and when EJBs are accessed.
In another situation, they can be used in a situation where we need to check whether a client has the authority or clearance to execute a transaction on a particular object in the database. Well, this is where Interceptors come in handy; they can check whether the client/user has that authority by checking whether he/she can invoke that method on that database object or EJB.
However, I would still have a look at the following article and the following tutorial to get an idea of how they are used in a Java EE setting/environment.
You can use Interceptor for the places where you want to perform some tasks before sending a request to the Controller class and before sending a request to a responce.
Ex:- Think you want to validate the auth token before sending a request to the Controller class in this case, you can use Intercepters.
Sample code:
#Component
public class AuthInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse
response, Object handler) throws Exception {
//Here you can write code to validate the auth token.
}
}
There is something I am not sure I understand correctlty, therefore, I need help:)
I have seen this: example,
#Path("/resource")
public class Resource {
#Context
private HttpHeaders headers;
#GET
public void get(#Context UriInfo uriInfo) {
/* use headers or uriInfo variable here */
}
}
Does this mean that for each request the class that is transformed to 'endpoint' creates a separate thread? Because, otherwise, the headers information would not be accurate...
Can you please indicate a (short:) ) resource, not JAX-WS specifications, where I can find info about this?
I can't think of a shorter and more direct resource than the JAX-RS 1.1 spec itself. It is clear about what you are asking:
JAX-RS provides facilities for obtaining and processing information about the application deployment context and the context of individual requests. (...)
Context is specific to a particular request (...).
May I add for completeness: that context information is obtained through the #Context annotation. As of resources, the context information is only available to the ones annotated with #Path (also called root resources). Also, #Context can inject the following context types: Application, UriInfo, HttpHeaders, Request, SecurityContext and Providers.
And about the lifecycle (request/thread management):
3.1.1 Lifecycle and Environment
By default a new resource class instance is created for each request
to that resource. First the constructor is called,
then any requested dependencies are injected (context is one of those dependencies), then
the appropriate method is invoked and finally the
object is made available for garbage collection.
An implementation MAY
offer other resource class lifecycles, mechanisms for specifying these
are outside the scope of this specification. E.g. an implementation
based on an inversion-of-control framework may support all of the
lifecycle options provided by that framework.
The conclusion is:
Each request is, by default, handled by a different resource instance;
The context is injected at request time (thus a different context per instance).
Each specific implementation may change this lifecycle a bit, but the principles should be maintained (a context specific to each request).
As you can see, also, the spec says nothing about thread management. Since most JAX-RS implementations are Servlet-based, we can assume with certain safety that the each request instance goes to a different thread - as servlet containers are thread per request.
I am currently developing a REST webservice using Jersey and Guice as a DI-container.
For handling the requests I am relying on a GuiceServletContextListener which is configured similar to the following:
bind(UserResource.class);
//Some other root-level resources for REST
serve("/rest/*").with(GuiceContainer.class);
As I have to deal with hierarchical data (One user should have their own items and it should be possible to access items of other users in the form of /rest/user/[Username]/item). For this, I am using Jersey's support for subresources.
For example, my UserResource contains the following method (ItemResource.Factory is a factory interface whose implementation is automatically provided by Guice's FactoryModuleBuilder):
#Inject
private ItemResource.Factory _itemResourceFactory;
#Path("/{username}/item")
public ItemResource getItems(#PathParam("username") String username) {
User user = //...
return this._itemResourceFactory.create(user);
}
ItemResource (the subresource) then again is implemented as a normal Jersey class based on the User passed in in the constructor.
However, my subresources need access to #Context fields (like UriInfo or HttpServletRequest), too. According to the Jersey documentation, #Context fields are not injected for subresources as their lifecycle is unknown (and the documentation seems to be true).
This is very unfortuante for me: I really need access to those values.
As a workaround, I am currently passing those values as additional constructor parameters to my subresources which I perceive as everything but comfortable.
Is there any possibility to tell Jersey to inject them anyway?
Nevertheless, even better would be if Guice itself was able to inject the #Context fields.
Simply swapping the #Context for #Inject, however, doesn't work as Guice has no registrations for types like UriInfo or HttpServletRequest.
Can I somehow create those mappings?
The problem is, that I don't know how to access the request specific values inside a Guice Provider implementation.
Are there maybe any helper methods to get access to the current instances of those Jersey objects so I can write the necessary providers?
Or are those implementations maybe already available somewhere out there?
I am not sure I understood your problem. Can you post the code related to "passing those values as additional constructor parameters"?
You can inject the Context like this:
#Path("/{username}/item")
public ItemResource getItems(#Context HttpServletRequest request, #PathParam("username") String username) {
Maybe you could inject fields programmatically? Guice provides this through the Injector class:
Injector injector = Guice.createInjector(...);
injector.injectMembers(someObjectToInject);
See http://code.google.com/p/google-guice/wiki/Injections for more information on this topic.
I recently implemented a Jersey JAX-RS Rest service. I created a JIBX provider that allows one to unmarshal and marshall between XML and Java types. I would like to also version my service by specifying the version in the URL path. Versioning would include the version of message binding used to marshal and unmarshall the Java types.
Therefore, it is necessary that the version is passed to the custom JIBX provider, and therefore the URL path that contains the version. However, the Provider interfaces (MessageBodyWriter and MessageBodyReader) do not provide the URI path in their interface methods.
The following is the method signature of the writeTo() method of the MessageBodyWriter interface:
writeTo(Object, Type, Annotation[], MediaType, MultivaluedMap, OutputStream)
This method parameters does not contain the path uri, therefore, the custom jibx provider cannot know which message binding version it should use to marshall the Java type. Is there a way around this?
If you want something a bit more JAX-RS specific than HttpServletRequest, you can inject a javax.ws.rs.core.UriInfo.
public class MyProvider implements MessageBodyWriter {
#javax.ws.rs.core.Context
javax.ws.rs.core.UriInfo uriInfo;
}
I'm assuming that you're using a #javax.ws.rs.PathParam to capture the path parameter. You can then potentially use UriInfo.getPathParameters(). You can also fall back to UriInfo.getPathSegments() to get the information you're looking for. This saves you the trouble of parsing the request URI yourself. Any JAX-RS implementation should be able to do this.
You can access the URI path from the Provider by defining the #Context annotation on a field on the Provider.
For example,
public class CustomProvider implements MessageBodyWriter
{
#Context HttpServletRequest request;
....
}
This field will automatically be set for each request. Even though the request is set as a field, the value is thread-safe as the actual request is using a proxy and most likely thread local to determine the request that belongs to thread.