I keep getting the ConflictingBeanDefinitionException
error in my Spring boot application. I am not entirely sure as to how to address it, I have several @Configuration
annotated classes helping to set up Thymeleaf, Spring Security and Web. Why is the application trying to setup the homeController
twice? (and where is it trying to do this?)
The error is:
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [org.kemri.wellcome.hie.Application]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'homeController' for bean class [org.kemri.wellcome.hie.HomeController] conflicts with existing, non-compatible bean definition of same name and class [org.kemri.wellcome.hie.controller.HomeController]
My spring boot main application initializer:
@EnableScheduling @EnableAspectJAutoProxy @EnableCaching @Configuration @ComponentScan @EnableAutoConfiguration public class Application extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Override protected final SpringApplicationBuilder configure(final SpringApplicationBuilder application) { return application.sources(Application.class); } }
My database config file:
@Configuration @EnableTransactionManagement @EnableJpaRepositories(basePackages="org.kemri.wellcome.hie.repositories") @PropertySource("classpath:application.properties") public class DatabaseConfig { @Autowired private Environment env; @Autowired private DataSource dataSource; @Autowired private LocalContainerEntityManagerFactoryBean entityManagerFactory; @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName(env.getProperty("spring.datasource.driverClassName")); dataSource.setUrl(env.getProperty("spring.datasource.url")); dataSource.setUsername(env.getProperty("spring.datasource.username")); dataSource.setPassword(env.getProperty("spring.datasource.password")); return dataSource; } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean(); entityManagerFactory.setDataSource(dataSource); // Classpath scanning of @Component, @Service, etc annotated class entityManagerFactory.setPackagesToScan( env.getProperty("spring.jpa.hibernate.entitymanager.packagesToScan")); // Vendor adapter HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); entityManagerFactory.setJpaVendorAdapter(vendorAdapter); // Hibernate properties Properties additionalProperties = new Properties(); additionalProperties.put( "hibernate.dialect", env.getProperty("spring.jpa.hibernate.dialect")); additionalProperties.put( "hibernate.showsql", env.getProperty("spring.jpa.hibernate.showsql")); additionalProperties.put( "hibernate.hbm2ddl.auto", env.getProperty("spring.jpa.hibernate.hbm2ddl.auto")); entityManagerFactory.setJpaProperties(additionalProperties); return entityManagerFactory; } @Bean public JpaTransactionManager transactionManager() { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory( entityManagerFactory.getObject()); return transactionManager; } @Bean public PersistenceExceptionTranslationPostProcessor exceptionTranslation() { return new PersistenceExceptionTranslationPostProcessor(); } }
My Thymeleaf config file:
@Configuration public class ThymeleafConfig { @Bean public ServletContextTemplateResolver templateResolver(){ ServletContextTemplateResolver thymeTemplateResolver = new ServletContextTemplateResolver(); thymeTemplateResolver.setPrefix("/WEB-INF/views/"); thymeTemplateResolver.setSuffix(".html"); thymeTemplateResolver.setTemplateMode("HTML5"); return thymeTemplateResolver; } @Bean public SpringSecurityDialect springSecurityDialect(){ SpringSecurityDialect dialect = new SpringSecurityDialect(); return dialect; } @Bean public SpringTemplateEngine templateEngine() { SpringTemplateEngine engine = new SpringTemplateEngine(); engine.addTemplateResolver(templateResolver()); Set<IDialect> dialects = new HashSet<IDialect>(); dialects.add(springSecurityDialect()); engine.setAdditionalDialects(dialects); return engine; } @Bean public ThymeleafViewResolver thymeleafViewResolver() { ThymeleafViewResolver resolver = new ThymeleafViewResolver(); resolver.setTemplateEngine(templateEngine()); resolver.setViewClass(ThymeleafTilesView.class); resolver.setCharacterEncoding("UTF-8"); return resolver; }
}
My Web config class:
@Configuration @PropertySource("classpath:application.properties") public class WebConfig extends WebMvcAutoConfigurationAdapter { @Autowired private Environment env; @Bean public JavaMailSenderImpl javaMailSenderImpl() { JavaMailSenderImpl mailSenderImpl = new JavaMailSenderImpl(); mailSenderImpl.setHost(env.getProperty("smtp.host")); mailSenderImpl.setPort(env.getProperty("smtp.port", Integer.class)); mailSenderImpl.setProtocol(env.getProperty("smtp.protocol")); mailSenderImpl.setUsername(env.getProperty("smtp.username")); mailSenderImpl.setPassword(env.getProperty("smtp.password")); Properties javaMailProps = new Properties(); javaMailProps.put("mail.smtp.auth", true); javaMailProps.put("mail.smtp.starttls.enable", true); mailSenderImpl.setJavaMailProperties(javaMailProps); return mailSenderImpl; } @Bean public CacheManager cacheManager() { return new ConcurrentMapCacheManager(); } }
My controller (where there is an error setting up the controller)
@Controller public class HomeController { private static final Logger logger = LoggerFactory.getLogger(HomeController.class); /** * Simply selects the home view to render by returning its name. */ @RequestMapping(value = "/", method = RequestMethod.GET) public String home(Locale locale, Model model) { logger.info("Welcome home! The client locale is {}.", locale); Date date = new Date(); DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale); String formattedDate = dateFormat.format(date); model.addAttribute("serverTime", formattedDate ); return "index.html"; } }
What might be causing the ConflictingBeanDefinitionException
error for my controller class?
Advertisement
Answer
The solution, as I found out, is to disable double initialization by including a filter in the component scan. In my case:
@EnableScheduling @EnableAspectJAutoProxy @EnableCaching @Configuration @ComponentScan(basePackages = { "org.kemri.wellcome.hie" }, excludeFilters = {@Filter(value = Controller.class, type = FilterType.ANNOTATION)}) @EnableAutoConfiguration @PropertySource("classpath:application.properties") public class Application extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }