Jersey 2.*. How to replace InjectableProvider and AbstractHttpContextInjectable of Jersey 1.* - java

I would like to create a class whose objects can be injected using the #Context annotation (or better yet a custom annotation for cases where I need to pass an argument to the annotation) into resource methods. In Jersey 1.* I would have used InjectableProvider (in my case together with AbstractHttpContextInjectable). What I'm trying to achieve is something like #Auth [1] from dropwizard (which uses Jersey 1.7).
The injection capabilities of Jersey were replaced by HK2 as far as I know and I could not find any example of what I'm describing.
Edit: See this question for further problems I have encountered while trying to follow Michal's guide.

You need to implement InjectionResolver<T> interface from HK2. Take a look at existing implementations that are present in Jersey workspace:
ContextInjectionResolver handling #Context
ParamInjectionResolver handling #PathParam, #QueryParam, ... (via it's subclasses)
AutowiredInjectResolver handling #Autowired
Once you have this, you need to extend AbstractBinder from HK2 and bind your InjectionResolver via it's #configure() method:
public class MyResolverBinder extends AbstractBinder {
#Override
protected void configure() {
bind(MyInjectionResolver.class)
.to(new TypeLiteral<InjectionResolver<MyAnnotation>>() {})
.in(Singleton.class);
}
}
... and register an instance of this binder in your application class (or via feature):
Feature:
public class MyFeature implements Feature {
#Override
public boolean configure(final FeatureContext context) {
context.register(new MyResolverBinder());
return true;
}
}
register MyFeature into Application:
public class JaxRsApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
final HashSet<Class<?>> classes = new HashSet<Class<?>>();
classes.add(MyFeature.class);
// Register other providers or resources.
return classes;
}
}
register MyResolverBinder or Feature in the ResourceConfig
new ResourceConfig()
// Register either MyFeature
.register(MyFeature.class)
// or MyResolverBinder
.register(new MyResolverBinder())
// Register other providers or resources
.packages("my.package");

Providing an implementation of InjectionResolver only helps with injection, not when resolving values for the parameters of a resource method.
At least with Jersey 2.11, you need to define a ValueFactoryProvider annotated with #Provider.
#Provider
public class MyValueFactoryProvider implements ValueFactoryProvider {
#Inject
private MyFactory factory;
#Override
public Factory<?> getValueFactory(Parameter parameter) {
if (parameter.getAnnotation(MyAnnotationParam.class) != null) {
return factory;
}
return null;
}
#Override
public PriorityType getPriority() {
return Priority.NORMAL;
}
}
If you also want to get the value injected in, e.g., members and constructor parameters, then InjectionResolver works well.

Related

How to make Jersey work with Dagger dependency injection?

