Hy everybody
I have this simplified version of my trouble. I´m trying to run my application but it fails as Repository is not beign recognized to be injected. I already tried to annotate Repository as Service and to add the repository package to be scanned, but none works. Can someone help me?
I get an exception
Description:
Field topicRepository in br.com.alura.controller.TopicController required a bean of type 'br.com.alura.repository.TopicRepository' 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 'br.com.alura.repository.TopicRepository' in your configuration.
Controller/Service
#Autowired
private TopicRepository topicRepository;
#GetMapping(value = "/api/topics", produces = MediaType.APPLICATION_JSON_VALUE)
public Page<TopicBriefOutputDto> listTopics(TopicSearchInputDto topicSearch, #PageableDefault(sort="creationInstant", direction=Sort.Direction.DESC) Pageable pageRequest) {
Specification<Topic> topicSearchSpecification = topicSearch.build();
Page<Topic> topics = this.topicRepository.findAll(topicSearchSpecification, pageRequest);
return TopicBriefOutputDto.listFromTopics(topics);
}
Start
#SpringBootApplication
#Configuration
#ComponentScan(basePackages ={"br.com.alura.controller"})
#EntityScan
#EnableAutoConfiguration
#EnableJpaRepositories
#EnableSpringDataWebSupport
public class ForumApplication {
public static void main(String[] args) {
SpringApplication.run(ForumApplication.class, args);
}
}
Repository
public interface TopicRepository extends Repository<Topic, Long>, JpaSpecificationExecutor<Topic> {
}
Probably You set incorrect base package. The package scope is too narrow.
Try this:
#EnableJpaRepositories(basePackages = {"br.com.alura.repository"})
or change br.com.alura.controller to br.com.alura
#ComponentScan(basePackages ={"br.com.alura"})
Related
I have a spring batch application in which the writer has an #Autowired field (it is a service class). When running tests for the writer step, I am met with the error:
Field batchTrackingService in com.ally.cr.miscinfo.batch.writer.AdvantageClientItemWriter required a bean of type 'com.test.miscinfo.service.TestService' 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.test.miscinfo.service.batchTrackingService ' in your configuration.
I've looked at a few answers to related questions, and most of them are caused by the fact that the class being injected has not been annotated with #Component, #Service, #Repository, etc. However mine is. I also read questions where the supposed solution was to add the #ComponentScan() annotation to the Main class of my application. After trying this, it gave the same error. Can someone please help me? Any help is appreciated.
Here are the relevant classes:
Main class:
#SpringBootApplication
#EnableBatchProcessing
#EnableJpaRepositories("com.test.miscinfo.repository")
#EntityScan("com.test.miscinfo.entity")
#ComponentScan("com.test.miscinfo.service")
public class MiscInfoServiceApplication {
public static void main(String[] args) {
SpringApplication.run(MiscInfoServiceApplication.class, args);
}
}
Writer class:
#Slf4j
#Component
#AllArgsConstructor
#NoArgsConstructor
public class AdvantageClientItemWriter implements ItemWriter<MiscInfo> {
#Autowired private AdvantageClientConfig advantageClientConfig;
#Autowired WebClient advantageClientWebClient;
#Autowired private BatchTrackingService batchTrackingService;
#Override
public void write(List<? extends MiscInfo> miscInfos) throws Exception {
/* some call to a method in the injected service */
}
}
Service class:
#AllArgsConstructor
#NoArgsConstructor
#Slf4j
#Transactional
#Service
public class BatchTrackingService {
public void someMethod() {}
}
Please let me know if I am missing relevant info.
EDIT:
Adding test method:
#ExtendWith(SpringExtension.class)
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#EnableConfigurationProperties(value = AdvantageClientConfig.class)
#SpringBootTest
#ActiveProfiles("test")
#ContextConfiguration(classes = { AdvantageClientItemWriter.class })
public class AdvantageClientItemWriterTest {
#MockBean RestTemplate advantageClientRestTemplate;
#MockBean WebClient advantageWebClient;
WebClient.RequestBodyUriSpec requestBodyUriSpec = mock(WebClient.RequestBodyUriSpec.class);
WebClient.RequestBodySpec requestBodySpec = mock(WebClient.RequestBodySpec.class);
WebClient.ResponseSpec responseSpec = mock(WebClient.ResponseSpec.class);
WebClient.RequestHeadersSpec requestHeadersSpec = mock(WebClient.RequestHeadersSpec.class);
#Autowired AdvantageClientConfig advantageClientConfig;
#Autowired AdvantageClientItemWriter advantageClientItemWriter;
ArgumentCaptor<String> uriCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<MediaType> mediaTypeCaptor= ArgumentCaptor.forClass(MediaType.class);
ArgumentCaptor<String> headerNameCaptor= ArgumentCaptor.forClass(String.class);
ArgumentCaptor<String> headerValueCaptor= ArgumentCaptor.forClass(String.class);
ArgumentCaptor<String> bodyCaptor= ArgumentCaptor.forClass(String.class);
private MemoryAppender memoryAppender;
#BeforeEach
public void init(){
Logger logger = (Logger) LoggerFactory.getLogger("com.test");
memoryAppender = new MemoryAppender();
memoryAppender.setContext((LoggerContext) LoggerFactory.getILoggerFactory());
logger.setLevel(Level.DEBUG);
logger.addAppender(memoryAppender);
memoryAppender.start();
}
#Test
public void successfulAdvantageClientWrite() throws Exception {
setupMockReturns();
when(responseSpec.toBodilessEntity()).thenReturn(Mono.just(new ResponseEntity(null, HttpStatus.OK)));
List<MiscInfo> miscInfos = new ArrayList<>();
final MiscInfo miscInfo = createMiscInfo1();
miscInfos.add(miscInfo);
advantageClientItemWriter.write(miscInfos);
Assertions.assertEquals(advantageClientConfig.getEndpoint(), uriCaptor.getValue());
Assertions.assertEquals(MediaType.APPLICATION_JSON, mediaTypeCaptor.getValue());
Assertions.assertEquals( advantageClientConfig.getHeaderName(), headerNameCaptor.getValue());
Assertions.assertEquals(advantageClientConfig.getApiKey(), headerValueCaptor.getValue());
Assertions.assertEquals(new ObjectMapper().writer().withDefaultPrettyPrinter().writeValueAsString(miscInfos), bodyCaptor.getValue());
assertThat(memoryAppender.search("Write to Advantage status: ", Level.DEBUG).size()).isEqualTo(1);
}
}
This error means that Spring is trying to autowire of bean of type BatchTrackingService in your AdvantageClientItemWriter but it could not find one in the application context. In other words, your test context does not contain a bean definition of type BatchTrackingService, which could be due to one of the following causes:
Either the configuration class that defines that bean is not imported in the test class (in #ContextConfiguration(classes = { AdvantageClientItemWriter.class })
or the class of that bean is not in the package that is scanned by Spring (Boot).
Make sure that:
the class public class BatchTrackingService {} is defined in the package referenced in #ComponentScan("com.test.miscinfo.service")
the #ContextConfiguration annotation imports the class of that bean (something like #ContextConfiguration(classes = { AdvantageClientItemWriter.class, BatchTrackingService.class }), or that it imports a configuration class which defines an instance of that bean.
I see a lot of posts surrounding this error message, but none with a solution that's worked for me.
I'm writing a Spring application that has required me to configure multiple data sources. I got all of those working, but now I need to import a module my teammates built that uses an additional data source and several repositories. They've been using this module in their code and it seems to be working for them, but when I try to run my code I get the following error (some details obscured for work reasons):
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.company.teammodule.repositories.StatsRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
//I can't paste code, so there may be typos...
Spring Application Class:
package com.company.mymodule;
#SpringBootApplication
#EnableAutoConfiguration
#ComponentScan(basePackages={
"com.company.mymodule",
"com.company.mymodule.utils",
"com.company.mymodule.configuration",
"com.company.teammodule.repositories",
//I've been fiddling with packages here; I've added every package from the teammatemodule app and still get the error described})
#public class MyModuleApplication
{
public static void main(String[] args) { SpringApplication.run(MyModuleApplication.class, args); }
}
My class that uses the teammatemodule:
package com.company.mymodule.utils;
#Component
public class TeammateModuleUtil {
#Autowired
private TeammateModuleConfiguration config; //This class contains an object of another class which references the problem repository
#Value("${applicationName})
private final String applicationName;
public TeammateModuleUtil()
{
try {
config.setApplicationName(applicationName);
config.loadConfiguration();
}
catch (Exception e) {
//Error handling
}
}
}
The TeammateModuleConfiguration class:
package com.company.teammatemodule
#Component
public class TeammateModuleConfiguration extends ConfigurationBase {
#Autowired
TeammateModuleServiceData data; //This class contains a reference to the problem repository
#Autowired
Utilities util;
#Autowired
ConfigurationRepository configurationRepository;
public void loadConfiguration() throws Exception {
try {
this.alConfigure = this.configurationRepository.findByConfigureIdApplicationName(this.applicationName);
} catch (Exception e) {
//Error handling
}
}
}
Here's the class that has the problem reference:
package com.company.teammatemodule;
#Component
public class TeammateModuleServiceData {
#Autowired
StatsRepository statsRepository //This is the repo the code can't find a bean for
#Autowired
MessageAuthorizationRepository messageAuthorizationRepository;
#Autowired
LogMessagesRepository logMessagesRepository;
#Autowired
Utilities util;
//Class methods
}
And here's the repository class for good measure:
package com.company.teammatemodule.repositories;
#Repository
public interface StatsRepository extends JpaRepository<Stats, StatsId> {
#Procedure(
procedureName = "schema.log_service_stats",
outputParameterName = "o_stats_id"
)
String logServiceStats(#Param("i_request_payload") String var1, #Param("i_response_payload") String var2, #Param("i_operation_name") String var3, #Param("i_stats_id") String var4);
#Procedure(procedureName = "schema.update_service_stats)
void updateServiceStats(#Param("i_request_payload") String var1, #Param("i_response_payload") String var2, #Param("i_operation_name") String var3, #Param("i_stats_id) String var4);
}
The above repository is the one that can't be found when I try to launch the application. What I've checked and tried:
The main application has the #SpringApplication annotation, and all other involved classes have either #Component, #RestController, or #Repository, so I don't think it's an issue of some component not being labeled a bean...
None of the other repositories in teammatemodule are giving me a problem, but I'm guessing StatsRepository is just the first repository to be referenced
The only properties in my properties file are applicationName and data sources unrelated to the teammatemodule. I'm not listing any packages or exclusions there.
I've specified all packages in #ComponentScan ( basepackages = {//packages} ) as well as #SpringApplication( scanBasePackages = {//packages} )
I've tried excluding spring's autoconfigure by using the following annotations in my SpringAplication class:
#SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class })
#EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
So I don't think it's a missing #Component or other bean annotation, and to the best of my ability I've specified the package in which the repository bean is located and overridden Spring's built-in autoconfiguration tools... But the app still can't find the bean.
Thanks for your help!
It looks like this might just be a simple misspelling:
com.company.teammodule.repositories <- Component Scan
com.company.teammatemodule.repositories <- Package specified in Repository class
I have 2 spring boot microservice let's say core and persistence. where persistence has a dependency on core.
I have defined an interface in core whose implementation is inside persistence as below:
core
package com.mine.service;
public interface MyDaoService {
}
Persistence
package com.mine.service.impl;
#Service
public class MyDaoServiceImpl implements MyDaoService {
}
I am trying to inject MyDaoService in another service which is in core only:
core
package com.mine.service;
#Service
public class MyService {
private final MyDaoService myDaoService;
public MyService(MyDaoService myDaoService) {
this.myDaoService = myDaoService;
}
}
while doing this i am getting this weird error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.mine.service.MyService required a bean of type 'com.mine.service.MyDaoService' that could not be found.
Action:
Consider defining a bean of type 'com.mine.service.MyDaoService' in your configuration.
can anyone explain me why ?
NOTE: i have already included com.mine.service in componentscan of springbootapplication as below
package com.mine.restpi;
#SpringBootApplication
#EnableScheduling
#ComponentScan(basePackages = "com.mine")
public class MyRestApiApplication {
public static void main(String[] args) {
SpringApplication.run(MyRestApiApplication.class, args);
}
}
Try adding the #Service annotation to your impl classes and the #Autowired annotation to the constructor.
// Include the #Service annotation
#Service
public class MyServiceImpl implements MyService {
}
// Include the #Service annotation and #Autowired annotation on the constructor
#Service
public class MyDaoServiceImpl implements MyDaoService {
private final MyService myService ;
#Autowired
public MyDaoServiceImpl(MyService myService){
this.myService = myService;
}
}
As stated in the error message hint: Consider defining a bean of type 'com.mine.service.MyDaoService' in your configuration to solve this problem you can define in your package com.mine a configuration class named MyConfiguration annotated with #Configuration including a bean named myDaoService like below:
#Configuration
public class MyConfiguration {
#Bean
public MyDaoService myDaoService() {
return new MyDaoServiceImpl();
}
}
Try the following, move MyRestApiApplication class to com.mine package and remove #ComponentScan annotation.
package com.mine;
#SpringBootApplication
#EnableScheduling
public class MyRestApiApplication {
public static void main(String[] args) {
SpringApplication.run(MyRestApiApplication.class, args);
}
}
I am using a mock repository for my application.
Here is snippet how service looks:
#Service
public class WeatherStationService {
#Autowired
private WeatherStationRepositoryMock weatherRepository;
Here is repository code:
#Repository
public class WeatherStationRepositoryMock {
#Getter
private List<WeatherStation> stations = new ArrayList<>(
Arrays.asList(
new WeatherStation("huston", "Huston station", RandomGenerator.getRandomGeoInformation()),
new WeatherStation("colorado", "Colorado station", RandomGenerator.getRandomGeoInformation())
)
);
It works fine when I am executing main() with #SpringBootApplication.
However, when I want to run test class:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = MockConfig.class)
#DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
public class WeatherStationServiceTest {
#Autowired
#Real
private WeatherStationService weatherService;
It fails with the following stacktrace:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'edu.lelyak.repository.WeatherStationRepositoryMock' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Here is MockConfig content:
#Configuration
public class MockConfig {
//**************************** REAL BEANS ******************************
#Bean
#Real
public WeatherStationService weatherServiceReal() {
return new WeatherStationService();
}
Real is marker annotation for real instances:
#Retention(RUNTIME)
#Qualifier
public #interface Real {
}
I can fix it with next initialization at service:
#Service
public class WeatherStationService {
private WeatherStationRepositoryMock weatherRepository = new WeatherStationRepositoryMock();
It works fine.
Why does this happen?
How to fix autowiring for my custom repository class?
#SpringBootApplication implicitly defines #ComponentScan, which scans all subpackages for beans.
When you run a test using MockConfig's, it doesn't scan for beans.
Solution - use #ComponentScan OR define beans in MockConfig
(1) Using #ComponentScan:
#Configuration
#ComponentScan //Make sure MockConfig is below all beans to discover
public class MockConfig {
#Bean
#Real
public WeatherStationService weatherServiceReal() {
return new WeatherStationService();
}
}
(2) or define required beans:
#Configuration
public class MockConfig {
#Bean
#Real
public WeatherStationService weatherServiceReal() {
return new WeatherStationService();
}
#Bean
public WeatherStationRepositoryMock weatherStationRepository() {
return new WeatherStationRepositoryMock()
}
}
I've got a spring boot application (1.3.1.RELEASE) and recently experienced a strange behavior when trying to inject a #ConfigurationProperties bean into my configuration. I'm not an expert in Spring, so my question is how can this behavior be explained?
So the setup is like that:
MyApplication.java:
package me.developer;
#SpringBootApplication
public class MyApplication {
public static void main(final String... args) {
SpringApplication.run(<..>, args);
}
}
SecurityProperties.java:
package me.developer.document.security;
#Setter
#Getter
#Component
#ConfigurationProperties(prefix = "security")
public class SecurityProperties {
private List<String> apiKeys = new ArrayList<>();
}
SecurityConfiguration.java
package me.developer.document;
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private SecurityProperties securityProperties;
#Override
protected void configure(final HttpSecurity http) throws Exception {
<..>
}
}
When the application is started I get an error that Spring can't inject SecurityConfiguration.securityProperties because it knows nothing about me.developer.document.security.SecurityProperties bean.
But if I rename SecurityProperties to SicurityProperties (second letter "e" --> "i") - it works! Don't ask me how did I get to that, but I'm just curious how this behavior can be explained? I.e. from my perspective it should either work or not, but not depending of the bean name, etc...
Update:
I also works if I don't touch the class name but explicitly specify the bean name like that
package me.developer.document.security;
#Setter
#Getter
#Component("securityProperties.my")
#ConfigurationProperties(prefix = "security")
public class SecurityProperties {
private List<String> apiKeys = new ArrayList<>();
}
And I don't provide any additional qualifiers during autowiring... Why is it happening?
Assuming that you have a dependency on spring-boot-starter-security, Spring Boot will be auto-configuring its own SecurityProperties bean that's also annotated with #ConfigurationProperties. Unfortunately this bean will have the same name as your bean as the class names (ignoring the package) are the same. This name clash means that Spring Boot's been will be overriding your security properties bean. You should see a warning message to that effect logged during startup.
As you have observed, changing the name of your bean so that there's no longer a name clash will solve the problem.