Recently, when I played around with Google Guice I was trying to do something like this:
#Override
protected void configure() {
...
bind(Provider.class).to(ViewFactory.class);
...
}
Where ViewFactory was:
public class ViewFactory implements Provider<SomeType> {...}
Of course, Guice didn't let me do that returing error:
1) Binding to Provider is not allowed.
{stacktrace}
What is the reason why it is not possible to bind to provider?
I guess it is because Provider interface is very special to Guice. In fact, all its internal machinery is implemented in term of providers.
Moreover, this could create ambiguities. If bindings to providers were possible:
bind(SomeClass.class).to(SomeClassImpl1.class);
bind(new TypeLiteral<Provider<SomeClass>>() {}).to(() -> new SomeClassImpl2());
then what should Guice inject here?
#Inject
OtherClass(Provider<SomeClass> someClassProvider) { ... }
Should it be a provider which returns SomeClassImpl1 (because of the first binding; remember, direct injections and provider injections are interchangeable in Guice) or should it be a provider which returns SomeClassImpl2 (because of the second binding)?
It really is redundant. Because you can inject SomeClass or Provider<SomeClass> regardless of the actual binding, you can bind the class itself to its provider:
bind(SomeClass.class).toProvider(() -> new SomeClassImpl());
// Either of the following will work
#Inject
OtherClass1(Provider<SomeClass> someClassProvider) { ... }
#Inject
OtherClass2(SomeClass someClass) { ... }
Provider is a special case. Guice does a lot of things behind the scenes with Provider, so they just ban binding to the Provider class entirely. One example is with scoping: your custom Provider might call new every single time, but if you create the provider in the Singleton scope, that should not happen. So Guice doesn't actually inject your provider, it injects a wrapped version. Things like that is why they ban binding to Provider.class directly. Here's a code example:
import com.google.inject.*;
import com.google.inject.name.*;
public class ProviderBindExample {
public static class ProvModule extends AbstractModule {
#Override
protected void configure() {
bind(Foo.class).toProvider(FooProvider.class);
bind(Foo.class).annotatedWith(Names.named("singleton"))
.toProvider(FooProvider.class)
.in(Singleton.class);
}
}
public static interface Foo { }
public static class FooProvider implements Provider<Foo> {
#Override
public Foo get() {
return new Foo() {};
}
}
public static class SomeClass {
#Inject public Provider<Foo> provider;
#Inject #Named("singleton") public Provider<Foo> singletonProvider;
}
public static void main(String... args) {
Injector inj = Guice.createInjector(new ProvModule());
SomeClass s = inj.getInstance(SomeClass.class);
System.out.println("Provider class = " + s.provider.getClass());
System.out.println("Singleton provider class = " + s.singletonProvider.getClass());
Foo first = s.provider.get();
Foo second = s.provider.get();
System.out.printf("regular scope: objects are %s%n", first == second ? "the same" : "different");
first = s.singletonProvider.get();
second = s.singletonProvider.get();
System.out.printf("singleton scope: objects are %s%n", first == second ? "the same" : "different");
}
}
Output:
Provider class = class com.google.inject.internal.InjectorImpl$4
Singleton provider class = class com.google.inject.internal.InjectorImpl$4
regular scope: objects are different
singleton scope: objects are the same
Related
I've implemented a JAX-RS server application using Jersey 2.24.
I use the Guice-HK2 bridge so that the controller classes (those annotated with #Path) are injected with dependencies from Guice, not Jersey/HK2.
However, HK2 still creates instances of the #Path annotated classes itself.
Is there a way I can plug into Jersey/HK2 so that I'm notified when a #Path annotated class is created? Like some sort of lifecycle listener? Every time a #Path annotated class is created by Jersey/HK2 I want to do some registering/logging of that class.
If Guice were doing the actual creation of the #Path annotated class I think I could do it using a generic Provider but that's not available in this case, since Jersey/HK2 is creating the actual instance.
Thank you!!
I think the least intrusive way would be to just use AOP. HK2 offers AOP. What you can do is create a ConstructorInterceptor. Something like
public class LoggingConstructorInterceptor implements ConstructorInterceptor {
private static final Logger LOG
= Logger.getLogger(LoggingConstructorInterceptor.class.getName());
#Override
public Object construct(ConstructorInvocation invocation) throws Throwable {
Constructor ctor = invocation.getConstructor();
LOG.log(Level.INFO, "Creating: {0}", ctor.getDeclaringClass().getName());
// returned instance from constructor invocation.
Object instance = invocation.proceed();
LOG.log(Level.INFO, "Created Instance: {0}", instance.toString());
return instance;
}
}
Then create a InterceptorService to only use the interceptor for classes annotated with #Path
public class PathInterceptionService implements InterceptionService {
private static final ConstructorInterceptor CTOR_INTERCEPTOR
= new LoggingConstructorInterceptor();
private final static List<ConstructorInterceptor> CTOR_LIST
= Collections.singletonList(CTOR_INTERCEPTOR);
#Override
public Filter getDescriptorFilter() {
return BuilderHelper.allFilter();
}
#Override
public List<MethodInterceptor> getMethodInterceptors(Method method) {
return null;
}
#Override
public List<ConstructorInterceptor> getConstructorInterceptors(Constructor<?> ctor) {
if (ctor.getDeclaringClass().isAnnotationPresent(Path.class)) {
return CTOR_LIST;
}
return null;
}
}
Then just register the InterceptionService and ConstructorInterceptor with the DI system
new ResourceConfig()
.register(new AbstractBinder(){
#Override
public void configure() {
bind(PathInterceptionService.class)
.to(InterceptionService.class)
.in(Singleton.class);
bind(LoggingConstructorInterceptor.class)
.to(ConstructorInterceptor.class)
.in(Singleton.class);
}
});
See complete example in this Gist
See Also:
HK2 documentation on AOP
I'm learning Google Guice.
I understood how to bind an interface to its implementation.
Now, I have the following helper class :
class PersonHelper {
public static FakeDatabaseConfiguration dbConfig;
public PersonHelper(){
if (dbConfig == null){
dbConfig = new FakeDatabaseConfiguration();
dbConfig.setHost('127.0.0.1');
dbConfig.setPort('3306');
dbConfig.setUsername('root');
dbConfig.setPassword('root');
}
}
public List<Person> getPersons(){
FakeResult fakeResult = dbConfig.executeSQL("select * from Person");
return fakeResult.asList();
}
}
Today, I'm using it like this:
PersonHelper personHelper = new PersonHelper();
List<Person> personsList = personHelper. getPersons();
I'm pretty sure there is a way to make this class better.
Question : How can I make this class as a singleton using Guice so that I don't lazy load the dbConfig variable at each instanciation ?
(I read that there is a #Singleton annotation but, it's considered in Guice just as a scope.)
Regards
First, in your module, you have to declare a provider (FakeDatabaseConfigurationProvider). As stated, this is the best way to inject a configuration object.
Then, declare your helper class as a Singleton and bind it in your module.
This will allow your helper class to be used like this :
public class SomeClass{
#Inject
private PersonHelper personHelper;
...
public void someMethod(){
...
List<Person> personsList = personHelper.getPersons();
..
}
}
And the same instance will be shared through your app.
Here is the suggested code :
public class MyModule extends AbstractModule {
#Override
protected void configure() {
bind(FakeDatabaseConfiguration.class).toProvider(FakeDatabaseConfigurationProvider.class);
bind(PersonHelper.class).in(Scopes.SINGLETON);
}
/**
* FakeDatabaseConfigurationProvider implementation
*/
static class FakeDatabaseConfigurationProvider implements Provider<FakeDatabaseConfiguration> {
#Override
public FakeDatabaseConfiguration get() {
FakeDatabaseConfiguration dbConfig = new FakeDatabaseConfiguration();
dbConfig.setHost('127.0.0.1');
dbConfig.setPort('3306');
dbConfig.setUsername('root');
dbConfig.setPassword('root');
return dbConfig;
}
}
}
Then, in your PersonHelper :
public class PersonHelper{
private FakeDatabaseConfiguration fakeDatabaseConfiguration;
#Inject
public PersonHelper(final FakeDatabaseConfiguration fakeDatabaseConfiguration){
this.fakeDatabaseConfiguration = fakeDatabaseConfiguration;
}
public List<Person> getPersons(){
FakeResult fakeResult = fakeDatabaseConfiguration.executeSQL("select * from Person");
return fakeDatabaseConfiguration.asList();
}
}
Please look at Binding #Provides method as eager singleton See if that helps. The eagerSingleton part might work for you.
Having it as a scope is exactly what you want: Scopes effectively tell Guice when it's allowed to reuse the same object it's already created, and for #Singleton that answer is "always".
If you were to list the class like this:
#Singleton // Could also be in your module or #Provides method.
class PersonHelper {
private FakeDatabaseConfiguration dbConfig;
public PersonHelper(){
dbConfig = new FakeDatabaseConfiguration();
dbConfig.setHost('127.0.0.1');
dbConfig.setPort('3306');
dbConfig.setUsername('root');
dbConfig.setPassword('root');
}
public List<Person> getPersons(){
FakeResult fakeResult = dbConfig.executeSQL("select * from Person");
return fakeResult.asList();
}
}
Then the the class itself becomes a Singleton. The FakeDatabaseConfiguration will be created whenever the class is instantiated, but for all accesses through Guice, that will only happen once.
Of course, none of this applies to direct constructor calls as new PersonHelper(), but with few exceptions Guice is only good at making guarantees about objects that it provides. Any accesses that Guice can control, including through getInstance or #Inject-annotated fields and constructors, will only see PersonHelper (and therefore FakeDatabaseConfiguration) created exactly once.
I would like to be able to change the Guice injections at runtime to support multiple injections based on user input. This is what I would like to achieve:
public interface IDao {
public int someMethod();
}
public class DaoEarth implements IDao {
#Override
public int someMethod(){ ... }
}
public class DaoMars implements IDao {
#Override
public int someMethod(){ ... }
}
public class MyClass {
#Inject
private IDao myDao;
public int myMethod(String domain) {
//If Domain == Earth, myDao should be of the type DaoEarth
//If Domain == DaoMars, myDao should be of the type DaoMars
}
}
I was thinking of writing my own Provider, but I don't know how to use that provider to change my bindings at runtime. Any input is welcome and appreciated :)!
Update
Here's what I currently came up with, it's not as pretty as I'd like, so I'm still looking for feedback
public class DomainProvider {
#Inject #Earth
private IDaoProvider earthDaoProvider;
#Inject #Mars
private IDaoProvider marsDaoProvider;
public IDaoProvider get(Domain domain){
switch (domain){
case EARTH:
return earthDaoProvider;
case MARS:
return marsDaoProvider;
}
}
public IDaoProvider get(String domain){
Domain parsedDomain = Domain.valueOf(domain.toUpperCase());
return get(parsedDomain);
}
}
//MarsDaoProvider would be equivalent
public class EarthDaoProvider implements IDaoProvider {
#Inject #Earth
private IDao earthDao;
public IDao getDao() {
return earthDao;
}
}
// This means that in "MyClass", I can do:
public class MyClass {
#Inject
private DomainProvider domainProvider;
public int myMethod(String domain) {
IDaoProvider daoProvider = domainProvider.get(domain);
IDao dao = daoProvider.getDao();
//Now "dao" will be of the correct type based on the domain
}
}
//Of course elsewhere I have the bindings set like
bind(IDao.class).annotatedWith(Earth.class).to(EarthDao.class);
Your version is almost perfect as it is: You're going to need to inject some kind of object that returns one or the other based on code you write, and don't need assisted injection or anything like that. That said, you can skip some of the boilerplate:
public class DomainProvider {
// Just inject Providers directly without binding them explicitly.
#Inject #Earth Provider<IDao> earthDaoProvider;
#Inject #Mars Provider<IDao> marsDaoProvider;
public Provider<IDao> get(Domain domain){
switch (domain){
case EARTH:
return earthDaoProvider;
case MARS:
return marsDaoProvider;
}
}
public Provider<IDao> get(String domain){
Domain parsedDomain = Domain.valueOf(domain.toUpperCase());
return get(parsedDomain);
}
}
Your MyClass in that case would be exactly identical. Here, Provider is either the one-method generic interface com.google.inject.Provider, or the equivalent builtin javax.inject.Provider that it extends. Read more about Guice Providers on the relevant Guice wiki topic.
bind(IDao.class).annotatedWith(Earth.class).to(EarthDao.class);
// You can now inject "#Earth IDao" and also "#Earth Provider<IDao>".
Basically, if you bind a key Foo (to a class, provider, #Provides method, or instance), you automatically get to inject either a Foo or Provider<Foo> with no additional work. Providers are also a great way to ensure that you get a new instance with every call to get, if that's what you want; with your original, you'll always get the same instance of EarthDao or MarsDao for any given DomainProvider you inject. (If you have a scoped binding like #Singleton, Guice will respect that too; Provider just lets Guice get involved, rather than reusing a plain old Java reference.)
This means you can skip your custom EarthDaoProvider and MarsDaoProvider, unless you really need to perform any external initialization on them—at which point you'd probably be better off calling bind(EarthDao.class).toProvider(EarthDaoProvider.class) so the preparation also happens when injecting EarthDao directly. You could also just have DomainProvider return an IDao instance directly by calling get on the appropriate Provider, and be assured that it'll be a new instance every time.
I have 2 modules containing classes:
blog.model.ArticleDAO
blog.model.CategoryDAO
users.model.UserDAO
users.model.UserGroupDAO
All these DAOs have a dependency on the same service, but I need to inject a different instance based on the package.
I mean the module blog should have a specific instance of MyService, and the module users should have another instance of MyService.
I don't want to create 2 named services because some day I may want to use the same service for all DAOs. Or I could also want to inject another specific instance for a specific class...
Is there a way to inject a service based on the package of a class?
A way to say:
inject foo (instance of MyService) into classes that are in blog.*
inject bar (instance of MyService) into classes that are in users.*
but keeping all my classes unaware of that! Their configuration should only state "Inject an instance of MyService".
First I want to say, I find this a strange requirement. I am also wondering why your DAOs need a Service. In a normal layered design, this is the opposite (the Service uses the DAO).
However I find the challenge interesting, I tried to use a FactoryBean to create a Java Proxy class which would redirect at runtime to the correct instance of MyService depending of the caller package. Here is the code:
public class CallerPackageAwareProxyFactoryBean implements
FactoryBean<MyService>, ApplicationContextAware {
private Class<?> targetServiceType;
private ApplicationContext applicationContext;
private InvocationHandler invocationHandler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if (ReflectionUtils.isEqualsMethod(method)) {
// Only consider equal when proxies are identical.
return (proxy == args[0]);
} else if (ReflectionUtils.isHashCodeMethod(method)) {
// Use hashCode of service locator proxy.
return System.identityHashCode(proxy);
} else if (ReflectionUtils.isToStringMethod(method)) {
return "Service dispatcher: " + targetServiceType.getName();
} else {
String callerPackageFirstLevel = getCallerPackageFirstLevel();
Map<String, ?> beans = applicationContext
.getBeansOfType(targetServiceType);
for (Map.Entry<String, ?> beanEntry : beans.entrySet()) {
if (beanEntry.getKey().startsWith(callerPackageFirstLevel)) {
return method.invoke(beanEntry.getValue(), args);
}
}
throw new IllegalArgumentException(
String.format(
"Could not find any valid bean to forward call for method %s.",
method.getName()));
}
}
private String getCallerPackageFirstLevel() {
Throwable t = new Throwable();
StackTraceElement[] elements = t.getStackTrace();
String callerClassName = elements[3].getClassName();
return callerClassName.split("\\.")[0];
}
};
public MyService getObject() throws Exception {
return (MyService) Proxy.newProxyInstance(Thread.currentThread()
.getContextClassLoader(), new Class<?>[] { MyService.class },
invocationHandler);
}
public Class<?> getObjectType() {
return MyService.class;
}
public boolean isSingleton() {
return true;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void setTargetServiceType(Class<?> targetServiceType) {
this.targetServiceType = targetServiceType;
}
}
I didn't had to change anything to the Dao or Service configuration. I just had to add the creation of the FactoryBean in the Spring context:
<bean id="myService" class="stackoverflow.CallerPackageAwareProxyFactoryBean">
<property name="targetServiceType" value="a.b.c.MyService" />
</bean>
Maybe a few comments:
The caller package can only be get by creating an exception and looking at the stacktrace.
The code of the InvocationHandler is inspired from ServiceLocatorFactoryBean.
I am still wondering if there is an easier way but I think there is not.
You could replace part of the InvocationHandler to use a configuration Map (package => MyService bean name)
I would not recommend using such code in a productive environment.
If I have interface Validator and multiple implementations for this interface. How can I inject any of the multiple implementations with Guice? Now I know that I can use following code to inject one, but it allows only one implementation:
public class MyModule extends AbstractModule {
#Override
protected void configure() {
bind(Validator.class).to(OneOfMyValidators.class);
}
}
What I would like to do is:
Validator v1 = injector.getInstance(Validator1.class);
Validator v2 = injector.getInstance(Validator2.class);
Is it possible at all?
Short answer: binding annotations. They're basically a way of letting the depender give a hint that points towards a particular instance or implementation without requiring a dependency on the full concrete implementation class.
See:
https://github.com/google/guice/wiki/BindingAnnotations
For example, in the module, you might do:
bind(Validator.class).annotatedWith(ValidatorOne.class).to(OneOfMyValidators.class);
bind(Validator.class).annotatedWith(ValidatorTwo.class).to(SomeOtherValidator.class);
And in your constructor, you'd do:
#Inject
MyClass(#ValidatorOne Validator someValidator,
#ValidatorTwo Validator otherValidator) {
...
}
To get an annotated value straight from an Injector, you'll have to use the Guice Key class, like:
Validator v1 = injector.getInstance(Key.get(Validator.class, ValidatorOne.class));
On a side note, binding annotations are very useful for injecting runtime constants. See the comments for bindConstant in:
https://google.github.io/guice/api-docs/latest/javadoc/index.html?com/google/inject/Binder.html
I found this thread when looking for a solution for dynamically binding multiple implementations to an interface, similar to ServiceLoader in Java. The answer covers a more general case, but it can also be used to obtain a particular implementation from the set. Multibinder allows to bind multiple implementations to a type:
public class ValidatorsModule extends AbstractModule {
protected void configure() {
Multibinder<Validator> multibinder
= Multibinder.newSetBinder(binder(), Validator.class);
multibinder.addBinding().toInstance(new ValidatorOne());
multibinder.addBinding().toInstance(new ValidatorTwo());
}
}
//Usage
#Inject Set<Validator> validators;
Very similar to ejboy's proposal, but since you own different Validator classes, you can bind to the classes itself, not creating instances manually.
protected void configure() {
...
Multibinder<Validator> mb = Multibinder.newSetBinder(binder(), Validator.class);
mb.addBinding().to(Validator1.class);
mb.addBinding().to(Validator2.class);
mb.addBinding().to(Validator3.class);
...
}
Then viewed from the perspective of usage, e.g. by Constructor Injection:
class UseCase {
private Set<Validator> allOfThem;
#Inject
public UseCase(Set<Validator> allOfThem) {
this.allOfThem = allOfThem;
// e.g. iteratation
for (Validator oneOfThem : allOfThem) {
...
}
}
}
Kotlin
This is how we can do binding for multiple implementations for an interface
Class SomeModule : AbstractModule() {
override fun configure() {
val myBinder: Multibinder<MyInterface> = Multibinder.newSetBinder(binder(), MyInterface::class.java)
myBinder.addBinding().to(Implementation1::class.java)
myBinder.addBinding().to(Implementation2::class.java)
}
Usage
#Inject constructor(private val someVar:Set<#JvmSuppressWildcards MyInterface>)