How to extend #Service with spring,NoUniqueBeanDefinitionException - spring

Here is a sample class below
#Service("testService")
public class TestService {
public String something() {
return "abc";
}
}
I want to extend the class and let the container know that it needs to pick up my extended class from now.
#Service("extendedTestService")
public class ExtendedTestServiceMock extends TestService {
#override
public String something() {
return "xyz";
}
}
Test class
public class TestClass extends SpringTest {
#Autowired
#Qualifier("extendedTestService")
private ExtendedTestServiceMock testService;
public void testMethod(){
......
}
}
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [TestService] is defined: expected single matching bean but found 2: ExtendedTestServiceMock,testService
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:865) ~[spring-beans-3.2.8.RELEASE.jar:3.2.8.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:770) ~[spring-beans-3.2.8.RELEASE.jar:3.2.8.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:489) ~[spring-beans-3.2.8.RELEASE.jar:3.2.8.RELEASE]
... 91 common frames omitted
How to resolve it?

You haven't defined a bean of type ExtendedTestService.
You have only defined a bean of type ExtendedTestServiceMock.
Try this:
#Autowired
#Qualifier("extendedTestService")
private TestService testService;

The solution is use a #service anotation, you should inject the service like this:
#Autowired
private TestService testService;
And then you can use the methods of TestService

Related

How to autowire a method of a generic service

I have a Service class that has a generic type and a setController method that is based on the same generic type. the generic type of the servic object is only known at the time of declaration.
The problem is now when i define a ControllerImpl where the generic type is defined the #Autowired method of setController does not use that component.
Has somebody an idea how to fix it and keep the ServiceImpl generic. (it would work when i define the typ in ServiceImpl as well).
The following example show the problem i'm facing with:
#SpringBootTest
#ActiveProfiles("local")
public class AccessTest {
#Autowired
private ServiceA<BeanA> service;
#Test
void test(){
Assertions.assertNotNull(service.controller);
}
interface ValueGetter{
}
static class BeanA implements ValueGetter{
}
static class AbstractService<B extends ValueGetter>{
Controller<B> controller;
#Autowired
void setController(#Nullable Controller<B> controller){
this.controller = controller;
}
}
interface Controller<B extends ValueGetter>{
void doSomething(B value);
}
//not inner class
#Service
public class ServiceA<B extends AccessTest.ValueGetter> extends AccessTest.AbstractService<B> {
}
//not inner class
#Component
public class ControllerImpl implements AccessTest.Controller<AccessTest.BeanA> {
#Override
public void doSomething(final AccessTest.BeanA value) {
}
}
}

Spring Boot cannot autowired component with abstract and interface

