Configuring guice for basic field injection without a main method - java

I have been recently looking into guice and have the need to have some field injection in my automation framework. For example I have an EnvironmentSetter class which I want to inject as a singleton to various other classes.
1) I do not have a standard main method, so I am struggling with how to bootstrap guice correctly. I am using testNG so I am attempting to bootstrap using a static block like so:
public class TestExecutionListener implements IExecutionListener {
private static final Logger LOG = LogManager.getLogger(TestExecutionListener.class);
static {
Bootstrapper.BootStrapGuiceDI();
}
#Inject
EnvironmentSetter env;
#Override
public void onExecutionStart() {
LOG.debug("Starting test run!");
env.generateEnvironmentProperties();
}
#Override
public void onExecutionFinish() {
LOG.debug("Finished test run!");
}
}
I have also created the following:
public class EnvironmentSetterModule extends AbstractModule {
#Override
protected void configure() {
bind(EnvironmentSetter.class);
}
}
and this is what I am calling from the static block:
public static void BootStrapGuiceDI() {
LOG.debug("Bootstrapping");
Injector injector = Guice.createInjector(new Module());
EnvironmentSetter env = injector.getInstance(EnvironmentSetter.class);
}
In this scenario, my injected EnvironmentSetter env is still null, what do I need in order to use this effectively?
EnvironmentSetter class:
public class EnvironmentSetter implements IEnvironmentPopulator {
private static final Logger LOG = LogManager.getLogger(EnvironmentSetter.class);
PropertyProvider properties = PropertyProvider.INSTANCE;
public EnvironmentSetter() {
}
public void generateEnvironmentProperties() {
Properties props = new Properties();
properties.getAllProperties().forEach((k,v) -> props.setProperty(k,v));
try {
File f = new File("target\\allure-results\\environment.properties");
f.getParentFile().mkdirs();
f.createNewFile();
props.store(new FileOutputStream(f), "Allure Environment Properties");
} catch(IOException ioe) {
LOG.fatal(ioe);
}
}
}

You should be adding the modules you create in the createInejector method not a new Module();.
public static void BootStrapGuiceDI() {
LOG.debug("Bootstrapping");
// Injector injector = Guice.createInjector(new Module()); // use your module (EnvironmentSetterModule )
// Now, guice will be able to "see" your class
Injector injector = Guice.createInjector(new EnvironmentSetterModule());
EnvironmentSetter env = injector.getInstance(EnvironmentSetter.class);
}
Also, only bootstraping it won't make it automatically inject all fields everywhere in test classes, to inject on test you could use your new Injector and inject the members of your test class injectMembers(this), where this would refer to your test instance, so must be executed on some setup block.
Checkout the documentation on guice about how to properly boostrap it on Test => Guice BoundFields

If you are using TestNG, there is a much more simple way to do this using the annotation guiceModule. Basically, TestNG does the bootstrapping for you and all you need to do is mention the Guice module name in the annotation. Example:
#Test(guiceModule = GuiceExampleModule.class)
public class GuiceTest {
#Inject
ExternalDependency dependency;
#Test
public void singletonShouldWork() {
Assert.assertTrue(true, dependency.shouldExecute());
}
}
Read more about this in Cedric's blogpost: TestNG and Guice: a match made in heaven

Related

Spring Boot: how to inject dependencies into a class called by a library?

