Skip to content

Creation of auto-configured DataSource fails when using UCP and the environment contains a non-enumerable property source such as JndiPropertySource #38514

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
fmeheust opened this issue Nov 23, 2023 · 6 comments
Labels
status: declined A suggestion or change that we don't feel we should currently apply

Comments

@fmeheust
Copy link

Spring boot fails to start when using UCP and Spring Boot 3.1.5 with JndiPropertySource enabled.

This happens because UCP exposes a property SSLConext of type javax.net.ssl.SSLContext. The constructor for SSLContext has a parameter of type java.security.Provider. This Provider class implements Map and is therefore treated by Spring Boot as a Map, an attempt will be made to create a Map using CollectionFactory which will cause the error because java.security.Provider does not expose a constructor with no parameters.

The following workarounds are possible :

  1. if JndiPropertySource is not being used, disable it by setting the following property in the spring.properties file:
    spring.jndi.ignore=true
  2. create the data source programatically.

This is the error when deploying the WAR on a Tomcat server:

23-Nov-2023 15:23:37.329 SEVERE [RMI TCP Connection(2)-127.0.0.1] org.apache.tomcat.util.modeler.BaseModelMBean.invoke Exception invoking method [createStandardContext]
	javax.management.RuntimeOperationsException: Exception invoking method [manageApp]
		at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:304)
		at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:803)
		at java.management/com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:802)
		at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:422)
		at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:376)
		at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
		at java.base/java.lang.reflect.Method.invoke(Method.java:580)
		at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:294)
		at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:803)
		at java.management/com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:802)
		at java.management/com.sun.jmx.remote.security.MBeanServerAccessController.invoke(MBeanServerAccessController.java:472)
		at java.management.rmi/javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1472)
		at java.management.rmi/javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1310)
		at java.base/java.security.AccessController.doPrivileged(AccessController.java:714)
		at java.management.rmi/javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1412)
		at java.management.rmi/javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829)
		at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
		at java.base/java.lang.reflect.Method.invoke(Method.java:580)
		at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360)
		at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
		at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
		at java.base/java.security.AccessController.doPrivileged(AccessController.java:714)
		at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
		at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:598)
		at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:844)
		at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:721)
		at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
		at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:720)
		at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
		at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
		at java.base/java.lang.Thread.run(Thread.java:1583)
	Caused by: java.lang.IllegalStateException: Error starting child
		at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:686)
		at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:658)
		at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:712)
		at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1824)
		at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
		at java.base/java.lang.reflect.Method.invoke(Method.java:580)
		at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:294)
		... 30 more
	Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/my_todo_list_war_exploded]]
		at org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:419)
		at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:186)
		at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:683)
		... 36 more
	Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Unsatisfied dependency expressed through method 'dataSourceScriptDatabaseInitializer' parameter 0: Error creating bean with name 'dataSource': Could not bind properties to 'PoolDataSourceImpl' : prefix=spring.datasource.oracleucp, ignoreInvalidFields=false, ignoreUnknownFields=true
		at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:801)
		at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:545)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1332)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1162)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:560)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520)
		at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325)
		at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
		at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323)
		at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
		at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312)
		at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
		at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1166)
		at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:940)
		at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616)
		at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
		at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:738)
		at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:440)
		at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
		at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:174)
		at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:154)
		at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:96)
		at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:171)
		at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4850)
		at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171)
		... 37 more
	Caused by: org.springframework.boot.context.properties.ConfigurationPropertiesBindException: Error creating bean with name 'dataSource': Could not bind properties to 'PoolDataSourceImpl' : prefix=spring.datasource.oracleucp, ignoreInvalidFields=false, ignoreUnknownFields=true
		at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.bind(ConfigurationPropertiesBindingPostProcessor.java:99)
		at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(ConfigurationPropertiesBindingPostProcessor.java:79)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:419)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1762)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:598)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520)
		at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325)
		at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
		at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323)
		at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
		at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254)
		at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1417)
		at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1337)
		at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:910)
		at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:788)
		... 61 more
	Caused by: org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'spring.datasource.oracleucp.s-s-l-context.provider' to java.security.Provider
		at org.springframework.boot.context.properties.bind.Binder.handleBindError(Binder.java:392)
		at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:352)
		at org.springframework.boot.context.properties.bind.Binder.lambda$bindDataObject$4(Binder.java:478)
		at org.springframework.boot.context.properties.bind.ValueObjectBinder$ConstructorParameter.bind(ValueObjectBinder.java:318)
		at org.springframework.boot.context.properties.bind.ValueObjectBinder.bind(ValueObjectBinder.java:76)
		at org.springframework.boot.context.properties.bind.Binder.lambda$bindDataObject$5(Binder.java:482)
		at org.springframework.boot.context.properties.bind.Binder$Context.withIncreasedDepth(Binder.java:596)
		at org.springframework.boot.context.properties.bind.Binder$Context.withDataObject(Binder.java:582)
		at org.springframework.boot.context.properties.bind.Binder.bindDataObject(Binder.java:480)
		at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:419)
		at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:348)
		at org.springframework.boot.context.properties.bind.Binder.lambda$bindDataObject$4(Binder.java:478)
		at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:99)
		at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:87)
		at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:63)
		at org.springframework.boot.context.properties.bind.Binder.lambda$bindDataObject$5(Binder.java:482)
		at org.springframework.boot.context.properties.bind.Binder$Context.withIncreasedDepth(Binder.java:596)
		at org.springframework.boot.context.properties.bind.Binder$Context.withDataObject(Binder.java:582)
		at org.springframework.boot.context.properties.bind.Binder.bindDataObject(Binder.java:480)
		at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:419)
		at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:348)
		at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:337)
		at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:267)
		at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:254)
		at org.springframework.boot.context.properties.ConfigurationPropertiesBinder.bind(ConfigurationPropertiesBinder.java:94)
		at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.bind(ConfigurationPropertiesBindingPostProcessor.java:96)
		... 75 more
	Caused by: java.lang.IllegalArgumentException: Could not instantiate Map type: java.security.Provider
		at org.springframework.core.CollectionFactory.createMap(CollectionFactory.java:327)
		at org.springframework.core.CollectionFactory.createMap(CollectionFactory.java:273)
		at org.springframework.boot.context.properties.bind.MapBinder.bindAggregate(MapBinder.java:57)
		at org.springframework.boot.context.properties.bind.AggregateBinder.bind(AggregateBinder.java:56)
		at org.springframework.boot.context.properties.bind.Binder.lambda$bindAggregate$3(Binder.java:443)
		at org.springframework.boot.context.properties.bind.Binder$Context.withIncreasedDepth(Binder.java:596)
		at org.springframework.boot.context.properties.bind.Binder.bindAggregate(Binder.java:443)
		at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:404)
		at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:348)
		... 99 more
	Caused by: java.lang.NoSuchMethodException: java.security.Provider.<init>()
		at java.base/java.lang.Class.getConstructor0(Class.java:3761)
		at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2930)
		at org.springframework.util.ReflectionUtils.accessibleConstructor(ReflectionUtils.java:185)
		at org.springframework.core.CollectionFactory.createMap(CollectionFactory.java:324)
		... 107 more

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Nov 23, 2023
@wilkinsona
Copy link
Member

