How to retrieve annotated instance from Guice's injector? - java

Let's say I have a module:
Module extends AbstractModule
{
#Override
protected void configure()
{
bind(String.class).
annotatedWith(Names.named("annotation")).
toInstance("DELIRIOUS");
}
}
and I want to test the module and check if it injects the right value in a String field annotated with Names.named("annotation") without having a class and a field but obtaining the value directly from the injector:
#Test
public void test()
{
Injector injector = Guice.createInjector(new Module());
// THIS IS NOT GOING TO WORK!
String delirious = injector.getInstance(String.class);
assertThat(delirious, IsEqual.equalTo("DELIRIOUS");
}

injector.getInstance(Key.get(String.class, Names.named("annotation")));

I'm using the following method
public <T> T getInstance(Class<T> type, Class<? extends Annotation> option) {
final Key<T> key = Key.get(type, option);
return injector.getInstance(key);
}
for this. In general, you still have the problem of creating the annotation instance, but here Names.named("annotation") works.

Related

Creating guice injector of another module installed inside current module

Have an interface that needs many implementations to be bound to it.
Going for the following design because of many constraints (May not seem good, please ignore the design).
Is it possible to create an injector for another module installed in current module while still running the configure() method for the current module.?
public class CurrentModule extends AbstractModule{
#Override
protected void configure() {
install(new OtherModule());
final someInterface getInstance = methodToGetInstance();
bind(SomeInterface.class).to(getInstance);
}
public SomeInterface methodToGetInstance() {
Injector injector = Guice.createInjector(new OtherModule());
return new ClassImplementingSomeInterface(injector.getInstance(dependency));
}
}
Yes, what you ask is possible with provider methods. This is how you should do it:
class CurrentModule extends AbstractModule {
#Override protected void configure() {
install(new OtherModule());
// Optional, but it's good to write it if the dependency becomes missing from OtherModule.
requireBinding(DependencyFromOtherModule.class);
}
#Singleton
#Provides SomeInterface createSomeInterface(DependencyFromOtherModule dependency) {
return new ClassImplementingSomeInterface(dependency);
}
}

Guice and generic factory

I'm new to guice, and using guice 4.1 I want to instantiate the following class:
public class GuiceMain<T> implements IGuiceMain<T> {
private ObjectWrapperFactory<T> factory;
#Inject
public GuiceMain(ObjectWrapperFactory<T> factory) {
this.factory = factory;
}
public void process(T t) {
ObjectWrapper wrapper = factory.create(t);
}
}
I dont have strong requirements how to create it, but I came to the solution to create interface GuiceMainFactory
public interface GuiceMainFactory {
<T> GuiceMain<T> create();
}
so my client code will look like this:
Injector injector = Guice.createInjector(new Configuration());
GuiceMain<File> instance = injector.getInstance(GuiceMainFactory.class).create();
File f = new File("text.txt");
instance.process(f);
and in my guice configuration class I write
install(new FactoryModuleBuilder().implement(IGuiceMain.class, GuiceMain.class).build(GuiceMainFactory.class))
But I get the error: 1) com.guice.GuiceMainFactory cannot be used as a key; It is not fully specified.
So I decided to write the implementation of GuiceMainFactory
public class GuiceMainFactoryImpl implements GuiceMainFactory {
private ObjectWrapperFactory objectWrapperFactory;
#Inject
public GuiceMainFactoryImpl(ObjectWrapperFactory objectWrapperFactory) {
this.objectWrapperFactory = objectWrapperFactory;
}
#Override
public <T> GuiceMain<T> create() {
return new GuiceMain<T>(objectWrapperFactory);
}
}
but in this case, on the line return new GuiceMain(objectWrapperFactory); I get unchecked assignment warning, because I cant specify generic type of objectWrapperFactory
I think I've over complicated everything, but I dont know how to deal with it

Google Guice: Mock a #provides method consists of set of object

