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.
Related
For the general setup I was following this tutorial. Now, in my guice module I would like to pass construct different Singletons based on the server configuration. The problem is that I can not get the configuration here. How could I achieve this?
public class ServerModule implements Module {
#Override
public void configure(Binder binder) {
}
#Provides
#Singleton
public AnInterface provideSingleton() {
return myServerConfiguration.isSomething()
? new SomeObject() : new SomeOtherObject();
}
}
If you read the tutorial carefully again, you will see how they are doing exactly this: by letting guice inject the configuration into the provides method.
Example copied from given link:
#Provides
#Named("message")
public String provideMessage(ServerConfiguration serverConfiguration) {
return serverConfiguration.getMessage();
}
I am trying to #Inject a Guice service into a #ServerEndpoint. I am using Tomcat 8.0.15 as the JSR-356 implementation. However, the dependency injection isn't working. Is there any additional configuration that needs to be done in order to enable Guice injection? Note that I am using all standard javax annotations only.
I figured this out. The Websocket endpoint needs to have a custom configurator, which creates and returns instances using the Guice injector instance.
Example:
Custom Guice servlet context listener:
public class CustomServletContextListener extends GuiceServletContextListener {
public static Injector injector;
#Override
protected Injector getInjector() {
injector = Guice.createInjector(...);
return injector;
}
}
Websockets custom configurator:
public class CustomConfigurator extends Configurator {
#Override
public <T> T getEndpointInstance(Class<T> clazz)
throws InstantiationException {
return CustomServletContextListener.injector.getInstance(clazz);
}
}
And then in the Websocket endpoint:
#ServerEndpoint(value = "/ws/sample_endpoint", configurator = CustomConfigurator.class)
public class SampleEndpoint {
private final SomeService service;
#Inject
public SampleEndpoint(SomeService service) {
this.service = service;
}
...
}
Building upon Aritra's own answer:
To be honest, I don't know for sure if this works with Guice 3.0, but it does work for 4.0, which is the current stable release.
I think a somewhat cleaner approach is to change your CustomConfigurator into something like this:
public class CustomConfigurator extends Configurator {
#Inject
private static Injector injector;
public <T> T getEndpointInstance(Class<T> endpointClass) {
return injector.getInstance(endpointClass);
}
}
And then from your extended ServletModule class' configureServlets method, call requestStaticInjection(CustomConfigurator.class)
That way you won't expose the injector to everyone. I don't know about you, but it gives me a nice and fuzzy feeling inside to know that no one will be able to mess with my injector :-).
I understand how to inject a single dependency using Google Guice.
The following snippets are from the Guice site.
To code a configuration the code would be
public class BillingModule extends AbstractModule {
#Override
protected void configure() {
bind(TransactionLog.class).to(DatabaseTransactionLog.class);
bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
}
}
The component which use the dependencies to be injected shuold looks like the following:
class BillingService {
private final CreditCardProcessor processor;
private final TransactionLog transactionLog;
#Inject
BillingService(CreditCardProcessor processor,
TransactionLog transactionLog) {
this.processor = processor;
this.transactionLog = transactionLog;
}
public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
...
}
}
FInally, the client code would use Guice to inject the dependencies where needed:
public static void main(String[] args) {
Injector injector = Guice.createInjector(new BillingModule());
BillingService billingService = injector.getInstance(BillingService.class);
...
}
My question is:
Is there a built-in feature in Guice to inject not only -for example- BillingService.class but another different implementation in runtime?
I think I can implement the variation of the different classes to be injected thru reflection or some manual mechanism like reading a configuration file to indicate which class to inject but I still want to know if this can be done from Guice itself.
You can make BillingService an interface and bind a different implementation of it decided in runtime in Module's configure method.
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.
We have a situation where we use JSR-330 based injections to configure our stand-alone Java 6 applications, which works very well for getting configuration parameters across all the layers.
We have also used JAX-WS web services for quite a while by using first stand-alone Metro distribution with Java 5 inside a web container, but with Java 6 we just use the Endpoint class to get a smaller footprint.
So now I have a situation where I have
A stand-alone Java 6 application - no servlet container (Jetty, Tomcat)
A Guice 3 Injector set up as I like it.
An Endpoint handling my #javax.jws.WebService annotated class which expose my methods as web services.
I would like the web service methods to either have their #Inject fields handled transparently, or to get access to the injector. I can grab it as a static field from the main method, but I'd like a cleaner solution.
Any suggestions?
(I understand from JAX-WS and Guice 3 that the http://jax-ws-commons.java.net/guice/ module does not work with Guice 3, and the workaround suggested is Tomcat specific)
Would JSR-250 #Resource annotations be useful here?
I'm not sure that I've understood every bit of the question. It looks to too easy for +500 bounty. Please post some code if that's not what you're searching for.
Anyway, a simple solution which creates a web service with dependency injection:
final Module module = new HelloModule();
final Injector injector = Guice.createInjector(module);
final HelloService helloService = injector.getInstance(HelloService.class);
Endpoint.publish("http://localhost:8080/helloService", helloService);
Below a more sophisticated solution with classpath scanning (Reflections) based on Marcus Eriksson's code from JAX-WS Guice integration. It publishes all classes which is annotated with #GuiceManaged as a webservice with Endpoint.publish().
private void initGuicedWebservices(final String packageNamePrefix)
throws Exception {
final Reflections reflections = new Reflections(packageNamePrefix);
final Set<Class<?>> guiceManaged =
reflections.getTypesAnnotatedWith(GuiceManaged.class);
for (final Class<?> clazz : guiceManaged) {
doGuice(clazz);
}
}
private void doGuice(final Class<?> clazz) throws Exception {
final GuiceManaged guiceManagedAnnotation =
clazz.getAnnotation(GuiceManaged.class);
final Injector injector = createInjector(guiceManagedAnnotation);
final Object serviceObject = clazz.newInstance();
injector.injectMembers(serviceObject);
final String address = guiceManagedAnnotation.address();
Endpoint.publish(address, serviceObject);
}
private Injector createInjector(final GuiceManaged guiceManagedAnnotation)
throws Exception {
final Class<? extends Module>[] moduleClasses =
guiceManagedAnnotation.module();
final List<Module> moduleInstances = new ArrayList<Module>();
for (final Class<? extends Module> moduleClass : moduleClasses) {
moduleInstances.add(moduleClass.newInstance());
}
return Guice.createInjector(moduleInstances);
}
The GuiceManaged annotation:
#Retention(RUNTIME)
#Target(TYPE)
#Documented
public #interface GuiceManaged {
public Class<? extends Module>[] module();
public String address();
}
And the HelloServiceImpl snippet:
#GuiceManaged(module = HelloModule.class,
address = "http://localhost:8080/helloService")
#WebService
public class HelloServiceImpl implements HelloService {
#Inject // bound in HelloModule
public GreetingsService greetingsService;
#Override
#WebMethod
public String sayHello(final String name) {
return greetingsService.sayHello(name);
}
}
you need to use the AbstractMultiInstanceResolver extension point.
create the annotation GuiceManaged;
#Retention(RUNTIME)
#Target(TYPE)
#Documented
#WebServiceFeatureAnnotation(id=GuiceManagedFeature.ID, bean=GuiceManagedFeature.class)
#InstanceResolverAnnotation(GuiceManagedInstanceResolver.class)
public #interface GuiceManaged {
}
implement the GuiceManagedFeature which is WebServiceFeature :
public class GuiceManagedFeature extends WebServiceFeature {
public static final String ID="FEATURE_GuiceManaged";
#FeatureConstructor
public GuiceManagedFeature()
{
this.enabled=true;
}
public String getID() {
return ID;
}
}
Implement InstanceResolver by Extending AbstractMultiInstanceResolver
public class GuiceManagedInstanceResolver extends AbstractMultiInstanceResolver {
private T instance=null;
public GuiceManagedInstanceResolver(#NotNull Class clazz)
{
super(clazz);
}
public T resolve(#NotNull Packet request) {
if(instance==null)
{
instance=create();
Injector injector= Guice.createInjector(new WebServiceModule());
injector.injectMembers(instance);
}
return instance;
}
}
Now Annotate your Service with #GuiceManaged & use #Inject for method level DI on your business method.