how to inject the multiple bean in to single referenced variable dynamically using spring annotation - spring-annotations

I have interface A.java and 3 classes which are implementing A.java interface named B.java, C.java and D.java. Now i am try to inject the bean like this.
interface A{}
#Component
#Scope("request")
class B implements A{
//......
}
#Component
#Scope("request")
class C implements A{
//.....
}
#Component
#Scope("request")
class D implements A{
}
class Implementation{
#Autowired
public A obj;
#Autowired
private BeanFactory beanFactory;
String[] beans = {"B","C","D"}; //actually these are coming from database in my case
for(String beanName : beans){
obj = (A)beanFactory.getBean(beanName);
....//calling some method of particular bean class
}
}
It is showing Error message something: "Unique bean not found: contains multiple beans["B","C","D"]".
If I am configuring these beans in XML file, it is working fine but I don't want to use xml config
How to solve this problem Using spring Annonantion??

It seems to me that the problem is with the Autowired annotation, because it'll do the injection by type, and the type of your variable is A, so It will be difficult to decide which bean to actually inject, B, C or D.
Try to use Resource annotation which decide to inject by name. Or instead just add Qualifier annotation.
Look here for further explanation:
Difference between #Qualifier and #Resource

Related

EclipseContext get beans of type

I have classes:
#Creatable
#Singleton
public class Sample1 implements ISample {
}
#Creatable
#Singleton
public class Sample2 implements ISample {
}
How can i get all beans of type ISample from EclipseContext?
The Eclipse context does not support anything like this. All you can do is look for objects with a specific name (or specific class which is just converted to a name).
Additionally objects declared using #Creatable are not even created and added to the context until something actually uses them.

Abstract components via org.osgi.service.component annotations