I have class A which is taking a set as guice dependency. The set is singleton. Below is the code example:
class A
{
private Set<InetAddress> set;
private String pingUriPath;
#Inject
public A(Set<InetAddress> set, #Named("pingUri") String pingUriPath)
{
this.set = set;
this.pingUriPath = pingUriPath; // this is used somewhere
}
public void storeValue(String str)
{
if(str.equals("abc"))
{
set.add(str);
}
}
}
Here is the guice module that injects dependency:
private class GuiceModule extends AbstractModule {
#Override
public void configure() {
bindConstant().annotatedWith(Names.named("pingUri")).to("/ping");
}
#Provides
#Singleton
Set<InetAddress> healthyTargets(){
return Sets.newConcurrentHashSet();
}
}
I want to mock the method storeValue and for that i have to mock the set. I am not able to mock the set using guice.
If i mock like below, it gives assertion error(no interactions with this mock)
#Mock
Set<InetAddress> mockHealthyTargets;
private class MockClassesModule extends AbstractModule {
#Override
public void configure() {
bindConstant().annotatedWith(Names.named("pingUri")).to("/ping");
}
#Provides
#Singleton
Set<InetAddress> healthyTargets(){
return Sets.newConcurrentHashSet();
}
}
public test_storeValue()
{
Injector injector = Guice.createInjector(new MockClassesModule());
A a = injector.getInstance(A.class);
a.storeValue("abc");
verify(mockHealthyTargets).add("abc")
}
If you have the need to use guice in your unit tests, something is most likely going the wrong direction. One of the biggest benefits of dependency injection is that testing becomes easy, because you can pass dependencies that are controlled by you.
I assume you want to test the class A and specifically the method storeValue. For this you don't even need mocking
#Test
public void test() {
// prepare dependencies
Set<InetAddress> set = Sets.newConcurrentHashSet();
String pingUri = "example.com";
// prepare input
String input = "someValue";
// prepare class under test
A classUnderTest = new A(set, pingUri);
// call class under test
classUnderTest.storeValue(input);
// check that what you expected happened
// in this case you expect that the dependency set now contains the input
assertThat(set, contains(input));
}
I have found what the mistake was, I should return mock when providing to my unit test. It should look like this:
#Mock
Set<InetAddress> mockHealthyTargets;
private class MockClassesModule extends AbstractModule {
#Override
public void configure() {
bindConstant().annotatedWith(Names.named("pingUri")).to("/ping");
}
#Provides
#Singleton
Set<InetAddress> healthyTargets(){
return mockHealthyTargets;
}
}

Guice: Injecting a Module and then installing it

Here's something weird. Suppose you have a module like this:
public class ParentModule extends AbstractModule {
#Override
public void configure() {
bindConstant().annotatedWith(Names.named("key")).to("key");
}
}
Then we also have something like this:
public class DependentModule extends AbstractModule {
private final String key;
#Inject public DependentModule(#Named("key") String key) { this.key = key; }
#Override
public void configure() {
// Configure bindings that make use of key...
}
}
Injector parent = Guice.createInjector(new ParentModule());
Injector child = parent.createChildInjector(parent.getInstance(DependentModule.class));
// Now just ignore parent and work with child exclusively
This seems extremely cumbersome, but possibly necessary and useful in certain situations (if the key is a more complex datatype, for instance). Regardless, is there a way to restructure this code such that ParentModule binds the key, creates the DependentModule using the key, and install the created DependentModule? That is, such that the consumer can simply use a single injector instead of having to do this two-injector trick?
It isn't possible to inject something and then install it. Injection only happens after all your configure() methods have run, by which point it's too late. But you can do this:
public class MyModule extends AbstractModule {
#Override
public void configure() {
bindConstant().annotatedWith(Names.named("key")).to("key");
}
#Provides
Dependency provideDependency(#Named("key") String key) {
// Use key here
}
}

Injecting specific instance with Guice

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);
}
}
}

Categories

Resources