Commit b6d31fb6 authored by Phillip Webb's avatar Phillip Webb

Use correct type for deriveFromProperties

Fix `DataSourceBuilder` so that the type used to access `deriveFrom`
properties is based on the actual instance type rather than the
user-defined type which could have been changed.

Fixes gh-26644
parent eed620fc
...@@ -91,7 +91,7 @@ public final class DataSourceBuilder<T extends DataSource> { ...@@ -91,7 +91,7 @@ public final class DataSourceBuilder<T extends DataSource> {
private Class<T> type; private Class<T> type;
private final T deriveFrom; private final DataSource deriveFrom;
private DataSourceBuilder(ClassLoader classLoader) { private DataSourceBuilder(ClassLoader classLoader) {
this.classLoader = classLoader; this.classLoader = classLoader;
...@@ -168,27 +168,20 @@ public final class DataSourceBuilder<T extends DataSource> { ...@@ -168,27 +168,20 @@ public final class DataSourceBuilder<T extends DataSource> {
*/ */
public T build() { public T build() {
DataSourceProperties<T> properties = DataSourceProperties.forType(this.classLoader, this.type); DataSourceProperties<T> properties = DataSourceProperties.forType(this.classLoader, this.type);
DataSourceProperties<T> deriveFromProperties = (this.deriveFrom != null) DataSourceProperties<DataSource> deriveFromProperties = getDeriveFromProperties();
? DataSourceProperties.forType(this.classLoader, this.type) : null;
Class<? extends T> instanceType = (this.type != null) ? this.type : properties.getDataSourceInstanceType(); Class<? extends T> instanceType = (this.type != null) ? this.type : properties.getDataSourceInstanceType();
T dataSource = BeanUtils.instantiateClass(instanceType); T dataSource = BeanUtils.instantiateClass(instanceType);
Set<DataSourceProperty> applied = new HashSet<>(); Set<DataSourceProperty> applied = new HashSet<>();
for (DataSourceProperty property : DataSourceProperty.values()) { for (DataSourceProperty property : DataSourceProperty.values()) {
if (this.values.containsKey(property)) {
String value = this.values.get(property); String value = this.values.get(property);
if (value != null) { if (!this.values.containsKey(property) && deriveFromProperties != null && properties.canSet(property)) {
properties.set(dataSource, property, value); value = deriveFromProperties.get(this.deriveFrom, property);
applied.add(property);
} }
}
else if (deriveFromProperties != null && properties.canSet(property)) {
String value = deriveFromProperties.get(this.deriveFrom, property);
if (value != null) { if (value != null) {
properties.set(dataSource, property, value); properties.set(dataSource, property, value);
applied.add(property); applied.add(property);
} }
} }
}
if (!applied.contains(DataSourceProperty.DRIVER_CLASS_NAME) if (!applied.contains(DataSourceProperty.DRIVER_CLASS_NAME)
&& properties.canSet(DataSourceProperty.DRIVER_CLASS_NAME) && properties.canSet(DataSourceProperty.DRIVER_CLASS_NAME)
&& this.values.containsKey(DataSourceProperty.URL)) { && this.values.containsKey(DataSourceProperty.URL)) {
...@@ -199,6 +192,14 @@ public final class DataSourceBuilder<T extends DataSource> { ...@@ -199,6 +192,14 @@ public final class DataSourceBuilder<T extends DataSource> {
return dataSource; return dataSource;
} }
@SuppressWarnings("unchecked")
private DataSourceProperties<DataSource> getDeriveFromProperties() {
if (this.deriveFrom == null) {
return null;
}
return DataSourceProperties.forType(this.classLoader, (Class<DataSource>) this.deriveFrom.getClass());
}
/** /**
* Create a new {@link DataSourceBuilder} instance. * Create a new {@link DataSourceBuilder} instance.
* @return a new datasource builder instance * @return a new datasource builder instance
......
...@@ -318,6 +318,19 @@ class DataSourceBuilderTests { ...@@ -318,6 +318,19 @@ class DataSourceBuilderTests {
assertThat(built.getUrl()).startsWith("jdbc:hsqldb:mem"); assertThat(built.getUrl()).startsWith("jdbc:hsqldb:mem");
} }
@Test // gh-26644
void buildWhenDerivedFromExistingDatabaseWithTypeChange() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setUsername("test");
dataSource.setPassword("secret");
dataSource.setJdbcUrl("jdbc:postgresql://localhost:5432/postgres");
DataSourceBuilder<?> builder = DataSourceBuilder.derivedFrom(dataSource).type(SimpleDriverDataSource.class);
SimpleDriverDataSource built = (SimpleDriverDataSource) builder.username("test2").password("secret2").build();
assertThat(built.getUsername()).isEqualTo("test2");
assertThat(built.getPassword()).isEqualTo("secret2");
assertThat(built.getUrl()).isEqualTo("jdbc:postgresql://localhost:5432/postgres");
}
final class HidePackagesClassLoader extends URLClassLoader { final class HidePackagesClassLoader extends URLClassLoader {
private final String[] hiddenPackages; private final String[] hiddenPackages;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment