Skip to content

Instantly share code, notes, and snippets.

@mdonkers
Created October 15, 2013 12:34
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mdonkers/a48bfeef62d979412861 to your computer and use it in GitHub Desktop.
Save mdonkers/a48bfeef62d979412861 to your computer and use it in GitHub Desktop.
Jersey 2 custom injection of method parameters (incl Spring integration)
/**
* Annotation for injecting {@link Identity} objects into Jersey Resource implementations Use annotation
* for fields, method parameter or method based injection.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
public @interface IdentityParam {
}
/**
* Class to take {@link Identity} object from the Http Request attributes and make sure it can be
* automatically injected in resources.
*/
@Singleton
final class IdentityParamValueFactoryProvider extends AbstractValueFactoryProvider {
/**
* Injection resolver for {@link IdentityParam} annotation. Will create a Factory Provider for
* the actual resolving of the {@link Identity} object.
*/
@Singleton
static final class InjectionResolver extends ParamInjectionResolver<IdentityParam> {
/**
* Create new {@link IdentityParam} annotation injection resolver.
*/
public InjectionResolver() {
super(IdentityParamValueFactoryProvider.class);
}
}
/**
* Factory implementation for resolving request-based attributes and other information.
*/
private static final class IdentityParamValueFactory extends AbstractContainerRequestValueFactory<Identity> {
@Context
private ResourceContext context;
/**
* Fetch the Identity object from the request. Since HttpServletRequest is not directly available, we need to get it via
* the injected {@link ResourceContext}.
*
* @return {@link Identity} stored on the request, or NULL if no object was found.
*/
public Identity provide() {
final HttpServletRequest request = context.getResource(HttpServletRequest.class);
final Identity identity = (Identity) request.getAttribute(IDENTITY_ATTRIBUTE);
return identity;
}
}
/**
* {@link IdentityParam} annotation value factory provider injection constructor.
*
* @param mpep
* multivalued parameter extractor provider.
* @param injector
* injector instance.
*/
@Inject
public IdentityParamValueFactoryProvider(MultivaluedParameterExtractorProvider mpep, ServiceLocator injector) {
super(mpep, injector, Parameter.Source.UNKNOWN);
}
/**
* Return a factory for the provided parameter. We only expect {@link Identity} objects being annotated with
* {@link IdentityParam} annotation
*
* @param parameter
* Parameter that was annotated for being injected
* @return {@link IdentityParamValueFactory} if parameter matched {@link Identity} type
*/
@Override
public AbstractContainerRequestValueFactory<?> createValueFactory(Parameter parameter) {
Class<?> classType = parameter.getRawType();
if (classType == null || (!classType.equals(Identity.class))) {
LOG.warn("IdentityParam annotation was not placed on correct object type; Injection might not work correctly!");
return null;
}
return new IdentityParamValueFactory();
}
}
/**
* Jersey Controller for handling REST calls.
*/
@Produces({ MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_JSON })
@Path("/")
public class MyResource {
@GET
public Response getSomeValue(@IdentityParam final Identity identity) {
// Do work and return something
return Response.status(OK).entity(myValue).build();
}
}
/**
* {@link ResourceConfig} instance class for configuration of Jersey 2.x specific settings. Class should be loaded by
* applications (next to Spring configuration) from the web.xml.
*/
public class RestResourceConfig extends ResourceConfig {
/**
* Internal {@link AbstractBinder} implementation to register our needed bindings for injecting parameters.
*/
private static final class InjectionBinder extends AbstractBinder {
/**
* Implement to provide binding definitions using the exposed binding methods.
*/
@Override
protected void configure() {
bind(IdentityParamValueFactoryProvider.class).to(ValueFactoryProvider.class).in(Singleton.class);
bind(IdentityParamValueFactoryProvider.InjectionResolver.class).to(
new TypeLiteral<InjectionResolver<IdentityParam>>() {
}).in(Singleton.class);
}
}
/**
* Constructor, used to setup all bindings for the HK2 DI service, so that we can inject our own objects. Register all classes
* that provide certain Jersey features. E.g. the {@link JacksonFeature} must be loaded to enable Jackson object mapping to
* JSON
*/
public RestResourceConfig() {
LOG.debug("====> Registering features and injection providers ====");
// Register all general provider classes (annotated with @provider)
packages("nl.codecentric.rest.providers");
// Register the Jackson object mapper
register(JacksonFeature.class);
// Register injection bindings, InjectionBinder needs to be instantiated for some reason
register(new InjectionBinder());
}
}
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>nl.codecentric.rest.providers.RestResourceConfig</param-value>
</init-param>
<init-param>
<!-- Package that is being scanned for resources (interface) -->
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
nl.codecentric.app.resources
</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment