Guice custom scope entry and exit in Java console application - java

I'm currently trying to implement injection in a Java console application using Guice. The application imports XML files in a database. Every import operation is done in an AbstractImporter, which can either be a UserImporter, a ScheduleImporter, etc.
public class ScheduleMigrator extends AbstractMigrator {
private final UserImporter userImporter;
private final ScheduleImporterFactory scheduleImporterFactory;
#Inject
public ScheduleMigrator(UserImporter userImporter,
ScheduleImporterFactory scheduleImporterFactory) {
this.userImporter = userImporter;
this.scheduleImporterFactory = scheduleImporterFactory;
}
public void migrate() {
// Migrate users
userImporter.run();
// Migrate schedules for each type
for (ScheduleType scheduleTypes : ScheduleType.values()) {
ScheduleImporter importer =
scheduleImporterFactory.create(scheduleTypes);
importer.run();
}
}
}
public class UserImporter extends AbstractImporter {
private final UserTransformer userTransformer;
private final ConfigurationService configurationService;
#Inject
public UserImporter(UserTransformer userTransformer,
ConfigurationService configurationService) {
this.userTransformer = userTransformer;
this.configurationService = configurationService;
}
public void run() {
// do stuff here
}
}
#Singleton
public class UserTransformer {
// ...code ommited...
}
#ImporterScoped
public class ConfigurationService {
// ...code ommited...
}
I have successfully created my own scope (#ImporterScoped) for classes that should only be available and instantiated only in an Importer. The scope was created by following the steps in the wiki. My problem is, how should I enter and exit the scope in ScheduleMigrator?
As you can see in ScheduleMigrator, each Importer is injected and its run() method is invoked. There are also factories (based on Guice's #AssistedInject feature). This is where I want each scope to start and end, UserImporter and ScheduleImporterFactory should run in their own scope.
This is a rough idea of what I'm trying to achieve:
importerScope.enter();
(new UserImporter()).run();
importerScope.exit();
Guice's documentation mentions the use of interceptors, but I'm a little lost on how it can be implemented.

Using AOP seems a very over-engineered approach and might introduce problems. When do I enter the scope? When do I exit? What happens if I instantiate two Importer objects?
Instead, I added a runScoped method in AbstractMigrator that takes a Runnable and executes it. Using injection I get the ImporterScope scope, enter and exit it appropriately.
protected void runScoped(Runnable function)
{
scenarioScope.enter();
try {
function.run();
}
finally {
scenarioScope.exit();
}
}
Usage:
runScoped(() -> {
ScheduleImporter importer =
scheduleImporterFactory.create(scheduleTypes);
importer.run();
});
This introduces one problem though. In ScheduleMigrator, I can't have Importers injected, because their instantiation would occur outside of a scope and Guice throws an OutOfScopeException. I had to wrap each Importer in a Provider.
private final Provider<UserImporter> userImporterProvider;
runScoped(() -> {
UserImporter importer = userImporterProvider.get();
importer.run();
});

Related

Should I never use #PostConstruct in Spring Boot when I have All Args Constructor?

In out project we don't use setter or filed injection, we use only constructor injection, and I know that both options 1. and 2. may work.
Is it unsafe to work with beans in constructor in that case?
Or spring boot 2+ makes something, and I should better use option 1. instead of 2. I can't imagine case when option 1 will go wrong
#Component
#ConfigurationProperties("config")
public class ServiceConfigProperties {
// .... some code
}
Can be unsafe? - but it looks better
#Component
public class Service {
private boolean skipCheck;
public Service(ServiceConfigProperties configProps) {
this.skipCheck = configProps.isSkipCheck();
}
}
Can't be unsafe?
#Component
public class Service {
private boolean skipCheck;
private ServiceConfigProperties configProps;
public Service(ServiceConfigProperties configProps) {
this.configProps= configProps;
}
#PostConstruct
public void initConfig() {
this.skipCheck= configProps.isSkipCheck();
}
}
With a couple of caveats, interacting with constructor-injected beans inside the constructor is completely safe.

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

Module depending on another module in Dagger

I'm trying to use Dagger to do Dependency Injection on an app that I'm building, and running into trouble constructing proper DAGs when I have one package's Module depending on values provided by the Injector (presumably provided by another Module).
If I have a simple module for some configurable variables (that I might want to swap out for testing environments, for example)
#Module(
injects = DependentModule.class,
)
public class ConfigModule {
#Provides #Named("ConfigOption") String provideConfigOption() {
return "This Module's configurable option!";
}
}
and another module depends on it, e.g.
#Module(
injects = {
TopLevelClass.class
}
)
public class DependentModule {
#Inject #Named("ConfigOption") String configOption;
public DependentModule() {
ObjectGraph.create(this).inject(this);
doSomethingWithConfig(configOption);
}
#Provides #Singleton UsefulValue provideUsefulValue() {
// Whatever this module needs to do...
}
}
The line where I try to bootstrap the injection in the constructor fails, and it complains that I haven't specified an explicit injects line in a proper module.
Through trial-and-error I see this goes away if in #Module I add a line include = ConfigModule.class, but this strikes me as semantically wrong, since a) the DAG I'll be creating will now include the values of both modules, rather than just one, and b) it defeats the purpose/flexibility of DI in the first place to link a specific Module rather than simply let Dagger inject the appropriate value.
I'm presuming I shouldn't be creating an Object Graph with this only to inject into it? But then I run into the issue of not linking a specific Module...
Succinctly:
What is the 'proper' way to Inject values into one Modules that may be provided from other Modules? Here I'm using field injection, but my experiments with constructor injection have also resulted in a lot of failure.
Relatedly, when is it appropriate to use addsTo vs. includes?
Thanks :)
You don't need to do any of injection (field or constructor) in one module from another explicitly. Just use addsTo and includes.
includes allows to add modules to another and use everything they provide. Example:
#Module()
public class ModuleA {
#Provides #Named("ValueA") String provideValueA() {
return "This is ValueA";
}
}
#Module(
includes = ModuleA.class
)
public class ModuleB {
// ValueA comes from ModuleA
#Provides #Named("ValueB") String provideValueB(#Named("ValueA") String valueA) {
return valueA + " and ValueB";
}
}
addsTo is used with ObjectGraph.plus(Object... modules). When graph is already created and contains some modules (e.g. in Application class), you can create new graph (e.g. in Activity) using plus. Example:
#Module()
public class ApplicationModule {
#Provides #Named("ValueA") String provideValueA() {
return "This is ValueA";
}
}
#Module(
addsTo = ApplicationModule.class
)
public class ActivityModule {
// ValueA comes from ApplicationModule
#Provides #Named("ValueB") String provideValueB(#Named("ValueA") String valueA) {
return valueA + " and ValueB";
}
}
public class DemoApplication extends Application {
private ObjectGraph graph;
#Override public void onCreate() {
super.onCreate();
graph = ObjectGraph.create(getModules().toArray());
}
protected List<Object> getModules() {
return Arrays.asList(
new ApplicationModule()
);
}
public void inject(Object object) {
graph.inject(object);
}
public ObjectGraph getObjectGraph() {
return graph;
}
}
public class DemoActivity extends Activity {
private ObjectGraph activityGraph;
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create the activity graph by .plus-ing our modules onto the application graph.
DemoApplication application = (DemoApplication) getApplication();
activityGraph = application.getApplicationGraph().plus(new ActivityModule());
// Inject ourselves so subclasses will have dependencies fulfilled when this method returns.
activityGraph.inject(this);
}
#Override protected void onDestroy() {
// Eagerly clear the reference to the activity graph to allow it to be garbage collected as
// soon as possible.
activityGraph = null;
super.onDestroy();
}
}
Also you can check this example to create scopes of graphs.

