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();
}
}
}
}
Related
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);
}
});
As of right now in order to inject an object of type Foo into Bar I do the following.
Class to be injected into:
class Bar {
#Inject
Foo field;
public Foo getField() { return field; }
}
Code implementing Factory:
public class Foo implements Factory<Foo> {
#Override
public Foo provide() {
return new Foo();
}
#Override
public void dispose(Foo f) {
}
}
Code in Main Configuration:
final ResourceConfig rc = new ResourceConfig()
.packages("com.example")
.register(
new AbstractBinder() {
#Override
protected void configure() {
bindFactory(new FooFactory()).to(Foo.class).in(Singleton.class);
}
})
My question is... In Jersey 2.0 which uses hk2 for dependency injection is there anyway to inject an object without creating a factory class?
It is possible to use an AbstractBinder for injection binding without a Factory or an InjectionResolver.
register(new AbstractBinder() {
#Override
protected void configure() {
bind(Foo.class).to(Foo.class);
bind(Bar.class).to(Bar.class);
}
});
In this case the classes Foo and Bar have empty constructors.
public class Bar {
#Inject
Foo field;
public Foo getField() { return field; }
}
public class Foo {}
Now you can inject Bar into a resource or other hk2 beans.
Description
Using the vlcj component, the custom component appears as a result of the AOP proxy object null.
MediaList Class
public class MediaList {
private libvlc_media_list_t mediaListInstance;
public MediaList(LibVlc libvlc, libvlc_instance_t instance, libvlc_media_list_t mediaListInstance) {
this.libvlc = libvlc;
this.instance = instance;
createInstance(mediaListInstance);
}
private void createInstance(libvlc_media_list_t mediaListInstance) {
logger.debug("createInstance()");
if(mediaListInstance == null) {
mediaListInstance = libvlc.libvlc_media_list_new(instance);
}
else {
libvlc.libvlc_media_list_retain(mediaListInstance);
}
this.mediaListInstance = mediaListInstance; // <- assignment
logger.debug("mediaListInstance={}", mediaListInstance);
mediaListEventManager = libvlc.libvlc_media_list_event_manager(mediaListInstance);
logger.debug("mediaListEventManager={}", mediaListEventManager);
registerEventListener();
}
public final libvlc_media_list_t mediaListInstance() {
return mediaListInstance; // <- proxy object return null, if use aop
}
}
Custom MediaList Class
public class TestMediaList extends MediaList {
public TestMediaList(LibVlc libvlc, libvlc_instance_t instance) {
super(libvlc, instance);
}
public void xTest(String test){
System.out.println(test);
}
}
Spring Configuration Class
#Configuration
public class PlayerBeanConfig {
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
#Resource
public TestMediaList testMediaList(LibVlc libvlc, libvlc_instance_t instance) {
return new TestMediaList(libvlc, instance);
}
}
AOP Configuration Class
#Aspect
public class MediaListAspect {
#Pointcut("execution(* TestMediaList.xTest(..))")
private void anyMethod() {
}
#Around("anyMethod()")
public Object lockAndUnlock(ProceedingJoinPoint joinPoint) throws Throwable {
Object object = joinPoint.proceed();
return object;
}
}
Test Code
public static void main(String[] args) {
boolean b = new NativeDiscovery().discover();
if (b) {
springContext = new AnnotationConfigApplicationContext(PlayerBeanConfig.class);
String[] kkk = new String[]{};
TestMediaList list = springContext.
getBean(TestMediaList.class, LibVlc.INSTANCE, LibVlc.INSTANCE.libvlc_new(kkk.length, kkk));
System.out.println(list.mediaListInstance()); // <- proxy object return null
} else {
logger.error("Cannot find vlc lib, exit application");
}
}
I try to single step tracking, when TestMediaList the build is complete. MediaListInstance () of the method to return to normal values, but when the spring returns to the proxy object, null is returned. At the same time, I also try to return the value correctly if you don't use AOP.
Therefore, I determine the basic problem in AOP dynamic proxy, but I don't know why, did not previously encountered such a situation.
Minimal example
all class in package : vod.demo
TargetClass
public class TargetClass {
private String returnValue;
public TargetClass() {
this.returnValue = "Hello World";
}
public final String test() {
System.out.println("TargetClass.test();");
return returnValue;
}
}
Aspect Class
#Aspect
public class AspectClass {
#Pointcut("execution(* vod.demo.TargetClass.*(..))")
private void targetMethod() {
}
#Around("targetMethod()")
public Object aroundTarget(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("AspectClass.aroundTarget();");
return joinPoint.proceed();
}
}
Spring Config Class
#Configuration
#EnableAspectJAutoProxy
#Import(AspectClass.class)
public class SpringConfig {
#Bean
public TargetClass target() {
return new TargetClass();
}
}
Client Class
public class Client {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
TargetClass target = context.getBean(TargetClass.class);
System.out.println("Client invoke:" + target.test()); // <- output null
}
}
This is a combination of potentially unexpected behaviors. First, Spring uses CGLIB to proxy your beans for AOP. CGLIB proxies are instances of a dynamic subtype of your class that delegate all method calls to a real instance of your class. However, even though the proxy is of a subtype, its fields are not initialized (ie. your TargetClass super constructor is not invoked). A lengthier explanation can be found here.
Additionally, your method
public final libvlc_media_list_t mediaListInstance() {
return mediaListInstance; // <- proxy object return null, if use aop
}
or
public final String test() {
System.out.println("TargetClass.test();");
return returnValue;
}
are final. CGLIB therefore cannot override them to delegate to the real instance. This would be hinted at in Spring logs. For example, you would see
22:35:31.773 [main] INFO o.s.aop.framework.CglibAopProxy - Unable to proxy method [public final java.lang.String com.example.root.TargetClass.test()] because it is final: All calls to this method via a proxy will NOT be routed to the target instance.
Put all of the above together and you get a proxy instance where the field is null and where the proxy cannot delegate to the real instance's method. So your code will actually invoke
public final String test() {
System.out.println("TargetClass.test();");
return returnValue;
}
for an instance where the returnValue field is null.
If you can, change your method, remove the final modifier. If you can't, you'll have to rethink your design.
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);
}
});
Im trying to configure hibernatebundle with guice/dropwizard and need help.
Im using hubspot / dropwizard-guice / 0.7.0 3rd party library in addition to dropwizard lib.
The code below obviously wont work and need help on figuring it out. How do I rewrite this so that hibernatebundle and ultimately, session factory, be auto injected to whatever bean that needs it.
MyApplication.java
public class MyApplication extends Application<MyAppConfiguration> {
private final HibernateBundle<MyAppConfiguration> hibernateBundle = new HibernateBundle<MyAppConfiguration>(MyModel.class) {
#Override
public DataSourceFactory getDataSourceFactory(MyAppConfiguration configuration) {
return configuration.getDataSourceFactory();
}
};
#Override
public void initialize(Bootstrap<MyAppConfiguration> bootstrap) {
bootstrap.addBundle(hibernateBundle); // ???
bootstrap.addBundle(
GuiceBundle.<MyAppConfiguration>newBuilder()
.addModule(new MyAppModule())
.enableAutoConfig(getClass().getPackage().getName())
.setConfigClass(MyAppConfiguration.class)
.build()
);
}
}
MyAppModule.java
public class MyAppModule extends AbstractModule {
#Provides
public SessionFactory provideSessionFactory(MyAppConfiguration configuration) {
// really wrong as it creates new instance everytime.
return configuration.getHibernateBundle().getSessionFactory(); // ???
}
}
MyAppConfiguration.java
public class MyAppConfiguration extends Configuration {
#Valid
#NotNull
private DataSourceFactory database = new DataSourceFactory();
#JsonProperty("database")
public DataSourceFactory getDataSourceFactory() {
return database;
}
#JsonProperty("database")
public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
this.database = dataSourceFactory;
}
// ???
public HibernateBundle<MyAppConfiguration> getHibernateBundle() {
return new HibernateBundle<MyAppConfiguration>(MyModel.class) {
#Override
public DataSourceFactory getDataSourceFactory(MyAppConfiguration configuration) {
return database;
}
};
}
}
Here is how I end up doing. I never got an answer from here or mailing list so I would consider this hackish and probably not the proper way to do it but it works for me.
In my module (that extends abstractmodule) :
private final HibernateBundle<MyConfiguration> hibernateBundle =
new HibernateBundle<MyConfiguration>(MyModel.class) {
#Override
public DataSourceFactory getDataSourceFactory(MyConfiguration configuration) {
return configuration.getDataSourceFactory();
}
};
#Provides
public SessionFactory provideSessionFactory(MyConfiguration configuration,
Environment environment) {
SessionFactory sf = hibernateBundle.getSessionFactory();
if (sf == null) {
try {
hibernateBundle.run(configuration, environment);
} catch (Exception e) {
logger.error("Unable to run hibernatebundle");
}
}
return hibernateBundle.getSessionFactory();
}
revised:
public SessionFactory provideSessionFactory(MyConfiguration configuration,
Environment environment) {
SessionFactory sf = hibernateBundle.getSessionFactory();
if (sf == null) {
try {
hibernateBundle.run(configuration, environment);
return hibernateBundle.getSessionFactory();
} catch (Exception e) {
logger.error("Unable to run hibernatebundle");
}
} else {
return sf;
}
}
I thought the explicit run(configuration, environment) call (in the answer provided by #StephenNYC) was a bit weird so a digged a little deeper. I found out that AutoConfig in dropwizard-guice wasn't setting up ConfiguredBundle's correctly (HibernateBundle is such a type).
As of https://github.com/HubSpot/dropwizard-guice/pull/35 the code can now look like this instead:
#Singleton
public class MyHibernateBundle extends HibernateBundle<NoxboxConfiguration> implements ConfiguredBundle<MyConfiguration>
{
public MyHibernateBundle()
{
super(myDbEntities(), new SessionFactoryFactory());
}
private static ImmutableList<Class<?>> myDbEntities()
{
Reflections reflections = new Reflections("com.acme");
ImmutableList<Class<?>> entities = ImmutableList.copyOf(reflections.getTypesAnnotatedWith(Entity.class));
return entities;
}
#Override
public DataSourceFactory getDataSourceFactory(NoxboxConfiguration configuration)
{
return configuration.getMyDb();
}
}
#Provides
public SessionFactory sessionFactory(MyHibernateBundle hibernate)
{
return checkNotNull(hibernate.getSessionFactory());
}
The magic behind this is that MyHibernateBundle implements ConfiguredBundle which dropwizard-guice now automatically picks up and instantiates.
Here is the way I solved it :
Put the Hibernate bundle in the guice module and pass the bootstap object as argument of guice module constructor so the hibernate bundle can be added to it.
The configuration can remain exactly as you would use a hibernate-bundle without guice.
I got this working with dropwizard-hibernate v0.7.1 and dropwizard-guice v0.7.0.3
MyAppModule.java :
public class MyAppModule extends AbstractModule {
private final HibernateBundle<MyAppConfiguration> hibernateBundle = new HibernateBundle<MyAppConfiguration>(MyModel.class) {
#Override
public DataSourceFactory getDataSourceFactory(MyAppConfiguration configuration) {
return configuration.getDataSourceFactory();
}
};
public MyAppModule(Bootstrap<MyAppConfiguration> bootstrap) {
bootstrap.addBundle(hibernateBundle);
}
#Override
protected void configure() {
}
#Provides
public SessionFactory provideSessionFactory() {
return hibernateBundle.getSessionFactory();
}
}
MyApplication.java :
public class MyApplication extends Application<MyAppConfiguration> {
#Override
public void initialize(Bootstrap<MyAppConfiguration> bootstrap) {
bootstrap.addBundle(
GuiceBundle.<MyAppConfiguration>newBuilder()
.addModule(new MyAppModule(bootstrap))
.enableAutoConfig(getClass().getPackage().getName())
.setConfigClass(MyAppConfiguration.class)
.build()
);
}
#Override
public void run(final MyAppConfiguration configuration, final Environment environment) throws Exception {
}
}
MyAppConfiguration.java :
public class MyAppConfiguration extends Configuration {
#Valid
#NotNull
#JsonProperty("database")
private DataSourceFactory database = new DataSourceFactory();
public DataSourceFactory getDataSourceFactory() {
return database;
}
}
I have not used hibernate in dropwizard, but I have used Guice and you really only need to worry about MyAppModule. That's where the magic will happen:
public class MyAppModule extends AbstractModule {
#Singleton
#Provides
public SessionFactory provideSessionFactory(MyAppConfiguration configuration) {
HibernateBundle<MyAppConfiguration> hibernate = new HibernateBundle<ExampleConfiguration>(MyModel.class) {
#Override
public DataSourceFactory getDataSourceFactory(MyAppConfiguration configuration) {
return configuration.getDataSourceFactory();
}
}
return hibernate.getSessionFactory();
}
}
(see here for multiple Classes)
MyAppConfiguration.java and MyApplication.java should not have any of the hibernate bundle references in. You should then be able to #Inject a SessionFactory where ever you need it.