Enum-based State Machine, Dagger2 injection of state handler - java

I'm trying to create a state machine that uses an enum to specify the states. Since there are a lot of states and the logic implemented by each is pretty complex, I wanted to associate each state with a state handler that will be defined in a different class. Each state handler would implement a common interface (or extend a common abstract class), but each one might have its own set of injected dependencies that the others might not need. So far, something like this....
StateHandler Interface:
public interface StateHandler {
void onActivation();
void onDeactivation();
}
Example StateHandlers:
#Singleton
public class DefaultStateHandler implements StateHandler {
#Inject
public DefaultStateHandler(SomeDependency someDependency) {...}
/** implement onActivation, onDeactivation and state specific logic **/
}
#Singleton
public class OtherStateHandler implements StateHandler {
#Inject
public OtherStateHandler(SomeOtherDependency someOtherDependency) {...}
/** implement onActivation, onDeactivation and state specific logic **/
}
StateManager implementation:
#Singleton
public class StateManager {
private StateType stateType = StateType.DEFAULT;
#Inject
public StateManager() { }
public void changeState(StateType newStateType) {
if (stateType != newStateType) {
stateType.getStateHandler().onDeactivation();
stateType = newStateType;
stateType.getStateHandler().onActivation();
}
}
}
Enum Definition:
public enum StateType {
DEFAULT (/* not sure what to do here */),
OTHER_STATE (...);
private StateHandler stateHandlerInstance;
public getStateHandler { return stateHandlerInstance; }
StateType(/* not sure what to do here */) {
/* assign stateHandlerInstance */
}
}
What I'm trying to figure out is... how do I inject the specific instances of the state handlers when declaring their associated enums? Or if that isn't possible, is there another way of specifying the state handler class for each enum, and then (either in the constructor or by the time its first needed), get the associated state handler instance?

I was originally thinking I needed to inject the state's handler instance into the state enum definition. However, since injection requires public constructors and enums use private constructors, I don't think that approach is feasible.
As mentioned in the comments above, the solution was to use map multibindings.
First the enum StateType is simplified:
public enum StateType {
DEFAULT, OTHER_STATE
}
Now we need a dagger MapKey interface specific to this enum type:
#MapKey
#interface StateTypeKey {
StateType value();
}
Next we need a dagger module which will have provider functions for each StateType / StateHandler combination:
#Module
public StateTypeHandlersModule {
// #Provides #IntoMap // Syntax for dagger >= 2.9
#Provides(type = Provides.Type.MAP) // Syntax for dagger <= 2.8
#StateTypeKey(StateType.DEFAULT)
StateHandler provideDefaultStateHandler(DefaultStateHandler handler) {
return handler;
}
// #Provides #IntoMap // Syntax for dagger >= 2.9
#Provides(type = Provides.Type.MAP) // Syntax for dagger <= 2.8
#StateTypeKey(StateType.OTHER_STATE)
StateHandler provideOtherStateHandler(OtherStateHandler handler) {
return handler;
}
}
Its unfortunately a lot of boilerplate code, which is why I'm using a separate module just for the handlers, and including that in the higher-level state machine module. Note that if you declare two provider functions with the same StateTypeKey, the second handler is ultimately available in the injected map.
Finally, we can inject the Map<StateType, StateHandler> into the StateManager:
#Singleton
public class StateManager {
private Map<StateType, StateHandler> stateHandlerMap;
private StateType stateType = StateType.DEFAULT;
#Inject
public StateManager(Map<StateType, StateHandler> stateHandlerMap) {
this.stateHandlerMap = stateHandlerMap;
}
public void changeState(StateType newStateType) {
if (stateType != newStateType) {
stateHandlerMap.get(stateType).onDeactivation();
stateType = newStateType;
stateHandlerMap.get(stateType).onActivation();
}
}
}

Related

Helper class as a singleton with Guice