Java EJB Modify Schedule Property Values At Runtime

I have a Singleton class in Java and I have a timer using the #Schedule annotation. I wish to change the property of the Schedule at runtime. Below is the code:
#Startup
#Singleton
public class Listener {
public void setProperty() {
Method[] methods = this.getClass().getDeclaredMethods();
Method method = methods[0];
Annotation[] annotations = method.getDeclaredAnnotations();
Annotation annotation = annotations[0];
if(annotation instanceof Schedule) {
Schedule schedule = (Schedule) annotation;
System.out.println(schedule.second());
}
}
#PostConstruct
public void runAtStartUp() {
setProperty();
}
#Schedule(second = "3")
public void run() {
// do something
}
}
I wish to change the value at runtime of Schedule second based on the information from a Property file. Is this actually possibe? The Property file contains the configuration information. I tried to do #Schedule(second = SOME_VARIABLE) where private static String SOME_VARIABLE = readFromConfigFile(); This does not work. It expects a constant meaning a final and I don't want to set final.
I also saw this post: Modifying annotation attribute value at runtime in java
It shows this is not possible to do.
Any ideas?
EDIT:
#Startup
#Singleton
public class Listener {
javax.annotation.#Resource // the issue is this
private javax.ejb.TimerService timerService;
private static String SOME_VARIABLE = null;
#PostConstruct
public void runAtStartUp() {
SOME_VARIABLE = readFromFile();
timerService.createTimer(new Date(), TimeUnit.SECONDS.toMillis(Long.parse(SOME_VARIABLE)), null);
}
#Timeout
public void check(Timer timer) {
// some code runs every SOME_VARIABLE as seconds
}
}
The issue is injecting using #Resource. How can this be fixed?
The Exception is shown below:
No EJBContainer provider available The following providers: org.glassfish.ejb.embedded.EJBContainerProviderImpl Returned null from createEJBContainer call
javax.ejb.EJBException
org.glassfish.ejb.embedded.EJBContainerProviderImpl
at javax.ejb.embeddable.EJBContainer.reportError(EJBContainer.java:186)
at javax.ejb.embeddable.EJBContainer.createEJBContainer(EJBContainer.java:121)
at javax.ejb.embeddable.EJBContainer.createEJBContainer(EJBContainer.java:78)
#BeforeClass
public void setUpClass() throws Exception {
Container container = EJBContainer.createEJBContainer();
}
This occurs during unit testing using the Embeddable EJB Container. Some of the Apache Maven code is located on this post: Java EJB JNDI Beans Lookup Failed
I think the solution you are looking for was discussed here.
TomasZ is right you should use programmatic timers with TimerService for the situations when you want dynamically change schedule in run time.
Maybe you could use the TimerService. I have written some code but on my Wildfly 8 it seems to run multiple times even if its a Singleton.
Documentation http://docs.oracle.com/javaee/6/tutorial/doc/bnboy.html
Hope this helps:
#javax.ejb.Singleton
#javax.ejb.Startup
public class VariableEjbTimer {
#javax.annotation.Resource
javax.ejb.TimerService timerService;
#javax.annotation.PostConstruct
public void runAtStartUp() {
createTimer(2000L);
}
private void createTimer(long millis) {
//timerService.createSingleActionTimer(millis, new javax.ejb.TimerConfig());
timerService.createTimer(millis, millis, null);
}
#javax.ejb.Timeout
public void run(javax.ejb.Timer timer) {
long timeout = readFromConfigFile();
System.out.println("Timeout in " + timeout);
createTimer(timeout);
}
private long readFromConfigFile() {
return new java.util.Random().nextInt(5) * 1000L;
}
}

