Spring Boot ConflictingBeanDefinitionException: Annotation-specified bean name for @Controller class
Asked Answered
D

10

29

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?

Driftwood answered 13/2, 2015 at 11:10 Comment(5)
Try to add @EnableWebMvc on your WebConfig.classAngloirish
That has not worked. I still get the same error.Driftwood
mvn clean and rebuild the project .....It worked for me.Calque
1) Delete folders: build and out; 2) Gradle: clean and refresh.Deliverance
A reason may also be a transitive dependency that adds the same bean name in Spring context. The solution is as you already found out - filtering the packages.Vanburen
D
9

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);
    }
}
Driftwood answered 13/2, 2015 at 16:3 Comment(1)
Where did you spot exactly the double initialization (except from the stack trace) ? Did you find the cause ?Angloirish
W
53

I ran into the same problem but for a different reason.

This can also occur if you move your classes around in your project and fail to do a 'clean'.

I use gradle with spring-boot plugin. Now I usually run:

$> ./gradlew clean bootRun
Wargo answered 22/12, 2015 at 15:52 Comment(2)
I think this should be the correct answer. The accepted solution helps also, but it is most likely caused by stale data also.Cambogia
I'm using Maven. I ran mvn clean but still got the error. In Eclipse I ran Project -> Clean then the error went away.Vaginate
B
12

I had the same problem on a Spring integration test when I ran it with InteliJ.

After a refactor, one of my controller class was actually duplicate in the /out/production/classes directory which is the default output directory for Intelij since version 2017.2. Since the gradle output directory is different (It's build/classes), the gradle clean goal had no effect.

For me the solution was to manually remove /out/production/classes and re run my integration test.

For a possible durable solution not having 2 output directories see here

Booster answered 14/8, 2018 at 10:2 Comment(2)
you can also check the parameter "Settings > Build, Execution, Deployment > Build Tools > Gradle > Runner > Delegate IDE build/run actions to gradle"Pintail
It seems (as of 2020.3) that "Preferences > Build, Execution, Deployment > Compiler > Clear output directory on rebuild" might also provide a solution. Rather than hand-deleting the output, IntelliJ can do it for you. For what it's worth, I don't have this setting checked and hand-deleting the troublesome subdirectory (not the whole classes folder) worked just fine.Griffe
D
9

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);
    }
}
Driftwood answered 13/2, 2015 at 16:3 Comment(1)
Where did you spot exactly the double initialization (except from the stack trace) ? Did you find the cause ?Angloirish
S
7

I encountered this with mvn after changing several folder names and related package names. Than I applied maven clean and run spring boot again, all solved:

mvn clean
mvn spring-boot:run
Sarsaparilla answered 26/8, 2019 at 19:27 Comment(0)
L
1

It seems you have two entityManagerFactory, one you will autowire and one you resolve programmatically as Bean:

@Autowired
private LocalContainerEntityManagerFactoryBean entityManagerFactory;

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
...
}

I think you just need your configured Factory in entityManagerFactory() method.

Lenard answered 13/2, 2015 at 11:55 Comment(3)
You dont need to override the configure method in your Application Class, because your Class is itself an Application.Lenard
I have removed the configure function in the main application class and I still get the same error.Driftwood
Maybe the entityManagerFactory.setPackagesToScan() and the @ComponentScan annotation does the same job and create the conflict you have.Angloirish
F
1

let's assume your package name - com.example.company and the class name is RestExceptionHandler. Then you need to add the full name with the package to be identical.

add annotation @Component("com.example.company.RestExceptionHandler")

It will identify your class without conflict.

Fabio answered 17/11, 2022 at 6:59 Comment(0)
B
0

I was having the same problem with a generated .war file from spring-boot. the approved solution (Timothy Tuti's own solution) didn't quite work for me exactly as-is, but I tweaked it a little bit and it worked. I just added the following line to my Application.java:

@ComponentScan(basePackages = { "com.mypackage" })

For reference, here goes my full Application.java

package com.inmoment.devchallenge;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.config.Neo4jConfiguration;

@SpringBootApplication
@Configuration
@ComponentScan(basePackages = { "com.inmoment.devchallenge.controller" })
@EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {

    @Configuration
    @EnableNeo4jRepositories(basePackages = "com.inmoment.devchallenge.repository")
    static class ApplicationConfig extends Neo4jConfiguration {

        public ApplicationConfig() {
            setBasePackage("com.inmoment.devchallenge.repository");
        }

        @Bean
        GraphDatabaseService graphDatabaseService() {
            return new GraphDatabaseFactory().newEmbeddedDatabase("accessingdataneo4j.db");
        }
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }

}
Beestings answered 22/4, 2015 at 16:24 Comment(0)
D
0

I solved my problem by adding a bean name on top of the class.

@Component("myBeanName1")
public class MyBean {

}

And initialize it with @Autowire in this way:

@Autowire
@Qualifier("myBeanName1")
MyBean myBean;
Dirk answered 13/9, 2021 at 21:28 Comment(0)
V
0

I ran into same problem when one of dependencies(say module Y) of current module(say X) also had definition of same class. So I had to create a separate module(say Z) to store common classes and then add dependency on Z for both X and Y to use.

Vincenza answered 12/12, 2022 at 4:32 Comment(0)
N
0

For me the solution was to use this gradle task:

gradle clean build --no-build-cache

the command is used to perform a clean build of a Spring application using Gradle, ensuring that no build cache is used and all the necessary components are built from scratch.

Nickinickie answered 22/6, 2023 at 8:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.