I'm using Kinesis Client Library (KCL) and Spring boot. To use KCL, I have to implement a class (I named it RecordProcessor) for interface IRecordProcessor. And KCL will call this class and process records from kinesis. But when I tried to use dependency injection, I found it was not succeeded.
Here's the snippet for RecordProcessor:
#Component
public class RecordProcessor implements IRecordProcessor {
#Autowired
private SingleRecordProcessor singleRecordProcessor;
#Override
public void initialize(String shardId) {
...
}
#Override
public void processRecords(List<Record> records, IRecordProcessorCheckpointer checkpointer) {
...
}
}
I use Class SingleRecordProcessor to process single each record from kinesis. And this is my SingleRecordProcessor class snippet:
#Component
public class SingleRecordProcessor {
private Parser parser;
private Map<String, Table> tables;
public SingleRecordProcessor() {
}
#Autowired
private void setParser(Parser parser) {
this.parser = parser;
}
#Autowired
private void setTables(Map<String, Table> tables) {
this.tables = tables;
}
public void process(String record) {
...
}
}
I want to let spring framework automatically inject the SingleRecordProcessor instance into the class and use it. But I found that the field singleRecordProcessor is null.
Any idea why the dependency injection is failed? Or is it impossible to inject dependencies into a class which is called by other framework (in this case it's KCL)? Any suggestions will be appreciated! Really need some help please!!
[UPDATE]:
Sorry for not expressing the error clearly. The error was NullPointerException. I tried to inject singleRecordProcessor and call method process() on it. I think the injection was not successful so the instance singleRecordProcessor is null and there comes the NullPointerException.
More information is as follows:
I have a major class called Application
#SpringBootApplication
public class Application{
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Application.class);
application.addListeners(new ApplicationPidFileWriter("./app.pid"));
ConfigurableApplicationContext ctx = application.run(args);
}
}
And I have the MainProcessor class which will call KCL.
#Service
public final class MainProcessor {
#EventListener(ApplicationReadyEvent.class)
public static void startConsumer() throws Exception {
init();
IRecordProcessorFactory recordProcessorFactory = new RecordProcessorFactory();
Worker worker = new Worker(recordProcessorFactory, kinesisClientLibConfiguration);
...
worker.run(); // this line will call KCL library and eventually call ProcessorRecord class.
}
}
[UPDATE2]
RecordProcessorFactory only has one method like this
#Component
public class RecordProcessorFactory implements IRecordProcessorFactory {
#Autowired
RecordProcessor recordProcessor;
#Override
public IRecordProcessor createProcessor() {
return recordProcessor;
}
}
It creates a new RecordProcessor instance for KCL to use it.
You should autowire an instance of this into your MainProcessor:
#Component
public class RecordProcessorFactory {
#Lookup IRecordProcessor createProcessor() { return null; }
}
Spring will instantiate a RecordProcessorFactory for you, and replace the implementation of createProcessor() in it with one that will return a new IRecordProcessor each time it's called. Both the factory and the processors will be Spring beans - which is what you want.

How to inject mocks while testing classes using CDI in production

I am programming in a Java SE environment using WELD-SE for dependency injection. Therefore dependencies of a class look something like this:
public class ProductionCodeClass {
#Inject
private DependencyClass dependency;
}
When writing a unit test for this class I am creating a mock for DependencyClass and as I don't want to start a complete CDI environment for every test I run, I "inject" the mock manually:
import static TestSupport.setField;
import static org.mockito.Mockito.*;
public class ProductionCodeClassTest {
#Before
public void setUp() {
mockedDependency = mock(DependencyClass.class);
testedInstance = new ProductionCodeClass();
setField(testedInstance, "dependency", mockedDependency);
}
}
The statically imported method setField() I have written myself in a class with tools I use in testing:
public class TestSupport {
public static void setField(
final Object instance,
final String field,
final Object value) {
try {
for (Class classIterator = instance.getClass();
classIterator != null;
classIterator = classIterator.getSuperclass()) {
try {
final Field declaredField =
classIterator.getDeclaredField(field);
declaredField.setAccessible(true);
declaredField.set(instance, value);
return;
} catch (final NoSuchFieldException nsfe) {
// ignored, we'll try the parent
}
}
throw new NoSuchFieldException(
String.format(
"Field '%s' not found in %s",
field,
instance));
} catch (final RuntimeException re) {
throw re;
} catch (final Exception ex) {
throw new RuntimeException(ex);
}
}
}
What I don't like about this solution is, that I need this helper over and over in any new project. I already packaged it as a Maven project I can add as a test dependency to my projects.
But isn't there something ready made in some other common library I am missing? Any comments on my way of doing this in general?
Mockito supports this out of the box:
public class ProductionCodeClassTest {
#Mock
private DependencyClass dependency;
#InjectMocks
private ProductionCodeClass testedInstance;
#Before
public void setUp() {
testedInstance = new ProductionCodeClass();
MockitoAnnotations.initMocks(this);
}
}
The #InjectMocks annotation will trigger injection of classes or interfaces mocked in the test class, in this case DependencyClass:
Mockito tries to inject by type (using name in case types are the same). Mockito does not throw anything when injection fails - you will have to satisfy the dependencies manually.
Here, I am also using the #Mock annotation instead of calling mock(). You could still use mock(), but I prefer using annotations.
As a side note, there are reflection tools available, which supports the functionality you implemented in TestSupport. One such example is ReflectionTestUtils.
Perhaps better still is to use constructor injection:
public class ProductionCodeClass {
private final DependencyClass dependency;
#Inject
public ProductionCodeClass(DependencyClass dependency) {
this.dependency = dependency;
}
}
The main advantage here is that it is clear what classes the class depends on, and that it cannot easily be constructed without providing all the dependencies. Also, it allows the injected class to be final.
By doing this, #InjectMocks is not necessary. Instead, just create the class by providing the mock as a parameter to the constructor:
public class ProductionCodeClassTest {
#Mock
private DependencyClass dependency;
private ProductionCodeClass testedInstance;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
testedInstance = new ProductionCodeClass(dependency);
}
}
Alternative when mockitos build in functions do not suffice: Try needle4j.org
It's a injection/mock framework that allows injection of mocks and concrete instances and also supports postConstruct for lifecycle simulation.
public class ProductionCodeClassTest {
#Rule
public final NeedleRule needle = new NeedleRule();
// will create productionCodeClass and inject mocks by default
#ObjectUnderTest(postConstruct=true)
private ProductionCodeClass testedInstance;
// this will automatically be a mock
#Inject
private AServiceProductionCodeClassDependsOn serviceMock;
// this will be injected into ObjectUnderTest
#InjectIntoMany
private ThisIsAnotherDependencyOfProdcutionCodeClass realObject = new ThisIsAnotherDependencyOfProdcutionCodeClass ();
#Test
public void test_stuff() {
....
}
}

