How to inject values without explicit calls? - java

I'm familiar with dependency injection concepts and its benefits, but using frameworks that would handle this business for me gets kind of confusing.
This question is valid for any DI framework, but I will stick to the Guice with this question.
The problem
Let's say, I have following classes:
public interface Tea {
void prepare();
}
public class GreenTea implements Tea {
public void prepare() {
System.out.println("Preparing Green Tea");
}
}
public class BlackTea implements Tea {
public void prepare() {
System.out.println("Preparing Black Tea");
}
}
Without frameworks, in my main method, I would do something like this:
public static void main(String[] args) {
Tea tea = new GreenTea();
tea.prepare();
}
With the help of Google Guice Inject I could get futher and do something like this:
public class TeaModule extends AbstractModule {
protected void configure() {
bind(Tea.class).to(GreenTea.class);
}
}
public class Main {
#Inject
private Tea tea;
public static void main(String[] args) {
Injector injector = Guice.createInjector(new TeaModule());
Main main = injector.getInstance(Main.class);
main.tea.prepare();
}
}
Now, let's say I have some random class, which needs my tea interface injected:
public class RandomClass {
private Tea tea;
public void doStuff() {
System.out.print("Doing stuff and.. ");
tea.prepare();
}
public Tea getTea() {
return tea;
}
#Inject
public void setTea(Tea tea) {
this.tea = tea;
}
}
Unfortunately this throws NullPointerException, because RandomClass is not aware of any injections from outside.
Solutions I found so far
1) I've read about creating custom Providers, such as:
public class TeaProvider implements Provider<Tea> {
public Tea get() {
Tea tea = new BlackTea();
return tea;
}
}
As far as I know, this solution requires creating new class in order to work:
//In main method
injector.injectMembers(new RandomClass());
2) Worse solution, is to inject injector inside RandomClass and manually asking for class instance, like so:
public class RandomClass {
#Inject
Injector injector;
private Tea tea;
public RandomClass() {
tea = injector.getInstance(Tea.class);
}
public void doStuff() {
System.out.print("Doing stuff and.. ");
tea.prepare();
}
}
Even so, I must get RandomClass instance from injector in my bootstrapping method.
The questions
I really don't get the whole concept of DI frameworks, if they require providing classes either way.
1) Is there any possible way to inject Tea instance into RandomClass without explicitly telling injecting in bootstrapping method to do so? If possible, then how?
2) What's the pros in using DI frameworks, if I've to manually "load" all classes to inject values? I mean, I can provide new instance of some class to the dependent without using frameworks at all. Then why people would use it?

The idea behind DI frameworks is simple: A class shouldn't be responsible for instantiating its dependencies. So, though I wouldn't recommend going this far, a 100% DI solution should include zero calls to new. It should happen entirely from a factory class.
Here's your RandomClass with no DI:
public class RandomClass {
private Tea tea;
public RandomClass() {
tea = new BlackTea();
}
public void doStuff() {
System.out.print("Doing stuff and.. ");
tea.prepare();
}
}
At this point, you should notice that it is impossible to test RandomClass without testing Tea's functionality, because you've provided no way to provide an alternative implementation.
Another way you could do it:
public class RandomClass {
private Tea tea;
public RandomClass(Tea tea) {
this.tea = tea;
}
public void doStuff() {
System.out.print("Doing stuff and.. ");
tea.prepare();
}
}
public class RandomClassProvider {
public RandomClass create() {
return new RandomClass(new BlackTea());
}
}
Now, with DI annotations:
public class RandomClass {
private Tea tea;
#Inject public RandomClass(Tea tea) {
this.tea = tea;
}
public void doStuff() {
System.out.print("Doing stuff and.. ");
tea.prepare();
}
}
// Guice writes Provider<RandomClass> automatically.
Now you can use RandomClass manually (by calling the #Inject-annotated constructor) or automatically (just requesting an instance through Guice). This should make it easy to switch implementations, including to switch implementations only in tests to test doubles you've written or that you've created through Mockito.
A final word about providers: You shouldn't have to worry about Providers yourself: No matter how you bind an instance or provider, you can access it using #Inject X or #Inject Provider<X> anywhere in a constructor or field (or getInstance or getProvider). Inject a Provider if you're not sure you need an instance, or if you'll need more than one, and only write a Provider manually if you need to call some external method to get an instance if you need to postprocess.

Related

Is it possible to make a JUnit5 Extension implement an interface that is fulfilled by the extended class?

I would like to write a JUnit5 Extension that extends my test class,
#ExtendWith(MyExtension.class)
public class MyTestClass {
#Test myTest1() {}
#Test myTest2() {}
// ...
}
However, my test class also implements a certain interface, so it looks more like this:
public interface SomeInterface {
SomeClient getSomeClient();
SomeClient getSomeClientAsAdministrator();
}
#ExtendWith(MyExtension.class)
public class MyTestClass implements SomeInterface {
#Test myTest1() {}
#Test myTest2() {}
// ...
SomeClient getSomeClient() {
// ...
}
SomeClient getSomeClientAsAdministrator() {
// ...
}
}
No mysteries so far.
But now, I want those interface implementations to be available to the extension as well, e.g.
public class MyExtension implements BeforeEachCallback, SomeInterface
{
#Override
public void beforeAll(ExtensionContext extensionContext) {
// be able to use getSomeClient();
}
}
How can I set up my classes to achieve this? (Or, what is the inherent flaw or code smell against doing this?)
You need to use the #RegisterExtension annotation which allows you to construct your extension instance manually.
When an extension is registered declaratively via #ExtendWith, it can
typically only be configured via annotations. In contrast, when an
extension is registered via #RegisterExtension, it can be configured
programmatically — for example, in order to pass arguments to the
extension’s constructor, a static factory method, or a builder API.
It sounds like SomeClient is provided from elsewhere (a DI like Spring perhaps) but you need it in MyExtension. Assuming this scenario, you can start with something like:
#ExtendWith(SpringExtension.class)
public class MyTestClass {
#Autowired SomeClient someClient;
#RegisterExtension
MyExtension myExtension = new MyExtension(someClient);
}
One way to achieve that is to use getTestInstance() on the context object:
public class MyExtension implements BeforeEachCallback {
#Override
public void beforeEach(ExtensionContext context) throws Exception {
context.getTestInstance().ifPresent(instance -> {
if (instance instanceof SomeInterface) {
SomeInterface some = (SomeInterface) instance;
System.out.println(some.getSomeClient());
}
});
}
}
What you can see here is two things:
There might not be a test instance object, e.g. in a BeforeAllCallback because test instances are usually created per test.
A cast is required. That means you should check if your test instance really does implement SomeInterface
Having said that, I'm not really sure why you'd want to go down that rather complicated route. What's MyExtension supposed to abstract from?

Mocking with anonymous class in Java

I'm learning about dependecy injection and testing with Mockito. And I just found a tutorial where someone explain an application with dependency injection and without dependency injection. This is the link: https://www.journaldev.com/2394/java-dependency-injection-design-pattern-example-tutorial
I have 2 questions:
The first question is about the code that he writes for testing. What kind of mock is that? Don't you need to use #Mock to mock an object?
This is his code for testing:
public class MyDIApplicationJUnitTest {
private MessageServiceInjector injector;
#Before
public void setUp(){
//mock the injector with anonymous class
injector = new MessageServiceInjector() {
#Override
public Consumer getConsumer() {
//mock the message service
return new MyDIApplication(new MessageService() {
#Override
public void sendMessage(String msg, String rec) {
System.out.println("Mock Message Service implementation");
}
});
}
};
}
#Test
public void test() {
Consumer consumer = injector.getConsumer();
consumer.processMessages("Hi Pankaj", "pankaj#abc.com");
}
#After
public void tear(){
injector = null;
}
}
And the second question is about testing the app without dependency injection. I don't understand why he say that: "Testing the application will be very difficult since our application is directly creating the email service instance. There is no way we can mock these objects in our test classes." Why we cannot mock these objects in our test cases.
The first question is about the code that he writes for testing. What kind of mock is that? Don't you need to use #Mock to mock an object?
To mock an object you have to provide an object that has same type i.e behaves the same or is a subtype of the class that object you want to mock. So to mock an object you can use an instance of anonymous class (in your case it would be an object of anaonymous class that extends MyDIApplication) or you can use Mockito with its #Mock annotation which does basically similiar thing. Bascially using #Mock annotation is similiar to doing :
MyDIApplication myDiApplication = Mockito.mock(MyDIApplication.class)
which creates a mock object extending class passed in constructor. Here you may pass interface or class depending on what you want to mock.
When using anonymous class you provide implementation of methods that you want to mock in overriden implementations of methods, but in case of Mockito you provide intender behaviour by using methods like Mockito::when.
And the second question is about testing the app without dependency injection. I don't understand why he say that: "Testing the application will be very difficult since our application is directly creating the email service instance. There is no way we can mock these objects in our test classes." Why we cannot mock these objects in our test cases.
I guess you are refering to this piece of code :
public class MyApplication {
private EmailService email = new EmailService();
public void processMessages(String msg, String rec){
//do some msg validation, manipulation logic etc
this.email.sendEmail(msg, rec);
}
}
Here you create an instance of EmailService as class field. So there is no possibilty you can mock this (although you could use reflection or PowerMock). So you are tightly coupled to EmailService and it is hard to test MyApplication class logic. To be able to test it you can use constructor injection :
public class MyApplication {
private EmailService email;
public MyApplication(EmailService emaliService) {
this.email = emailService;
}
public void processMessages(String msg, String rec){
//do some msg validation, manipulation logic etc
this.email.sendEmail(msg, rec);
}
}
Or setter injection :
public class MyApplication {
private EmailService email;
public void setEmailService(EmailService emailService) {
this.email = emailService;
}
public void processMessages(String msg, String rec){
//do some msg validation, manipulation logic etc
this.email.sendEmail(msg, rec);
}
}

What is actually involved in a mvp scenario to use google guice?

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.

How to call constructor of Eclipse 4 RCP part when application start?

I have a few Parts in one PartStack. When application start, only constructor of the first part is called. Other constructors are called when I click on these Parts.
I have something like this:
public class OneOfParts {
#Inject OneOfParts(final BorderPane pane) {
//some initialization stuff
}
//other methods
}
How can I call constructors of all Parts in this PartStack when application start?
E: Or is there another way to initialize final field from Parts when application start?
You could try to do your initializations during application start using a LifeCycleHandler. Lars Vogel describes how to implement one here.
Alternatively you could write a data class and annotate it with #Creatable and #Singleton which you then use in all parts sharing that data by DI.
#Singleton
#Creatable
public class SharedData() {
private SharedData() {
// initialize Data here - alternatively: Use #PostConstruct method in this class
}
}
public class PartShowingHex {
#PostConstruct
private void initializePart(SharedData pData) {
// do whatever you need
}
}
For a field based approach:
public class PartShowingTxt {
#Inject
private SharedData myData;
#PostConstruct
private void initializePart() {
// ...
}
}
I'd recommand using the Data-Singleton with method-DI approach (first code example).

Google Guice desktop application - how to make it work?

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

Categories

Resources