Skip to content
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

Empty value for spring.datasource.password can cause NullPointerException #26633

Closed
chrischall opened this issue May 21, 2021 · 4 comments
Closed
Assignees
Labels
type: regression A regression from a previous release
Milestone

Comments

@chrischall
Copy link

chrischall commented May 21, 2021

After upgrading to Spring Boot 2.5.0, my application will no longer start locally when my local database user has no password.

I am able to get it to start if I set a password for the user and update my config accordingly.

Given the following properties:

spring:
  datasource:
    username: ${user.name}
    password: 
    driver-class-name: org.postgresql.Driver
    url: jdbc:postgresql://localhost/database?OpenSourceSubProtocolOverride=true
    tomcat:
      initial-size: 2
      max-active: 25
      min-idle: 2
      max-idle: 2
      test-while-idle: true
      time-between-eviction-runs-millis: 30000

A NullPointerException is raised:

Caused by: java.lang.NullPointerException: null
	at java.base/java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1011) ~[na:na]
	at java.base/java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:1006) ~[na:na]
	at java.base/java.util.Properties.put(Properties.java:1340) ~[na:na]
	at java.base/java.util.Properties.setProperty(Properties.java:228) ~[na:na]
	at org.apache.tomcat.jdbc.pool.DataSourceProxy.setPassword(DataSourceProxy.java:367) ~[tomcat-jdbc-9.0.46.jar:na]
	at org.springframework.boot.jdbc.DataSourceBuilder$MappedDataSourceProperty.set(DataSourceBuilder.java:431) ~[spring-boot-2.5.0.jar:2.5.0]
	at org.springframework.boot.jdbc.DataSourceBuilder$MappedDataSourceProperties.set(DataSourceBuilder.java:333) ~[spring-boot-2.5.0.jar:2.5.0]
	at org.springframework.boot.jdbc.DataSourceBuilder.build(DataSourceBuilder.java:179) ~[spring-boot-2.5.0.jar:2.5.0]
	at org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration.createDataSource(DataSourceConfiguration.java:48) ~[spring-boot-autoconfigure-2.5.0.jar:2.5.0]
	at org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Tomcat.dataSource(DataSourceConfiguration.java:64) ~[spring-boot-autoconfigure-2.5.0.jar:2.5.0]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.7.jar:5.3.7]
	... 163 common frames omitted

This results in:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.flywaydb.core.Flyway]: Factory method 'flyway' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Tomcat.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.tomcat.jdbc.pool.DataSource]: Factory method 'dataSource' threw exception; nested exception is java.lang.NullPointerException
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.3.7.jar:5.3.7]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-5.3.7.jar:5.3.7]
	... 141 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Tomcat.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.tomcat.jdbc.pool.DataSource]: Factory method 'dataSource' threw exception; nested exception is java.lang.NullPointerException
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:658) ~[spring-beans-5.3.7.jar:5.3.7]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:638) ~[spring-beans-5.3.7.jar:5.3.7]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1334) ~[spring-beans-5.3.7.jar:5.3.7]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.3.7.jar:5.3.7]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564) ~[spring-beans-5.3.7.jar:5.3.7]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.7.jar:5.3.7]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.7.jar:5.3.7]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.7.jar:5.3.7]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.7.jar:5.3.7]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.7.jar:5.3.7]
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.3.7.jar:5.3.7]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1380) ~[spring-beans-5.3.7.jar:5.3.7]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory$DependencyObjectProvider.getIfUnique(DefaultListableBeanFactory.java:2063) ~[spring-beans-5.3.7.jar:5.3.7]
	at org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration$FlywayConfiguration.flyway(FlywayAutoConfiguration.java:116) ~[spring-boot-autoconfigure-2.5.0.jar:2.5.0]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.7.jar:5.3.7]
	... 142 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.tomcat.jdbc.pool.DataSource]: Factory method 'dataSource' threw exception; nested exception is java.lang.NullPointerException
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.3.7.jar:5.3.7]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-5.3.7.jar:5.3.7]
	... 160 common frames omitted

After poking around a bit, I noticed this method in DataSourceProperties:

	public String determinePassword() {
		if (StringUtils.hasText(this.password)) {
			return this.password;
		}
		if (EmbeddedDatabaseConnection.isEmbedded(determineDriverClassName(), determineUrl())) {
			return "";
		}
		return null;
	}
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label May 21, 2021
@mbhave
Copy link
Contributor

mbhave commented May 24, 2021

@chrischall I wasn't able to reproduce the issue with a quick test on my end. Can you provide a small sample application that we can run to reproduce the issue?

@mbhave mbhave added the status: waiting-for-feedback We need additional information before we can continue label May 24, 2021
@chrischall
Copy link
Author

Apologies. I neglected to include the type: org.apache.tomcat.jdbc.pool.DataSource in the yaml. I've attached demo.tar.gz which was built from start.spring.io and has been modified to include and use tomcat-jdbc for connection pooling. Here is its application.yaml for convenience:

spring:
  datasource:
    username: ${user.name}
    password: 
    driver-class-name: org.postgresql.Driver
    type: org.apache.tomcat.jdbc.pool.DataSource
    url: jdbc:postgresql://localhost/database

@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 May 25, 2021
@snicoll snicoll added type: regression A regression from a previous release and removed status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged labels May 25, 2021
@snicoll snicoll added this to the 2.5.1 milestone May 25, 2021
@snicoll
Copy link
Member

snicoll commented May 25, 2021

Thanks for the followup @chrischall. This is a regression in DataSourceBuilder.

Previously, we used the binder to bind a map of properties, where password was registered with null, and it does not invoke the setter if the value is null.

In 2.5.x, we use a DataSourceProperty that calls the method via reflection with a different mechanism. This one invokes the setter if the value is null.

@philwebb philwebb self-assigned this May 25, 2021
@philwebb philwebb changed the title empty value for spring.datasource.password causes a NullPointerException when auto-configuring Flyway Empty value for spring.datasource.password can cause NullPointerException May 26, 2021
@young0264
Copy link

Apologies. I neglected to include the type: org.apache.tomcat.jdbc.pool.DataSource in the yaml. I've attached demo.tar.gz which was built from start.spring.io and has been modified to include and use tomcat-jdbc for connection pooling. Here is its application.yaml for convenience:

spring:
  datasource:
    username: ${user.name}
    password: 
    driver-class-name: org.postgresql.Driver
    type: org.apache.tomcat.jdbc.pool.DataSource
    url: jdbc:postgresql://localhost/database

THx Thx Thx Thx!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: regression A regression from a previous release
Projects
None yet
Development

No branches or pull requests

6 participants