Jersey normally uses HK2 dependency injection, but I would like to use Jersey with Dagger 2. Both Dagger and HK2 implement JSR 330, which I have taken as evidence that this should be possible without too much effort. I found ways to make Jersey work with CDI (e.g. Weld), Spring DI and Guice, but I can't find anything on Dagger.
To provide some context: I'm running a Grizzly–Jersey server in an SE environment, not in an EE container. My Maven project has com.google.dagger:dagger and org.glassfish.jersey.containers:jersey-container-grizzly2-http as dependencies, but not org.glassfish.jersey.inject:jersey-hk2, since I want to replace HK2 with Dagger.
The resource classes look like this:
#Path("/example")
public final class ExampleResource {
private final Dependency dependency;
#Inject
public ExampleResource(final Dependency dependency) {
this.dependency = Objects.requireNonNull(dependency);
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public Example getExample() {
return this.dependency.giveExample();
}
}
And the Dagger component could e.g. be defined as follows:
#Component
public interface Application {
public ExampleResource exampleEndpoint();
public XyzResource xyzEndpoint();
// etc.
}
So that the main method would look similar to:
public final class Main {
public static void main(final String[] args) {
final Application application = DaggerApplication.create();
final URI baseUri = UriBuilder.fromUri("http://0.0.0.0/").port(80).build();
final ResourceConfig resourceConfig = new ResourceConfig();
// how to initialize `resourceConfig` using `application`?
final HttpServer httpServer = GrizzlyHttpServerFactory
.createHttpServer(baseUri, resourceConfig, false);
try {
httpServer.start();
} catch (final IOException ex) {
...
}
}
}
Running the application immediately results in an exception: IllegalStateException: InjectionManagerFactory not found. It seems that a Dagger implementation of this factory is needed.
My question is: how to integrate Dagger with Jersey?
You shouldn't think of it as "how to integrate dagger with jersey". Figure out how to setup jersey, then once you have that figured out, then you can worry about using dagger.
Here's (very roughly) how I would do it.
Create your own implementation of the ResourceConfig class.
#ApplicationPath("/service")
public class MyResourceConfig extends ResourceConfig {
#Inject
public MyResourceConfig(
#Nonnull final ExampleResource exampleResource) {
this.register(exampleResource);
}
}
Then create a module that sets up everything you need to create an HttpServer
#Module
public class MyServiceModule {
#Provides
#Singleton
#Named("applicationPort")
public Integer applicationPort() {
return 80;
}
#Provides
#Singleton
#Named("applicationBaseUri")
public URI baseUri(
#Named("applicationPort") #Nonnull final Integer applicationPort) {
return UriBuilder.fromUri("http://0.0.0.0/").port(applicationPort).build();
};
#Provides
#Singleton
public HttpServer httpServer(
#Named("applicationBaseUri") #Nonnull final URI applicationBaseUri,
#Nonnull final MyResourceConfig myResourceConfig) {
return GrizzlyHttpServerFactory
.createHttpServer(applicationBaseUri, myResourceConfig, false);
}
}
Then create your component that exposes the HttpServer. I typically like to make components that expose as little as possible. In this case, all you need to expose is the HttpServer.
#Singleton
#Component(modules = { MyServiceModule.class })
protected interface ServiceComponent {
HttpServer httpServer();
#Component.Builder
interface Builder {
// Bind any parameters here...
ServiceComponent build();
}
}
Then just go ahead and build your component, and start your HttpServer
public static void main(String[] args) {
final ServiceComponent component = DaggerServiceComponent.builder().build()
try {
component.httpServer().start();
} catch (Exception ex) {
// handle exception...
}
}
One more thing to note. I personally do not ever use the #Named("") annotation. I prefer to use a Qualifier. So you create a Qualifier annotation with a unique value. Then you can inject things like
#Provides
#Singleton
#MyUniqueQualifier
public String myUniqueQualifierProviderValue() {
return "something";
}
Then when injecting it
#Inject
public SomeClass(#MyUniqueQualifier #Nonnull final String myUniqueQualifiedValue)
If you use the #Named annotation you don't get compile time checks for conflicts or missing values. You would find out at run time that a value was not injected or then name conflicts with something else. It gets messy quick.
You need to implement an InjectionManagerFactory that will return an InjectionManager delegating to Dagger and have it registered as a service by putting an entry in META-INF/services, similar to the hk2 one here:
https://github.com/jersey/jersey/blob/master/inject/hk2/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory
but referencing your own implementation.

Best way to override beans in Spring

I have an application that consists of 2 modules.
First of them is main one and it can work without second module installed.
I have beans with default implementation defined in beans.xml file of main module. And when installing second module I want to keep the ids of those beans but change the implementation to use new classes.
What is the best way to do that?
beans.xml of first module:
...
<bean id="myCoolService" class="com.blabla.defaultCoolServiceImpl">
...
and after the installation of second module I want to use the implementation of myCoolService that is defined in second module.
Upd:
Spring version is 3.2.4.
I need to make as little changes as possible so I need to continue using xml-driven configuration.
One way of doing this is introducing a common interface (I guess one should already be present):
public interface MyInterface {
//...
}
And then in the main module annotate the default implementation with #Service
#Service
public class DefaultImplementation implements MyInterface {
//...
}
Then, if one of your modules needs to override this implementation, use the #Primary-annotation:
#Service
#Primary
public class OverridingImplementation implements MyInterface {
//...
}
Then, the following code:
#Inject
private MyInterface myInterface;
will inject DefaultImplementation if OverridingImplementation is not scanned, and inject OverridingImplementation (without complaining about multiple beans) if it is scanned.
One way to achieve this is going through a proxy, that redirects to the proper implementation. The proxy would normally redirect to the default. It will redirect to module 2 if it is available.
To help the proxy figure out what is available, you may need to have
a member that always points to the default implementation using "name" property.
have a method to register a different bean as the alternate implementation.
For example
Inside MyProxy:
#Autowired
public void setDefaultWorker(Worker defaultWorker) {
this.defaultWorker = defaultWorker;
}
private Worker defaultWorker;
private Worker alternateWorker;
public void registerAlternateWorker(Worker alternateWorker) {
this.alternateWorker = alternateWorker;
}
//To use the worker
private Worker getWorker() {
return alternateWorker == null? defaultWorker : alternateWorker;
}
In Module 1, your default implementation bean should be declared as having the defaultWorker as name
<bean id="defaultWorker" class="MyDefaultWorkerImpl"/>
Module 2 can register itself to the proxy registry on startup using SmartLifeCycle.
if possible,use :
<bean id="myCoolService" class="${IMPL_CLASS_NAME}"/>
Define impl class in a property file.
IMPL_CLASS_NAME=com.blabla.SecondMduleCoolServiceImpl
OR other approach could be :
Lets say your defaultCoolServiceImpl and SecondMduleCoolServiceImpl implement ICoolService interface
You define these bean and an implementation of FactoryBean as below :
<bean id="mydefaultServiceimpl" class="com.blabla.defaultCoolServiceImpl">
<bean id="secondModuleCoolserviceimpl" class="com.blabla.SecondMduleCoolServiceImpl">
<bean id="myCoolService" class="com.blabla.ImplSelector"/>
public class ImplSelector implements FactoryBean<ICoolService>, ApplicationContextAware {
private ApplicationContext iApplicationContext;
// #Value("#{corePropertyConfigurer['defaultOrCool']}") you can injcet via property file.
private String defaultOrCool = "cool" ;
#Override
public ICoolService getObject() throws Exception {
if (StringUtils.equals(defaultOrCool, "default")) {
return iApplicationContext.getBean("mydefaultServiceimpl", ICoolService.class);
}
return iApplicationContext.getBean("secondModuleCoolserviceimpl", ICoolService.class);
}
#Override
public Class<?> getObjectType() {
return ICoolService.class;
}
#Override
public boolean isSingleton() {
return true;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
iApplicationContext = applicationContext;
}
}
Then you can access myCoolService via autowiring or applicationContext.getBean("myCoolService", ICoolService.class);

How to provide a default bean in Spring by condition?

I'd like to provide a default bean by a custom jar. Only if the user implements a specific abstract class the default bean injection should be skipped.
The following setup already works fine, except one thing: any injected classes within the default wired class are null! What might I be missing?
#Configration
public class AppConfig {
//use the default service if the user does not provide an own implementation
#Bean
#Conditional(MissingServiceBean.class)
public MyService myService() {
return new MyService() {};
}
}
#Component
public abstract class MyService {
#Autowired
private SomeOtherService other;
//default impl of the method, that may be overridden
public void run() {
System.out.println(other); //null! Why?
}
}
public class MissingServiceBean implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getBeanFactory().getBeansOfType(MyService.class).isEmpty();
}
}
The MyService bean is created and can also be injected. But contained classes are null.
If I remove the #Conditioanl annotation everything works as expected.
Your simplest possibility is the usage of the #Primary annotation. You define your interface/abstract class and build a default implementation. Until here thats the basic spring autowiring.
Now you create another implementation with #Primary and make it available in the application context. Spring will now pick up the primary implementation for the autowiring.
Another possibilty in Spring 4.1+ would be to autowire an ordered List<Intf> and ask the interface with a supports(...) call to fetch the current implementation for whatever parameter you give into supports. You give the default implementation a low priority and the more detailed ones a higher priority. Like this you can even build a more detailed default behavior. I'm using this approach for several configurations to handle different classes with default and specific implementations.
One example would be during permission evaluation where we have a default config for the base classes, another higher one for domain classes, and a even higher possible one for specific domain entities. The permission evaluator goes through the list and checks each implementation if it supports that class and delegates to the implementation in that case.
I dont have the code here but i could share it later if desired to make that more clear.
Change your code to the following:
public abstract class MyService {
private final SomeOtherService other;
public MyService(SomeOtherService other) {
this.other = other;
}
//default impl of the method, that may be overridden
public void run() {
System.out.println(other);
}
}
#Configration
public class AppConfig {
#Autowired
private SomeOtherService other;
//use the default service if the user does not provide an own implementation
#Bean
#Condition(MissingServiceBean.class)
public MyService myService() {
return new MyService(other) {};
}
}

