Using @Context, @Provider and ContextResolver in JAX-RS
I found another way. In my case i want to provide the user currently logged in as a User entity from my persitence layer. This is the class:
@RequestScoped
@Provider
public class CurrentUserProducer implements Serializable, ContextResolver<User> {
/**
* Default
*/
private static final long serialVersionUID = 1L;
@Context
private SecurityContext secContext;
@Inject
private UserUtil userUtil;
/**
* Tries to find logged in user in user db (by name) and returns it. If not
* found a new user with role {@link UserRole#USER} is created.
*
* @return found user or a new user with role user
*/
@Produces
@CurrentUser
public User getCurrentUser() {
if (secContext == null) {
throw new IllegalStateException("Can't inject security context - security context is null.");
}
return userUtil.getCreateUser(secContext.getUserPrincipal().getName(),
secContext.isUserInRole(UserRole.ADMIN.name()));
}
@Override
public User getContext(Class<?> type) {
if (type.equals(User.class)) {
return getCurrentUser();
}
return null;
}
}
I only used implements ContextResolver<User>
and @Provider
to get this class discovered by Jax-Rs and get SecurityContext
injected.
To get the current user i use CDI with my Qualifier @CurrentUser
. So on every place where i need the current user i type:
@Inject
@CurrentUser
private User user;
And indeed
@Context
private User user;
does not work (user is null).
I don't think there's a JAX-RS specific way to do what you want. The closest would be to do:
@Path("/something/")
class MyResource {
@Context
javax.ws.rs.ext.Providers providers;
@GET
public Response get() {
ContextResolver<StorageEngine> resolver = providers.getContextResolver(StorageEngine.class, MediaType.WILDCARD_TYPE);
StorageEngine engine = resolver.get(StorageEngine.class);
...
}
}
However, I think the @javax.ws.rs.core.Context annotation and javax.ws.rs.ext.ContextResolver is really for types related to JAX-RS and supporting JAX-RS providers.
You may want to look for Java Context and Dependency Injection (JSR-299) implementations (which should be available in Java EE 6) or other dependency injection frameworks such as Google Guice to help you here.
Implement a InjectableProvider. Most likely by extending PerRequestTypeInjectableProvider or SingletonTypeInjectableProvider.
@Provider
public class StorageEngineResolver extends SingletonTypeInjectableProvider<Context, StorageEngine>{
public MyContextResolver() {
super(StorageEngine.class, new InMemoryStorageEngine());
}
}
Would let you have:
@Context StorageEngine storage;
If anyone is using Resteasy this is what worked for me.
If you add something like this:
ResteasyContext.pushContext(StorageEngine.class, new StorageEngine());
into something like a jaxrs filter, it allows you to do something like this:
@GET
@Path("/some/path")
public Response someMethod(@Context StorageEngine myStorageEngine) {
...
}
This is specific to Resteasy, which doesn't have something like SingletonTypeInjectableProvider
.