I am migrating from org.apache.felix.scr annotations to org.osgi.service.component annotations. I have a set of Components that inherit from a common abstract class. In the felix case, I can use a #Component annotation with the option componentAbstract=true on the super class, and then use #Reference annotation in the super class. I cannot find how to migrate this to osgi annotations.
Is it possible to use Component annotations in a super class of a Component? And if so, what is then the appropriate way to handle the properties and metatype generation?
So, what I am looking for, is something like this
/* No component definition should be generated for the parent, as it is
abstract and cannot be instantiated */
#Component(property="parent.property=parentValue")
public abstract class Parent {
#Reference
protected Service aService;
protected activate(Map<String,Object> props) {
System.out.println("I have my parent property: "+props.get("parent.property"));
#Override
public abstract void doSomething();
}
/* For this class, the proper Component definition should be generated, also
including the information coming from the annotations in the parent */
#Component(property="child.property=childValue")
public class Child extends Parent {
#Activate
public activate(Map<String,Object> props) {
super.activate(props);
System.out.println("I have my child property: "+props.get("child.property"));
}
public void doSomething() {
aService.doSomething();
}
}
By default BND will not process DS annotations in parent classes. You can change that with -dsannotations-options: inherit but please see http://enroute.osgi.org/faq/ds-inheritance.html why you shouldn't!
2021-02-23 UPDATE: It seems like the page mentioned above is no longer available. I don't know if it was moved elsewhere or simply removed but its content (in Markdown format) is still available on GitHub: https://github.com/osgi/osgi.enroute.site/blob/pre-R7/_faq/ds-inheritance.md

javax.inject.Qualifier Spring JavaConfig

I have the following code
The 2 javax.Inject Qualifiers
#Qualifier
#Target(value={ElementType.FIELD,ElementType.TYPE,ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
public #interface Hibernate {
--nothing goes here
}
#Qualifier
#Target(value={ElementType.FIELD,ElementType.TYPE,ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
public #interface Toplink{
--nothing goes here
}
I Qualify the repositories
#Named
#Hibernate
public class HibernateRepository implements IRepository{
-- some code
}
#Named
#Toplink
public class ToplinkRepository implements IRepository{
-- some code
}
These repositories are injected using javax.Inject
public class InvoiceService {
#Inject
//#Hibernate I alternate between the two to test
#Toplink
private IRepository iRepository;
public void saveInvoice(Invoice invoice){
iRepository.save(invoice);
}
using the following configuration class
#Configuration
public class Myconfig {
#Bean
public IRepository getHibernateRepository(){
return new HibernateRepository();
}
#Bean
public InvoiceService getInvoiceService(){
return new InvoiceService();
}
#Bean
public IRepository getToplinkRepository(){
return new ToplinkRepository();
}
}
This code works perfectly fine when I use the XML configuration , any idea how to get it working with javaConfig ?? Or is there something fundamentally wrong in my code ?? When used its throws the following exception
Exception in thread "main"
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'getInvoiceService': Injection of autowired
dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private com.domain.IRepository
com.service.InvoiceService.iRepository; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
matching bean of type [com.domain.IRepository] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for
this dependency. Dependency annotations: {#javax.inject.Inject(),
#com.domain.Toplink()}
Thanks in anticipation.
In the case of #Bean methods, it's the return type that counts. Even though you may be returning a TopLinkRepository from one method, and a HibernateRepository from another, from the container's point of view, all it knows is that there are two beans of type IRepository, and therefore does not understand that one is #Toplink annotated and one is #Hibernate annotated.
You have several of choices here. The simplest, given your current configuration, would be to change the return types to make them more specific.
The second is to leave the return types generic, but move the #Toplink and #Hibernate qualifier annotations to the #Bean method level.
The third is to component-scan for the repository types instead of declaring them as #Bean methods.
The third approach is generally recommended, given that you're already using #Inject on the repository components, and have them marked with #Named. This makes them natural candidates for component-scanning in the first place. Check out the Javadoc for #ComponentScan to see how to do this in the #Configuration class world.

JAX-RS #PathParam to inject in class member variable?

I want to do something like this:
#Stateless
#Path("/sensors/{sensorid}/version")
#Consumes({MediaType.APPLICATION_XML, MediaType.TEXT_XML})
#Produces({MediaType.APPLICATION_XML, MediaType.TEXT_XML})
public class SensorVersionRestView extends VersionRestView{
#PathParam("sensorid")
private String sensorid;
#GET
#Path("count")
// so the complete path is i.e.
// domain.com/rs/sensors/111211/version/count
public void getCount() {
// do something with the sensorId....
}
}
But the only thing I get is null on runtime (I use Glassfish v3 with Jersey). The compiler and eclipse never mentions a problem with the #PathParam at the member class variable.
What's wrong with my construct?
The main problem is, why I doesn't want to use the whole path on each method in this class, that there exists another class which handles some rest operations on the sensor layer (deomain.com/rs/sensors/count i.e.)
I believe you need to change it to this:
#Stateless
#Path("/sensors/{sensorid}/version")
public class SensorVersionRestView extends VersionRestView {
#GET
#Path("count")
#Consumes({MediaType.APPLICATION_XML, MediaType.TEXT_XML})
#Produces({MediaType.APPLICATION_XML, MediaType.TEXT_XML})
// domain.com/rs/sensors/111211/version/count
public void getCount(#PathParam("sensorid") String sensorid) {
// do something with the sensorId....
}
}
Because injection occurs at object
creation time, use of this annotation
on resource class fields and bean
properties is only supported for the
default per-request resource class
lifecycle. Resource classes using
other lifecycles should only use this
annotation on resource method
parameters. - JSR-311 Javadocs
You should be able to annotate fields with #PathParam as long as the resource class lifecyle is per-request. By default the life-cycle of root resource classes is per-request.
EDIT: I don't think you can achieve this using EJBs. If you remove the #Stateless annotation, it should work.

How to test annotation object in the class that implement AbstractModule

I got a question regarding binding and annotation.
I have the following class:
public class MailFacadeImpl implements MailFacade {
private final PersonDao personDao;
#Inject
public MailFacadeImpl(#Mail PersonDao personDao) {
super();
this.personDao = personDao;
}
The PersonDao is annotated with a custom annotation.
I would like to be able to test this annotation inside the class that implement AbstractModule.
here is a piece of code:
bind(new TypeLiteral<SecurityRulesFactory<Person>>(){}).toProvider(FactoryProvider.newFactory(
new TypeLiteral<SecurityRulesFactory<Person>>(){}, new TypeLiteral<MailSecurityRulesCrdb>(){}));
I would like to have somthing similar to :
if(PersonDAO is annotated with(Mail.class) ){
bind(new TypeLiteral<SecurityRulesFactory<Person>>(){}).toProvider(FactoryProvider.newFactory(
new TypeLiteral<SecurityRulesFactory<Person>>(){}, new TypeLiteral<MailSecurityRulesCrdb>(){}));
}
Do you think it's possible?
thx for your help :-)
Have a nice friday!
It's not clear why you want your module to do this test. Instead, your module can specify how to get or create an instance of PersonDao for injection points annotated with Mail:
bind(PersonDao.class).annotatedWith(Mail.class).to(EmailAwarePersonDao.class);
Note that your PersonDao.class.isAnnotationPresent(Mail.class) won't help here, since the PersonDao class itself isn't annotated with Mail; the parameter to the MailFacadeImpl constructor has that annotation. There are ways to test for that, but if you are trying to do that from a Guice module, you're probably doing something wrong.