How can I get resource annotations in a Jersey 2.4 filter?

My question is essentially the same as this one: How can I get resource annotations in a Jersey ContainerResponseFilter.
But I'm using Java Jersey 2.4 and can't find any sign of the ResourceFilterFactory or ResourceFilter classes. The documentation also doesn't mention them. Have they been deprecated or are they just really well hidden? If they've been deprecated, what can I use instead? Is there now a way with Jersey 2.4 and 2.5 to get the resource annotations from a ContainerRequestFilter?
Thanks
If you want to modify processing of a request based on annotations available on a resource method/class then I'd recommend using DynamicFeature from JAX-RS 2.0. Using DynamicFeatures you can assign specific providers for a subset of available resource methods. For example, consider I have a resource class like:
#Path("helloworld")
public class HelloWorldResource {
#GET
#Produces("text/plain")
public String getHello() {
return "Hello World!";
}
}
And I'd like to assign a ContainerRequestFilter to it. I'll create:
#Provider
public class MyDynamicFeature implements DynamicFeature {
#Override
public void configure(final ResourceInfo resourceInfo, final FeatureContext context) {
if ("HelloWorldResource".equals(resourceInfo.getResourceClass().getSimpleName())
&& "getHello".equals(resourceInfo.getResourceMethod().getName())) {
context.register(MyContainerRequestFilter.class);
}
}
}
And after registration (if you're using package scanning then you don't need to register it in case it has #Provider annotation on it) MyContainerRequestFilter will be associated with your resource method.
On the other hand you can always inject ResourceInfo in your filter (it can't be annotated with #PreMatching) and obtain the annotations from it:
#Provider
public class MyContainerRequestFilter implements ContainerRequestFilter {
#Context
private ResourceInfo resourceInfo;
#Override
public void filter(final ContainerRequestContext requestContext) throws IOException {
resourceInfo.getResourceMethod().getDeclaredAnnotations();
}
}

Hierarchical Dependencies with Guice

I'm trying to figure out the best practice for dealing with the following situation:
public class AppModule extends Module {
#Override
protected void configure() {
install(new JpaPersistModule("myJpaUnit").addFinder(Dao.class));
bind(MyJpaInitializer.class).asEagerSingleton();
}
#Provides
#IndicatesSomeConstantMap
#Singleton
Map<String, String> getMappings(Dao dao) {
ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<String, String>();
// Build map from Dao
return builder.build();
}
}
I need to inject #IndicatesSomeConstantMap in other classes. It seem the only way that getMappings can get the Dao is if I bind MyJpaInitializer as an EagerSingleton - which feels wrong. What's the preferred way of dealing with these hierarchical dependencies?
EDIT:
Based on the answer from #jeffcrowe I came up with something like:
public class Module1 extends PrivateModule {
#BindingAnnotation #Target({ FIELD, PARAMETER, METHOD }) #Retention(RUNTIME)
public #interface Jpa1{}
#Singleton
public static class JpaInitializer1 {
#Inject
public JpaInitializer1(#Jpa1 PersistService service) {
service.start();
}
}
public interface Finder1 {
#Finder(query="FROM Foo", returnAs = ArrayList.class)
List<Foo> getAll();
}
#Override
protected void configure() {
install(new JpaPersistModule("firstJpaUnit").addFinder(Finder1.class));
bind(JpaInitializer1.class);
}
#Provides
#Exposed
#Jpa1
PersistService getPersistService(Provider<PersistService> provider) {
return provider.get();
}
#Provides
#Exposed
#Jpa1
Finder1 getFinder(Finder1 finder, JpaInitializer1 init) {
return finder;
}
}
This handles the the dependency by wrapping it behind the provider and feels cleaner to me than using the eagerSingleton approach. This also hides the JpaModule behind a private module making it useful in a situation where multiple persistence modules are bound. The new problem is that since the Finder is already bound by the JpaPersistModule we have to add the #Jpa1 annotation to every injection of Finder1. Is there a way around that?
This is an interesting case. Normally in a scenario like this you could bind the initializer in normal Singleton scope and inject it into the Dao implementation, and this would ensure that it was done before the Dao was used. Due to the way the Jpa persistence modules are set up, there doesn't seem to be an easy way to add this dependency.
As the OP pointed out to me, JpaPersistModule is final, so we can't work around this by subclassing it. We can, however wrap the binder used to install the JpaPersistModule.
First wrap the binder in a proxy with an overridden the bind() method to intercept the EntityManager.class binding. (BinderProxy implements Binder and passes every call to the Binder given in it's constructor. Source available here)
new BinderProxy(binder()) {
#Override
public <T> AnnotatedBindingBuilder<T> bind(Class<T> clazz) {
if (clazz == EntityManager.class) {
return (AnnotatedBindingBuilder<T>) super.bind(clazz).annotatedWith(DefaultEntityManager.class);
} else {
return super.bind(clazz);
}
}
}.install(new JpaPersistModule("myJpaUnit"));
Then add a provides method to your module which ensures Jpa init before an EntityManager is used
#Provides EntityManager provideEm(MyJpaInitializer init, #DefaultEntityManager EntityManager em){
return em;
}

Categories