Spring Multiple Implementation of same interface - java

I have an Interface and multiple implementation classes, around 10, of this interface.
I have a naming convention like prefix + name + suffix so during runtime, I can add
#Autowired
private Map<String, MyInterface> myImplementations;
and then access the implementation class with myImplementations.get() method.
Is there a better way of accessing those implementations? I only know which impl. I needed during runtime, changes depends on the message I received.

You can implement BeanFactoryAware interface in your class and then use injected bean factory to get needed implementation:
Interface impl = beanFactory.getBean("interfaceimpl");
or
Interface impl = beanFactory.getBean(InterfaceImpl.class);

Related

CDI conditional Bean with Instance<T>

I have the necessity to provide the correct Bean implementation at runtime.
The common interface:
public interface MyInterface { ... }
The implementations:
#Named("one")
class MyInterfaceImpl1 implements MyInterface { ... }
#Named("two")
class MyInterfaceImpl2 implements MyInterface { ... }
#Named("three")
class MyInterfaceImpl3 implements MyInterface { ... }
Notice these classes are package-private.
I then wrote a #Produces method:
#Produces
#Singleton
MyInterface getMyInterface(
final Instance<MyInterface> myInterfaceImplementations,
final Configuration configuration) {
// Might be one, two or three.
final String parameter = configuration.getString("value");
return myInterfaceImplementations.select(new NamedLiteral(parameter)).get();
}
Is this the correct way to go, or is there a better solution?
Your solution would work fine, here are my 0.02$ just to make sure you intended it that way:
What Nikos Paraskevopoulos meant in his comment is that your are effectively creating four beans to inject one. MyInterfaceImpl1, MyInterfaceImpl2, MyInterfaceImpl3 are all legitimate beans for injection anywhere in the app. If these beans are heavy, creation may take some time, also the ability to inject them anywhere might not be intended? And then there is your producer method - the fourth bean - which I assume is ultimately the only one you are after.
Secondly, the three implementation beans have different scope from the producer method. If they are eligible for injection, in your case it seems logical that they share same scope perhaps?
Thirdly, using #Singleton. I would also advice for #ApplicationScoped, there is no harm and no overhead by having a proxy. You won't be able to tell the difference and can easily avoid some unpleasant surprises with CDI singleton (which doesn't behave like EJB singleton).
I think a more elegant solution would be to let the CDI do all the magic ;-)
Something like:
import javax.enterprise.inject.spi.CDI;
#Produces
#Singleton
MyInterface getMyInterface(final Configuration configuration) {
// Might be one, two or three.
final String parameter = configuration.getString("value");
Set<MyInterface> candidates = CDI.current().getBeanManager().getBeans(parameter);
return ( candidates.size()>0 ? candidates.get(0) : null);
}
You could also use the alternate signature of getBeans() signature to play with qualifiers when looking for a particular impl of your interface:
cfr https://docs.oracle.com/javaee/7/api/javax/enterprise/inject/spi/BeanManager.html#getBeans-java.lang.reflect.Type-java.lang.annotation.Annotation...-

How to get Interface implemented from Annotation

I am using guice for dependency injection in my project. I have a few interfaces for which I have default bindings.
I want to provide the facility where the user can implement the interface and that custom implementation would be binded over default one. If no custom implementation is present Default binding should happen.
How can this be done?
I thought of a way where the user annotates the implemented classes with an annotation and I can get the interface from that and bind that class to that interface. Is this possible?
Please help.
Thank you.
when you use spring framework, you can use declare a bean with #ConditionalOnMissingBean, if not, you can try to implement like this(check whether the object has bean declared)
Probably best would be to have a BeanFactory, and the user should then provide his implementation for a given interface:
class BeanFactory {
private static final Map<Class<?>, ?> beans = new HashMap<>();
public static <T> void register(Class<T> type, T impl){
beans.put(type, impl);
}
}
That way you could have your beans initially declared in above factory and then they could get overwritten by a user.
class MyImpl implements MyService{
static{
BeanFactory.register(MyService.class, new MyImpl());
}
// Rest of code
}
also, you can use SPI
ServiceLoader<SayHello> services = ServiceLoader.load(SayHello.class);
if services is empty, you can new the default instance.

Annotation Inheritance in jersey

