Could not autowire. No beans of 'InstructionRepository' type found - spring-boot

Trying to create a bean in SpringBoot application, but getting the following error "Could not autowire. No beans of 'InstructionRepository' type found."
InstructionRepository is annotated with #Repository annotation in the jar and is an Interface extending a Spring Data Interface
ScheduleProcessor is a method
When I Try adding the #ComponentScan annotation by passing the base package value, the error goes away BUT, when I boot up the application get the following error
Parameter 0 of constructor in com.xxx.resync.config.AppConfig required a bean of type 'com.xxx.repo.InstructionRepository' that could not be found. Action: Consider defining a bean of type 'com.xxx.repo.InstructionRepository' in your configuration.
#Configuration
#EnableAutoConfiguration
//#ComponentScan(basePackages = {"com.xxx.repo"})
public class AppConfig {
#Value("${pssHttp.connectTimeout:3000}")
private int connectTimeout;
#Bean
public RestTemplate getRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
final HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(connectTimeout);
factory.setReadTimeout(connectTimeout);
restTemplate.setRequestFactory(factory);
return restTemplate;
}
#Bean
public ScheduleUpdater getScheduleUpdater() {
return new ScheduleUpdater(true);
}
#Bean
public ScheduleProcessor scheduleProcessor(InstructionRepository instructionRepository, ScheduleUpdater scheduleUpdater) {
return new ScheduleProcessor(instructionRepository, scheduleUpdater);
}
}
InstructionRepository
#Repository
public interface InstructionRepository extends CouchbaseRepository<Instruction, String> {
}
How can we fix the error and be able to boot up the Spring boot application?
Any suggestions appreciated.

You need to add #EnableCouchbaseRepositories to enable repo building eg to AppConfig.

Related

Unable to mock component that uses RestTemplateBuilder

