javax.inject.Qualifier Spring JavaConfig - annotations

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.

Related

multiple #Qualifier EJB injection

i have 2 EJB implements same interface, i have some qualifier :
#java.lang.annotation.Documented
#java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE,ElementType.FIELD})
#javax.inject.Qualifier
public #interface PayEseConnector {
}
and
#java.lang.annotation.Documented
#java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE,ElementType.FIELD})
#javax.inject.Qualifier
public #interface MetrilioConnector {
}
example of EJB:
#Stateless
#PayEseConnector
#Local
public class PayEseServiceImpl implements IConnectorService {
or
#Stateless
#MetrilioConnector
#Local
public class MetrilioServiceImpl implements IConnectorService {
i inject one of those into a class:
public class TestResource {
#MetrilioConnector
#Inject
IConnectorService metrilioService;
and my error :
Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type IConnectorService with qualifiers #MetrilioConnector
at injection point [UnbackedAnnotatedField] #MetrilioConnector #Inject com.real.hr.rest.TestResource.metrilioService
at com.real.hr.rest.TestResource.metrilioService(TestResource.java:0)
WELD-001475: The following beans match by type, but none have matching qualifiers:
- Session bean [class com.real.hr.services.MetrilioServiceImpl with qualifiers [#MetrilioConnector #Any]; local interfaces are [IConnectorService],
- Session bean [class com.real.hr.services.PayEseServiceImpl with qualifiers [#PayEseConnector #Any]; local interfaces are [IConnectorService]
what i am doing wrong?, with one #Qualifier it is working
Finally the example is OK the error was i renamed a package and dependency was still present so you can use this example to make simple Qualifier for EJB implements same interface, normally #Local is not mandatory...

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

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

How to load spring application context even if Cassandra down

When using
#Configuration
#EnableCassandraRepositories(basePackages={"com.foo"})
public class CassandraConfig{
#Bean
public CassandraClusterFactoryBean cluster()
{
final CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
cluster.setContactPoints(nodesRead);
cluster.setPort(port);
return cluster;
}
Where in the com.foo package there is a interface that extends CrudRepository.
Is there a way to make it so that at startup time an exception is not thrown if the database is down?
Ideally what occurs is that we startup and anytime you call a method on the repository, it will first attempt to connect to the database and then if the database is still down return an error saying can't connect.
The behavior I currently observe is that NoHostAvailableException is thrown and the web container does not start up.
I was able to come up with a solution. I removed the #EnableCassandraRepositories(basePackages={"com.foo"}) annotation from the repository and defined a Bean in my Config that would return my repository. Removing the EnableCassandraRepositories allowed lazy loading of the repository. This new bean in my Config allowed me to instantiate my repository using the RepositoryFactorySupport getRepository() method. I annotated this bean as lazy and made sure references to the bean were also lazy.
Assume my repository looks like the following
public interface IBarRepository extends CrudRepository<Bar, BarKey>{}
My Config file now looks like
#Configuration
public class CassandraConfig{
#Bean
#Lazy(value=true)
public IBarRepository barRepository() throws Exception
{
final RepositoryFactorySupport support = CassandraRepositoryFactory(cassandraTemplate());
return support.getRepository(IBarRepository.class);
}
#Bean
#Lazy(value=true)
public CassandraClusterFactoryBean cluster()
{
final CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
cluster.setContactPoints(nodesRead);
cluster.setPort(port);
return cluster;
}
//More beans down here defining things like cluster, mappingContext, session, etc.

Is it possible to annotate a method with #TransactionAttribute in BMT EJB?

I came across a piece of code where the bean implementation class has #TransactionManagement(TransactionManagementType.BEAN) annotation wherein methods are annotated with CMT #TransactionAttribute. Is is valid?
Can an EJB with BMT persistence use CMT transaction annotation? What will be the behavior at runtime?
Though javadoc http://docs.oracle.com/javaee/6/api/javax/ejb/TransactionAttribute.html says that "It can only be specified if container managed transaction demarcation is used.", specifying it doesn't throw any compilation error. Does it mean that jvm simply ignores it at runtime?
#Stateless( mappedName = "Abc")
#Remote("AbcRemote.class")
#Local("AbcLocal.class")
#TransactionManagement(TransactionManagementType.BEAN)
public class AbcBean implements AbcLocal, AbcRemote{
#Resource
private UserTransaction utx;
#PersistenceUnit
private EntityManagerFactory emf;
#Override
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public Abc getAlpbabets(String name) {
EntityManager em = null;
try {
em = emf.createEntityManager();
}
catch (RuntimeException re) {
throw re;
}
finally {
}
}
}
If you use CMT, then #TransactionAttribute(TransactionAttributeType.REQUIRED) would tell the container to check for an existing transaction and open one if there is none.
But if you use BMT, then it's your responsibility to do such a thing, so there's no one to observe the annotation above. Since it is still syntactically correct and the class is available, there is no need for the JVM to complain about.
Concerning ignoring annotations, there's a hint in the answer to this question.

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.