We have a new Play 2.0 project and we are planning to introduce DI as we add some complex 3rd party integration code.
There is a Guice plugin for Play 2.0 but it looks like it will be obsolete at 2.1 and I have a hunch that 2.1 is not that far anymore.
https://github.com/typesafehub/play-plugins/tree/master/guice
Is Guice a safe bet for Play 2.0/2.1 or should we consider other options?
I'd go with the 2.1 version, and the new controller instanciation from the Global object.
Here is a Guice example from the doc:
import play.GlobalSettings;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class Global extends GlobalSettings {
private static final Injector INJECTOR = createInjector();
#Override
public <A> A getControllerInstance(Class<A> controllerClass) throws Exception {
return INJECTOR.getInstance(controllerClass);
}
private static Injector createInjector() {
return Guice.createInjector();
}
}
You have to declare a special route for these controllers, with the special #:
GET /myUrl #controllers.MyController.myMethod()
And you can also take a look at this demo using Spring: https://github.com/guillaumebort/play20-spring-demo
Related
My team owns a library that provides components that must be referencable by code that consumes the library. Some of our consumers use Spring to instantiate their apps; others use Guice. We'd like some feedback on best-practices on how to provide these components. Two options that present themselves are:
Have our library provide a Spring Configuration that consumers can #Import, and a Guice Module that they can install.
Have our library provide a ComponentProvider singleton, which provides methods to fetch the relevant components the library provides.
Quick sketches of what these would look like:
Present in both approaches
// In their code
#AllArgsConstructor(onConstructor = #__(#Inject))
public class ConsumingClass {
private final FooDependency foo;
...
}
First approach
// In our code
#Configuration
public class LibraryConfiguration {
#Bean public FooDependency foo() {...}
...
}
---
public class LibraryModule extends AbstractModule {
#Provides FooDependency foo() {...}
...
}
========================
========================
// In their code
#Configuration
#Import(LibraryConfiguration.java)
public class ConsumerConfiguration {
// Whatever initiation logic they want - but, crucially, does
// *not* need to define a FooDependency
...
}
---
// *OR*
public class ConsumerModule extends AbstractModule {
#Override
public void configure() {
// Or, simply specify LibraryModule when creating the injector
install(new LibraryModule());
...
// As above, no requirement to define a FooDependency
}
}
Second approach
// In our code
public class LibraryProvider {
public static final INSTANCE = buildInstance();
private static LibraryProvider buildInstance() {...}
private static LibraryProvider getInstance() {return INSTANCE;}
}
========================
========================
// In their code
#Configuration
public class ConsumerConfiguration {
#Bean public FooDependency foo() {
return LibraryProvider.getInstance().getFoo();
}
...
}
// or equivalent for Guice
Is there an accepted Best Practice for this situation? If not, what are some pros and cons of each, or of another option I haven't yet thought of? The first approach has the advantage that consumers don't need to write any code to initialize dependencies, and that DI frameworks can override dependencies (e.g. with mocked dependencies for testing); whereas the second approach has the advantage of being DI-framework agnostic (if a new consumer wanted to use Dagger to instantiate their app, for instance, we wouldn't need to change the library at all)
I think the first option is better. If your library has inter-dependencies between beans then the code of #Configuration in case of spring in the second approach) will be:
Fragile (what if application doesn't know that a certain bean should be created)
Duplicated - this code will appear in each and every consumer's module
When the new version of your library gets released and a consumer wants to upgrade- there might be changes in consumer's configuration ( the lib might expose a new bean, deprecate or even remove some old stuff, etc.)
One small suggestion:
You can use Spring factories and then you don't even need to make an #Import in case of spring boot. just add a maven dependency and it will load the configuration automatically.
Now, make sure that you work correctly with dependencies in case of that approach.
Since you code will include both spring and Juice dependent code, you'll add dependencies on both for your maven/gradle module of the library. This means, that consumer that uses, say, guice, will get all the spring stuff because of your library. There are many ways to overcome this issue depending on the build system of your choice, just want wanted to bring it up
I am a novice in weld, and through several days exploration but I only know some fundamental concept of weld.
I'm intended to use weld container in java se environment. And follw What is the easiest way to have CDI and JPA in Java SE? my code segment is below:
public class SayHello {
public SayHello(){}
public void sayHello(){
System.out.println("Hello");
}
}
import javax.inject.Inject;
import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;
public class UseInject {
private SayHello obj;
public UseInject(){}
#Inject
public UseInject(SayHello obj){
this.obj = obj;
}
public void show(){
obj.sayHello();
}
public static void main(String[] args){
Weld weld = new Weld();
WeldContainer container = weld.initialize();
UseInject ui = container.instance().select(UseInject.class).get();
ui.show();
weld.shutdown();
}
}
and my application is based on maven. Here is the jar dependency segment in pom.xml
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se-core</artifactId>
<version>3.0.0.Alpha17</version>
my intention is inject SayHello object into UseInject Object so the final output of this application is "Hello".
But things are not so smooth, the jvm report the follow error:
and through search from internet,there is a saying that build a empty beans.xml is ok, and I follow it can't make effect. And as for the main method I imitate What is the easiest way to have CDI and JPA in Java SE? I don't know what thing it do, and What is the easiest way to have CDI and JPA in Java SE? use the #Produces annotation, I don't know whether I should use it too. And I had intended use it for the SayHello Class, but I don't know which jar should I import in order to use it,so I give up.
Now I want to:
1. know how the weld service for se application in other words what things the main method does?
2. How can I run my application successfully using weld?
3. when we should use the annotation #Produces
And I made reference to a number of relevant issues e.g.weld and java seHow to bootstrap weld-se in a JUnit testetc. but find they are all to senior for me.
thanks for your attention advance.
How can I run my application successfully using weld?
The error message is telling you that you have to create a file named beans.xml under the directory META-INF. So to solve the problem just do the following:
Directory named META-INF under src/main/resources directory
Create an empty file named beans.xml under META-INF so that your project is CDI enabled.
when we should use the annotation #Produces
You use this annotation if you want to use any Java primitive types such as Integer, String, ... as CDI beans, or any type / class in an external library which does not contain the META-INF/beans.xml file in the classpath.
Example:
public class SayHello {
#Produces
private double pi = 3.14159;
// the rest of the code
}
and you can inject the value of PI in another place in your code as:
public class UseInject {
#Inject
private double pi; // 3.14159 will be injected here
// the rest of the code
public static void main(...) {
// ....
UseInject ui = container.instance().select(UseInject.class).get();
ui.show();
System.out.println(ui.pi);
// ...
}
The value 3.14159 should be displayed on the console.
I need to create tests for some class. This class in main project (src/main/java/..) is injected easily into another classes, since I have custom ResourceConfig class which declares which packages have to be scanned to seek for service classes.
Now I created test directories (in src/test/java/..) and created a class, something like:
public class TheMentionedClassIntegrationTest {
#Inject
private TheMentionedClass theMentionedClass ;
#Test
public void testProcessMethod() {
assertNotNull(theMentionedClass);
}
}
But the problem is that whatever I do the class is always null. In another tests in the project I was using JerseyTest class. So I tried to do the same here, extend TheMentionedClassIntegrationTest with JerseyTest, override configure method, create my private ResourceConfig class which registers Binder (default for whole project) and register TheMentionedClassIntegrationTest as well.
It didnt work. I did many different attempts but none of them were successfull. I think working with HK2 is extremly difficult, there is no good documentation or so..
Do you guys have an idea how to inject TheMentionedClass into the test class? Maybe my approach is wrong?
Thanks!
The easiest thing to do is to just create the ServiceLocator and use it to inject the test class, as see here. For example
public class TheMentionedClassIntegrationTest {
#Inject
private TheMentionedClass theMentionedClass;
#Before
public void setUp() {
ServiceLocator locator = ServiceLocatorUtilities.bind(new YourBinder());
locator.inject(this);
}
#Test
public void testProcessMethod() {
assertNotNull(theMentionedClass);
}
}
You could alternatively use (make) a JUnit runner, as seen here.
For some other ideas, you might want to check out the tests for the hk2-testing, and all of its containing projects for some use case examples.
GitHub Project Link
I have made a project on GitHub which is a model of the dagger 2 architecture of my projects actual architecture. This question will be based off of the GitHub project.
I have provided many code snippets in this question, however, it may be easier to just compile the project yourself in Android Studio to understand the problem.
If you check out the code, it won't compile. Go into AppModule.java and comment out both provides methods and it should compile.
The main question is the last line on this post.
https://github.com/qazimusab/Dagger2LibraryProject
Architecture
I have a library which contains all the code needed to make the application. The point of this architecture is that each app I create in the project should be able to use the library and ,through dagger 2, be able to provide different implementations for any single class or activity it wants in it's own module. At this point I only have one application in this sample project which uses the library.
The Problem
With dagger one, I had the same architecture, and in the app specific module (as opposed to the library module), I was able to add a new provides annotated method to override any implementation which was being provided in the any of the library modules as long as
The method was in a module in the app module
The method was annotated with #Provides
The method had the same return type as the one you want to override
With Dagger 2, the architecture works when I either don't override any provides or if I do, when I override every single provides in that module and remove that module from the includes from the Application specific module.
For example, in my project, I have an app and a library.
The app has an AppModule; the library has a CatModule to provide a Cat and CatFood, a dog module to provide a Dog and DogFood, and a LibraryModule to provide the activities.
CatModule.java
package com.example.qaziahmed.library.application.modules;
import com.example.qaziahmed.library.classes.Cat; import
com.example.qaziahmed.library.classes.CatFood; import
com.example.qaziahmed.library.classes.contract.ICat; import
com.example.qaziahmed.library.classes.contract.ICatFood;
import javax.inject.Singleton;
import dagger.Module; import dagger.Provides;
/** * Created by qaziahmed on 11/23/15. */ #Module public class
CatModule {
#Provides
#Singleton
ICat provideCat() {
return new Cat();
}
#Provides
ICatFood provideCatFood(){
return new CatFood();
} }
DogModule.java
package com.example.qaziahmed.library.application.modules;
import com.example.qaziahmed.library.classes.Dog; import
com.example.qaziahmed.library.classes.DogFood; import
com.example.qaziahmed.library.classes.contract.IDog; import
com.example.qaziahmed.library.classes.contract.IDogFood;
import javax.inject.Singleton;
import dagger.Module; import dagger.Provides;
/** * Created by qaziahmed on 11/23/15. */ #Module public class
DogModule {
#Provides
#Singleton
IDog provideDog() {
return new Dog();
}
#Provides
IDogFood provideDogFood(){
return new DogFood();
}
}
So, in my application module, I want to provide a house cat implementation of ICat instead of a generic cat and an AllNaturalDogFood implementation of IDogFood instead of just regular DogFood, then in my AppModule I add two provides to override those
AppModule.java
package com.example.qaziahmed.dagger2libraryproject.application;
import
com.example.qaziahmed.dagger2libraryproject.classes.AllNaturalDogFood;
import com.example.qaziahmed.dagger2libraryproject.classes.HouseCat;
import com.example.qaziahmed.library.application.modules.CatModule;
import com.example.qaziahmed.library.application.modules.DogModule;
import
com.example.qaziahmed.library.application.modules.LibraryModule;
import com.example.qaziahmed.library.classes.contract.ICat; import
com.example.qaziahmed.library.classes.contract.IDogFood;
import javax.inject.Singleton;
import dagger.Module; import dagger.Provides;
/** * Created by ogre on 2015-07-12 */ #Module(includes = {
LibraryModule.class,
DogModule.class,
CatModule.class }) public class AppModule {
#Provides
#Singleton
ICat provideHouseCat() {
return new HouseCat();
}
#Provides
IDogFood provideAllNaturalDogFood(){
return new AllNaturalDogFood();
} }
Now, when I run this setup, this is the error I get:
Error:com.example.qaziahmed.library.classes.contract.ICat is bound multiple times:
#Provides #Singleton com.example.qaziahmed.library.classes.contract.ICat com.example.qaziahmed.dagger2libraryproject.application.AppModule.provideHouseCat()
#Provides #Singleton com.example.qaziahmed.library.classes.contract.ICat com.example.qaziahmed.library.application.modules.CatModule.provideCat()
Error:com.example.qaziahmed.library.classes.contract.IDogFood is bound multiple times:
#Provides com.example.qaziahmed.library.classes.contract.IDogFood com.example.qaziahmed.dagger2libraryproject.application.AppModule.provideAllNaturalDogFood()
#Provides com.example.qaziahmed.library.classes.contract.IDogFood com.example.qaziahmed.library.application.modules.DogModule.provideDogFood()
Now, if in AppModule.java, I also add provides annotated methods to provide Cat Food and Provide Dog and then remove CatModule.class and DogModule.class from the includes in App Module then it works.
However, the whole question is how do I override a single provides method in some module in the library without having to override every provides annotated method inside that specific module and then removing that module from the includes in AppModule.java
Will try to decrypt this quote from the Dagger 2 docs:
Dagger 2 doesn't support overrides. Modules that override for simple testing fakes can create a subclass of the module to emulate that behavior. Modules that use overrides and rely on dependency injection should be decomposed so that the overridden modules are instead represented as a choice between two modules.
In your current example you don't rely on dependency injection because your provides* methods create simple new objects so you will be able to just create a subclass of the module, override the provides method that you need overridden and then include that new module in your component.
When you have reliance on DI (and in reality you will at some stage of your project) like this:
#Provides
#Singleton
ICat provideCat(IBowtie bowtie) { // 'bowtie' needs to be injected
return new CatWithBowtie(Bowtie);
}
it comes to "Modules that use overrides and rely on dependency injection should be decomposed" which basically means: you have to split CatModule in two: CatModule with just providesCat and 'CatFoodModule' with provideCatFood(). Then your app's component you just use your new CatWithBowtieModule instead of CatModule.
There two useful advises:
In library projects split modules so there is just one provides* method per module. Yes, it sounds like BS but this is the only way to provide easy overriding later in your app.
For a moment lets pretend that the library is given to you from a third party as a JAR/AAP and you don't even have the source. In that case you will not be able to reuse modules defined in the lib, so you will have to create all of them by yourself. This is exactly what happens with Dagger 2.
When you try to use modules from your lib in your app directly (as you did) these two projects are not two separate projects any more but one project that just looks like two projects (which are clusterf*ck tightly coupled). It is OK for the app to depend on the lib but it is not OK for the lib to depend on the app. It boils down to: In Dagger 2 it is best not to use cross (project) border modules and components.
Someone may ask: "What is the good of using Dagger 2 in a lib if I can't use lib's modules/components in my app?!". Well, you still will be able to use your dagger modules/components in your unit tests which is the main benefit of using Dagger after all. Also if your lib is meant to be used by other people you may (must?) provide a referent app which shows how to "wire" things so lib's users will be able to just copy that code if it suits them or at least see how to start.
The problem is that your Injection sees two methods that are providing the same object.
If you read this link: http://google.github.io/dagger/ you can remedies to that by naming your provider as:
#Provides #Named("water")
Then, in your Injection, reference it like:
#Inject #Named("water")
As a workaround , I write two methods, one for #Provides and one for #Overrides.
#Override
protected X getX() {
return new X();
}
#Provides
X provideX() {
return getX();
}
I'm currently trying to add Dagger to my android projects. For the apps projects its easy and clear to me, how to build the ObjectGraph. But I dont quite know whats the best way to do this in my android library projects.
Should I keep building the ObjectGraph in the Application class of the apps and pass the OG over to a LibraryModule - plussing the OG of library to the Apps OG? Or should i build the whole ObjectGraph in the library?
What if I need to inject a class in the library by ObjectGraph.inject(this)? In my Apps projects I can get the OG from the Application class. But how to handle this in the library? Should I add a #Provides method for the ObjectGraph?
Big thanks for your help.
Edit:
In short: How can I call ObjectGraph.inject(this) in my library project where I don't have access to the OG because it is being builded in the Application Class?
In case someone using Dagger 2 gets here, this is the way I've done in my App:
In the library module I've created the following Module and Component:
#Module
public class ModuleUtil {
#Provides
public RestTemplate provideRestTemplate() {
return new RestTemplate();
}
}
#Singleton
#Component(
modules = {
ModuleUtil.class
})
public interface MainComponent {
void inject(Postman postman);
}
And then I've created the Singleton below in order to manage the injections:
public class DaggerWrapper {
private static MainComponent mComponent;
public static MainComponent getComponent() {
if (mComponent == null) {
initComponent();
}
return mComponent;
}
private static void initComponent () {
mComponent = DaggerMainComponent
.builder()
.utilModule(new ModuleUtil())
.build();
}
}
When some class from the library module needs to inject its members, I simply call DaggerWrapper.getComponent().inject(this); and that't it.
I'm doing this way:
#Module classes belong to the main project and they provide implementations which you are injecting to library elements, so there are no #Module classes in the library projects
Library elements which are expecting dependency must have access to ObjectGraph and call .inject() on themselves, but main project should give ObjectGraph instance to the library with provided #Module dependency
How to get ObjectGraph from main project into the library? You could have interface like this:
interface Injector {
void inject(Object object);
public ObjectGraph getObjectGraph();
}
Context objects like Activity or Application class implements this interface (holders of ObjectGraph objects).
If you have example of Activity in the library module which needs something to inject from the main project this would look like this:
class LibraryActivity extends Activity {
#Inject ActivationModule instance;
void onCreate(... ) {
Injector injector = (Injector)getApplicationContext();
injector.inject(this)
}
}
ActivationModule is the class/interface in the library project.
Main project has application class which implements Injector interface and creates ObjectGraph with provided dependecy for ActivationModule in the library project.
class MyApplicationInTheMainProject extends Application implements Injector {
ObjectGraph graph;
#Override
public void onCreate() {
super.onCreate();
graph = ObjectGraph.create(new ActivationModuleImpl(this));
}
#Override public void inject(Object object) {
graph.inject(object);
}
#Override public ObjectGraph getObjectGraph() {
return graph;
}
}
#Module(injects = {
LibraryActivity.class
}, library = true)
class ActivationModuleImpl implements ActivationModule {
....
}
if you are giving this library to people and they dont know nothing about your scenario so you must write it in a way that your Dagger works perfectly without any help from user. (the easier to work with the better practice)
i just wrote some library for you to show how to do it. i wrote the library in a way that you can even run it standalone and see the result in the messages tab. user of your library doesnt need to know nothing about dagger and does nothing he just uses the library and dagger will be configured:
https://github.com/amirziaratii/libraryUsingDagger.git
if this library is something you use it yourself and for your own project, the best practice is do it like in this project of my friend:
https://github.com/mmirhoseini/trakt.tv
all your questions are answered in these two projects. ask any question and ill answer in comment.