I am very familiar with using spring to inject using #Bean & #Autowired. I have switched over to looking at guice and I am wondering what is the minimum involved to have it functioning. The following basic example throws a NPE:
import javax.inject.Inject;
public class ClassA {
String a = "test";
#Inject
public ClassA() {
System.out.println(a);
}
public void go() {
System.out.println("two");
}
}
The following class attempting to instantiate a new instance of ClassA:
import javax.inject.Inject;
public class ClassB {
#Inject
ClassA guice;
public ClassB() {
guice.go();
}
public static void main(String[] args) {
ClassB b = new ClassB();
}
}
I have tried all sorts of combinations of the following with no success:
public class SupportModule extends AbstractModule {
#Override
protected void configure() {
bind(ClassA.class);
//bind(ClassA.class).to(ClassB.class);
//others too
}
}
I must be missing a key thing somewhere here, I'm not quite sure where? do I need some manual instantiation of guice/configuration itself? I assume I possibly do.
guice.go(); <= NullPointerException occurs here, obviously the obj is null because my guice setup isn't right
In Spring i can do the following, I assume Guice can aid me in doing this too:
#Bean
public FrameworkProperties properties() {
return new FrameworkProperties();
}
and then just:
#Autowired
FrameworkProperties props;
do I need some manual instantiation of guice/configuration itself? I assume I possibly do.
Yes, you assumed right. You'll have to bootstrap the Injector modules that you have defined using the Guice.createInjector() method. Also, one other thing to note is when using a custom defined constructor like in ClassB, you'll have to use constructor injection. So in order to get this working, ClassB should look like:
public class ClassB {
private ClassA guice;
#Inject //This will inject the dependencies used in the constructor arguments
public ClassB(final ClassA guice) {
this.guice = guice;
guice.go();
}
public static void main(String[] args) {
/**
* If only type to type binding is required, you can skip creating a Module class &
* bootstrap the injector with empty argument createInjector like used below. But, when
* there are other kind of bindings like Type to Implementations defined in modules, you can use:
* final Injector injector1 = Guice.createInjector(new GuiceModule1(), new GuiceModule2());
*/
final Injector injector = Guice.createInjector();
final ClassB b = injector.getInstance(ClassB.class); //This will create dependency graph for you and inject all dependencies used by ClassB and downwards
}
}
Also, you can remove the #Inject annotation used in ClassA's constructor as you are not injecting any external dependencies in that constructor. You can look up the Guice's getting started wiki for more documentation.
Related
I'm new to Java Spring and trying to use Java configuration and inject a dependency into a class constructor. I want to use constructor injection because the class methods require the dependency. It isn't working for me.
Use case: Create a JSON string from a Java object and validate it before returning.
Class: FakeJsonBuilder
Dependency: JsonValidator
Main class: Per Spring documentation the #SpringBootApplication annotation is a convenience annotation that adds #Configuration, #EnableAutoConfiguration and #ComponentScan so I should be good to go as far as dependency injection is concerned.
#SpringBootApplication
public class MySpringApplication {
public static void main(String[] args){
// Register the class we use for Java based configuration
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext();
context.register(ApplicationConfiguration.class);
context.refresh();
SpringApplication.run(MySpringApplication .class, args);
}
}
Java configuration class:
#Configuration
public class ApplicationConfiguration {
#Bean
public JsonValidator jsonValidator(){
return new JsonValidatorImpl();
}
#Bean
public JsonBuilder(){
return new FakeJsonBuilder();
}
}
FakeJsonBuilder class:
public class FakeJsonBuilder implements JsonBuilder{
private static Log logger = LogFactory.getLog(FakeJsonBuilder.class);
private static JsonValidator jsonValidator;
// I need an empty constructor for the ApplicationConfiguration setup to work.
public MlrModelJsonBuilder(){};
#Autowired
public FakeJsonBuilder (JsonValidator jsonValidator){
this.jsonValidator = jsonValidator;
boolean validatorInjected = (jsonValidator != null);
logger.info("Validator injected: " + validatorInjected);
}
.......... More methods
The jsonValidator dependency is not being injected, i.e. the log message is Validator injected: false
Quoting Martin: Fowler http://martinfowler.com/articles/injection.html
"My long running default with objects is as much as possible, to create valid objects at construction time. This advice goes back to Kent Beck's Smalltalk Best Practice Patterns: Constructor Method and Constructor Parameter Method. Constructors with parameters give you a clear statement of what it means to create a valid object in an obvious place. If there's more than one way to do it, create multiple constructors that show the different combinations."
I come from a .NET background and use Ninject to inject my dependencies into the class constructor for the reasons Fowler gives. I quoted Fowler because of his credibility but you will find many sources providing the same argument, i.e. if the class methods require the dependency then it should be injected into the constructor. So here's how I figured how to do it with Java Spring (I revert to my C# syntax - forgive the transgression):
The configuration class
#Configuration
public class ApplicationConfiguration {
#Bean
public IJsonValidator jsonValidator(){
return new JsonValidator();
}
#Bean
public IJsonBuilder jsonBuilder(){
return new JsonBuilder(jsonValidator());
}
}
The class into which we inject the dependency
public class JsonBuilder implements IJsonBuilder {
private static IJsonValidator _jsonValidator;
// #Autowired // not needed per Sotirios. tested and verified
public JsonBuilder(IJsonValidator jsonValidator) {
_jsonValidator = jsonValidator;
}
public String getFoobar() {
// Returns false. jsonValidator was injected
boolean foo = (_jsonValidator == null);
return "Validator was injected: " + foo;
}
... more methods
I´m using Guice to initalize a class with some arguments from a config file
#Provides
#Singleton
RetryServiceCaller provideMaxRetryAttempts(#Named("config") JsonObject config) throws IOException {
JsonObject retryDetails = config.getJsonObject("retry_details");
return new RetryServiceCaller(retryDetails.getInteger("maxRetryAttempts"), retryDetails.getInteger("upperBoundary"), retryDetails.getInteger("lowerBoundary"),
retryDetails.getLong("multiplicationFactor"), retryDetails.getInteger("timeout"), retryDetails.getInteger("increaseTimeout"));
}
This class is injected in another class which is singleton as well.
class A{
#Inject private RetryServiceCaller retryServiceCaller;
}
But now the problem is that since this new class A is singleton, I need to clone the retryServiceCaller every time that somebody use this class A.
I´ve been investigating FactoryModuleBuilder to use it and create a factory for this class. But since the class has parameters from the config file I could not find the way to make it works.
Something like this
class A{
#Inject private RetryServiceCaller.Factory retryServiceCallerFactory;
}
Then in my RetryServiceCaller implement this
public interface Factory {
#Inject
RetryServiceCaller create();
}
#Inject
public RetryServiceCaller(int maxRetryAttempts, int upperBoundary, int lowerBoundary, long multiplicationFactor, int timeout, int incrementTimeout) {
this.maxRetryAttempts = maxRetryAttempts;
this.upperBoundary = upperBoundary;
this.lowerBoundary = lowerBoundary;
this.multiplicationFactor = multiplicationFactor;
this.timeout = timeout;
this.incrementTimeout = incrementTimeout;
}
But guice throw me errors saying
No implementation for com.proxy.handlers.RetryServiceCaller$Factory was bound
Guice can automatically provide a zero-argument factory: Instead of injecting Foo, you can always inject Provider<Foo>. This allows you to call fooProvider.get() to create an instance whenever and wherever you'd like. You don't have to bind to a Provider or use a Provides method to get access to this; you can inject Foo or Provider<Foo> whether you use a bind(...).to(...) type binding, a toProvider binding, a toInstance binding, a #Provides method, or anything else, and Guice will call get or return an internal Provider automatically.
(The returned Provider will also respect scopes, so you'll need to drop your #Singleton scope in order to get more than one instance, and be aware that toInstance bindings will always return the same instance.)
This is not a job for FactoryModuleBuilder; only use FactoryModuleBuilder when you need to mix injected and non-injected constructor parameters in the same type.
Your finished binding should look like this:
#Provides
/* NOT #Singleton */
RetryServiceCaller provideMaxRetryAttempts(#Named("config") JsonObject config) throws IOException {
JsonObject retryDetails = config.getJsonObject("retry_details");
return new RetryServiceCaller(retryDetails.getInteger("maxRetryAttempts"), retryDetails.getInteger("upperBoundary"), retryDetails.getInteger("lowerBoundary"),
retryDetails.getLong("multiplicationFactor"), retryDetails.getInteger("timeout"), retryDetails.getInteger("increaseTimeout"));
}
And in your class:
#Inject public YourCallerConsumer(Provider<RetryServiceCaller> callerProvider) {
this.callerProvider = callerProvider;
}
public void doAction() {
RetryServiceCaller newCaller = callerProvider.get();
// interact with caller
}
Your first approach should work just fine. If you don't want the RetryServiceCaller to be a singleton, remove the #Singleton annotation from the provider method, and a new instance will be created for every injection point.
Assisted inject could work here too, but it's overkill. If you want to go that route:
interface RetryServiceCallerFactory {
RetryServiceCaller create(String configParam1, String configParam2);
}
public class RetryServiceCaller {
#AssistedInject
public RetryServiceCaller(String configParam1, String configParam2) {}
}
then, in your module
install(new FactoryModuleBuilder().build(Factory.class);
and in your injection points
#Inject RetryServiceCallerFactory factory;
RetryServiceCaller create(JsonObject config) {
return factory.create(config.getFirstParam(), config.getSecondParam());
}
You can refer to the documentation for more extensive examples.
class A {
public A() {
}
}
class B {
#Inject
#Named("A")
private A a;
public B() {
}
public A getA() {
return a;
}
}
class AModule extends AbstractModule {
#Override
protected void configure() {
}
#Provides
#Singleton
#Named("A")
public A providesA() {
return new A();
}
}
We are doing like this:
AModule module = new AModule();
Injector injector = Guice.createInjector(module);
B b = injector.getInstance(B.class);
System.out.println(sample.getA());
But we have many classes with A as dependency and we don't want to add this code every time we create an instance.
So, is there any way to auto inject instance of A while creating instance of B?
It is (usually) not correct to create as many top-level Injectors as you suggest in your question. Injector creation is expensive, and once Guice has calculated your graph of dependencies, you should not need to calculate it all over again. In general there should be one top-level Injector across your application, and any other Injectors are either "child injectors" or parts of a separate and unrelated object graph.
In order from "worst" to "best":
Keep the Injector statically
If you are introducing DI into a lot of existing or legacy code, then it may be tempting to stash the Injector into a publicly-accessible object.
public class InjectorHolder() {
private InjectorHolder() {} // Not instantiable
private static Injector injector;
public static void initializeInjector() {
injector = Guice.createInjector(new AModule(), new BModule(), andSoOn());
}
public static Injector get() {
return injector;
}
public static B getB() {
return injector.getInstance(B.class);
}
}
At this point you can call InjectorHolder.get().getInstance(B.class) or InjectorHolder.getB() from the parts of the app you've migrated so far. Note that this may be difficult to test, and relies on Guice directly from across your application—both of which are not ideal.
Use Guice static injections
Guice provides a few features for static injection, notably the method call requestStaticInjection(Class... types). With a call to that in your module, Guice will inject static members that have #Inject annotations as soon as the Injector is created.
public class StaticBModule extends AbstractModule() {
#Override public void configure() { requestStaticInjection(BFactory.class); }
}
public class BFactory() {
#Inject #Named("B") private static Provider<B> bProvider;
public B get() {
return bProvider.get();
}
}
Now you can call new BFactory().get() instead of new B(), and it'll all go to the same injector. Naturally, you could also allow new B() instead if you put a static Provider<A> into your B class and request static injection for that instead, or you could keep your BFactory as an instance and replace it during tests to issue the B instances you need. At that point, you might as well just retrofit the classes that call new BFactory() to instead include a static Provider<B>, and have them inject statically, and then migrate those, all the way up until you have a full DI solution (explained below).
You may also consult this SO question, which has an example.
Ideal solution
You've shown us A and B, but presumably some other class C uses many instances of B, and maybe YourApplication (which contains your static main method) uses C. You can use Guice to create an instance of YourApplication or C, and then C can contain an injected Provider<B> bFactory. Then, rather than call new B(), you can call bFactory.get() to create as many B instances as you might need.
This way, your classes depend on exactly what they depend on, with no static state or references to Guice other than at the top level.
I have a class with a constructor, e.g.:
#Inject
public ClassTest(ITestInterface testInterface, Class<?> clazz){
...
}
The problem is how do I bind a class to an implementation which can be injected in this constructor and will the ClassTest binding pick the right class?
I want to inject different classes at different point of time. When I attempted to solve it Guice gives an error that it cannot find any suitable constructor on java.lang.Class.
I think you have to use assisted inject extension of Guice.
Basically, you define your ClassTest as it is, but mark 'varying' dependencies as #Assisted:
#Inject
public ClassTest(ITestInterface testInterface, #Assisted Class<?> clazz){
...
}
Then you create a factory interface for ClassTest objects which will accept Class argument and return ClassTests:
public interface ClassTestFactory {
ClassTest create(Class<?> clazz);
}
Then you install special kind of module which will create factories for you:
// Inside your module
install(new FactoryModuleBuilder().build(ClassTestFactory.class));
Then wherever you need ClassTest instances you should inject ClassTestFactory interface instead:
#Inject
YourLogicClass(ClassTestFactory ctFactory) {
this.ctFactory = ctFactory;
}
And finally you use it to create ClassTests for every class object you want:
ClassTest ct1 = ctFactory.create(SomeClass.class);
ClassTest ct2 = ctFactory.create(AnotherClass.class);
But if I were you, I would really reconsider the whole class architecture to avoid the need in such things.
This can be solved even without assisted inject, simply by using a TypeLiteral when creating the binding:
import javax.inject.Inject;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
public class ClassTest
{
static interface ITestInterface {}
#Inject
public ClassTest(ITestInterface testInterface, Class<?> clazz)
{
System.err.println("testInterface=" + testInterface);
System.err.println("clazz=" + clazz);
}
public static void main(String... argument)
{
ITestInterface testObject = new ITestInterface() {};
Module module = new AbstractModule()
{
#Override
protected void configure()
{
binder().bind(ITestInterface.class).toInstance(testObject);
binder().bind(new TypeLiteral<Class<?>>() {}).toInstance(testObject.getClass());
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
};
Injector injector = Guice.createInjector(module);
injector.getInstance(ClassTest.class);
}
}
The output when running this code is something like:
testInterface=ClassTest$1#3d921e20
clazz=class ClassTest$1
I have to agree with #VladimirMatveev though, that this is a somewhat unusual use case, and that the need for injection of java.lang.Class objects might be indicative of a design flaw. The only seemingly valid case of this type of injection that I've come across is for type checking, where an injected class needs the Class object to check the type of some other object (via Class.isInstance(...)) but it is not desirable to inject an instance (!) of that class (e.g., because it is not a singleton and might spawn all sorts of other undesired object creations). Still, even that scenario is somewhat hokey and might be solvable in a better way.
At the very least, I would use a more specific type argument, like Class<? extends ITestInterface> (which, I suspect, is what's intended by the OP).
To change injected value over time you could use the Provider bindings. And then it could look like this:
The module configuration:
public class SomeModule extends AbstractModule{
#Override
protected void configure() {
bind(Class.class).toProvider(SomeProvider.class);
}
}
The provider(not very elegant but may be for a start...):
public class SomeProvider implements Provider<Class<?>>{
private static Class<?> myClazz;
public static void setClass(Class<?> clazz){
myClazz = clazz;
}
#Override
public Class<?> get() {
return myClazz;
}
}
Some different classes:
public class SomeClass{
public int itWorks;
}
public class SomeOtherClass{
public int itWorksGreat;
}
Example client code:
public static void main(String[] args){
SomeProvider.setClass(SomeClass.class);
Injector injector = Guice.createInjector(new SomeModule());
printFields(injector.getInstance(Class.class));
SomeProvider.setClass(SomeOtherClass.class);
printFields(injector.getInstance(Class.class));
}
private static void printFields(Class clazz) {
Field[] declaredFields = clazz.getDeclaredFields();
for(Field field : declaredFields){
System.out.println(field.getName());
}
}
And finally the result:
itWorks
itWorksGreat
I have used Guice in my web app without problems and I wanted to use it in desktop app. I am certainly missing one thing - some way to tell my app how to bind everything and know what is what. In web app, I had declaration for that in Application class, how should I do it in my desktop app?
Here is relevant code that I am using:
public class GuiceModule extends AbstractModule
{
#Override
protected void configure()
{
// Enable per-request-thread PersistenceManager injection.
install(new PersistenceManagerFilter.GuiceModule());
// Business object bindings go here.
bind(ProjectQueries.class).to(JdoProjectQueries.class);
bind(new TypeLiteral<Repository<Project>>() { }).to(JdoProjectRepository.class);
}
My main class:
#Inject
public Repository<Project> projectRepo;
public void createNewProject() {
...
projectRepo.persist(newProject);
}
I am of course getting on projectRepo.persist(newProject);
So, what else do I have to do to make it work?
EDIT:
Ok, that part work now, thanks :) It seems that I need to do a bit more though to make persistence work that way.
I am getting NPE here now:
public void persist(T entity)
{
pmProvider.get().makePersistent(entity);
}
get() returns null here
It looks like
install(new PersistenceManagerFilter.GuiceModule());
is not enough. What do I need to do? My Repository class starts with:
public abstract class JdoRepository<T> implements Repository<T> {
private final Class<T> clazz;
private final Provider<PersistenceManager> pmProvider;
protected JdoRepository(Class<T> clazz, Provider<PersistenceManager> pmProvider) { this.clazz = clazz; this.pmProvider = pmProvider;
}
At my PMF I have:
public static class GuiceModule extends AbstractModule {
#Override protected void configure() {
bind(PersistenceManager.class).toProvider(new Provider<PersistenceManager>() {
public PersistenceManager get() {
return PersistenceManagerFilter.pm.get();
}
});
}
}
Create Bootstrap class with main method.
Move your current static main method code to non-static one. For example Application#run.
Create main method in Bootstrap class:
public static void main(String[] args) {
Injector injector = Guice.createInjector(new GuiceModule())
Application app = injector.getInstance(Application.class);
app.run();
}
Run Bootstrap class.
Any object that is created using a Guice injector will inject objects into its properties and methods. So one way will be to create an injector in createNewProject.
Injector injector = Guice.createInjector(new BeanModule(),.....
YourMainClass startClass = injector.getInstance(YourMainClass.class);
startClass.kickOfEveryThing();....
You need to at least ask one root object to the injector. This root object will be injected with objects, which will be injected with objects, etc. The the process needs to bootstrap.
See http://code.google.com/p/google-guice/wiki/GettingStarted
Injector injector = Guice.createInjector(new GuiceModule());
Main main = injector.getInstance(Main.class);