Reputation: 12810
I have the most puzzling Spring error message I ever had, well, I had a few over the years, but this one is one to remember.
The error message is:
Field orderService in com.thalasoft.butik.rest.config.FixtureService required a single bean, but 2 were found:
- com.thalasoft.butik.data.service.OrderServiceImpl: defined in URL [jar:file:/home/stephane/.m2/repository/com/thalasoft/butik-data/0.0.1-SNAPSHOT/butik-data-0.0.1-SNAPSHOT.jar!/com/thalasoft/butik/data/service/OrderServiceImpl.class]
- OrderService: defined by method 'OrderService' in class path resource [com/thalasoft/butik/data/config/JpaService.class]
The butik
application is composed of 2 Spring projects, one being the butik-data
project and the other one being the butik-rest
project.
The error occurs when running the integration tests in the butik-rest
project
mvn clean install -Denv="test" -Ddb="h2"
The very same error occurs when running the application and not running the integration tests:
mvn clean spring-boot:run
The dependency is only present once in the pom.xml
file:
<dependency>
<groupId>com.thalasoft</groupId>
<artifactId>butik-data</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
My butik-rest
project configuration looks like:
@EnvProd
@SpringBootApplication
@Slf4j
public class Application implements CommandLineRunner {
@Component
@ComponentScan(nameGenerator = PackageBeanNameGenerator.class, basePackages = { "com.thalasoft.butik.rest.service", "com.thalasoft.butik.data" })
public class ApplicationConfiguration {
}
@Component
@EnableWebMvc
@EnableSpringDataWebSupport
@ComponentScan(nameGenerator = PackageBeanNameGenerator.class, basePackages = { "com.thalasoft.butik.rest.exception",
"com.thalasoft.butik.rest.controller", "com.thalasoft.butik.rest.assembler" })
public class WebConfiguration implements WebMvcConfigurer {
The integration test configuration:
@RunWith(SpringRunner.class)
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = {
"classpath:mysql/clean-up-before-each-test.sql" })
public abstract class BaseTest {
@Configuration
@EnableAutoConfiguration
@ComponentScan(nameGenerator = PackageBeanNameGenerator.class, basePackages = { "com.thalasoft.butik.rest.config",
"com.thalasoft.butik.rest.service", "com.thalasoft.butik.data" })
public class TestConfiguration {
}
@EnableWebSecurity
@ComponentScan(nameGenerator = PackageBeanNameGenerator.class, basePackages = { "com.thalasoft.butik.rest.filter" })
public class NoSecurityConfiguration extends WebSecurityConfigurerAdapter {
The service beans are instantiated explicitly in the dependency project:
@Configuration
public class JpaService {
@Bean
public ProductServiceImpl ProductService() {
return new ProductServiceImpl();
}
@Bean
public OrderServiceImpl OrderService() {
return new OrderServiceImpl();
}
}
Could it be that Spring gets one bean from the explicit instantiation above in the butik-data
project, and another one from the "com.thalasoft.butik.data"
scanning in the dependant butik-rest
project ?
UPDATE: Even when changing the 2 instances of "com.thalasoft.butik.data"
(there is one to run the application and another one to run the integration tests) into "com.thalasoft.butik.data.config"
I still get the same error.
UPDATE: I see I had 2 mistakes compounding making the whole issue a bit tricky. I had to remove the "com.thalasoft.butik.data.config"
instance from the integration tests also. And now the issue is gone.
Upvotes: 2
Views: 858
Reputation: 11
It looks like you've scanned both of those locations. You need to investigate places which are currently scanned and which should be scanned.
If you think that current way of scanning (which include two beans which are suitable for autowiring 'orderService' field), you can mark one of those beans by annotation @Primary ( docs: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Primary.html ).
Bean marked by this annotation will be prefered over another ones, which should solve your problem.
Good luck :)
Upvotes: 1