I'm creating a main class in Play framework. Then I tried to #Inject another DAO object, as below:
public class HistoricalTask {
#Inject
protected static DataDao dataDao =
Play.current().injector().instanceOf(DataDao.class);
public static void main(String[] args) {
List<DataObject> rs = dataDao.getData();
}
}
But, it doesn't work. And I got an error:
Caused by: java.lang.RuntimeException: There is no started application
So, Is there any solution to create another main class, using #Inject feature and separate with Play web server?
Thank you, guys!
It is not possible to do that since your application is still in initialisation process.
If you want to initialise something at the time of application startup consider creating a module and add it to your application.conf file. Here you can register all the beans you want and any specific initialisation that you want to do by binding an eager singleton.
For example:
public class DaoHelperModule extends AbstractModule {
#Override
protected void configure() {
bind(DaoService.class).asEagerSingleton();
}
}
Then in application.conf file:
play.modules.enabled += "services.producer.DaoHelperModule"
You can inject dependencies in the module as well.
Related
I'm trying to get a repository into a class annotated with #Service using the #Autowired annotation in a Spring-boot class. However, the repository turns up as a null.
Here's the relevant code:
#Service
public class ImportLicenses {
#Autowired
private LicenseRepository licenseRepository;
public static void main (String[] args) {
ImportLicenses importLicenses = new ImportLicenses();
importLicenses.listFiles("/Users/admin/Licenses/licenses");
}
private void processLicense (Path path) {
try {
count++;
BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class);
FileTime fileTime = attr.lastModifiedTime();
Permission permission = new Permission(readLineByLineJava8(path.toFile().getAbsolutePath()));
LicensePojo licensePojo = new LicensePojo(permission, path);
Optional<License> licenseOptional = licenseRepository.findById(licensePojo.getId());
at which point it gets an NPE since licenceReposity is null.
I am able to access the licenseRepository in a controller class with this constructor
public LicenseController(LicenseRepository licenseRepository,
UserRepository userRepository) {
this.licenseRepository = licenseRepository;
this.userRepository = userRepository;
}
However, since I'm calling the constructor directly in the static main method, this doesn't seem like it's available. What's the best way to get the repository into this class?
Edit: Thanks for the responses. To clarify the question, I'm trying to pull this class into the structure of the existing Spring Boot application, instead of creating a separate one.
Option 1: Create a button or menu selection on the UI, and create a new controller class to run the import. This would be the simplest, but I don't want to necessarily have that on the UI.
Option 2: Code the import class create another Spring Application
#SpringBootApplication
public class ImportLicenses implements ApplicationRunner {
private final Logger logger = LoggerFactory.getLogger(LicenseGenApplication.class);
#SpringBootApplication
public static void main() {
main();
}
public static void main(String[] args) {
SpringApplication.run(ImportLiceneses.class, args);
}
#Override
public void run(ApplicationArguments args) throws Exception {
listFiles("/Users/admin//licenses");
}
public void listFiles(String path) {
try {
Files.walk(Paths.get(path))
.filter(ImportLicenses::test)
.forEach(p -> processLicense(p));
} catch (IOException e) {
e.printStackTrace();
}
}
....
}
Option 3 - Create a non-executable jar file from the existing application for use in the new application to avoid duplicating code.
Option 1 is the quickest, I'm not sure if option 2 work, Option 3 I'll take a look at to see if it's do-able.
Your application is a usual Java application. It is not a Spring Boot application.
What should you do? Make a Spring Boot application of it. For instance, create a demo app at https://start.spring.io/, compare your main class to the main class in the demo application, then adjust your main class correspondingly. Also compare your Maven or Gradle config to the config of the demo app and adjust correspondingly.
At least, your application should have an annotation #SpringBootApplication. Also, it should be launched via SpringApplication.run(...). This is a minimum. Depending on what you need, you may want to use #EnableAutoConfiguration and other configuration options.
I have just learned about Dependency injection (DI) and I am beginning to like it. To inject dependencies I am using Google Guice framework. Everything was running conceptually fine but while writing a module a thought came to my mind that what if my module require dependencies as a constructor, after all, it is just a class extending AbstractModule.
So, basically, I have 3 modules as a whole.
Environment Module
public class EnvModule extends AbstractModule {
#Override
protected void configure() {
install(new Servicemodule());
}
}
ServiceModule
public class ServiceModule extends AbstractModule {
private final boolean isEnabled;
#Override
protected void configure() {
if (isEnabled) {
install (new ThirdModule());
}
}
ThirdModule (It does not take any arguments in any constructor and have some bindings of its own)
Basically, the variable in the service module defines whether my application needs to install the third module or not. And that variable is defined in an application configuration file. So how do I inject that variable in the ServiceModule? As the field is final, setter injection is not possible, is there a way to use construction injection or field injection to inject the value.
I see the following options:
Use system variable:
ServiceModule() {isEnabled = System.getProperty("isThirdModuleEnabled")};
Read the config file directly in the ServiceModule() constructor
Use #Provides:
class ServiceModule ... {
#Provide #Singleton ThirdModuleParam getThirdModuleParam(...) {
//read the config file
ThirdModuleParam res = new ThirdModuleParam();
res.setIsEnabed(...);
return res;
}
}
class ThirdModule {
#Provide SomeThirdModuleClass getIt(ThirdModuleParam param) {
return param.isEnabled() ? new SomeThirdModuleClass() : null;
}
I'm trying to migrate from Play 2.3 to 2.5 but I have an issue on replacing the GlobalSettings.OnStart method.
In my old Global class that was extending GlobalSettings, in the onStartMethod I was initialising the Global Config and reading basic things from the DB.
I have created a new class and I m moving the code from the onStart method to the constructor of this one as mentioned in the doc.
https://www.playframework.com/documentation/2.5.x/GlobalSettings
https://www.playframework.com/documentation/2.4.x/PluginsToModules
I'm doing the binding as eagerSingleton from an AbstractModule. The class is correctly started but I keep getting the error:
GlobalBootstrapModule.configure:20 - Binding
OnStartConfig.:35 - Global...on start
Caused by: java.lang.RuntimeException: No EntityManager bound to this thread. Try wrapping this call in JPAApi.withTransaction, or ensure that the HTTP context is setup on this thread.
This is my code:
New class to replace onStart
public class OnStartConfig implements StartConfigInterface{
private final JPAApi jpaApi;
#Inject
public OnStartConfig(Application application, JPAApi jpa){
this.jpaApi = jpa;
Logger.debug("Global...on start");
jpaApi.withTransaction( ()-> {
GlobalConfiguration.aggregationCriteria = AggregationCriterion.getAll();
});
}
The interface I'm extending is just an empty placeholder.
AbstractModule used for the binding:
public class GlobalBootstrapModule extends AbstractModule {
#Override
protected void configure() {
Logger.debug("Binding");
bind(StartConfigInterface.class).to(OnStartConfig.class).asEagerSingleton();
}
}
And I have enabled the module in the application.conf file:
play {
modules {
enabled += modules.GlobalBootstrapModule
}
}
I suppose the problem is due to the lack of HttpContext. Where can I grab it from during the initialisation?
Any help would be hugely appreciated
I am currently trying to integrate Dagger 2 into an Android application. My project setup is as follows:
library
app (depends on library)
In my library project I defined a class that I'll later inject into other classes that need it (Activities and regular classes) in the library as well as the app project.
#Singleton
public class MyManager{
#Inject
public MyManager(){
//Do some initializing
}
}
Now - for instance in my Fragments or Activities or regular classes I'd inject the above Singleton as follows:
public class SomeClass{
#Inject
MyManager myManager;
}
Or so I thought, because in practice myManager is always null. And apparently it's constructor is never called either, so I guess I must be missing something configuration-wise? Or maybe I misunderstood the documentation and it's not meant to work this way at all? The purpose of MyManager class is to be an application-wide accessible component-accumulating entity - that's why I went for the #Singleton.
UPDATE
To avoid confusion: I mentioned my having components somewhere in a comment I think - this refers to components in the sense of "component based design" and has nothing to do with dagger. The dagger-based code I have is all listed above - there is nothing else related to dagger in my code.
When I started adding #Component I had some compiler issues, because my dagger2 was not setup properly - check out this really helpful thread on how to setup dagger2 correctly: https://stackoverflow.com/a/29943394/1041533
UPDATE 2
Here is my updated code, based on G. Lombard's suggestions - I changed the code as follows - the original Singleton is in the library project:
#Singleton
public class MyManager{
#Inject
public MyManager(){
//Do some initializing
}
}
Also in the library project is the bootstrap class:
#Singleton
#Component
public interface Bootstrap {
void initialize(Activity activity);
}
Then I use the above Bootstrap class in my activity (in my concrete app, NOT in the library project! I do however also have Classes/Activities in the library that'll access Bootstrap to inject MyManager):
public class MyActivity extends Activity{
#Inject
MyManager manager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//DONT DO THIS !!! AS EXPLAINED BY EpicPandaForce
DaggerBootstrap.create().initialize(this);
}
}
But even after this line:
DaggerBootstrap.create().initialize(this);
the manager instance is still null, i.e. not injected.
I just found this: https://stackoverflow.com/a/29326023/1041533
Which if I don't misread, implies I need to specify every single class in the Bootstrap class that will use #Inject to have stuff injected. Sadly - this is not an option, as I have more than 40 classes and activities for which I'd have to do that.
Meaning my Bootstrap interface apparently would have to look something like this:
#Singleton
#Component
public interface Bootstrap {
void initialize(ActivityA activity);
void initialize(ActivityB activity);
void initialize(ActivityC activity);
void initialize(ActivityD activity);
void initialize(ActivityE activity);
void initialize(ActivityF activity);
//and so on and so forth...
}
If the above is true, that would not be worth it for my use case. Plus: Seems there is no compile-time check, if I forgot to specify one of my 40+ classes here? It just wont work - i.e. crash the app at runtime.
You're making a mistake in that you are using
DaggerBootstrap.create().initialize(this);
in your Activity, as scopes are not shared across multiple component instances. What I recommend is using a custom application class
public class CustomApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Bootstrap.INSTANCE.setup();
}
}
#Component
#Singleton
public interface _Bootstrap {
void initialize(ActivityA activityA);
//void initiali...
}
public enum Bootstrap {
INSTANCE;
private _Bootstrap bootstrap;
void setup() {
bootstrap = Dagger_Bootstrap.create();
}
public _Bootstrap getBootstrap() {
return bootstrap;
}
}
Then you could call it as
Bootstrap.INSTANCE.getBootstrap().initialize(this);
This way, you share the component across your classes. I personally named Bootstrap as injector, and _Bootstrap as ApplicationComponent, so it looks like this:
Injector.INSTANCE.getApplicationComponent().inject(this);
But that's just my typical setup. Names don't really matter.
EDIT: To your last question, you can solve this by subscoping and component dependencies.
Your library project should be able to see only the library classes, correct? In that case, all you do is
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface LibraryScope {
}
#Component(modules={LibraryModule.class})
#LibraryScope
public interface LibraryComponent {
LibraryClass libraryClass(); //provision method for `MyManager`
}
#Module
public class LibraryModule {
#LibraryScope
#Provides
public LibraryClass libraryClass() { //in your example, LibraryClass is `MyManager`
return new LibraryClass(); //this is instantiation of `MyManager`
}
}
public enum LibraryBootstrap {
INSTANCE;
private LibraryComponent libraryComponent;
static {
INSTANCE.libraryComponent = DaggerLibraryComponent.create();
}
public LibraryComponent getLibraryComponent() {
return libraryComponent;
}
}
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface ApplicationScope {
}
#Component(dependencies={LibraryComponent.class}, modules={AdditionalAppModule.class})
#ApplicationScope
public interface ApplicationComponent extends LibraryComponent {
AdditionalAppClass additionalAppClass();
void inject(InjectableAppClass1 injectableAppClass1);
void inject(InjectableAppClass2 injectableAppClass2);
void inject(InjectableAppClass3 injectableAppClass3);
}
#Module
public class AdditionalAppModule {
#ApplicationScope
#Provides
public AdditionalAppClass additionalAppClass() { //something your app shares as a dependency, and not the library
return new AdditionalAppClass();
}
}
public enum ApplicationBootstrap {
INSTANCE;
private ApplicationComponent applicationComponent;
void setup() {
this.applicationComponent = DaggerApplicationComponent.builder()
.libraryComponent(LibraryBootstrap.INSTANCE.getLibraryComponent())
.build();
}
public ApplicationComponent getApplicationComponent() {
return applicationComponent;
}
}
Then
#Inject
LibraryClass libraryClass; //MyManager myManager;
...
ApplicationBootstrap.INSTANCE.getApplicationComponent().inject(this);
It's hard to say what your problem was, since you didn't show what your Component looks like and whether you have multiple components etc.
Assuming this logical structure:
/app
MainComponent
SomeClass // where MyManager is to be injected
MainActivity // where SomeClass is to be injected
/library
LibraryComponent
MyManager // Singleton
Then your classes as listed would inject correctly with the following configuration:
#Singleton
#Component
public interface LibraryComponent {
MyManager getMyManager();
}
and the app-level component to inject dependencies into the activity:
#ActivityScope
#Component(dependencies = LibraryComponent.class)
public interface MainComponent {
void inject(MainActivity mainActivity);
}
Note that MainComponent depends on LibraryComponent, but because the latter has singleton scope, you need to define a scope for the other one too, which I was I used the "activity scope" here. (Or you could also just make the MainComponent a singleton and get rid of the LibraryComponent completely if that suits your needs.)
Finally it's all injected into the activity like this:
#Inject
SomeClass someClass;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainComponent.builder()
.libraryComponent(DaggerLibraryComponent.create())
.build()
.inject(this);
someClass.doSomething();
}
I've put a working sample here on GitHub
Update 1:
If I understand your setup correctly, you've so far only used the #Singleton and #Inject annotations on the two classes listed (MyManager and SomeClass), and there is no other Dagger-related code in your project.
In that case, the reason your MyManager isn't getting injected, is because Dagger doesn't know how to provide/instantiate the dependencies. This is where the "components" come in that I mentioned above. Without any Dagger 2 components (interface or abstract class annotated with #Component), your dependencies won't get injected automatically.
I don't know if you have experience with Dependency Injection concepts, but assuming you don't, I'll step through the minimum basics you'll need to understand to get your MyManager injected into SomeClass:
First: when you use DI, you need to understand the difference between "newables" and "injectables". This blogpost by Misko Hevery explains the details.
This means, you can't new up your SomeClass. This won't work:
mSomeClass = new SomeClass();
Because if you did that (say in an activity or fragment), Dagger will have no idea that you expected a dependency to get injected into SomeClass and it has no opportunity to inject anything.
In order for its dependencies to get injected, you have to instantiate (or inject) SomeClass itself through Dagger too.
In other words, say in your Activity where SomeClass is used, you'll need:
#Inject
SomeClass mSomeClass;
Next, you need a Dagger component to perform the actual injection. To create a component, you create an interface with a method that takes your root object (say MainActivity) as argument, e.g.:
#Singleton
#Component
public interface Bootstrap {
void initialize(MainActivity activity);
}
Now when you build your project, Dagger 2 generates a class called DaggerBootstrap that implements this interface. You use this generated class to perform the injection, say in your activity's onCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerBootstrap.create().initialize(this);
mSomeClass.doSomething();
}
I believe this generated component is the key part you're missing. Full code for above here.
Some useful Dagger 2 resources:
the official Dagger 2 guide
reddit page with lots of links
Update 2:
Seems like the final missing piece of the puzzle was that your component provided an inject method for the Activity base class, but not for your actual concrete activity.
Unfortunately Dagger 2 requires an inject method for each activity or other class you want to inject into.
As you mentioned, this will be annoying when you have many different activities in your app. There some possible workarounds for this, search for "dagger 2 inject base class", for example this suggestion by #EpicPandaForce: Dagger 2 base class injections
Also note, as pointed out by #EpicPandaForce in the comments, that in my simplistic example I called DaggerLibraryComponent.create() every time which is probably not what you want, since that component is supposed to provide your singletons, so you're probably better off getting the existing instance from somewhere else such as from your Application instance.
Do we always require a beans.xml for a dependency injection in a simple java program using only CDI,and do we need to construct a bean to get the objects injected???
Below are the codes for simple java project with dependency Injection::
Interface
public interface Hello
{
public void sayHello(String str);
}
class
public class HelloImpl1 implements Hello{
public void sayHello(String str){
System.out.println("Hello from 1st block")
}
}
class
public class HelloImpl2 implements hello{
public void sayHello(String str){
System.out.println("Hello from 2nd block")
}
}
Class
public CallingHello(){
#Inject
Hello hello;
public void callHello(){
hello.sayHello("Hey");
}
}
Class
public Test(){
public static void main(String[] args){
CallingHello hello=new CallingHello();
hello.callHello();
}
Thats all i am doing and while running the test class its throwing nullpointerexception,and i am making simple classes no bean in eclipse,m i going right??
You can use autowiring , in order to inject dependencies (and possibly apply post processors) to an object that is not part of the application context.
You can use java config class with factory methods to configure ApplicationContext:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class AppConfig {
#Bean(name="HelloImpl1")
public HelloImpl1 helloImpl1() {
return new HelloImpl1();
}
#Bean(name="HelloImpl2")
public HelloImpl1 helloImpl2() {
return new HelloImpl2();
}
}
And then to instantiate:
ApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
HelloImpl1 helloImpl1= (HelloImpl1)ctx.getBean("HelloImpl1");
helloImpl1.sayHello("#?*")
If you are using Spring for the dependency injection, you always need a configuration file. But it does not need to be named beans.xml.
Yes the beans are injected in other beans.
Technically no you don't have use an XML file define your beans and inject dependencies. It depends on the type of ApplicationContext you use. But, for most practical applications you'll use one of the AbstractXMLContextApplication instances which will load an XML file to figure out the beans your app has declared. The name of that file doesn't have to be beans.xml. That's a convention used, but it you don't have to name it that. You can override which file it looks for when you constructor the implementation of AbstractXMLApplicationContext object.
All you need to do is construct the bean container, and it will load the beans, resolve the dependencies, and startup the program (if you are using init-method). Typically my Spring Container Java programs look like this:
ApplicationContext context = null;
try {
context = new FileSystemXmlApplicationContext( new String[] { file } );
// pause until we want to shutdown or after something happens.
System.in.readLine();
} finally {
context.close(); // remember to clean up!
}
And I let the init methods on the bean startup my application.