I'm creating some resource class with same form so a good idea is use DRY and use inheritance.
So I've create a RootResource class and put some methods there. I want to annotate them and then implement them in subclass but it doesn't work! Here is a sample code:
public abstract class RootResource {
#GET
#Path("/{id: .*}")
public abstract String getInfo(String uid);
}
#Path("/user")
public class UserResource extends RootResource{
public String getInfo(#PathParam("id") String uid) {
System.out.println("Hello!");
}
}
I'm using jersey 2.6.
Any Idea?
Thanks.
I've been through the same issue while using Jersey. The Java EE standard for JAX-RS states the following:
3.6 Annotation Inheritance
JAX-RS annotations MAY be used on the methods and method parameters of a > super-class or an implemented
interface. Such annotations are inherited by a corresponding sub-class
or implementation class method provided that method and its parameters
do not have any JAX-RS annotations of its own. Annotations on a
super-class take precedence over those on an implemented interface.
The precedence over conflicting annotations defined in multiple
implemented interfaces is implementation specific.
If a subclass or implementation method has any JAX-RS annotations then all of the annotations on the super class or interface method are
ignored.
While Jersey as the reference implementation is very strict with this statement, Resteasy implementation is more lenient and did the trick for me.
It's important to specify the path over the class since it's the root resource class so the it will get where to look at the class loading and not for individual overridden methods:
#Path("/account/member/")
public class RootResource {
. . .

Understanding the Spring Data JPA #NoRepositoryBean interface

I encountered the #NoRepositoryBean interface several times whilst reading the Spring Data documentation.
To quote from the documentation:
If you're using automatic repository interface detection using the
Spring namespace using the interface just as is will cause Spring
trying to create an instance of MyRepository. This is of course not
desired as it just acts as indermediate between Repository and the
actual repository interfaces you want to define for each entity. To
exclude an interface extending Repository from being instantiated as
repository instance annotate it with #NoRepositoryBean.
However, I am still not sure when and where to use it. Can someone please advise and give me a concrete usage example?
The annotation is used to avoid creating repository proxies for interfaces that actually match the criteria of a repo interface but are not intended to be one. It's only required once you start going into extending all repositories with functionality. Let me give you an example:
Assume you'd like to add a method foo() to all of your repositories. You would start by adding a repo interface like this
public interface com.foobar.MyBaseInterface<…,…> extends CrudRepository<…,…> {
void foo();
}
You would also add the according implementation class, factory and so on. You concrete repository interfaces would now extend that intermediate interface:
public interface com.foobar.CustomerRepository extends MyBaseInterface<Customer, Long> {
}
Now assume you bootstrap - let's say Spring Data JPA - as follows:
<jpa:repositories base-package="com.foobar" />
You use com.foobar because you have CustomerRepository in the same package. The Spring Data infrastructure now has no way to tell that the MyBaseRepository is not a concrete repository interface but rather acts as intermediate repo to expose the additional method. So it would try to create a repository proxy instance for it and fail. You can now use #NoRepositoryBean to annotate this intermediate interface to essentially tell Spring Data: don't create a repository proxy bean for this interface.
That scenario is also the reason why CrudRepository and PagingAndSortingRepository carry this annotation as well. If the package scanning picked those up by accident (because you've accidentally configured it this way) the bootstrap would fail.
Long story short: use the annotation to prevent repository interfaces from being picked up as candidates to end up as repository bean instances eventually.
We can declare a new interface as our custom method:
#NoRepositoryBean
public interface ExtendedRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
List<T> findByAttributeContainsText(String attributeName, String text);
}
Our interface extends the JpaRepository interface so that we'll benefit from all the standard behavior.
You'll also notice we added the #NoRepositoryBean annotation. This is necessary because otherwise, the default Spring behavior is to create an implementation for all subinterfaces of Repository.
public interface ExtendedStudentRepository extends ExtendedRepository<Student, Long> {
}

Guice - How to get an instance when all you know is the interface

In all of the Guice examples I have found, getting an instance involves calling Injector.getInstance() with the concrete class as a parameter. Is there a way to get an instance from Guice using only the interface?
public interface Interface {}
public class Concrete implements Interface {}
Interface instance = injector.getInstance(Interface.class);
Thanks
Actually that's exactly what Guice is made for.
In order to make getInstance() work with an interface you'll need to first bind an implementation of that interface in your module.
So you'll need a class that looks something like this:
public class MyGuiceModule extends AbstractModule {
#Override
protected void configure() {
bind(Interface.class).to(Concrete.class);
}
}
Then when you create your injector you just need to pass an instance of your module in:
Injector injector = Guice.createInjector(new MyGuiceModule());
Now your call to injector.getInstance(Interface.class) should return a new instance of Concrete using the default constructor.
Of course there are many many more ways you can do bindings but this is probably the most straight forward.
It works for interface as well:
bind( Interface.class ).to( Concrete.class );
Without using a Module, you can also specify the implementation class to be used by default, directly in the interface declaration:
#ImplementedBy(Concrete.class)
public interface Interface {}
This doesn't necessarily fit every situation but I found this comes in handy most of the times.
Additionnally, when using #ImplementedBy annotation, you can still override the implementation class by binding another concrete class in a Module. That can also be useful.

Categories

Resources