How to use #Qualifier with Service and Repository - java

I have a generic repository interface called UserRepository.
I then have an interface which extends from that called MyUserRepository.
It deals with an MyUser class which extends User.
I also have a Service Interface called UserService and a class called MyUserServiceImpl.
The service wants an instance of the UserRepository and I though I could use some sort of annotation like #Qualifier but it doesn't work.
#NoRepositoryBean
public interface UserRepository <T extends User> extends JpaRepository<T, Long>{
<S extends T> S findByLoginName(String loginName);
<S extends T> S saveAndFlush(User user);
}
#Repository
#Qualifier("myUserRepository")
public interface MyUserRepository extends UserRepository<MyUser> {
}
public interface UserService {
public List<User> getUsers();
}
#Service
public class MyUserServiceImpl implements UserService {
#Autowired
#Qualifier("myUserRepository")
private UserRepository<User> userRepository;
#Override
public List<User> getUsers() {
....
}
}
APPLICATION FAILED TO START
Description:
Parameter 0 of constructor in com....services.MyUserServiceImpl
required a bean of type 'com....repositories.UserRepository' that
could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com....repositories.UserRepository'
in your configuration.

#Qualifier annotation is used only when calling a bean already created. So you shouldn't call on class head, you might name it #Repository("myUserRepository") and call it on after #Autowired #Qualifier("myUserRepository")