how can I make Google Guice to automatically detect a binding?

I understand how to inject a single dependency using Google Guice.
The following snippets are from the Guice site.
To code a configuration the code would be
public class BillingModule extends AbstractModule {
#Override
protected void configure() {
bind(TransactionLog.class).to(DatabaseTransactionLog.class);
bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
}
}
The component which use the dependencies to be injected shuold looks like the following:
class BillingService {
private final CreditCardProcessor processor;
private final TransactionLog transactionLog;
#Inject
BillingService(CreditCardProcessor processor,
TransactionLog transactionLog) {
this.processor = processor;
this.transactionLog = transactionLog;
}
public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
...
}
}
FInally, the client code would use Guice to inject the dependencies where needed:
public static void main(String[] args) {
Injector injector = Guice.createInjector(new BillingModule());
BillingService billingService = injector.getInstance(BillingService.class);
...
}
My question is:
Is there a built-in feature in Guice to inject not only -for example- BillingService.class but another different implementation in runtime?
I think I can implement the variation of the different classes to be injected thru reflection or some manual mechanism like reading a configuration file to indicate which class to inject but I still want to know if this can be done from Guice itself.
You can make BillingService an interface and bind a different implementation of it decided in runtime in Module's configure method.

Using Assisted Inject with FactoryModuleBuilder in guice - Factory injection not being done

I am a guice newbie trying to figure out how to implement assisted inject in the guice using FactoryModuleBuilder. I consulted the guice java docs for implementing FactoryModuleBuilder.
I have done everything exactly as it says in the docs.
Its not injecting the factory.
I referred to this stack overflow question :Guice AssistedInject won't inject the factory
which had the same problem.
It talks about the field injection before constructor injection problem. I followed it and I am trying to call the Parent class using a caller class but I am still getting the null pointer exception. What is going wrong here?
Caller class
public class MAIN {
#Inject private static MyFactory factory;
public static void main(String[] args){
ParentClass newbie = new ParentClass(factory);
}
}
I am still getting the exception:
Exception in thread "main" java.lang.NullPointerException
at com.pkg.ParentClass.<init>(ParentClass.java:19)
at com.pkg.MAIN.main(MAIN.java:10)
Parent Class
public class ParentClass {
private final Foo test;
#Inject
public ParentClass(MyFactory factory){
test = factory.create(new HashMap<String,Object>());
}
}
Module Implementation: ParentModule
public class ParentModule extends AbstractModule{
#Override
protected void configure() {
install(new FactoryModuleBuilder()
.implement(Foo.class, FooImpl.class)
.build(MyFactory.class));
}
}
Factory Interface: MyFactory
public interface MyFactory {
Foo create(Map<String,Object> map);
}
Class Interface : Foo
public interface Foo{
}
Class:FooImpl
public class FooImpl implements Foo {
private final Map<String,Object> mapA;
#AssistedInject
public FooImpl(#Assisted Map<String,Object> map){
mapA=map;
}
}
You have two problems here.
First and most important, you are not creating Injector anywhere. Obviously, without an injector nothing will work. You have to create an injector instance using your module:
Injector injector = Guice.createInjector(new ParentModule());
Your second problem is that you want to inject your factory into a static field:
#Inject private static MyFactory factory;
Although Guice can work with static fields if you tell it explicitly, it is considered very bad practice. You should never inject into static fields unless you are working with some legacy code.
What you really want is something like this:
public class Main {
#Inject
private MyFactory factory;
public void run() {
ParentClass newbie = new ParentClass(factory);
}
public static void main(String[] args) {
Injector injector = Guice.createInjector(new ParentModule());
Main main = injector.getInstance(Main.class);
main.run();
}
}
Note that program entry point (main) is now creates an injector and then uses it to create an instance of Main class, which will have its field injected automatically. And then it calls method run() on the instance which performs actual work.
Note, however, that this is all really valid only for illustrative purposes for assisted injection. You should not structure your real code like this. For example, you're using new operator to create classes whose constructors are annotated with #Inject. Don't ever do this! If you mark some class (i.e. its constructors or fields) as #Injectable, then this class should be used only by the means of injection. Your Main code can be shortened to the following:
public class Main {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new ParentModule());
ParentClass newbie = injector.getInstance(ParentClass.class);
}
}
Here newbie will automatically receive an instance of MyFactory into its constructor since it is annotated with #Inject.
And I already wrote about statics.

