0
votes

I have two classes CustomerDAOImpl and UserDAOImpl, both annotated with @Repository annotation. I have @Bean defined and autowired in each class.

@Repository
public class CustomerDAOImpl implements CustomerDAO {
private static final String CUSTOMER_LOCK_INSERT = "INSERT INTO CUSTOMER_LOCKS (customerid, userid, session) VALUES (?, ?, ?)";

    @Bean
    @Lazy(true)
    public PreparedStatement customerLockAddStmt () {
        return cassandraTemplate.getSession().prepare(CUSTOMER_LOCK_INSERT);
    }

    @Autowired
    @Lazy
    PreparedStatement customerLockAddStmt;

    @Autowired
    CassandraOperations cassandraTemplate;

    public void create(CustomerLock lock) {
    ...
    Statement statement = customerLockAddStmt.bind(lock.customerId,lock.userId, lock.sessionId);
    cassandraTemplate.execute(statement);

    }

   }

Exactly the same way, I have defined, autowired and used following beans in UserDAOImpl class methods(just showing the bean definitions and autowiring code to keep it clean and short here):

    @Bean
    @Lazy(true)
    public PreparedStatement userAddStmt () {
        return cassandraTemplate.getSession().prepare(USER_INSERT);
    }

    @Bean
    @Lazy(true)
    public PreparedStatement userUpdateStmt () {
        return cassandraTemplate.getSession().prepare(USER_UPDATE);
    }

    @Autowired
    @Lazy
    PreparedStatement userAddStmt;

    @Autowired
    @Lazy
    PreparedStatement userUpdateStmt;

    @Autowired
    CassandraOperations cassandraTemplate;

   public void update(User user){
   //Beans userAddStmt and userUpdateStmt defined and autowired in this class are being used here
   ....
   }

Now both these DAO Beans are being autowired in my service class OrderServiceImpl (annotated with @Service); here is the snippet:

@Service
    public class OrderServiceImpl implements OrderService {
       @Autowired
       UserDAO userDAO;
       @Autowired
       CustomerDAO customerDAO;

       public void createOrder(Order order) {
       ....
       customerDAO.create(CustomerLock); // Getting the exception on this line
       ....
       userDAO.update(user);
       ....
       }
    }

When OrderService code executes "customerDAO.create(CustomerLock);" , I'm getting this exception.

No qualifying bean of type [com.datastax.driver.core.PreparedStatement] is defined: expected single matching bean but found 2: userAddStmt,userUpdateStmt".

After getting this error, I added the attribute name="customerLockAddStmt" in "customerLockAddStmt" bean definition and used @Qualifier("customerLockAddStmt") while autowiring this bean, it worked but now it fails on following line due to the same error for the beans wired in userDAOImpl:

userDAO.update(user); 

No qualifying bean of type [com.datastax.driver.core.PreparedStatement] is defined: expected single matching bean but found 1: customerLockAddStmt".

Could someone please help?

1
...apply the same to the other onex80486
Thanks for the quick response @ɐuıɥɔɐɯ. You mean using the Qualifiers for autowiring? Is this the only option in this scenario? Would it work with first scenario(not using qualifiers) if I define all the PreparedStatement beans in a Base DAO class that all DAO implementations extend?ktewari
Also, where can I get a good explanation on why it doesn't find the other preparedstatment beans, I thought all the beans would be present in spring context.ktewari

1 Answers

1
votes

The Spring IoC container will manage the dependency between objects using configurations; it wires the related objects, instantiates and supplies them based on your configuration. It doesn't matter if you have multiple beans of the same type, the container will handle that till the point you need them — which is your case.

You have multiple beans of the same type, and they are available to be injected indeed, but the container can't figure it out what's the one you are asking for at that time, so basically you need more control over the selection process and hence, Spring's @Qualifier annotation can be used.

On the other hand, if you have many annotation-driven injection by name, do not primarily use @Autowired; instead, use the @Resource which is semantically defined to identify a specific target component by its unique name, with the declared type being irrelevant for the matching process.

UPDATE: You can refer to this post and also to the Spring Framework Reference Documentation (Dependency Injection and Inversion of Control).