I'm learning Google Guice.
I understood how to bind an interface to its implementation.
Now, I have the following helper class :
class PersonHelper {
public static FakeDatabaseConfiguration dbConfig;
public PersonHelper(){
if (dbConfig == null){
dbConfig = new FakeDatabaseConfiguration();
dbConfig.setHost('127.0.0.1');
dbConfig.setPort('3306');
dbConfig.setUsername('root');
dbConfig.setPassword('root');
}
}
public List<Person> getPersons(){
FakeResult fakeResult = dbConfig.executeSQL("select * from Person");
return fakeResult.asList();
}
}
Today, I'm using it like this:
PersonHelper personHelper = new PersonHelper();
List<Person> personsList = personHelper. getPersons();
I'm pretty sure there is a way to make this class better.
Question : How can I make this class as a singleton using Guice so that I don't lazy load the dbConfig variable at each instanciation ?
(I read that there is a #Singleton annotation but, it's considered in Guice just as a scope.)
Regards
First, in your module, you have to declare a provider (FakeDatabaseConfigurationProvider). As stated, this is the best way to inject a configuration object.
Then, declare your helper class as a Singleton and bind it in your module.
This will allow your helper class to be used like this :
public class SomeClass{
#Inject
private PersonHelper personHelper;
...
public void someMethod(){
...
List<Person> personsList = personHelper.getPersons();
..
}
}
And the same instance will be shared through your app.
Here is the suggested code :
public class MyModule extends AbstractModule {
#Override
protected void configure() {
bind(FakeDatabaseConfiguration.class).toProvider(FakeDatabaseConfigurationProvider.class);
bind(PersonHelper.class).in(Scopes.SINGLETON);
}
/**
* FakeDatabaseConfigurationProvider implementation
*/
static class FakeDatabaseConfigurationProvider implements Provider<FakeDatabaseConfiguration> {
#Override
public FakeDatabaseConfiguration get() {
FakeDatabaseConfiguration dbConfig = new FakeDatabaseConfiguration();
dbConfig.setHost('127.0.0.1');
dbConfig.setPort('3306');
dbConfig.setUsername('root');
dbConfig.setPassword('root');
return dbConfig;
}
}
}
Then, in your PersonHelper :
public class PersonHelper{
private FakeDatabaseConfiguration fakeDatabaseConfiguration;
#Inject
public PersonHelper(final FakeDatabaseConfiguration fakeDatabaseConfiguration){
this.fakeDatabaseConfiguration = fakeDatabaseConfiguration;
}
public List<Person> getPersons(){
FakeResult fakeResult = fakeDatabaseConfiguration.executeSQL("select * from Person");
return fakeDatabaseConfiguration.asList();
}
}
Please look at Binding #Provides method as eager singleton See if that helps. The eagerSingleton part might work for you.
Having it as a scope is exactly what you want: Scopes effectively tell Guice when it's allowed to reuse the same object it's already created, and for #Singleton that answer is "always".
If you were to list the class like this:
#Singleton // Could also be in your module or #Provides method.
class PersonHelper {
private FakeDatabaseConfiguration dbConfig;
public PersonHelper(){
dbConfig = new FakeDatabaseConfiguration();
dbConfig.setHost('127.0.0.1');
dbConfig.setPort('3306');
dbConfig.setUsername('root');
dbConfig.setPassword('root');
}
public List<Person> getPersons(){
FakeResult fakeResult = dbConfig.executeSQL("select * from Person");
return fakeResult.asList();
}
}
Then the the class itself becomes a Singleton. The FakeDatabaseConfiguration will be created whenever the class is instantiated, but for all accesses through Guice, that will only happen once.
Of course, none of this applies to direct constructor calls as new PersonHelper(), but with few exceptions Guice is only good at making guarantees about objects that it provides. Any accesses that Guice can control, including through getInstance or #Inject-annotated fields and constructors, will only see PersonHelper (and therefore FakeDatabaseConfiguration) created exactly once.

Spring switch implementations based on a runtime condition

This is a simplified version of what I am trying to achieve.
I have multiple implementations of the same interface. Based on the user input at runtime I want to pick the correct implementation.
For example suppose I an interface called Color. There are many classes that implement this interface, the Red class, the Blue class, the Green class and so on.
At run time I need to pick implementations based on the user input. One way to achieve this would be something like this
#Autowired
#Qualifier("Red")
private Color redColor;
#Autowired
#Qualifier("Green")
private Color greenColor;
private Color getColorImplementation()
{
if(userInput=="red")
{
return redColor;
}
else if(userInput=="green")
{
return greenColor;
}
else
{
return null;
}
}
But the problem with this is that everytime a new implementation is added, I would have to update the code that picks the implementation, which beats the whole purpose of inversion of control part of spring. What is the right way to do this using spring?
You could autowire all implementations of the interface in question and then decide based on properties provided by interface which to use.
#Autowired
private List<Color> colors;
public void doSomething(String input) {
colors.stream().filter(c -> c.getName().contains(input)).findFirst().ifPresent(c -> {
// something
}
}
This is also less magical and more in line with OO principles. Dependency injection is to wire up things initially, not for dynamic switching at runtime.
You want to Autowire the ApplicationContext, then you can get all the Color beans with Map<String, Color> colors = appContext.getBeansOfType(Color.class);. This presumes that the userInput and the bean name are identical.
If that isn't the case, a solution would be to add a getName() to the Color interface; then you can autowire a List<Color> and construct the Map yourself.
Can't you make the Color an Enum?
The Spring ServiceLocatorFactoryBean (scroll down to the middle) API was built just for this purpose:
Create a dummy interface (ColorFactory) that provides a single method such as Color getColor(String color)
Create the proxy bean instance for org.springframework.beans.factory.config.ServiceLocatorFactoryBean passing ColorFactory as the serviceLocatorInterface parameter
Define beans for all of your color implementations with names matching the parameter you'd like to pass to getColor
Inject the factory into the collaborators and invoke getColor as needed
You could contrive this with similar APIs on the ApplicationContext, but the advantage of this approach is that it abstracts Spring from your Java implementation (for XML configured projects).
Same issue happen in my implementation where in, the scenario was based on user input, where the respective interface implementation needs to be invoked.
This solve my problem:
**Base Interface**
#Service
public interface ParentInterface {
public String doThis(ClassA param);
}
**First Implementation**
#Component("FirstImp")
public class FirstServiceImp implements ParentInterface {
public String doThis(ClassA param){
}
**Second Implementation**
#Component("SecondImp")
public class SecondServiceImp implements ParentInterface {
public String doThis(ClassA param){
}
**Factory**
#Service
public class ServiceResolver {
#Autowired
#Qualifier("FirstImp")
private ParentInterface firstImpl;
#Autowired
#Qualifier("SecondImp")
private ParentInterface secondImpl;
public ParentInterface getInstance(String condition){
switch(condition) {
case "X": return firstImpl;
case "Y": return secondImpl;
default:
throw new IllegalArgumentException(condition);
}
}
}
**Controller**
#RestController
public class UserController {
#Resource
private ServiceResolver serviceresolver;
#PostMapping("/userbase/{inp1}/messages/{inptype}")
public ResponseEntity<String> sendData(#PathVariable String
inp1,#PathVariable String inptype, #RequestBody XYZBean msg)
{
for(ABC data : msg.getSubData())
serviceresolver.getInstance(data.getType()).doThis(msg);
return new ResponseEntity<String>("created",HttpStatus.OK);
}
}

Dagger: class could not be bound with key

I'm trying for first time dagger and, after configuring the module, I get an error I don't understand.
My code is:
public class Parrot {
private Language language;
#Inject
public Parrot(Language language) {
this.language = language;
}
public void sayHello() {
System.out.println(language.getSalute());
}
}
public interface Language {
public String getSalute();
}
public class EnglishLanguage implements Language {
#Override
public String getSalute() {
return "Hello!";
}
}
My module is
#Module(
injects = Language.class
)
public class PetShopModule {
#Provides Parrot provideParrot(Parrot parrot){
return parrot;
}
}
And in the code I use it this way
EnglishLanguage lang=SystemApp.getSystemLanguage();
ObjectGraph objectGraph = ObjectGraph.create(new PetShopModule());
objectGraph.inject(myLanguage);
Parrot parrot = objectGraph.get(Parrot.class);
The compiler complains with:
error: com.example.petshop.Language could not be bound
with key com.example.petshop.Language required by com.example.petshop.PetShopModule
for com.example.petshop.PetShopModule
What do I am doing wrong?
Note: This is only a simplified example, in the real code the EnglishLanguage is a system class, and I can't modify nor create it, just get a reference
Instead of commenting on what you're doing wrong, let's give the correct example, and explain what's happening there.
This snippet is perfect, and stays as it is:
public class Parrot {
private Language language;
#Inject
public Parrot(Language language) {
this.language = language;
}
public void sayHello() {
System.out.println(language.getSalute());
}
}
public interface Language {
public String getSalute();
}
public class EnglishLanguage implements Language {
#Override
public String getSalute() {
return "Hello!";
}
}
With the #Inject annotation on the Parrot constructor, you're telling Dagger, "Whenever I request an instance of Parrot, use this constructor to instantiate it".
Dagger sees that Parrot needs an instance of the Language interface, and tries to find a way to retrieve it. However, since Language is an interface, Dagger needs to know which concrete type to use.
Since you cannot edit the EnglishLanguage class, you'll need to write a #Provider method for it:
#Module
public class PetshopModule {
#Provides
Language provideLanguage() {
return SystemApp.getSystemLanguage();
}
}
Now, you should be able to get an instance of Parrot out of your ObjectGraph, like this:
ObjectGraph graph = ObjectGraph.create(new PetshopModule());
Parrot parrot = graph.get(Parrot.class);
I have not tested this, bit this should work.
If you were able to modify the EnglishLanguage class, you could do the following. Annotate the EnglishLanguage constructor with #Inject, and request an EnglishLanguage instance in the Language provider method:
public class EnglishLanguage implements Language {
#Inject
public EnglishLanguage() {
}
#Override
public String getSalute() {
return "Hello!";
}
}
#Module
public class PetshopModule {
#Provides
Language provideLanguage(EnglishLanguage language) {
return language;
}
}
In this case, Dagger looks for the Language provider method, and instantiates an EnglishLanguage to return.
The existing answer is perfect, but didn't solve my obscure case.
If you have a base Activity with a couple of DI helper classes, make sure your Activity that extends this does so properly!
Base Activity class:
private fun initializeObjectGraph() {
activityObjectGraph = (application as App).getObjectGraph()
.plus(ActivityModule(this))
.plus(*getAdditionalModulesForObjectGraph())
}
protected open fun getAdditionalModulesForObjectGraph() = arrayOf<Any>()
abstract fun injectDependencies(activityObjectGraph: ObjectGraph): LifecycleReceiver
Overrides needed in extension Activity:
override fun injectDependencies(activityObjectGraph: ObjectGraph): LifecycleReceiver {
activityObjectGraph.plus(MyModule(this)).inject(this)
return DummyLifecycleReceiver
}
override fun getAdditionalModulesForObjectGraph(): Array<Any> = arrayOf(MyModule(this))

Why Guice prevents from binding to Provider?

Recently, when I played around with Google Guice I was trying to do something like this:
#Override
protected void configure() {
...
bind(Provider.class).to(ViewFactory.class);
...
}
Where ViewFactory was:
public class ViewFactory implements Provider<SomeType> {...}
Of course, Guice didn't let me do that returing error:
1) Binding to Provider is not allowed.
{stacktrace}
What is the reason why it is not possible to bind to provider?
I guess it is because Provider interface is very special to Guice. In fact, all its internal machinery is implemented in term of providers.
Moreover, this could create ambiguities. If bindings to providers were possible:
bind(SomeClass.class).to(SomeClassImpl1.class);
bind(new TypeLiteral<Provider<SomeClass>>() {}).to(() -> new SomeClassImpl2());
then what should Guice inject here?
#Inject
OtherClass(Provider<SomeClass> someClassProvider) { ... }
Should it be a provider which returns SomeClassImpl1 (because of the first binding; remember, direct injections and provider injections are interchangeable in Guice) or should it be a provider which returns SomeClassImpl2 (because of the second binding)?
It really is redundant. Because you can inject SomeClass or Provider<SomeClass> regardless of the actual binding, you can bind the class itself to its provider:
bind(SomeClass.class).toProvider(() -> new SomeClassImpl());
// Either of the following will work
#Inject
OtherClass1(Provider<SomeClass> someClassProvider) { ... }
#Inject
OtherClass2(SomeClass someClass) { ... }
Provider is a special case. Guice does a lot of things behind the scenes with Provider, so they just ban binding to the Provider class entirely. One example is with scoping: your custom Provider might call new every single time, but if you create the provider in the Singleton scope, that should not happen. So Guice doesn't actually inject your provider, it injects a wrapped version. Things like that is why they ban binding to Provider.class directly. Here's a code example:
import com.google.inject.*;
import com.google.inject.name.*;
public class ProviderBindExample {
public static class ProvModule extends AbstractModule {
#Override
protected void configure() {
bind(Foo.class).toProvider(FooProvider.class);
bind(Foo.class).annotatedWith(Names.named("singleton"))
.toProvider(FooProvider.class)
.in(Singleton.class);
}
}
public static interface Foo { }
public static class FooProvider implements Provider<Foo> {
#Override
public Foo get() {
return new Foo() {};
}
}
public static class SomeClass {
#Inject public Provider<Foo> provider;
#Inject #Named("singleton") public Provider<Foo> singletonProvider;
}
public static void main(String... args) {
Injector inj = Guice.createInjector(new ProvModule());
SomeClass s = inj.getInstance(SomeClass.class);
System.out.println("Provider class = " + s.provider.getClass());
System.out.println("Singleton provider class = " + s.singletonProvider.getClass());
Foo first = s.provider.get();
Foo second = s.provider.get();
System.out.printf("regular scope: objects are %s%n", first == second ? "the same" : "different");
first = s.singletonProvider.get();
second = s.singletonProvider.get();
System.out.printf("singleton scope: objects are %s%n", first == second ? "the same" : "different");
}
}
Output:
Provider class = class com.google.inject.internal.InjectorImpl$4
Singleton provider class = class com.google.inject.internal.InjectorImpl$4
regular scope: objects are different
singleton scope: objects are the same

Changing Guice bindings at runtime

I would like to be able to change the Guice injections at runtime to support multiple injections based on user input. This is what I would like to achieve:
public interface IDao {
public int someMethod();
}
public class DaoEarth implements IDao {
#Override
public int someMethod(){ ... }
}
public class DaoMars implements IDao {
#Override
public int someMethod(){ ... }
}
public class MyClass {
#Inject
private IDao myDao;
public int myMethod(String domain) {
//If Domain == Earth, myDao should be of the type DaoEarth
//If Domain == DaoMars, myDao should be of the type DaoMars
}
}
I was thinking of writing my own Provider, but I don't know how to use that provider to change my bindings at runtime. Any input is welcome and appreciated :)!
Update
Here's what I currently came up with, it's not as pretty as I'd like, so I'm still looking for feedback
public class DomainProvider {
#Inject #Earth
private IDaoProvider earthDaoProvider;
#Inject #Mars
private IDaoProvider marsDaoProvider;
public IDaoProvider get(Domain domain){
switch (domain){
case EARTH:
return earthDaoProvider;
case MARS:
return marsDaoProvider;
}
}
public IDaoProvider get(String domain){
Domain parsedDomain = Domain.valueOf(domain.toUpperCase());
return get(parsedDomain);
}
}
//MarsDaoProvider would be equivalent
public class EarthDaoProvider implements IDaoProvider {
#Inject #Earth
private IDao earthDao;
public IDao getDao() {
return earthDao;
}
}
// This means that in "MyClass", I can do:
public class MyClass {
#Inject
private DomainProvider domainProvider;
public int myMethod(String domain) {
IDaoProvider daoProvider = domainProvider.get(domain);
IDao dao = daoProvider.getDao();
//Now "dao" will be of the correct type based on the domain
}
}
//Of course elsewhere I have the bindings set like
bind(IDao.class).annotatedWith(Earth.class).to(EarthDao.class);
Your version is almost perfect as it is: You're going to need to inject some kind of object that returns one or the other based on code you write, and don't need assisted injection or anything like that. That said, you can skip some of the boilerplate:
public class DomainProvider {
// Just inject Providers directly without binding them explicitly.
#Inject #Earth Provider<IDao> earthDaoProvider;
#Inject #Mars Provider<IDao> marsDaoProvider;
public Provider<IDao> get(Domain domain){
switch (domain){
case EARTH:
return earthDaoProvider;
case MARS:
return marsDaoProvider;
}
}
public Provider<IDao> get(String domain){
Domain parsedDomain = Domain.valueOf(domain.toUpperCase());
return get(parsedDomain);
}
}
Your MyClass in that case would be exactly identical. Here, Provider is either the one-method generic interface com.google.inject.Provider, or the equivalent builtin javax.inject.Provider that it extends. Read more about Guice Providers on the relevant Guice wiki topic.
bind(IDao.class).annotatedWith(Earth.class).to(EarthDao.class);
// You can now inject "#Earth IDao" and also "#Earth Provider<IDao>".
Basically, if you bind a key Foo (to a class, provider, #Provides method, or instance), you automatically get to inject either a Foo or Provider<Foo> with no additional work. Providers are also a great way to ensure that you get a new instance with every call to get, if that's what you want; with your original, you'll always get the same instance of EarthDao or MarsDao for any given DomainProvider you inject. (If you have a scoped binding like #Singleton, Guice will respect that too; Provider just lets Guice get involved, rather than reusing a plain old Java reference.)
This means you can skip your custom EarthDaoProvider and MarsDaoProvider, unless you really need to perform any external initialization on them—at which point you'd probably be better off calling bind(EarthDao.class).toProvider(EarthDaoProvider.class) so the preparation also happens when injecting EarthDao directly. You could also just have DomainProvider return an IDao instance directly by calling get on the appropriate Provider, and be assured that it'll be a new instance every time.

Categories