Is it possible to instantiate and assign a singleton to a reference with Guice before creating the Module and pass that instance to the Module constructor be bound during configuration?
Here is an example of what I mean:
I have a method that allows me to create objects depending on a custom implementation of an interface which is being passed in constructor as an Optional (if the user won't provide a custom implementation, we will use the default one), which is being done by binding the interface to that particular implementation in the Module class. :
public static MyClass createMyClassObject(Optional<SpecialInterface> customSpecialInterfaceObject) {
SpecialInterface specialInterfacebject;
if(customSpecialInterfaceObject.isPresent() {
specialInterfaceObject = customSpecialInterfaceObject.get()
} else {
/* here I would like to bind it to an instance of the DefaultSpecialInterfaceObject but can't really do something like:
Injector injector = Guice.createInjector(myClassModule);
DefaultSpecialInterface instance = injector.getInstance(DefaultSpecialInterface.class);
as the module is yet to be created */
}
MyClassModule myClassModule = new MyClassModule(specialInterfaceObject);
Injector injector = Guice.createInjector(myClassModule);
return injector.getInstance(MyClass.class);
}
I'm currently using classes instead of instances to solve this problem, such as in the example below, but I don't quite like this solution. Would be happy to see a better way of doing it:
private static Class resolveSpecialInterfaceObject(Optional<SpecialInterface> customSpecialInterfaceObject) {
Class specialInterfaceObjectClass;
if (customSpecialInterfaceObject.isPresent()) {
specialInterfaceObjectClass= customSpecialInterfaceObject.get().getClass();
} else {
specialInterfaceObjectClass = DefaultSpecialInterface.class;
}
return specialInterfaceObjectClass;
}
public abstract class MyClassModule extends AbstractModule {
private final Class<SpecialInterface> specialInterfaceObjectClass;
public MyClassModule(Class<SpecialInterface> specialInterfaceObjectClass) {
this.specialInterfaceObjectClass= specialIntefaceObjectClass;
}
#Override
protected void configure() {
bind(SpecialInterface.class).to(specialInterfaceObjectClass);
}
}
Edit, from a comment below:
one more thing- didn't want to make the question too long; actually, I also want to perform another operation on the resulting instance of SpecialInterface, but only if it is the instance of DefaultSpecialInterface and I don't think it should be done in the Module. I was thinking if I could just have this bean up and running before, such as in Spring, so I could just pass it to the Module, but also use it in another method call before?
Can you take the whole Optional and use bind(...).toInstance(...)?
public static MyClass createMyClassObject(
Optional<SpecialInterface> customSpecialInterfaceObject) {
MyClassModule myClassModule = new MyClassModule(customSpecialInterfaceObject);
Injector injector = Guice.createInjector(myClassModule);
MyClassFactory instance = injector.getInstance(MyClassFactory.class);
return instance.createMyClassObject();
}
class MyClassModule extends AbstractModule {
private final Optional<SpecialInterface> customObject;
MyClassModule(Optional<SpecialInterface> customObject) {
this.customObject = customObject;
}
#Override public void configure() {
if (customObject.isPresent()) {
// Singleton by necessity: Guice doesn't know how to create another one.
bind(SpecialInterface.class).toInstance(customObject.get());
} else {
// Default scoped. Add ".in(Singleton.class)" if necessary.
bind(SpecialInterface.class).toInstance(DefaultSpecialInterfaceClass.class);
}
}
}
If you want to perform additional initialization on DefaultSpecialInterface and nothing else, you have a number of options:
If some kind of initialization is important for all implementations and likely too heavy to put into a class constructor, add an initialize method on your SpecialInterface. Make the custom one a no-op, and implement it for DefaultSpecialInterface.
If the initialization is unique to DefaultSpecialInterface, I see no reason why it shouldn't be in the Module. Write a #Provides method or bind to a Provider<SpecialInterface> that creates and initializes DefaultSpecialInterface correctly.
If your real goal is to keep the business logic out of a Module, you can do so by extracting it into a free-standing Provider or DefaultSpecialInterfaceFactory that is responsible for that.
Remember, Guice is responsible for feeding fully-constructed objects into your object graph, and that means that injecting a SpecialInterface should get a ready-to-use implementor of the SpecialInterface general contract. If Guice needs to perform some initialization to make that happen, it's not unreasonable to have it do so, and a Module isn't a bad place to do it.
Related
I am trying to figure out a way to pass one instance of the same class to multiple classes so I am able to build an object. The problem is it cannot be static or use singleton because many users will be hitting the application at the same time and I may run into other issues. Are there any design patterns that would work best with this scenario or if there is some way to use global variables in java? I am trying implement this with an existing rest service that was not designed very well.
public class OneInstanceOf
{//I want to build this map object without static
private Map<String, String> mapIwantToBuild = new HaspMap<String, String>();
public void methodIwantToCall(String name, String value)
{mapIwantToBuild.put(name, value)
}
The common pattern for you task is dependency injection. You can use spring framework for that task.
1.Create configuration with your bean:
#Configuration
public class YourConfiguration {
#Bean
public OneInstanceOf oneInstanceOf {
return new OneInstanceOf();
}
}
2.Inject your bean whatever you want (simplest - use autowiring):
#Component
public class Client1 {
#Autowire
private OneInstanceOf oneInstanceOf;
public void someMethod() {
oneInstanceOf.methodIwantToCall();
}
}
Spring will insure single instance of oneInstanceOf will be injected in all clients.
U can create a setter with parameter of instance class variable, in every class in which you want to pass the instance. Then create a method in one of the classes that calls setter of all those classes and pass parameter instance as parameter to that method.
Like below.
class A{
B b = new B;
set(B b){
C.setB(b);
D.setB(b);
E.setB(b);
}
}
In my scenario I have a BaseObject which is an interface and then a BaseObjectImpl.
Then I have two clients, ClientA and ClientB which both reference BaseObjectImpl with the minor different being that the constructor argument to BaseObjectImpl should change depending on which client is using it. The setup looks like this:
BaseObject:
public interface BaseObject {
void doAction();
}
BaseObjectImpl:
public class BaseObjectImpl implements BaseObject {
#Inject
public BaseObjectImpl(RandomInjectedObject random, String inputString) {
this.inputString = inputString;
}
public void doAction() {
// print input string
}
Now for the clients:
ClientA:
public class ClientA {
#Inject
public ClientA(BaseObject baseObject) {
this.baseObject = baseObject;
}
ClientB:
public class ClientB {
#Inject
public ClientB(BaseObject baseObject) {
this.baseObject = baseObject;
}
Now the issue is that when inside my ClientAModule I want to provide the inputString argument such that it is set to clientAString and inside ClientBModule I want to provide clientBString instead.
What is the best way to go about doing this? Note that the BaseObjectImpl takes in two arguments (the other one has the same definition for both clients).
What I tried doing was inside the BaseObjectModule class that I have defined, I created a Builder inside which I could set a specific annotation and set a specific inputString. Then inside my Client<AB>Module I created a different BindingAnnotation in each of them. Then when I installed the BaseObjectModule I did so using the builder and each passed in their specific BindingAnnotation and inputString.
Then I try to bind the BindingAnnotation / inputString scope to a Provider for BaseObject is that I try to instantiate the BaseObjectImpl with the corresponding inputString and the injected RandomInjectedObject which I've provided also in the BaseObjectModule. I get an error saying:
This Provider cannot be used until the Injector has been created because I haven't created the injector inside the module itself.
I was looking at AssistedInjection so that I could make it so I just passed in the inputString at this time, but the problem is I still need the injector for that.
Let's say there's a class that I use extensively and is returned by a method.
CommonClass obj = getCommonObject();
Now I want to extend this class to create some utility method to avoid repeating myself.
public CommonClassPlus extends CommonClass {
public String dontRepeatYourself() {
// the reason I'm creating a subclass
}
}
Of course I would like to use my improved class for the method above, however, downcasting isn't allowed.
CommonClassPlus obj = getCommonObject();
//Cannot cast to CommonClassPlus
How can I use the method dontRepeatYourself() if I can only work with the object that is an instance of the superclass?
CommonClass and getCommonObject() are from an external library and I cannot change them.
You cannot add behavior to an existing instance in Java (like you could in JavaScript, for example).
The closest you can get in Java is the Decorator pattern:
CommonClassPlus obj = decorate(getCommonObject());
where decorate() is
public CommonClassPlus decorate(CommonClass x) {
return new CommonClassPlus(x);
}
This approach creates a potentially huge amount of boilerplate because it must delegate each method call to the wrapped instance. If a method in CommonClass is final and there is no interface you can reimplement, then this approach fails altogether.
In most cases you will be able to get along with a simple static helper method:
public static String dontRepeatYourself(CommonClass x) {
...
}
If CommonClass is from an external library, you probably want to wrap it in an Adapter Pattern anyway, using the principle of Composition over Inheritance.
This gives you complete control if you want to, say, change the library you're using, and allows you to add functionality like dontRepeatYourself().
public class CommonClassAdapter implements MyAdapter {
private final CommonClass common;
private final String cachedResult;
// Note that I'm doing dependency injection here
public CommonClassAdapter(CommonClass common) {
this.common = common;
// Don't expose these because they shouldn't be called more than once
common.methodIOnlyCallOnce();
cachedResult = common.anotherMethodIOnlyCallOnce();
}
#Override
public void someMethod() {
common.someMethodWithDifferentName();
}
#Override
public String dontRepeatYourself() {
return cachedResult;
}
}
Note also that most modern IDEs have things like Eclipse's Source -> Generate Delegate Methods to make this process faster.
I have the following classes:
public class CacheModule extends AbstractModule {
#Override
protected void configure() {
bindConstant().annotatedWith(Names.named(TIMEOUT")).to(60);
// ...etc.
}
}
public class DefaultCacheAdaptor implements CacheAdaptor {
private CacheModule bootstrapper = new CacheModule();
#Named("TIMEOUT") private int timeout;
// other fields omitted for brevity
public DefaultCacheAdaptor() {
super();
Injector injector = Guice.createInjector(bootstrapper);
#Named("TIMEOUT") int t = injector.getInstance(Integer.class);
setTimeout(t);
}
}
public class QueueModule extennds AbstractModule {
#Override
public void configure() {
bind(CacheAdaptor.class).to(DefaultCacheAdaptor.class);
}
}
public class DefaultQueueAdaptor implements QueueAdaptor {
private QueueModule bootstrapper = new QueueModule();
private CacheAdaptor cacheAdaptor;
public DefaultQueueAdaptor() {
super();
Injector injector = Guice.createInjector(bootstrapper);
setCacheAdaptor(injector.getInstance(CacheAdaptor.class));
}
}
The CacheModule/CacheAdaptor/DefaultCacheAdaptor is located in a different JAR than QueueModule/QueueAdaptor/DefaultQueueAdaptor, and so the latter JAR depends on the former JAR at runtime (obviously).
The purpose of coding things this way is to allow the CacheModule to boostrap/inject the entire object graph under DefaultCacheAdaptor when the user writes:
CacheAdaptor cacheAdaptor = new DefaultCacheAdaptor();
Ditto for the QueueAdaptor.
It just so happens to be that the QueueAdaptor gets injected with a CacheAdaptor.
However, DefaultCacheAdaptor is the "root" of its own object tree, and should always be injected by the CacheModule.
So I ask: how can I bind DefaultCacheAdaptor to CacheAdaptor from inside QueueModule, but ensure that the DefaultCacheAdaptor is itself initialized/bootstrapped by the CacheModule?
To be honest it sounds like this problem isn't actually one of Guice, but instead the standard problem across software engineering: ensuring your dependencies do what they claim to do. QueueModule shouldn't concern itself about whether DefaultCacheAdaptor holds up to its general contract. Instead, write a unit test for DefaultCacheAdaptor that guarantees that it bootstraps itself, then use it in QueueModule without a second thought.
This is especially true because DefaultCacheAdaptor has a completely unrelated injector tree. You should be able to use DefaultCacheAdaptor opaquely, and stop concerning QueueAdaptor with its implementation details. Its bootstrapping is part of its implementation, not its API.
Even if you were to merge the two Injector graphs into one (by injecting the Injector and calling createChildInjector, for instance), there's very little way to guarantee at compile time that bindings you need in other modules will exist, because Modules work at runtime. Your best bet is to write a unit test. You can fail a little faster by calling requireBinding, which will fail at Injector creation if that particular dependency doesn't end up satisfied externally.
A question about Guice. I'm still learning it, but I can understand the fundamentals.
This question was already asked a couple of times on the net, but never with a concrete answer(none that I could find).
Say I have a situation like on the picture(a similar example was somewere on the net).
public class Dog {}
public class Walk implements Walkable {
private final Dog dog;
private final boolean leash;
#Inject
public Walk(Dog dog, #Assisted boolean leash) {
this.dog = dog;
this.leash = leash;
}
public void go() {
}
}
public interface Walkable {
void go();
}
public interface WalkFactory {
Walk create(boolean leash);
}
public class AssistedMain {
public static void main(String[] args) {
Injector i = Guice.createInjector(new AbstractModule() {
protected void configure() {
install(new FactoryModuleBuilder().
implement(Walkable.class, Walk.class).
build(WalkFactory.class));
}
});
Walk walk = i.getInstance(WalkFactory.class).create(true);
}
}
That's all great. But the question is - can I, somehow, reinject that object instance to the "container"(injector) to be used on the classes that rely on this dependency.
So, lets add a interface Person, class PersonImpl.
The new classes source are:
public interface Person {
void walkDog();
}
public class PersonImpl implements Person {
private Walkable walkable;
#Inject
public PersonImpl(Walkable walkable) {
this.walkable = walkable;
}
public void setWalkable(Walkable walkable) {
this.walkable = walkable;
}
public void walkDog() {
walkable.go();
}
}
So, the question is - am I, somehow able to actually inject this particular instance into the added object. This is a simple example, but we can presume there are 10 levels of classes below this one.
The solution I found is not very flexible. Something like:
Injector i = Guice.createInjector(new SimpleModule(false, dog));
And then bind to concrete instance. That's not very dynamic. Basically, every time I need a different runtime/dynamic parameter I have to recreate the injector.
The Provider<T> is nice, the FactoryModuleBuilder helps, but how can I inject the objects back?
Are there more dynamic solutions to this problem?
Thanks.
MPierce - agreed. Ill try to explain the way i visualized the problem(you can correct me if im wrong).
Being originaly derived from a "service locator" pattern, the idea that it can manage more than services is optimistic to say the least.
We could split the application into Service and Data classes, or you could say that we have application and infrastructure code - "Dependency Injection", a great book.
So, basicly, dependecy injection, and dependency injection frameworks in general are great. For solving infrastructure, or "service" code.
Any dynamic(runtime) parameters being injected into the Container/Injector are basicly forcing you to end the object graph.
For example, we have the folowing design:
EmailMessage is a runtime parameter. It can be "injected" into email service outside the Container/Injector, but it ends the object graph. If we want to request EmailDispatcher, after we injected the EmailMessage into EmailService(which is, I repeat, done outside injector), we could no longer fetch EmailDispatcher from the injector.
Then, you could redesign your model so it "fits" into the Container/Injector concept of dynamic parameters.
But then again, you forced the design, and suddenly, EmailDispatcher has too many responsibilites. It could be used in such a context, where you dont have many infrastructure classes.
And when you have a design like you have in the third example picture, you cannot use the Injector/Container to fetch you a NextService3 instance(nor any below the level of EmailDispatcher).
The problem being - if you have any dynamic(runtime) parameters, you can only use dependency injection for classes above the class that requires a dynamic parameter, you can forget the classes below.
Phew.
Correct?
Part of the problem depends on how you're resolving that 'false' is the thing you want to set for the leash field. Is that coming from config data or what?
A provider method may be helpful...
class FooModule extends AbstractModule {
...
#Provides
Walkable getWalkable(Dog dog) {
boolean leash = getBooleanFromSomewhere();
return new Walk(dog, leash);
}
}
If you can clarify where that boolean is coming from, it'll help me to understand what type of approach is applicable.
You can use custom scopes, much like when using guice servlets. That way you can create your instance, and then seed it in the injector.