I'm having a few problems injecting a specific field instance with Guice.
Here's what I currently have:
class Driver {
private ThreadLocal<Database> db;
...
}
I'd usually just pass the db instance in a constructor. But this class will be intercepted, using guice.
Here's the module:
class MyGuiceModule extends AbstractModule {
private ThreadLocal<Database> dbToInject;
public MyGuiceModule(ThreadLocal<Database> dbToInject) {
this.dbToInject = dbToInject;
}
#Override
protected void configure() {
// Binds the interceptor.
bindInterceptor(....);
bind(ThreadLocal.class).toInstance(this.dbToInject);
}
}
And here's how I'm instantiating all the stuff:
Injector injector = new Injector(new MyGuiceModule(db));
Driver driver = injector.getInstance(Driver.class);
I bet it's pretty obvious, but what am I doing wrong here?
EDIT:
Sorry if I wasn't clear. My problem is that this is not working. The instance is not being injected. I've annotated the field with #Inject and still doesn't work.
I think you need to use Guice.createInjector to create an injector instance.
Here's how I would create an injector:
Injector injector = Guice.createInjector(new MyGuiceModule(db));
Another thing is you used the following code to perform binding:
bind(ThreadLocal.class).toInstance(this.dbToInject);
Usually, it would be something like:
bind(MyInterface.class).toInstance(MyImplementation.class);
Your ThreadLocal.class is not an interface class, and this.dbToInject is not your implementation class.
Here's the documentation:
http://code.google.com/p/google-guice/wiki/Motivation
Hope this helps.
It would probably be better not to inject the ThreadLocal directly but to inject the Database into the constructor (as #Tobias suggested). And do you really want to use the same Database for all the instance of the Driver that are created (note the optional singleton in the comment)?
public class GuiceExample {
public static class MyGuiceModule extends AbstractModule {
#Override
protected void configure() {
bind(Driver.class);
}
#Provides
//Uncomment this to use the same Database for each Driver
//#Singleton
Database getDatabase() {
return new Database();
}
}
#Test
public void testInjection() {
Injector i = Guice.createInjector(new MyGuiceModule());
i.getInstance(Driver.class);
}
public static class Database {}
public static class Driver {
ThreadLocal<Database> db = new ThreadLocal<Database>();
#Inject
Driver(Database db) {
this.db.set(db);
}
}
}
Related
there is a configuration file that I want to bind using Guice but the problem is I get that file using my manager class and I don't have an instance of it. To make clear, I explain on code:
public class GuiceModule extends AbstractModule {
#Override
protected void configure() {
bind(ConfigManager.class).to(SimpleConfigManager.class).asEagerSingleton(); // My manager
bind(PropertiesConfiguration.class).annotatedWith(Names.named("versionConfig")).toInstance(configManager.getResourceConfig("version.properties"));
// ^ I need an instance of SimpleConfigManager here
}
}
So, how can I create/get an instance without using the "new" keyword?
You can use something called ProvidesMethod.
public class GuiceModule extends AbstractModule {
#Override
protected void configure() {
bind(ConfigManager.class).to(SimpleConfigManager.class).asEagerSingleton();
}
#Provides
#Singleton
#Named("versionConfig")
public PropertiesConfiguration providePropertiesConfiguration(ConfigManager configManager) {
return configManager.getResourceConfig("version.properties");
}
}
I have a Job, which should read data from deep storage. I am using Guice DI for my project.
There is a deep store already written and coming as an outer dependencie. I am struggling with instantiating the client in Guice
Here is the code
JobModule
public class JobModule extends AbstractModule {
private Config config;
JobModule(Config config) {
this.config = config;
}
#Override
protected void configure() {
bind(Reader.class).to(DeepStoreReader.class);
}
#Provides
#Named("config")
Config provideConfig() {
return this.config;
}
}
Reader Interface
public interface Reader {
List<String> getData(String path);
}
DeepStoreReader
public class DeepStoreReader implements Reader {
private final DeepStoreClient deepStoreClient;
DeepStoreReader(#Named("config") Config config) {
this.deepStoreClient = new DeepStoreClient(config);
}
#Override
public List<String> getData(String path) {
return this.deepStoreClient.getData(path);
}
}
The issue is I don't want to instantiate DeepStoreClient inside the DeepStoreReader constructor, because it becomes difficult to test DeepStoreReader, since I won't be able to mock DeepStoreClient
What is the preferred way to instantiate a client in such cases? DeepStoreClient is not a Guice module/implementation and is coming as an outer published dependency
PS: I am new to DI and learning Guice
What you want is constructor injection, e.g.:
#Inject
public DeepStoreReader(DeepStoreClient deepStoreClient) {
this.deepStoreClient = deepStoreClient;
}
Guice will take care of instantiating the DeepStoreClient for you.
EDIT:
If DeepStoreClient itself has dependencies, you can also annotate that constructor:
#Inject
public DeepStoreClient(#Named("config") Config config) {
// ... 8< ...
}
I have a interface here
interface Idemo{
public int getDemo(int i);
}
And it's one implementation
class DemoImpl implements Idemo{
#Override
public int getDemo(int i){
return i+10;
}
}
And there is a class which has a dependency on Idemo
class Sample{
#Inject
Idemo demo;
public int getSample(int i){
return demo.getDemo(i);
}
}
Now say I want to test Sample class
public class SampleTest extends JerseyTest {
#Inject
Sample s;
#Override
protected Application configure() {
AbstractBinder binder = new AbstractBinder() {
#Override
protected void configure() {
bind(Demo.class).to(Idemo.class);
bind(Sample.class).to(Sample.class); //**doesn't work**
}
};
ResourceConfig config = new ResourceConfig(Sample.class);
config.register(binder);
return config;
}
#Test
public void test_getSample() {
assertEquals(15, s.getSample(5)); //null pointer exception
}
}
Here the Sample instance is not getting created and s remains null.I suppose this is because by the time the execution reaches line where binding is specified this test class has already been created.But I am not sure.With Spring Autowired instead of jersey CDI the same works
Had Sample been a resource/controller class the test framework would create an instance of it with no need to inject it but is it possible to test any other non-web class using Jersey DI ?
The reason it works with Spring is that the test class is managed by the Spring container by using #RunWith(SpringJUnit4ClassRunner.class). The runner will inject all managed objects into the test object. JerseyTest is not managed this way.
If you want, you can create your own runner, but you need to understand a bit how HK2 (Jersey's DI framework) works. Take a look at the documentation. Everything revolves around the ServiceLocator. In a standalone, you might see something like this to bootstrap the DI container
ServiceLocatorFactory factory = ServiceLocatorFactory.getInstance();
ServiceLocator locator = factory.create(null);
ServiceLocatorUtilities.bind(locator, new MyBinder());
Then to get the service, do
Service service = locator.getService(Service.class);
In the case of the test class, we don't need to gain any access to the service object, we can simply inject the test object, using the ServiceLocator:
locator.inject(test);
Above, test is the test class instance that gets passed to us in our custom runner. Here is the example implementation of a custom runner
import java.lang.annotation.*;
import org.glassfish.hk2.api.*;
import org.glassfish.hk2.utilities.*;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.*;
public class Hk2ClassRunner extends BlockJUnit4ClassRunner {
private final ServiceLocatorFactory factory = ServiceLocatorFactory.getInstance();
private Class<? extends Binder>[] binderClasses;
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public static #interface Binders {
public Class<? extends Binder>[] value();
}
public Hk2ClassRunner(Class<?> cls) throws InitializationError {
super(cls);
Binders bindersAnno = cls.getClass().getAnnotation(Binders.class);
if (bindersAnno == null) {
binderClasses = new Class[0];
}
}
#Override
public Statement methodInvoker(FrameworkMethod method, final Object test) {
final Statement statement = super.methodInvoker(method, test);
return new Statement() {
#Override
public void evaluate() throws Throwable {
ServiceLocator locator = factory.create(null);
for (Class<? extends Binder> c : binderClasses) {
try {
ServiceLocatorUtilities.bind(locator, c.newInstance());
} catch (InstantiationException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
locator.inject(test);
statement.evaluate();
locator.shutdown();
}
};
}
}
In the runner, the methodInvoker is called for every test method, so we are creating a fresh new set of objects for each test method called.
Here is a complete test case
#Binders({ServiceBinder.class})
#RunWith(Hk2ClassRunner.class)
public class InjectTest {
public static class Service {
#Inject
private Demo demo;
public void doSomething() {
System.out.println("Inside Service.doSomething()");
demo.doSomething();
}
}
public static class Demo {
public void doSomething() {
System.out.println("Inside Demo.doSomething()");
}
}
public static class ServiceBinder extends AbstractBinder {
#Override
protected void configure() {
bind(Demo.class).to(Demo.class);
bind(Service.class).to(Service.class);
}
}
#Inject
private Service service;
#Test
public void testInjections() {
Assert.assertNotNull(service);
service.doSomething();
}
}
I was facing the same situation but in the context of running some integrations test that needs to have some of the singletons that my application have already defined.
The trick that I found is the following. You just need to create a normal test class or a standalone that use the DropwizardAppRule
In my case, I use JUnit as I was writing some integration test.
public class MyIntegrationTest{
//CONFIG_PATH is just a string that reference to your yaml.file
#ClassRule
public static final DropwizardAppRule<XXXConfiguration> APP_RULE =
new DropwizardAppRule<>(XXXApplication.class, CONFIG_PATH);
}
The #ClassRule will start your application like is said here . That
means you will have access to everything and every object your application needs to start. In my case, I need to get access to a singleton for my service I do that using the #Inject annotation and the #Named
public class MyIntegrationTest {
#ClassRule
public static final DropwizardAppRule<XXXConfiguration> APP_RULE =
new DropwizardAppRule<>(XXXAplication.class, CONFIG_PATH);
#Inject
#Named("myService")
private ServiceImpl myService;
}
Running this will set to null the service as #Inject is not working because we don't have at this point anything that put the beans into the references. There is where this method comes handy.
#Before
public void setup() {
ServiceLocator serviceLocator =((ServletContainer)APP_RULE.getEnvironment().getJerseyServletContainer()).getApplicationHandler().getServiceLocator();
//This line will take the beans from the locator and inject them in their
//reference, so each #Inject reference will be populated.
serviceLocator.inject(this);
}
That will avoid creating other binders and configurations outside of the existing on your application.
Reference to the ServiceLocator that DropwizardAppRule creates can be found here
I'm using the HK2 container in my Jersey application . I need to use my custom factory method to get the injected instance from the HK2 container.
For example ,
// Here I declare the IOC binding.
public class ApplicationBinder extends AbstractBinder {
#Override
protected void configure() {
bind(Logger.class).to(ILogger.class).in(Singleton.class);;
bind(MySqlRepository.class).to(IRepository.class).in(Singleton.class);
}
}
public class MyApplication extends ResourceConfig {
public static ApplicationBinder binder ;
public MyApplication () {
binder = new ApplicationBinder();
register(binder);
packages(true, "com.myapplication.server");
}
}
Here is my code :
public class BusinessLogic
{
//#Inject
//ILogger logger ;
//Instead
ILogger logger = DependencyResolver .resolve(ILogger.class) // resolve will get ILogger from HK2 container
}
The reason I need to do this way is for sometimes , I allocate classes manually which has dependencies , so in this way each use of #Inject return null.
For example, if I use new BusinessLogic() , then the logger with #Inject is null. I have to bind businesslogic also and use IOC in order to get the ILogge.
I need something like this:
public class DependencyResolver {
public static <T> T resolve(Class<T> beanClass){
return instance;
}
}
I need to use the DependencyResolver in order to get the instances I registered in MyApplication.
Any suggestions.
Thanks in advance...
I'm not 100% sure what exactly you want to do, but ...
I think you misunderstood AbstractBinder.bind(...) or bindings itself. Also, afaig you can't inject something into an instance which is not kinda managed component (like your BusinessLogic).
See jersey.java.net - ioc for examples regarding your BusinessLogic. You may have a look at ComponentProvider and/or InjectableProvider
For your ILogger I would suggest to create and bind a Factory like this:
public class LoggerFactory implements Factory<ILogger> {
// inject stuff here if you need (just an useless example)
#Inject
public LoggerFactory(final UriInfo uriInfo) {
this.uriInfo = uriInfo;
}
#Override
public ILogger provide() {
// here you resolve you ilogger
return MyLocator.resolve(ILogger.class);
}
#Override
public void dispose(ILogger instance) {
// ignore
}
}
Bind Factory
public class ApplicationBinder extends AbstractBinder {
#Override
protected void configure() {
bindFactory(LoggerFactory.class).to(ILogger.class).in(PerLookup.class /* or other scopeAnnotation if needed */);
// what's you Logger.class ?
// bind(Logger.class).to(ILogger.class).in(Singleton.class);
// bind(MySqlRepository.class).to(IRepository.class).in(Singleton.class);
}
}
Hope this was helpful somehow. Maybe someone is willing to write something about Providers for your case.
I have some sample code which is using factories. I'd like to clean up the code by removing the factories and use Guice instead. I attempted to do this but I hit a small roadblock. I am really new to Guice, so I am hoping someone can help me out here.
Existing client code (Using factories):
public class MailClient {
public static void main(String[] args) {
MailConfig config = MailConfigFactory.get();
config.setHost("smtp.gmail.com");
Mail mail = MailFactory.get(config);
mail.send();
}
}
My attempt to refactor using Guice:
//Replaces existing factories
public class MailModule extends AbstractModule {
#Override
protected void configure() {
bind(Mail.class)
.to(MailImpl.class);
bind(MailConfig.class)
.to(MailConfigImpl.class);
}
}
public class MailImpl implements Mail {
private final MailConfig config;
#Inject
public MailImpl(MailConfig config) {
this.config = config;
}
public void send() { ... }
}
public class MailClient {
public static void main(String[] args) {
MailModule mailModule = new MailModule();
Injector injector = Guice.createInjector(mailModule);
MailConfig config = injector.getInstance(MailConfig.class);
config.setHost("smtp.gmail.com");
Mail mail = //??
mail.send();
}
}
How would I construct an instance of MailImpl using the object config in my revised MailClient? Should I be using Guice in this way?
Take a look at AssistedInject. It appears to address this problem.
2 solutions are possible:
1) bind the config as a guice object also, including its host parameter. then just inject Mail, in your main method you cna ignore the fact that mail has further dependencies.
2) mail must be configured individually for each send (recipient?). then you have no choice, but create it yourself using MailFactory.
You can do everything in MailModule as follows:
public class MailModule extends AbstractModule {
#Override
protected void configure() {
... // other bindings
}
#Provides
MailConfig getMailConfig( ... ) {
MailConfig config = new MailConfig( ... );
config.setHost("smtp.gmail.com");
config;
}
}
If you want a singleton MailConfig, add the #Singleton annotation to getMailConfig(), and Bob's your uncle.
Note that arguments to getMailConfig must be bound. When you bind commonly used types like String, be sure to add a binding annotation.