I have a Springboot application that uses RestTemplate to access a third-party json api.
I have written a Component that has the RestTemplate field which is instantiated using Constructor Injection.
#Service("sample")
public class SampleService {
private RestTemplate restTemplate;
#Autowired
public SampleService(RestTemplateBuilder builder) {
this.restTemplate = builder.build();
}
The service works fine.
I am trying to write test cases for the same.
#RunWith(MockitoJUnitRunner.class)
#SpringBootTest(classes = {Application.class,ServiceTest.ContextConfiguration.class})
public class ServiceTest {
#InjectMocks
#Qualifier("sample")
SampleService sampleService;
#Configuration
static class ContextConfiguration {
#Bean
public RestTemplateBuilder restTemplateBuilder() {
RestTemplateBuilder rtb = mock(RestTemplateBuilder.class);
RestTemplate restTemplate = mock(RestTemplate.class);
when(rtb.build()).thenReturn(restTemplate);
return rtb;
}
}
}
I am getting the below exception on test class startup.
org.mockito.exceptions.misusing.InjectMocksException:
Cannot instantiate #InjectMocks field named 'sampleService' of type 'class com.xxx.xxx.core.SampleService'.
You haven't provided the instance at field declaration so I tried to construct the instance.
However the constructor or the initialization block threw an exception : Cannot invoke "org.springframework.boot.web.client.RestTemplateBuilder.build()" because "builder" is null
How to resolve this?

#ConfigurationProperites not binding to property source after upgrading to Spring Cloud Hoxton.SR7

I have a #ConfigurationProperties class that is no longer binding to a YML property source that gets resolved via Spring Cloud Config after upgrading to Hoxton.SR7. This code works fine using Hoxton.SR4 with the latest Spring Boot 2.2.9.RELEASE. Now, my properties are not bound and I'm receiving NPEs when I try to reference them. Following is a snapshot of my code:
#Configuration
public class MyConfiguration {
#Bean
public MyPropertiesBean myPropertiesBean() {
return new MyPropertiesBean();
}
}
#ConfigurationProperties(prefix = "com.acme.properties")
#Validated
public class MyPropertiesBean {
...
}
In src/main/resources/META-INF/spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.acme.MyConfiguration
Any ideas why my #ConfigurationProperties class doesn't bind after upgrading Spring Cloud to Hoxton.SR7?
You're mixing two ways of binding properties: class and method.
Using a method and #Bean annotation:
#Configuration
public class MyConfiguration {
#Bean
#ConfigurationProperties(prefix = "com.acme.properties")
#Validated
public MyPropertiesBean myPropertiesBean() {
return new MyPropertiesBean();
}
}
This will create MyPropertiesBean and store it inside the application context for you to inject.
Class level bean declaration also creates a bean for you:
#Configuration
#ConfigurationProperties(prefix = "com.acme.properties")
#Validated
public class MyPropertiesBean {
...
}
This will also store a bean.
Although, you should be getting a runtime error when you try to inject MyPropertiesBean as now in your case there's two beans of the same type and Spring cannot resolve with only the type.

Spring boot test: MockedBean conflicts with others

Currently, I've two RestTemplate beans:
#Bean
#Primary
public RestTemplate jwtRestTemplate(
RestTemplateBuilder builder,
JWTService jwtService) {
return builder
.additionalInterceptors(
Collections.singletonList(
new JWTHeaderRequestInterceptor(jwtService)
)
)
.build();
}
#Bean
public RestTemplate rawRestTemplate(RestTemplateBuilder builder) {
return builder.build();
}
The first one is primary and the other one is requested by #Qualifier("rawRestTemplate").
However, I'm mocking a ResTemplate into my tests:
#RunWith(SpringRunner.class)
#SpringBootTest()
public class AuditoryTest {
#MockBean()
private RestTemplate frontOfficeRestTemplate;
#Autowired
private DocumentServiceBackOffice documentService;
DocumentServiceBackOffice constructor is:
public DocumentServiceBackOffice(RestTemplate restTemplate);
I'm getting an exception:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in net.gencat.transversal.espaidoc.backoffice.service.DocumentServiceBackOffice required a single bean, but 2 were found:
- rawRestTemplate: defined by method 'rawRestTemplate' in class path resource [net/gencat/transversal/espaidoc/backoffice/config/BackOfficeConfiguration.class]
- jwtRestTemplate: defined by method 'createMock' in null
Action:
Consider marking one of the beans as #Primary, updating the consumer to accept multiple beans, or using #Qualifier to identify the bean that should be consumed
Message is pretty clear, but I don't quite figure out how to solve that.
Any ideas?
I've solved that using that additional Configuration class:
#TestConfiguration
public static class RestTemplateTestConfiguration {
#Bean("jwtRestTemplate")
#Primary
public static RestTemplate someService() {
return Mockito.mock(RestTemplate.class);
}
}

SpringBoot multiple #Configuration and SOAP clients

I have tried to follow this simple tutorial https://spring.io/guides/gs/consuming-web-service/, and it works.
I then try to connect to another SOAP service, with an additional #Configuration and client-class extending WebServiceGatewaySupport. It seems that both client-classes then use the same #Configuration-class, making the one I added first failing (unknown jaxb-context etc.). How can I ensure that the client-classes use the correct #Configuration-class?
TL;DR: You have to match the name of the "marshaller()" method with the param variable name in your client configuration.
Overriding bean definitions
What is happening is that both of your #Configuration clases are using the same bean name for the Jaxb2Marshaller, that is (using the spring example):
#Bean
public Jaxb2Marshaller marshaller() { //<-- that name
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("hello.wsdl");
return marshaller;
}
There the "marshaller()" method name is the bean name that will be injected below in your client:
#Bean
public QuoteClient quoteClient(Jaxb2Marshaller marshaller) { //<-- used here
QuoteClient client = new QuoteClient();
client.setDefaultUri("http://www.webservicex.com/stockquote.asmx");
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;
}
If you use "marshaller()" for your second client, Spring overrides that bean definition. You could spot this in the log file, look for something like this:
INFO 7 --- [main] o.s.b.f.s.DefaultListableBeanFactory : Overriding bean definition for bean 'marshaller'
Solution
So to create more clients that have their own marshaller without colliding you need to have a #Configuration like this:
#Configuration
public class ClientBConfiguration {
#Bean
public Jaxb2Marshaller marshallerClientB() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("hello.wsdl");
return marshaller;
}
#Bean
public ClientB clientB(Jaxb2Marshaller marshallerClientB) {
ClientB client = new ClientB();
client.setDefaultUri("http://www.webservicex.com/stockquote.asmx");
client.setMarshaller(marshallerClientB);
client.setUnmarshaller(marshallerClientB);
return client;
}
}
More about bean overriding: https://blog.tratif.com/2018/03/08/when-two-beans-collide/
Answer about spring boot #Configuration classes: Why Spring Boot Application class needs to have #Configuration annotation?
I ended up creating #Bean in the #Configuration-classes that returns a WebServiceTemplate. That is, I don't use Spring's autoconfiguration mechanisms. I removed the extend WebserviceGatewaySupport, and use #Autowired to autowire the WebserviceTemplateBean bean created in the #Configuration class.

Spring #Configuration class needs to be autowired

I've created a Spring #Configuration annotated class and I want to autowire a ResourceLoader to it so that I can use it in one of the #Bean methods to lookup a file given by a String. When I am running the app and initialising the context I get a NPE accessing the autowired field, and in debug mode it is shown as being null/not set. Am I wrong expecting the resourceLoader to be present? Am I wrong asserting the autowiring of the Configuration bean happens before its methods get called? The xml configuration loading this bean is tagged with <context:annotation-config/>
#Configuration
public class ClientConfig {
#Autowired
private ResourceLoader resourceLoader;
public #Bean
String configHome() {
return System.getProperty("CONFIG_HOME");
}
public #Bean
PropertiesFactoryBean appProperties() {
String location = "file:" + configHome() + "/conf/webservice.properties";
PropertiesFactoryBean factoryBean = new PropertiesFactoryBean();
factoryBean.setLocation(resourceLoader.getResource(location));
return factoryBean;
}
}
I'm not sure whether this is a bug or is the expected behavior. Sometimes it worked for me, sometimes didn't. Anyway, there is another way of achieving what you want:
public #Bean PropertiesFactoryBean appProperties(ResourceLoader resourceLoader) {
// resourceLoader is injected correctly
...
}

Resources