How to reset a Spring managed Bean

NOTE: This issue may or may not be Vaadin related, depending on wether there is a "better" solution to "resetting" the bean or not.
Background scenario
I am building a wizard for entering some values that, when finished, is sent to a table (using Vaadin and the add-on "Wizards for Vaadin").
The add-on does not provide a way to reset the Wizard (i.e. go back to step 1) without a forced call to the current steps (overridden) onAdvance() and onBack() methods, which will return false in some of my steps because I'm using logic in those methods in case the use for example haven't filled in all required data.
I cannot simple create a new instance of the Wizard, because I'm using Spring to manage this #Component.
So, this leaves me with actually resetting the bean in order to reset the wizard correctly.
My question is
How do I "reset" a Spring managed Bean (#Component)? I should add that this Bean also has some dependencies injected to it.
or... (for the Vaadin people):
Is there another way of resetting this wizard other than creating a new Wizard?
Some code
#Component
#Scope("session")
public class MyWizard extends Wizard {
#Inject
private MyWizardContainer myWizardContainer;
#Inject
private MyService myService;
#Inject
private MyWizardStep1 myWizardStep1;
#Inject
private MyWizardStep2 myWizardStep2;
#Inject
private MyWizardStep3 myWizardStep3;
#Inject
private MyMainTableContainer myMainTableContainer;
final static Logger logger = LoggerFactory.getLogger(MyWizard.class);
private static final long serialVersionUID = 1L;
public MyWizard() {
setupListener();
}
public void addSteps() {
this.addStep(myWizardStep1);
this.addStep(myWizardStep2);
this.addStep(myWizardStep3);
this.mainLayout.setComponentAlignment(this.footer, Alignment.BOTTOM_LEFT);
}
private void setupListener() {
this.addListener(new WizardProgressListener() {
#Override
public void wizardCompleted(WizardCompletedEvent event) {
endWizard("Wizard Finished Successfully!");
}
#Override
public void wizardCancelled(WizardCancelledEvent event) {
endWizard("Wizard Cancelled!");
}
#Override
public void stepSetChanged(WizardStepSetChangedEvent event) {
// TODO Auto-generated method stub
}
#Override
public void activeStepChanged(WizardStepActivationEvent event) {
// TODO Auto-generated method stub
}
});
}
private void resetWizard() {
myWizardContainer.removeAll(); //here I'm simply resetting all data that the user generated thus far in the wizard
this.activateStep(myWizardStep1); //this will not work, as some steps will not always return true on onBack() and/or onAdvance()
}
private void endWizard(String message) {
resetWizard();
this.setVisible(false);
Notification.show(message);
}
}
SpringVaadinIntegration, that you probably use, does not require all elements to be #Components, only UI has to be annotated.
Your wizard and it's steps should not be components in this case, if you really need to inject dependencies into them you can use #Configurable annotation, which allowes to inject dependencies to classes not managed by Spring (some more configuration needed to make it work). Just create wizard and steps as new objects when you need them.

Categories

Resources