In order to customise Spring Boot for Grails users, Grails overrides a few Spring Boot beans. This is seemingly disallowed in newer versions of Spring Boot.
To resolve this I attempted to add:
spring:
main:
allow-bean-definition-overriding: true
However this leads to:
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.boot.origin.OriginTrackedValue] to type [boolean]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:321)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:194)
at org.springframework.boot.context.properties.bind.BindConverter$CompositeConversionService.convert(BindConverter.java:179)
This is currently blocking me from upgrading Grails 4.x to Spring Boot 2.1.x
Comment From: graemerocher
I have found a workaround by calling setAllowBeanDefinitionOverriding directly, however the issue still stands for existing users
Comment From: wilkinsona
This sounds like a bug that we should fix, but I'd take a different approach to overriding beans if you can. We have a few places in Boot where we still need to override a bean, and we now do so by removing the old definition before adding a new one. I'd recommend taking the same approach in Grails so that the behaviour of the whole application context does not need to be changed.
Comment From: graemerocher
We will see how we can minimise overriding. Thanks for the feedback.
Comment From: wilkinsona
I can't reproduce the behaviour you've described with a minimal application:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@SpringBootApplication
public class Gh14831Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Gh14831Application.class, args);
System.out.println(context.getBean("one"));
}
@Configuration
public class ConfigurationOne {
@Bean
public String one() {
return "one";
}
}
@Configuration
public class ConfigurationTwo {
@Bean
public String one() {
return "one-again";
}
}
}
It fails to start without the property set:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.0.M4)
2018-10-15 16:46:09.729 INFO 15172 --- [ main] com.example.demo.Gh14831Application : Starting Gh14831Application on Andys-MacBook-Pro.local with PID 15172 (/Users/awilkinson/dev/workspaces/spring-projects/spring-boot/master/gh-14831/target/classes started by awilkinson in /Users/awilkinson/dev/workspaces/spring-projects/spring-boot/master/gh-14831)
2018-10-15 16:46:09.732 INFO 15172 --- [ main] com.example.demo.Gh14831Application : No active profile set, falling back to default profiles: default
2018-10-15 16:46:09.914 WARN 15172 --- [ main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'one' defined in com.example.demo.Gh14831Application$ConfigurationTwo: Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=com.example.demo.Gh14831Application$ConfigurationTwo; factoryMethodName=one; initMethodName=null; destroyMethodName=(inferred); defined in com.example.demo.Gh14831Application$ConfigurationTwo] for bean 'one': There is already [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=com.example.demo.Gh14831Application$ConfigurationOne; factoryMethodName=one; initMethodName=null; destroyMethodName=(inferred); defined in com.example.demo.Gh14831Application$ConfigurationOne] bound.
2018-10-15 16:46:09.922 INFO 15172 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2018-10-15 16:46:09.924 ERROR 15172 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'one', defined in com.example.demo.Gh14831Application$ConfigurationTwo, could not be registered. A bean with that name has already been defined in com.example.demo.Gh14831Application$ConfigurationOne and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
And starts as expected when it is set:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.0.M4)
2018-10-15 16:46:54.617 INFO 15197 --- [ main] com.example.demo.Gh14831Application : Starting Gh14831Application on Andys-MacBook-Pro.local with PID 15197 (/Users/awilkinson/dev/workspaces/spring-projects/spring-boot/master/gh-14831/target/classes started by awilkinson in /Users/awilkinson/dev/workspaces/spring-projects/spring-boot/master/gh-14831)
2018-10-15 16:46:54.620 INFO 15197 --- [ main] com.example.demo.Gh14831Application : No active profile set, falling back to default profiles: default
2018-10-15 16:46:54.992 INFO 15197 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2018-10-15 16:46:55.016 INFO 15197 --- [ main] com.example.demo.Gh14831Application : Started Gh14831Application in 0.631 seconds (JVM running for 0.909)
one-again
2018-10-15 16:46:55.018 INFO 15197 --- [ Thread-2] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
We also have a pair of tests that verify the behaviour: https://github.com/spring-projects/spring-boot/blob/ffe5e88d8e5de245b8e040190e90a22eb47fe379/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java#L1209-L1223
Can you please provide a minimal sample that reproduces the behaviour you've described?
Comment From: graemerocher
Will track it down.. maybe it is something related to how we handle property sources.
Comment From: graemerocher
Ok turns out this was a custom GroovyPropertySourceLoader that was leaking OriginTrackedValues
Comment From: ghost
I am trying to track down a similar issue in our application.
@graemerocher could you provide a bit more detail as to how you defined/created GroovyPropertySourceLoader for it to cause the issue? This would help me track down which one of our SourceLoaders is messing with the startup.
Thank you.
Comment From: mikebell90
I've been trying to get your example @wilkinsona working, and can't. Debug shows the postprocessor is never called.
Here's the sample class. The motivation (maybe wrongly) has been for a long time people that had tests with mixed contexts could Import this class to clear out their JMX beans, to avoid the mbean already registered error (RegistrationPolicy other than default isn't an option - we feel most of the time this SHOULD fail) but as of Spring Boot 2.1 this fails with mbeanExporter being a duplicate bean.
Note: Moving @Bean of foo to outer class makes no difference.
@Configuration
@EnableMBeanExport
@Import(TestMBeanServerConfiguration.InnerTestMBeanServerConfiguration.class)
public class TestMBeanServerConfiguration {
@Configuration
public static class InnerTestMBeanServerConfiguration extends MBeanExportConfiguration {
private final MBeanServer mbs = MBeanServerFactory.createMBeanServer();
@Bean
public static Foo foo() {
return new Foo();
}
@Bean
@Primary
public MBeanServer getTestMBeanServer() {
return mbs;
}
@Override // This makes Spring Boot 2.1 unhappy and was always fragile
public AnnotationMBeanExporter mbeanExporter() {
final AnnotationMBeanExporter amber = super.mbeanExporter();
amber.setServer(mbs);
return amber;
}
}
@Order(Ordered.LOWEST_PRECEDENCE)
public static class Foo implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(final BeanDefinitionRegistry registry) throws BeansException {
System.err.println("hi"); // will never be called
}
@Override
public void postProcessBeanFactory(final ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.err.println("hi"); // will never be called
}
}
}
Comment From: snicoll
@mikebell90 I am don't understand how the changes with MBeans export is related to this issue. If you have a sample that reproduces the issue (i.e. works with 2.0.x and breaks with 2.1.x), please create a separate issue with a reference to the sample we can clone or unzip and run ourselves. Thanks!
Comment From: kepha-korbit
`
APPLICATION FAILED TO START
Description:
The bean 'documentationPluginsManager', defined in class path resource [kr/co/korbit/gia/config/SwaggerConfig.class], could not be registered. A bean with that name has already been defined in URL [jar:file:/Users/kepha_local/.gradle/caches/modules-2/files-2.1/io.springfox/springfox-spring-web/2.9.2/ed2ed714a6cba8804d00f80f0534901e4c7a3211/springfox-spring-web-2.9.2.jar!/springfox/documentation/spring/web/plugins/DocumentationPluginsManager.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
Process finished with exit code 1`
I have same error even though adding spring.main.allow-bean-definition-overriding=true into application.yml
Comment From: stopme
Environment variables : spring.main.allow-bean-definition-overriding=true
System.getenv() System.getProperties()
Comment From: leomont
@wilkinsona I could replicate the issue long time after you requested: The bean 'XXXXX', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.
Once I tried to add spring.main.allow-bean-definition-overriding=truetoapplication.ymlfile
It effectively was not allowed. So then I found I was using JPA and JDBC dependencies on pom.xml in a concurrent way, overlapping base packages. I Solved the issue just leaving one of those, as it follows for my particular case:
I could inferred this from a previous forum https://coderanch.com/t/747155/java/bean-defined-myRepository