In my Spring Boot 2.0.2 application I am trying to inject a component herited from abstract class which implements an interface and it doesn't work.
Code :
Component Abstract : (Do I need to put #Component ?)
package app.project.service;
#Component
public abstract class AbstractStepService implements IStepService {
protected final void addTask() {
...
}
#Override
public StepDataDto launch() throws StepException {
...
}
}
Interface :
package app.project.service;
public interface IStepService {
StepDataDto launch() throws StepException;
}
package app.project.service;
Component :
#Component
public class CStepServiceImpl extends AbstractStepService implements IStepService {
#PostConstruct
private void defineTasks() {
}
}
package app.project.service;
Junit Test :
#RunWith(SpringRunner.class)
#SpringBootTest
public class CStepServiceTest {
#Autowired
#Qualifier("cStepServiceImpl")
private IStepService service;
}
package app.project;
Application :
#SpringBootApplication
#ComponentScan(basePackages ={"app.project.service"})
public class MyApplication {}
Error message when launching my Junit test :
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'app.project.service.IStepService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true), #org.springframework.beans.factory.annotation.Qualifier(value=cStepServiceImpl)}
Any idea ?
Thanks
Change your declaration like this
#Autowired
#Qualifier("CStepServiceImpl")
private IStepService service;
or
#Autowired
private IStepService CStepServiceImpl;
That should work. The bean name created automatically by spring has CStepServiceImpl name.
You can also name your bean like this
#Component(value = "myName")
public class CStepServiceImpl extends AbstractStepService implements IStepService {
}
and use myName during Autowiring.

spring framework : expected single matching bean but found 2

This super class DAO:
public class CrudDAO{
}
This child class:
#Repository
public class JnsTimeDao extends CrudDAO {
}
#Repository
public class BatchDAO extends CrudDAO {
}
this super service class
#Transactional(readOnly = true)
public abstract class CrudService<D extends CrudDAO> {
#Autowired
protected D dao;
}
startup error:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No
qualifying bean of type [com.gp.dao.CrudDAO] is defined: expected
single matching bean but found 2: batchDAO,jnsTimeDao
There are 2 beans of type CrudDAO. So, Spring won't be able to understand which bean to inject. Can be solved as follows
#Repository("jnsTimeDao")
public class JnsTimeDao extends CrudDAO {
}
#Repository("batchDao")
public class BatchDAO extends CrudDAO {
}
While injecting use #Qualifier
#Transactional(readOnly = true)
public abstract class CrudService<D extends CrudDAO> {
#Autowired
#Qualifier("batchDao")
protected D dao;
}

Unsatisfied dependency during test

I have a spring boot 2.0.0 M2 application who run well.
I use autowired on constructor
#RequestMapping(value = "/rest")
#RestController
public class AddressRestController extends BaseController{
private final AddressService AddressService;
#Autowired
public AddressRestController(final AddressService AddressService) {
this.AddressService = AddressService;
}
...
}
#Service
public class AddressServiceImpl extends BaseService implements AddressService {
#Autowired
public AddressServiceImpl(final AddressRepository AddressRepository) {
this.AddressRepository = AddressRepository;
}
private final AddressRepository AddressRepository;
...
}
public interface AddressRepository extends JpaRepository<Address, Integer>, AddressRepositoryCustom {
}
#Repository
public class AddressRepositoryImpl extends SimpleJpaRepository implements AddressRepositoryCustom {
#PersistenceContext
private EntityManager em;
#Autowired
public AddressRepositoryImpl(EntityManager em) {
super(Address.class, em);
}
...
}
When i try to run a basic test
#RunWith(SpringJUnit4ClassRunner.class)
public class AddressServiceTest {
#Autowired
private AddressService service;
#MockBean
private AddressRepository restTemplate;
#Test
public void getAddress(){
MockitoAnnotations.initMocks(this);
Pageable page = PageRequest.of(0, 20);
Page<Address> pageAdr = mock(Page.class);
given(this.restTemplate.findAll(page)).willReturn(pageAdr);
Page<AddressDto> pageDto = service.getAddress(page);
}
}
I get this error
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name
'com.sonos.arcor.service.AddressServiceTest': Unsatisfied dependency
expressed through field 'service'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type ''com.sonos.arcor.service.AddressService'
available: expected at least 1 bean which qualifies as autowire
candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
I don't understand why i get this error.
You need to annotate the test with SpringBootTest so that spring initialize an application context
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications
#SpringBootTest
#RunWith(SpringJUnit4ClassRunner.class)
public class AddressServiceTest {
// the remaining test
}
Also you do not need MockitoAnnotations.initMocks(this);
Spring takes care of the mock handling
When [#MockBean is]used on a field, the instance of the created mock will also be
injected. Mock beans are automatically reset after each test method
see Mocking and spying beans

Autowiring in implementation classes of an interface in Spring

I'm having a Spring boot application in which based on a variable, I need to call corresponding implementation classes of an interface. This is what I have right now:
public interface Parent{
public void call();
}
public class ABC implements Parent{
public void call(){
System.out.println("Called ABC");
}
}
public class XYZ implements Parent{
public void call(){
System.out.println("Called XYZ");
}
}
#Service("caller")
public class Caller{
#Autowired
protected OrderInfoRepository orderInfoRepository;
AnnotationConfigApplicationContext context;
public Caller(){
context = new AnnotationConfigApplicationContext(Config.class);
}
public void callMethod(String param){
Parent p = (Parent) context.getBean(param+"_Caller");
p.call();
}
}
#Configuration
public class Config{
#Bean(name="ABC_Caller")
public Parent getABC(){
return new ABC();
}
#Bean(name="XYZ_Caller")
public Parent getXYZ(){
return new XYZ();
}
}
#Repository
public interface MyRepo extends Repository<MyDAO, Long> {
// ....
}
Basically what I want to do is, based on the param passed to Caller.callMethod(), I want to add "_Caller" to the param, and call the corresponding implementation class. So, I'm defining a #Configuration class, where I define which implementation class to return. And then using the AnnotationConfigApplicationContext, I get the corresponding bean. This works fine.
The problem I'm having is, when I try to Autowire anything in the implementation classes, I get a NoSuchBeanDefinitionException. For instance, when I autowire in the implementation class ABC
public class ABC implements Parent{
#Autowired
MyRepo myRepo;
public void call(){
System.out.println("Called ABC");
}
}
I get Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.persistence.repositories.MyRepo] when I try to start the application. However, when I do the Autowiring in the Caller class instead, it works fine. I had asked a similar question a while back, but was not able to resolve it. Any ideas?

Resources