Thanks for the report.

The problem's occurring because JndiPropertySource is not enumerable. It can be reproduced by adding this test to OracleUcpDataSourceConfigurationTests:

@Test
void testDataSourceExistsWithNonEnumerablePropertySource() {
	this.contextRunner.withInitializer((context) -> {
		context.getEnvironment().getPropertySources().addFirst(new PropertySource<String>("name") {

			@Override
			public Object getProperty(String name) {
				return null;
			}

		});
	}).run((context) -> {
		assertThat(context.getBeansOfType(DataSource.class)).hasSize(1);
		assertThat(context.getBeansOfType(PoolDataSourceImpl.class)).hasSize(1);
		try (Connection connection = context.getBean(DataSource.class).getConnection()) {
			assertThat(connection.isValid(1000)).isTrue();
		}
	});
}

As far as I can tell, we've already addressed this in 3.2.0 through the changes made for #38201, although it's something of an unintended side-effect. We may want to back port that change to 3.1.x or consider a different fix.

@fmeheust can you please try 3.2.0 (released earlier today) and let us know if it fixes the problem?

@wilkinsona wilkinsona added status: waiting-for-feedback We need additional information before we can continue type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Nov 23, 2023
@wilkinsona wilkinsona added this to the 3.1.x milestone Nov 23, 2023
@wilkinsona wilkinsona changed the title Spring boot fails to create data source bean when using UCP and JndiPropertySource is enabled. Spring boot fails to create DataSource bean when using UCP and the environment contains an non-enumerable property source such as JndiPropertySource Nov 23, 2023
@wilkinsona wilkinsona changed the title Spring boot fails to create DataSource bean when using UCP and the environment contains an non-enumerable property source such as JndiPropertySource Creation of auto-configured DataSource fails when using UCP and the environment contains a non-enumerable property source such as JndiPropertySource Nov 23, 2023
@fmeheust
Copy link
Author

@wilkinsona I can't find 3.2.0 in maven central, where can I get it ?

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Nov 23, 2023
@wilkinsona
Copy link
Member

It's in Maven Central. See https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot/3.2.0/, for example. Note that sites like https://search.maven.org/ take some time to catch up to new releases and as such aren't a great source of up-to-date information.

@wilkinsona wilkinsona added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Nov 23, 2023
@fmeheust
Copy link
Author

@wilkinsona I confirm that my application starts correctly on spring boot 3.2.0. Thank you

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Nov 23, 2023
@wilkinsona
Copy link
Member

Thanks, @fmeheust.

@wilkinsona wilkinsona added for: team-meeting An issue we'd like to discuss as a team to make progress and removed status: feedback-provided Feedback has been provided labels Nov 27, 2023
@philwebb
Copy link
Member

We discussed this today and feel that backporting #38201 is a bit risky. We're going to recommend that folks with this issue upgrade to 3.2.x.

@philwebb philwebb closed this as not planned Won't fix, can't repro, duplicate, stale Feb 22, 2024
@philwebb philwebb added status: declined A suggestion or change that we don't feel we should currently apply and removed type: bug A general bug for: team-meeting An issue we'd like to discuss as a team to make progress labels Feb 22, 2024
@philwebb philwebb removed this from the 3.1.x milestone Feb 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: declined A suggestion or change that we don't feel we should currently apply
Projects
None yet
Development

No branches or pull requests

4 participants