I would like to inject implementations of my generic interface via constructor.
This is my interface
public interface BaseValidator<T> {
boolean isValid(T t);
}
First Implementation
public class FirstValidator implements BaseValidator<String> {
#Override
public boolean isValid(String string) {
// code here
}
Second Implementation
public class SecondValidator implements BaseValidator<Int> {
#Override
public boolean isValid(Int int) {
// code here
}
My provides in validation module
#Provides
#Singleton
#Named("FirstValidator")
public BaseValidator<String> provideFirstValidator(){
return new FirstValidator();
}
#Provides
#Singleton
#Named("SecondValidator")
public BaseValidator<Int> provideSecondValidator(){
return new SecondValidator();
}
And then when I try to inject it like this
private BaseValidator<String> mFirstValidator;
#Inject
public MainPresenter(#Named("FirstValidator") BaseValidator<String> firstValidator) {
this.mFirstValidator = firstValidator;
}
It throws error
error: [dagger.android.AndroidInjector.inject(T)] BaseValidator<java.lang.String> cannot be provided without an #Provides-annotated method.
How can I inject my implementations of generic interface to any class?
Related
My service has a #Controller with multiple APIs.
Each API accepts a specific kind of object.
I would like to inject a single interface into a controller class, but have different implementations of the interface depending on the type of the input argument - is that possible?
#Controller
public class ApiClass{
private final Service service;
public ApiClass(Service service) {
this.service = service;
}
public ResponseEntity<Response> apiFirst (Object1 object1) {
return ResponseEntity.ok(service.process(object1));
}
public ResponseEntity<Response> apiTwo (Object2 object2) {
return ResponseEntity.ok(service.process(object2));
}
}
public interface Service <T extends OwnObjectClass>{
void process (T object);
}
public class Implementation1 implements Service {
#Override
void process (Object1 object) {
--some code;
}
}
public class Implementation2 implements Service {
#Override
void process (Object2 object) {
--some code;
}
}
How to do it correctly so that for each implementation not to add a new injection to the ApiClass?
Spring will provide the primary bean for the interface implementation unless you use the #Qualifer annotation with the desired instance. The injected bean can not mutate to another instance.
If you don't want to use multiple injections in the controller, you can create a ServiceProvider and ask for a specific implementation each time.
Here is an example:
public class ApiClass{
private final ServiceProvider provider;
public ApiClass(ServiceProvider provider) {
this.provider = provider;
}
public ResponseEntity<Response> apiFirst (Object1 object1) {
return ResponseEntity.ok(provider.getService("Implementation1").process(object1));
}
public ResponseEntity<Response> apiTwo (Object2 object2) {
return ResponseEntity.ok(provider.getService("Implementation2").process(object1));
}
}
#org.springframework.stereotype.Service
public class ServiceProvider {
private Map<String, Service> services;
public ServiceProvider(List<Service> services) {
this.services = services.stream()
.collect(java.util.stream.Collectors.toMap(
Service::type,
service -> service
)
);
}
public Service getService(String type) {
return services.get(type);
}
}
interface Service<T extends OwnObjectClass> {
String type();
void process(T object);
}
#org.springframework.stereotype.Service("Implementation1")
class Implementation1 implements Service {
#Override
public String type() {
return "Implementation1";
}
#Override
public void process(OwnObjectClass object) {
}
}
#org.springframework.stereotype.Service("Implementation2")
class Implementation2 implements Service {
#Override
public String type() {
return "Implementation2";
}
#Override
public void process(OwnObjectClass object) {
}
}
You can change the string in the type for an Enum.
There is another way using HandlerMethodArgumentResolver where you can inject your dependency directly into the method definition.
Here is a nice article explaining it: https://reflectoring.io/spring-boot-argumentresolver/
So far, I had a very simple bean definition that looked like this:
#Bean
#Conditional(value=ConditionClass.class)
SomeInterface myMethodImpl(){
return new ImplementationOne();
}
However, I now have situation where additional implementation class has been added, let's call it ImplementationTwo, which needs to be used instead of ImplementationOne when the option is enabled in configuration file.
So what I need is something like this:
#Bean
#Conditional(value=ConditionClass.class)
SomeInterface myMethodImpl(){
return context.getEnvironment().getProperty("optionEnabled") ? new
ImplementationOne() : new ImplementationTwo();
}
Basically a way to instantiate correct implementation at bean definition time based on the configuration value. Is this possible and can anyone please provide an example? Thanks
It is possible to implement this without using #Conditional.
Assuming you have a Interface SomeInterface and two implementations ImplOne ImplTwo:
SomeInterface.java
public interface SomeInterface {
void someMethod();
}
ImplOne.java
public class ImplOne implements SomeInterface{
#Override
public void someMethod() {
// do something
}
}
ImplTwo.java
public class ImplTwo implements SomeInterface{
#Override
public void someMethod() {
// do something else
}
}
Then you can control which implementation is used in a configuration class like this:
MyConfig.java
#Configuration
public class MyConfig {
#Autowired
private ApplicationContext context;
#Bean
public SomeInterface someInterface() {
if (this.context.getEnvironment().getProperty("implementation") != null) {
return new ImplementationOne();
} else {
return new ImplementationTwo();
}
}
}
Make sure that the component scan of spring finds MyConfig. Then you can use #Autowired to inject the right implementation anywhere else in your code.
I think you are doing it wrong.
You should use #Conditional() on your implementation and not on your Interface.
Here is how I would do it :
The interface you will use on your code.
MyInterface.java
public interface MyInterface {
void myMethod();
}
The first implementation :
MyInterfaceImplOne.java
#Bean
#Conditional(MyInterfaceImplOneCondition.class)
public class MyInterfaceImplOne implements MyInterface {
void myMethod(){
// dosmthg
}
}
MyInterfaceImplOneCondition.java
public class MyInterfaceImplOneCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("optionEnabled")
}
}
And for the 2nd implementation :
MyInterfaceImplTwo.java
#Bean
#Conditional(MyInterfaceImplTwoCondition.class)
public class MyInterfaceImplTwo implements MyInterface {
void myMethod(){
// dosmthg 2
}
}
MyInterfaceImplTwoCondition.java
public class MyInterfaceImplTwoCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return !context.getEnvironment().getProperty("optionEnabled")
}
}
In that case, you now just have to call the interface, and Spring will inject the bean corresponding to the right condition.
Hope it is what you are looking for, and I was clear enough!
I have a pojo, decorated with Dagger 2's #Singleton annotation
#Singleton
public class CommonDataSingleton {
private String authToken;
private boolean isAuthenticated;
}
I have to inject this as a singleton in an activity.
I have created a module to tell how the object of CommonDataSingleton should be created.
#Module
public class SingletonModule {
#Provides
CommonDataSingleton getCommonDataSingleton() {
return new CommonDataSingleton();
}
}
And a component describing the places where the object should be injected
#Component(modules = {SingletonModule.class})
public interface SingletonComponent {
void inject(LoginActivity loginActivity);
void inject(LoginPresenter loginPresenter);
}
Along with this I have another Component for injecting completely different objects.
#Component(modules = {PresenterModule.class})
public interface DiComponent {
//to update the fields in the activities
void inject(LoginActivity loginActivity);
void inject(HomeActivity homeActivity);
}
But I get this weird error stating
DiComponent (unscoped) may not reference scoped bindings:
#Singleton test.in.singleton.CommonDataSingleton
I'll provide you some sketch, haven't tested it. Let me know whether some edits must be done here, but the concept is the following:
public class CommonDataSingleton {
private String authToken;
private boolean isAuthenticated;
}
#Module
public class SingletonModule {
#Singleton
#Provides
CommonDataSingleton getCommonDataSingleton() {
return new CommonDataSingleton();
}
}
#Singleton
#Component(modules = {SingletonModule.class})
public interface SingletonComponent {
void inject(LoginActivity loginActivity);
void inject(LoginPresenter loginPresenter);
CommonDataSingleton providesCommonDataSingleton();
}
#YourCustomScopeHere
#Component(modules = {PresenterModule.class}, dependencies = {SingletonComponent.class})
public interface DiComponent {
//to update the fields in the activities
void inject(LoginActivity loginActivity);
void inject(HomeActivity homeActivity);
}
I had this class as follows which works fine
#Singleton
public class EmpResource {
private EmpService empService;
#Inject
public EmpResource(EmpService empService) {
this.empService=empService;
}
}
public class EmpService {
public void getName(){..}
}
Now instead of using EmpService directly, I had to create an interface and EmpService implement that interface as follows.
public interface IEmpService{
void getName();
}
public class EmpServiceImpl implements IEmpService {
public void getName(){...}
}
So now my resource class has to use the interface but I am not sure how to reference the implementation it has to use.
#Singleton
public class EmpResource {
private IEmpService empService;
#Inject
public EmpResource(IEmpService empService) {
this.empService=empService;
}
}
I've seen this and I wasn't sure where my binding should go. (This is my first project related to Guice so I am a total newbie).
This is the error that came "No implementation for com.api.EmpService was bound." which is totally understandable but not sure how to fix it.
I appericiate your help.
FYI: I am using Dropwizard application.
You would configure your module similar to this:
public class YourModule extends AbstractModule {
#Override
protected void configure() {
bind(EmpService.class).to(EmpServiceImpl.class);
// ....
}
}
you also have to add a Provide Methode for your EmpServiceImpl class
public class MyModule extends AbstractModule {
#Override
protected void configure() {
bind(IEmpService.class).to(EmpServiceImpl.class);
}
#Provides
EmpServiceImpl provideEmpServiceImpl() {
// create your Implementation here ... eg.
return new EmpServiceImpl();
}
}
I have my AbstractBinder and I bind several classes with the same interface. Let's say I bind Fish and Cat which both implement Animal interface.
What is the easiest/proper way of injecting them into a bean which takes Collection<Animal> ?
PS: Spring has equivalent in simply #Autowire List<Animal> and the collection is created and populated by Spring.
HK2 has IterableProvider<T>, as mentioned here in the documentation. You can get the service by name, by qualifier annotation, or just iterate over them, as it's an Iterable. Just for fun, here is a test.
public class IterableProviderTest {
public static interface Service {}
public static class ServiceOne implements Service {}
#QualAnno
public static class ServiceTwo implements Service {}
#Qualifier
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public static #interface QualAnno {
public static class Instance
extends AnnotationLiteral<QualAnno> implements QualAnno {
public static QualAnno get() {
return new Instance();
}
}
}
public class Binder extends AbstractBinder {
#Override
protected void configure() {
bind(ServiceOne.class).to(Service.class).named("one");
bind(ServiceTwo.class).to(Service.class).qualifiedBy(QualAnno.Instance.get());
}
}
#Inject
private IterableProvider<Service> services;
#Test
public void test_IterableProvider() {
ServiceLocator locator = ServiceLocatorUtilities.bind(new Binder());
locator.inject(IterableProviderTest.this);
assertEquals(2, services.getSize());
Service serviceOne = services.named("one").get();
assertTrue(serviceOne instanceof ServiceOne);
Service serviceTwo = services.qualifiedWith(QualAnno.Instance.get()).get();
assertTrue(serviceTwo instanceof ServiceTwo);
}
}
UPDATE
For a List<Service> (to avoid HK2 InterablProvider), the only think I can think of is to use a Factory and inject the IterableProvider into it, and from there return the list. For example
public class Binder extends AbstractBinder {
#Override
protected void configure() {
...
bindFactory(ListServiceFactory.class).to(new TypeLiteral<List<Service>>(){});
}
}
public static class ListServiceFactory implements Factory<List<Service>> {
#Inject
private IterableProvider<Service> services;
#Override
public List<Service> provide() {
return Lists.newArrayList(services);
}
#Override
public void dispose(List<Service> t) {}
}
Yeah it's a little bit of extra work.
In the latest release of hk2 (2.4.0) you can
#Inject Iterable<Foo> foos;
That allows you to keep your pojo's without any hk2 API in them.
For more information see: Iterable Injection