Dagger: class could not be bound with key - java

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

Related

How to create an interface for any service in Spring Boot

I want all the Service classes in my backend to have CRUD methods.
For that purpose, I thought of creating an interface:
public interface ServiceCRUD {
public Object save(Object object);
...
}
And then on my service, implement it:
#Service
public class SampleService implements ServiceCRUD {
#Autowired
private SampleRepository repository;
#Override
public Sample save(Sample sample) {
return repository.save(sample);
}
...
}
I haven't touched Java in a while, but if I recall correctly, every object extend Object, so why is it that I can't use Object to have the service accept all the entities I might have?
Best regards
You can achieve such scenario using Generics
interface ServiceCRUD {
public < E > void save(E object);
}
class Sample {
private String name = "Joe";
#Override
public String toString() {
return "hello"+name;
}
}
class SampleService implements ServiceCRUD {
#Override
public < Sample > void save(Sample sample) {
System.out.print(sample.toString());
}
}
public class Main {
public static void main(String[] args) {
new SampleService().save(new Sample());
}
}
This is just an example ,you can extend it as per your use case.
See working here
Your interface declares that one is possible to save Object, i. e. any object. But your implementation declares that it cat get only Sample, that's why you get compilation error.
You should go with genetic and let each implementation to declare what kind of object it can deal with. I strongly suggest to have a look at spring data project. It will save you a lot if time

Pass generics class to an annotation

In the testing framework I'm using, there is a Precondition annotation that takes a class and calls call() method in it at runtime.
Core Modules of the Testing Framework:
Precondition Annotation
public #interface Precondition {
Class<? extends Scriptlet<? extends Context>> scriptlet();
String value() default Constants.EMPTY_STRING;
}
Scriptlet
public interface Scriptlet<V> extends Callable<V> {
}
Context
public interface Context {
}
If I pass the following precondition class to Precondition annotation there will be no errors.
CommonContextInit precondition class
class CommonContextInit implements Scriptlet<DataModel>{
CommonContextInit(Object script,String value){
}
#override
public DataModel call() throws Exception {
return null;
}
}
Script
#Precondition(scriptlet=CommonContextInit.class)
But I want to make CommonContextInit a generic where user can pass the type of the scriptlet so I changed the CommonContextInit class as follows
CommonContextInit precondition class
class CommonContextInit<T extends Context> implements Scriptlet<T>{
CommonContextInit(Object script,String value){
}
#override
public T call() throws Exception {
return null;
}
}
But the issue here is I have no idea how to pass the class to Precondition. The following I have tried but looks like it's totally invalid syntax.
// ERROR: The annotation #Precondition is disallowed for this location.
#Precondition(scriptlet=CommonContextInit<DataModel>.class)
How should I pass the Class of CommonContextInit<DataModel> to Precondition?
To extend my comment you shall have something like
class DataModelInstance extends CommonContextInit<DataModel> implements Scriptlet<DataModel>{
DataModelInstance(Object script,String value){
super(script, value);
}
//other overrides
}
and then call #Precondition(scriptlet=DataModelInstance.class)

Constructor DTO container pattern

Has anyone seen a pattern whereby Java constructor parameters are created using a DTO object and then injected into the class using Spring? I believe it is an anti-pattern but am curious if there is a reasonable case where it could be used.
In my mind the ideal thing to do is refactor the code so the need for the single constructor object is redundant.
What's everyones thoughts?
My particular example is of the form:
#Service
public class MyClass {
private MyClassConstructorDto constructorDependencyContainer;
#Autowired
public MyClass(MyClassConstructorDto constructorDependencyContainer) {
this.constructorDependencyContainer = constructorDependencyContainer;
}
public void doSomething() {
constructorDependencyContainer.getCoolDependency().performThing();
}
}
with supporting class
#Component
public class MyClassConstructorDto {
private CoolDependency coolDependency;
public MyClassConstructorDto(CoolDependency coolDependency) {
this.coolDependency = coolDependency;
}
public CoolDependency getCoolDependency() {
return coolDependency;
}
}

Enum-based State Machine, Dagger2 injection of state handler

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

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.

Categories