Reputation: 56944
Let's make the statement "All Rocks have Minerals.
":
public class Mineral
{
// Nevermind why a Mineral would have a GUID.
// This is just to show that each Mineral instance
// is universally-unique.
String guid;
@Inject
public Mineral(String id)
{
guid = id;
}
}
public class Rock
{
private Mineral mineral;
@Inject
public Rock(Mineral min)
{
mineral = min;
}
}
If we want 2 Rock
instances, each of them configured with different Mineral
instances (each with their own GUIDs):
public class RockModule extends AbstractModule
{
public void configure(Binder binder)
{
// Make two Minerals with different GUIDs.
Mineral M1 = new Mineral(UUID.getRandomId().toString());
Mineral M2 = new Mineral(UUID.getRandomId().toString());
// Configure two Rocks with these unique Minerals
Rock R1 = new Rock(M1);
Rock R2 = new Rock(M2);
// Define bindings
bind(Rock.class).toInstance(R1);
// No way for Guice to expose R2 to the outside world!
}
}
So now, when we ask Guice for a Rock
, it will always give us the R1
instance, which itself is configured with the M1
instance of Mineral
.
In Spring DI, you can define two beans to be the same type, but just give them different bean IDs. Then you "wire" beans together using their IDs. So I could wire R1
and M1
together, R1
and M2
together, etc. Then, I can ask Spring for R1
or R2
as I need them.
With Guice, you can only ask for the type you want (Rock.class
), not the instance.
How do you request different "wired beans" with Guice? By using different AbstractModule
concretions? Or is this a limitation of Guice?
Upvotes: 0
Views: 247
Reputation: 4676
Generally this would be a violation of what Guice recommends. You would not typically new
up a class inside of a module to create instances because it defeats the purpose of using a DI container in the first place. (Why then annotate your classes with @Inject
?)
Rather, you'd let Guice do this for you:
class RockModule extends AbstractModule {
public void configure() {}
@Provides
@Named("UUID")
public String getUuid() {
return UUID.getRandomId().toString();
}
}
Now each Mineral
automatically gets a unique UUID, and each Rock
gets a unique Mineral
.
This gets us part way, but if you want two unique pairings of a Rock and Mineral for use at runtime, then this is what Guice calls the "robot legs" problem, and you can solve it using private modules. See an example here.
Upvotes: 1
Reputation: 1503984
I suspect you want binding annotations. Guice doesn't bind by type - it binds by key - but if you don't do anything else, the key will just consist of the type. Binding annotations allow you to create richer keys.
The linked documentation explains it better than I can, but the result is that there are various ways of specifying what you want, including:
@Inject
public Foo(@Named("X") Rock rock)
or
@Inject
public Foo(@HardRockCafe Rock rock)
where in the latter case, @HardRockCafe
is a custom binding annotation.
Upvotes: 1