Using Google Guice to inject java properties

I want to use google guice to make properties available in all classes of my application. I defined a Module which loads and binds the properties file Test.properties.
Property1=TEST
Property2=25
package com.test;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
import com.google.inject.AbstractModule;
import com.google.inject.name.Names;
public class TestConfiguration extends AbstractModule {
#Override
protected void configure() {
Properties properties = new Properties();
try {
properties.load(new FileReader("Test.properties"));
Names.bindProperties(binder(), properties);
} catch (FileNotFoundException e) {
System.out.println("The configuration file Test.properties can not be found");
} catch (IOException e) {
System.out.println("I/O Exception during loading configuration");
}
}
}
I'm using a main class where I create a injector to inject the properties.
package com.test;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class Test {
public static void main(String[] args) {
TestConfiguration config = new TestConfiguration();
Injector injector = Guice.createInjector(config);
TestImpl test = injector.getInstance(TestImpl.class);
}
}
package com.test;
import com.google.inject.Inject;
import com.google.inject.name.Named;
public class TestImpl {
private final String property1;
private final Integer property2;
#Inject
public TestImpl(#Named("Property1") String property1, #Named("Property2") Integer property2) {
System.out.println("Hello World");
this.property1 = property1;
this.property2 = property2;
System.out.println(property1);
System.out.println(property2);
}
}
Now my question. If my TestImpl creates other classes where I also need to inject properties, and those classes also need to inject properties what is the correct way to do this?
Pass the injector to all subclasses and then use injector.getInstance(...) to create the subclasses?
Instanciate a new injector like
TestConfiguration config = new TestConfiguration();
Injector injector = Guice.createInjector(config);
TestImpl test = injector.getInstance(TestImpl.class);
in all nested classes?
Is there an other approach to make the properties available in all classes?
Pass the injector to all subclasses and then use
injector.getInstance(...) to create the subclasses?
no, by doing this you are defeating the purpose of the dependency injection pattern and also coupling all your implementation to Guice. Your implementations should not interact at all with guice, except through the (now standardized) annotations.
Instanciate a new injector like
TestConfiguration config = new TestConfiguration();
Injector injector = Guice.createInjector(config);
TestImpl test = injector.getInstance(TestImpl.class);
in all nested classes?
no, and this is even worse cause you will end up with multiple injectors, hence multiple contexts which will prevent a proper usage of the scopes.
Ideally, you should only use the injector during the bootstrapping of your application. Of course the way to bootstrap it will largely depend of the application.
Is there an other approach to make the properties available in all
classes?
The properties could be injected the same way you did for TestImpl.
If you want TestImpl to use let say a service which also needs some properties (or other services), just let Guice inject it to TestImpl. Guice is taking care of all the instantiation/wiring. You should only tell Guice "how to proceed", by using the binder, when Guice cannot figure this out itself :
public class TestImpl {
private final String property1;
private final Integer property2;
private final IService service;
#Inject
public TestImpl(#Named("Property1") String property1, #Named("Property2") Integer property2, IService service) {
this.property1 = property1;
this.property2 = property2;
this.service= service;
}
}
}
Library "Governator" provide a configuration mapping feature for guice injection. The approach is different, but load from properties files is available.
https://github.com/Netflix/governator/wiki/Configuration-Mapping
The library Guice configuration can inject for you values from Properties or JSON files to your services.
You can inject from the file application.properties to your service as :
#BindConfig(value = "application", syntax = PROPERTIES)
public class Service {
#InjectConfig
private int port;
#InjectConfig
private String url;
#InjectConfig
private Optional<Integer> timeout;
}
You must simply install the modules ConfigurationModule
public class GuiceModule extends AbstractModule {
#Override
protected void configure() {
install(ConfigurationModule.create());
requestInjection(Service.class);
}
}
guice-config
Usage example:
At first we have a properties file 'config.properties':
test.key=test value
And we want to inject this value like this:
#Inject
#Config( Property.TEST_KEY )
private String injectedValue;
We need to load contents of file 'config.properties' into java.util.Properties and pass it to Config module:
Properties props = new Properties();
props.load(...);
Module configModule = new ConfigModule( props, Property.values() );
... and injecting:
Injector injector = Guice.createInjector( configModule );
TestClass testClass = injector.getInstance( TestClass.class );
String injectedValue = testClass.getInjectedValue();
injected value will be 'test value'...
"Now my question. If my TestImpl creates other classes where I also need to inject properties, and those classes also need to inject properties what is the correct way to do this?"
Rule of thumb: avoid the use of "new" Unless it is absolutely necessary, dont let your Impl Class "create other classes". Instead, tell your TestImpl that when created with guice, it should get the required instances injected.

Categories