I am trying to inject a object provided by HK2 Factory service in a Jersey Test Class but getting unsatisfied dependencies exception.
I have a factory service as below
public class TestFactory implements Factory<TestObject>{
private final CloseableService closeService;
#Inject
public TestFactory(CloseableService closeService) {
this.closeService = closeService;
}
#Override
public TestObject provide() {
TestObject casualObject = new TestObject();
this.closeService.add(() -> dispose(casualObject));
return casualObject;
}
#Override
public void dispose(TestObject instance) {
instance.destroy();
}
}
And a Jersey Test class
public class SampleTestCass extends JerseyTestNg.ContainerPerClassTest
{
//#Inject
private TestObject myTestObject;
private ServiceLocator locator;
#Override
protected Application configure()
{
ResourceConfig resConfig = new ResourceConfig(MyApi.class);
resConfig.register(getBinder());
locator = setupHK2(getBinder());
return resConfig;
}
// setup local hk2
public setupHK2(AbstractBinder binder)
{
ServiceLocatorFactory factory = ServiceLocatorFactory.getInstance();
ServiceLocator locator = factory.create("test-locator");
DynamicConfigurationService dcs = locator.getService(DynamicConfigurationService.class);
DynamicConfiguration dc = dcs.createDynamicConfiguration();
locator.inject(binder);
binder.bind(dc);
dc.commit();
return locator;
}
// get the binder
public AbstractBinder getBinder()
{
return new AbstractBinder() {
#Override
protected void configure() {
bindFactory(TestFactory.class, Singleton.class).to(TestObject.class).in(PerLookup.class);
}
}
}
#BeforeClass
public void beforeClass()
{
myTestObject = locator.getService(TestObject.class);
// use myTestObject
}
#AfterClass
public void afterClass()
{
if (locator != null) {
locator.shutdown();
}
}
#Test()
public void someTest()
{
// some test code...
}
}
And getting below exceptions
A MultiException has 3 exceptions. They are:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=CloseableService,parent=TestFactory,qualifiers={},position=0,optional=false,self=false,unqualified=null,2053349061)
java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.test.factories.TestFactory errors were found
java.lang.IllegalStateException: Unable to perform operation: resolve on com.test.factories.TestFactory
CloseableService is a service available within a Jersey application. The ServiceLocator you created is not tied to the Jersey application. It is just a standalone locator. So trying to register the TestFactory with this locator will cause it to fail, as there is no CloseableService. The one that you registered with the ResourceConfig will work just fine.
Not sure what exactly you're trying to do, but if you want access to the service inside the test, one thing you can do is just bind the service as an instance, something like
class MyTest {
private Service service;
#Override
public ResourceConfig configure() {
service = new Service();
return new ResourceConfig()
.register(new AbstractBinder() {
#Override
public void configure() {
bind(service).to(Service.class);
}
})
}
}
Related
I want to use Guava's Service Manager to manage services in my Dropwizard application.
ServiceManagerProvider provides the service manager:
#Singleton
public class ServiceManagerProvider implements Provider<ServiceManager> {
#Inject
Set<Service> services;
public static Multibinder<Service> serviceRegistry(Binder binder) {
return Multibinder.newSetBinder(binder, Service.class);
}
#Override
public ServiceManager get() {
return new ServiceManager(services);
}
}
ManagedGuavaServices is a Managed object that interacts with the Service Manager to start/stop services:
public class ManagedGuavaServices implements Managed {
#Inject
private ServiceManager _serviceManager;
#Inject
public ManagedGuavaServices(ServiceManager serviceManager) {
_serviceManager = serviceManager;
}
#Override
public void start() throws Exception {
_serviceManager.startAsync();
}
#Override
public void stop() throws Exception {
_serviceManager.stopAsync();
}
}
MyModule is the module where the Guice bindings are specified:
public class MyModule extends DropwizardAwareModule<MyConfig> {
...
#Override
protected void configure() {
bind(ServiceManager.class).toProvider(ServiceManagerProvider.class);
bind(Managed.class).to(ManagedGuavaServices.class).in(Singleton.class);
}
}
And MyApplication is the Dropwizard application that depends on MyModule:
public class MyApplication extends Application<MyConfig> {
#Inject
private Managed managedServices;
...
#Override
public void initialize(Bootstrap<MyConfig> bootstrap) {
bootstrap.addBundle(GuiceBundle.builder()
.printDiagnosticInfo()
.printGuiceBindings()
.enableAutoConfig(getClass().getPackage().getName())
.modules(
new MyModule()
)
.build());
}
...
#Override
public void run(MyConfig config, Environment environment) {
environment.lifecycle().manage(managedServices);
}
}
It seems like everything has been wired together, but when I run the application, I get the error message:
java.lang.NullPointerException
at java.base/java.util.Objects.requireNonNull(Objects.java:221)
at io.dropwizard.lifecycle.setup.LifecycleEnvironment.manage(LifecycleEnvironment.java:45)
at com.example.MyApplication.run(MyApplication.java:188)
at com.example.MyApplication.run(MyApplication.java:60)
at io.dropwizard.cli.EnvironmentCommand.run(EnvironmentCommand.java:44)
at io.dropwizard.cli.ConfiguredCommand.run(ConfiguredCommand.java:87)
at io.dropwizard.cli.Cli.run(Cli.java:78)
at io.dropwizard.Application.run(Application.java:94)
at com.example.MyApplication.main(MyApplication.java:70)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.webobjects._bootstrap.WOBootstrap.main(WOBootstrap.java:118)
which essentially means that the injected managedServices in MZPaymentApplication is null when the application is run.
What is wrong here? Is it the same problem as in this SO question? If so, where should the #PostConstruct be?
The problem is in managedServices being field in Application and not injectable, since app object is not configured by Guice (usually in Dropwizard it is created via new keyword).
So you should store your GuiceBundle instance in initialize method as field and then access any Guice binding in run method with guiceBundle.getInjector().getInstance(), e.g.:
public class MyApplication extends Application<MyConfig> {
private GuiceBundle<MyConfig> guiceBundle;
public static void main(String[] args) throws Exception {
new MyApplication().run(args);
}
#Override
public void initialize(Bootstrap<MyConfig> bootstrap) {
guiceBundle = GuiceBundle.builder()
.printDiagnosticInfo()
.printGuiceBindings()
.enableAutoConfig(getClass().getPackage().getName())
.modules(
new MyModule()
)
.build();
bootstrap.addBundle(guiceBundle);
}
#Override
public void run(MyConfig config, Environment environment) throws Exception {
environment.lifecycle().manage(guiceBundle.getInjector().getInstance(Managed.class));
}
}
I have the following classes:
public FooDAO extends AbstractDAO<Foo> { // Dropwizard DAO
#Inject FooDAO(SessionFactory sf) { super(sf); }
public void foo() { /* use SessionFactory */ }
}
public class FooService {
private final FooDAO fooDAO; // Constructor-injected dependency
#Inject FooService (FooDAO fooDAO) { this.fooDAO = fooDAO; }
#UnitOfWork
public void foo() {
this.fooDAO.foo();
System.out.println("I went through FooService.foo()");
}
}
Now, FooService is not a resource, so Dropwizard doesn't know about it and doesn't automagically proxy it. However the smart guys at Dropwizard made it so I can get a proxy through UnitOfWorkAwareProxyFactory.
I tried doing feeding these proxies to Guice with an interceptor, but I faced an issue because UnitOfWorkAwareProxyFactory only ever creates new instances and never lets me pass existing objects. The thing with new instances is that I don't know the parameters to give it since they're injected by Guice.
How do I create #UnitOfWork-aware proxies of existing objects?
Here's the interceptor I've made so far:
public class UnitOfWorkModule extends AbstractModule {
#Override protected void configure() {
UnitOfWorkInterceptor interceptor = new UnitOfWorkInterceptor();
bindInterceptor(Matchers.any(), Matchers.annotatedWith(UnitOfWork.class), interceptor);
requestInjection(interceptor);
}
private static class UnitOfWorkInterceptor implements MethodInterceptor {
#Inject UnitOfWorkAwareProxyFactory proxyFactory;
Map<Object, Object> proxies = new IdentityHashMap<>();
#Override public Object invoke(MethodInvocation mi) throws Throwable {
Object target = proxies.computeIfAbsent(mi.getThis(), x -> createProxy(mi));
Method method = mi.getMethod();
Object[] arguments = mi.getArguments();
return method.invoke(target, arguments);
}
Object createProxy(MethodInvocation mi) {
// here, what to do? proxyFactory will only provide objects where I pass constructor arguments, but... I don't have those!
}
}
}
Of course, if Dropwizard (or Guice) offers me a simpler way to do so, which is it?
As from Dropwizard 1.1: (not yet released, as of August 10, 2016)
public class UnitOfWorkModule extends AbstractModule {
#Override
protected void configure() {
UnitOfWorkInterceptor interceptor = new UnitOfWorkInterceptor();
bindInterceptor(Matchers.any(), Matchers.annotatedWith(UnitOfWork.class), interceptor);
requestInjection(interceptor);
}
#Provides
#Singleton
UnitOfWorkAwareProxyFactory provideUnitOfWorkAwareProxyFactory(HibernateBundle<AlexandriaConfiguration> hibernateBundle) {
return new UnitOfWorkAwareProxyFactory(hibernateBundle);
}
private static class UnitOfWorkInterceptor implements MethodInterceptor {
#Inject
UnitOfWorkAwareProxyFactory proxyFactory;
#Override
public Object invoke(MethodInvocation mi) throws Throwable {
UnitOfWorkAspect aspect = proxyFactory.newAspect();
try {
aspect.beforeStart(mi.getMethod().getAnnotation(UnitOfWork.class));
Object result = mi.proceed();
aspect.afterEnd();
return result;
} catch (InvocationTargetException e) {
aspect.onError();
throw e.getCause();
} catch (Exception e) {
aspect.onError();
throw e;
} finally {
aspect.onFinish();
}
}
}
}
I have a Jersey resource with a facade object injected. This is configured in my ResourceConfig and the facade gets injected fine. The facade contains a DAO class which also should be injected and is configured in the same ResourceConfig. Now to my problem; the DAO class is null. Thus, not injected.
#ApplicationPath("/service")
public class SystemSetup extends ResourceConfig {
public SystemSetup() {
packages(false, "com.foo.bar");
packages("org.glassfish.jersey.jackson");
register(JacksonFeature.class);
final LockManager manager = getLockManager();
final SessionFactory sessionFactory = getSessionFactory();
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(InjectFactory.getDaoFactory(sessionFactory)).to(Dao.class).in(Singleton.class);
bindFactory(InjectFactory.getFacadeFactory(manager)).to(Facade.class).in(Singleton.class);
}
});
}
#Path("/")
#Produces("text/json")
public class ViewResource {
#Inject
private Facade logic;
public class Facade {
#Inject
private Dao dao; //Not injected
The factory instances are rather simple. They simply call the constructor and pass the argument to it.
The strange thing is that this worked absolut fine when I used bind(Class object) rather than bindFactory.
EDIT
Factories
class InjectFactory {
static Factory<Dao> getDaoFactory() {
return new Factory<Dao>() {
#Override
public Dao provide() {
return new Dao(new Object());
}
#Override
public void dispose(Dao dao) {}
};
}
static Factory<Facade> getFacadeFactory() {
return new Factory<Facade>() {
#Override
public Facade provide() {
return new Facade();
}
#Override
public void dispose(Facade facade) {}
};
}
}
As is the case with most Di frameworks, when you start instantiating things yourself, it's often the case that you are kicking the framework out of the equation. This holds true for the Factory instances, as well as the objects the factory creates. So the Facade instance never gets touch by the framework, except to inject it into the resource class.
You can can a hold of the ServiceLocator, and explicitly inject objects yourself if you want to create them yourself. Here are a couple options.
1) Inject the ServiceLocator into the Factory instance, then inject the Facade instance.
static Factory<Facade> getFacadeFactory() {
return new Factory<Facade>() {
#Context
ServiceLocator locator;
#Override
public Facade provide() {
Facade facade = new Facade();
locator.inject(facade);
return facade;
}
#Override
public void dispose(Facade facade) {}
};
}
#Inject
public SystemSetup(ServiceLocator locator) {
packages("foo.bar.rest");
packages("org.glassfish.jersey.jackson");
register(JacksonFeature.class);
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(InjectFactory.getDaoFactory()).to(Dao.class);
Factory<Facade> factory = InjectFactory.getFacadeFactory();
locator.inject(factory);
bindFactory(factory).to(Facade.class);
}
});
}
2) Or bind a Factory class, and let the framework inject the ServiceLocator
public static class FacadeFactory implements Factory<Facade> {
#Context
ServiceLocator locator;
#Override
public Facade provide() {
Facade facade = new Facade();
locator.inject(facade);
return facade;
}
#Override
public void dispose(Facade facade) {}
}
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(InjectFactory.getDaoFactory()).to(Dao.class);
bindFactory(InjectFactory.FacadeFactory.class).to(Facade.class);
}
});
I have a Jersey resource with a facade object injected. This is configured in my ResourceConfig and the facade gets injected fine. The facade contains a DAO class which also should be injected and is configured in the same ResourceConfig. Now to my problem; the DAO class is null. Thus, not injected.
#ApplicationPath("/service")
public class SystemSetup extends ResourceConfig {
public SystemSetup() {
packages(false, "com.foo.bar");
packages("org.glassfish.jersey.jackson");
register(JacksonFeature.class);
final LockManager manager = getLockManager();
final SessionFactory sessionFactory = getSessionFactory();
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(InjectFactory.getDaoFactory(sessionFactory)).to(Dao.class).in(Singleton.class);
bindFactory(InjectFactory.getFacadeFactory(manager)).to(Facade.class).in(Singleton.class);
}
});
}
#Path("/")
#Produces("text/json")
public class ViewResource {
#Inject
private Facade logic;
public class Facade {
#Inject
private Dao dao; //Not injected
The factory instances are rather simple. They simply call the constructor and pass the argument to it.
The strange thing is that this worked absolut fine when I used bind(Class object) rather than bindFactory.
EDIT
Factories
class InjectFactory {
static Factory<Dao> getDaoFactory() {
return new Factory<Dao>() {
#Override
public Dao provide() {
return new Dao(new Object());
}
#Override
public void dispose(Dao dao) {}
};
}
static Factory<Facade> getFacadeFactory() {
return new Factory<Facade>() {
#Override
public Facade provide() {
return new Facade();
}
#Override
public void dispose(Facade facade) {}
};
}
}
As is the case with most Di frameworks, when you start instantiating things yourself, it's often the case that you are kicking the framework out of the equation. This holds true for the Factory instances, as well as the objects the factory creates. So the Facade instance never gets touch by the framework, except to inject it into the resource class.
You can can a hold of the ServiceLocator, and explicitly inject objects yourself if you want to create them yourself. Here are a couple options.
1) Inject the ServiceLocator into the Factory instance, then inject the Facade instance.
static Factory<Facade> getFacadeFactory() {
return new Factory<Facade>() {
#Context
ServiceLocator locator;
#Override
public Facade provide() {
Facade facade = new Facade();
locator.inject(facade);
return facade;
}
#Override
public void dispose(Facade facade) {}
};
}
#Inject
public SystemSetup(ServiceLocator locator) {
packages("foo.bar.rest");
packages("org.glassfish.jersey.jackson");
register(JacksonFeature.class);
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(InjectFactory.getDaoFactory()).to(Dao.class);
Factory<Facade> factory = InjectFactory.getFacadeFactory();
locator.inject(factory);
bindFactory(factory).to(Facade.class);
}
});
}
2) Or bind a Factory class, and let the framework inject the ServiceLocator
public static class FacadeFactory implements Factory<Facade> {
#Context
ServiceLocator locator;
#Override
public Facade provide() {
Facade facade = new Facade();
locator.inject(facade);
return facade;
}
#Override
public void dispose(Facade facade) {}
}
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(InjectFactory.getDaoFactory()).to(Dao.class);
bindFactory(InjectFactory.FacadeFactory.class).to(Facade.class);
}
});
I am trying to inject an Interceptor with a Vaadin Application instance created by Guice.
I've followed the documentation for Vaadin-Guice integration in the Vaadin Wiki and
the documenation on Interceptor DI in the Guice Wiki:
public class RecruitmentServletConfig extends GuiceServletContextListener {
#Override
protected Injector getInjector() {
ServletModule servletModule = new ServletModule() {
#Override
protected void configureServlets() {
...
bind(Application.class).to(RecruitmentApplication.class).in(ServletScopes.SESSION);
SecurityGuard securityGuard = new SecurityGuard();
requestInjection(securityGuard);
bindInterceptor(Matchers.subclassesOf(CustomComponent.class), Matchers.annotatedWith(AllowedRoles.class), securityGuard);
}
};
return Guice.createInjector(servletModule);
}
}
The SecurityGuard interceptor:
public class SecurityGuard implements MethodInterceptor {
#Inject private Application application;
public Object invoke(MethodInvocation invocation) throws Throwable {
AllowedRoles allowedRoles = invocation.getMethod().getAnnotation(AllowedRoles.class);
if (((User) application.getUser()).hasRole(allowedRoles.value())) {
return invocation.proceed();
} else {
return null;
}
}
However, I get an OutOfScopeException on server startup:
SEVERE: Exception sending context initialized event to listener instance of class de.embl.eicat.recruit.ioc.RecruitmentServletConfig
com.google.inject.CreationException: Guice creation errors:
1) Error in custom provider, com.google.inject.OutOfScopeException: Cannot access scoped object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.
at recruit.ioc.RecruitmentServletConfig$1.configureServlets(RecruitmentServletConfig.java:86)
Does it work if you wrap your Application in a Provider?
public class SecurityGuard implements MethodInterceptor {
#Inject private Provider<Application> application;
public Object invoke(MethodInvocation invocation) throws Throwable {
AllowedRoles allowedRoles = invocation.getMethod().getAnnotation(AllowedRoles.class);
if (((User) application.get().getUser()).hasRole(allowedRoles.value())) {
return invocation.proceed();
} else {
return null;
}
}