No need to have a qualifier in your case.
#Repository
public interface MyUserRepository extends UserRepository<MyUser> {
}
Auto-wire the repository as :
#Service
public class MyUserServiceImpl implements UserService {
#Autowired
private UserRepository<User> userRepository;
...

#Qualifier is used with #Autowired annotation. By default #Autowired will inject beans based on types.When you have multiple beans of same types then #Qualifier helps to resolve the conflict. In your case using annotation #Repository will do you job. Also in your UserRepository interface , you have to supply the Id class along with JPA entity class.

Related

Consider defining a bean of type 'com.example.conferencedemo.services.SessionService' in your configuration

I am trying to implement as of enterprise level, there they have folders like Repository,Service,ServiceImpl
In Services they have interface with method declaration
In ServiceImpl they have class implementing the interface of services
In Repository they have all Repository interfaces
BeanInjection is a class where we have all repositories and service classes and interfaces with
#Autowired annotation.
When I tried to implement "#Autowired" to service class getting this Error.
Tried this no help link
Tried this no help but getting loop error link
Controller.java
public class SessionController extends BeanInjectionService {
#GetMapping
public ResponseEntity<List<Session>> list(){
LOGGER.info("Request received to view the sessions");
List<Session> sessions = sessionService.findAll();
LOGGER.info("Successfully fetched all the sessions");
return new ResponseEntity<>(sessions, HttpStatus.OK);
}
SessionService.java(Interface)
public interface SessionService {
List<Session> findAll();
}
SessionServiceImpl.java(Class)
public class SessionServiceImpl extends BeanInjectionService implements SessionService {
#Override
public List<Session> findAll(){
return sessionRepository.findAll();
}
BeanInjectionService.java(Class)
public class BeanInjectionService {
#Autowired
public SessionRepository sessionRepository;
**// Error Showing here while starting application
// Consider defining a bean of type 'com.example.conferencedemo.services.SessionService' in your configuration.**
#Autowired
public SessionService sessionService;
#Autowired
public SpeakerRepository speakerRepository;
#Autowired
public SpeakerService speakerService;
}
SessionRepository.java(Interface)
public interface SessionRepository extends JpaRepository<Session,Long> {
}
Thanks in advance
I find using BeanInjectionService a little weird, but I'll answer around it.
Unless you add #Service on SessionServiceImpl, you can't autowire it.
Circular dependency - If you do step 1, it will create a circular dependency because SessionServiceImpl needs its superclass object(BeanInjectionService) to be created first. But BeanInjectionService cannot be created unless it finds an object of SessionServiceImpl.
To break the circular dependency, you have only one option. Don't extend BeanInjectionService. Rather, autowire SessionRepository directly into SessionServiceImpl.
#Service
public class SessionServiceImpl implements SessionService {
#Autowired
private SessionRepository sessionRepository;
#Override
public List<Session> findAll(){
return sessionRepository.findAll();
}
}

conditional repository injection - Spring Boot

I Have two repository interfaces that connect MongoDB and CouchBase :
public interface UserRepositoryMongo extends MongoRepository<User, Long> {
}
public interface UserRepositoryCouch extends CouchbasePagingAndSortingRepository<User, Long> {
}
Is there a way to interchangeably #Autowire these repositories into UserService on condition?
The condition will be inside property file : application.properties.
**Note :**
*These repositories can have custom methods too.*
We can use either ConditionalOnProperty or ConditionalOnExpression to switch between two different repository implementation.
If we want to control the autowiring with simple property presence/absence or property value, then ConditionalOnProperty can be used.
If complex evaluation is required, then we can use ConditionalOnExpression.
ConditionalOnProperty (presence/absence of a property)
#Qualifier("specificRepo")
#ConditionalOnProperty("mongo.url")
public interface UserRepositoryMongo extends MongoRepository<User, Long>{
}
#Qualifier("specificRepo")
#ConditionalOnProperty("couch.url")
public interface UserRepositoryCouch extends CouchbasePagingAndSortingRepository<User, Long>{
}
ConditionalOnProperty (based on value)
#ConditionalOnProperty("repo.url", havingValue="mongo", matchIfMissing = true) //this will be default implementation if no value is matching
public interface UserRepositoryMongo extends MongoRepository<User, Long> {
}
#ConditionalOnProperty("repo.url", havingValue="couch")
public interface UserRepositoryCouch extends CouchbasePagingAndSortingRepository<User, Long> {
}
ConditionalOnExpression
#ConditionalOnExpression("#{'${repository.url}'.contains('couch')}")
public interface UserRepositoryCouch extends CouchbasePagingAndSortingRepository<User, Long> {
}
UPDATE
Use CrudRepository/Repository type to inject based on your requirement.
public class DemoService {
#Autowired
#Qualifier("specificRepo")
private CrudRepository repository;
}
Based on bean created, either UserRepositoryMongo or UserRepositoryCouch will be autowired. Make sure only one bean is instantiated to avoid ambiguity error.
Another attempt to solve this problem.
Based on the property, the autowired customRepository will be an instance of SimpleMongoRepository or SimpleCouchRepository.
public interface CustomRepository extends CrudRepository<User, Long> {
User findByLastName(String lastName); //custom methods
}
#Qualifier("specificRepo")
#ConditionalOnProperty("mongo.url")
public interface UserRepositoryMongo extends MongoRepository<User, Long>, CustomRepository{
}
#Qualifier("specificRepo")
#ConditionalOnProperty("couch.url")
public interface UserRepositoryCouch extends CouchbasePagingAndSortingRepository<User, Long>, CustomRepository{
}
public class UserService {
#Autowired
#Qualifier("specificRepo")
private CustomRepository repository;
}

Spring Boot/Data: Generic service class for crud operations

Let's say I want to create a REST API which performs basic CRUD operations on several entities. For that I've created generic interface:
public interface CrudService<T>{
//generic CRUD methods
}
And its implementation for Foo entity:
#Entity
public class Foo {
}
#Repository
public interface FooRepository extends JpaRepository<Foo, Long>{
}
#Service
#Transactional
public class FooCrudServiceImpl implements CrudService{
#Autowired
private FooRepository repository;
//CRUD methods implementation
}
#RestController
class FooController{
#Autowired
private CrudService<Foo> crudService;
//Controller methods
}
What I want to avoid now is creating service implementation for each entity with basically the same logic. So I tried to create a generic service class which can be called from multiple controllers(FooController, BarController etc.):
#Service
#Transactional
class GenericCrudServiceImpl<T> implements CrudService{
#Autowired
private JpaRepository<T, Long> repository;
//generic CRUD methods implementation
}
and pass that service class to each controller where the entity type would be specified. The problem is that there will be multiple repository beans that could be injected into GenericCrudServiceImpl (FooRepository, BarRepository etc.) and just by specifying the type of JpaRepository Spring still doesn't know which bean to inject. I don't want to call repository beans directly from controller classes to maintain seperation of responsibilities.
Additionally, for some reason this problem doesn't occur on controller level where I inject CrudService interface and Spring understands which bean should it choose, which messes with my whole understanding of dependency injection.
Is there a way to create such a generic service class? Other posts on stackoverflow didn't provide me with an answer.
Bonus question: what's the difference between using a #Qualifier annotation and injecting a specific implementation (in this example FooCrudServiceImpl instead of CrudService in controller class)? In both cases pointing to different use implementation requires changing one line of code.
What about that:
#Transactional
public class GenericCrudServiceImpl<T> implements CrudService{
private JpaRepository<T, Long> repository;
public GenericCrudServiceImpl(JpaRepository<T, Long> repository) {
this.repository = repository;
}
}
And Spring configuration:
#Configuration
public PersistanceConfiguration {
#Bean
public JpaRepository<Foo, Long> fooJpaRepository() {
...
}
#Bean
public JpaRepository<Foo, Long> booJpaRepository() {
...
}
#Bean
public CrudService<Foo> fooService(JpaRepository<Foo, Long> fooJpaRepository) {
return new GenericCrudServiceImpl(fooJpaRepository);
}
#Bean
public CrudService<Foo> booService(JpaRepository<Foo, Long> booJpaRepository) {
return new GenericCrudServiceImpl(booJpaRepository);
}
}
And Controller
#RestController
class FooController{
// Injection by bean name 'fooService'
#Autowired
private CrudService<Foo> fooService;
//Controller methods
}

NoUniqueBeanDefinitionException when injecting JpaRepository to Generic class

How to inject repository to generic class?
public class FruitComboBox<T extends Fruit> extends ComboBox {
#Autowired
private JpaRepository<T, Integer> repository;
...
}
public class FruitMarket {
#Autowired
FruitComboBox<Apple> appleCombobox; // Apple extends Fruit
#Autowired
FruitComboBox<Orange> orangeCombobox; // Orange extends Fruit
...
}
Also I have two repositories
#Repository
public interface AppleRepository extends JpaRepository<Apple, Integer> {
}
#Repository
public interface OrangeRepository extends JpaRepository<Orange, Integer> {
}
I suppose that the generic repository from FruitComboBox should be resolved as one of two existing repositories according it's T, and autowired by Spring.
The NoUniqueBeanDefinitionException: expected single matching bean but found 2 occurs at runtime (not at start of application). So I supposed that at runtime all the types are defined and Spring has known what concrete type is T.
Spring data needs to know at the bootstrap time the the entity the repository represents. That means you can not leave it with Generic Parameter during autowiring.
Create a separate interface like below.
#Repository
public interface MyGenericRepository<T> extends JpaRepository<T, Integer>{
}
Now you should be able to autowire it with a definite type (not generic type). This is as generic as it gets.
#Autowired
private MyGenericRepository<Apple, Integer> repository;
Above can not be left with generic parameter.
Reference http://docs.spring.io/spring-data/jpa/docs/1.6.5.RELEASE/reference/html/repositories.html
Also try to use Long for the ID's.

Resolving Spring conflict with #Autowired and #Qualifier

I have an interface
public interface ParentService{}
And Two Implementation Class
#Service("child1service")
public class Child1 implements ParentService{}
#Service("child2service")
public class Child2 implements ParentService{}
Now my Controller
public class ServeChild1Controller extendds AbstractController{
#Autowired
public ServeChild1Controller(#Qualifier("child1service") ParentService child1service){
super(child1service)
}
Similarly there is ServeChild2Controller..
So when i run I get the following error
Error for ServeChild1Controller: No unique bean of type [com.service.ParentService] is defined: expected single matching bean but found 2 child1service, child2service
Am trying to read more about these Annotations but not able to resolve it ..
Any pointers will be of help
Thanks
In order to use a specific instance you need to provide Annotate the service with #Qualifier(id) and in the constructor anotate the parameter with #Qualifier again, as follows:
#Service("child1service")
#Qualifier("child1service")
public class Child1 implements ParentService{}
#Service("child2service")
#Qualifier("child2service")
public class Child2 implements ParentService{}
And you constructor:
public class ServeChild1Controller extendds AbstractController{
#Autowired
public ServeChild1Controller(#Qualifier("child1service") ParentService child1service){
super(child1service)
}
}
With Spring (beans) 4.3 it works exactly the way you wrote it in your question.
I can give you example with implementation groupping that I faced recently. Spring can autowire based on on type and qualifier distinction. Using service names is not enough as they need to be unique so you would end up with type conflict.
Example:
public interface ServiceA {}
public interface ServiceB {}
#Qualifier("mockedA")
#Service
public class MockedA implements ServiceA {}
#Qualifier("realA")
#Service
public class RealA implements ServiceA {}
#Qualifier("mockedB")
#Service
public class MockedB implements ServiceB {}
#Qualifier("realB")
#Service
public class RealB implements ServiceB {}
#Autowired
public ABController (
#Qualifier("mockedA") ServiceA mockedA,
#Qualifier("realA") ServiceA realA,
#Qualifier("mockedB") ServiceB mockedB,
#Qualifier("realB") ServiceB realB) {
}
I think the #Qualifier annotation might need to be provided at the same level as the #Autowired annotation.

Categories