Skip to content

Commit

Permalink
Expand customization to any type of TransactionManager
Browse files Browse the repository at this point in the history
Closes gh-37628
  • Loading branch information
wilkinsona committed Sep 29, 2023
1 parent 96986a6 commit 1a22415
Show file tree
Hide file tree
Showing 12 changed files with 127 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public Neo4jTemplate neo4jTemplate(Neo4jClient neo4jClient, Neo4jMappingContext
public Neo4jTransactionManager transactionManager(Driver driver, DatabaseSelectionProvider databaseNameProvider,
ObjectProvider<TransactionManagerCustomizers> optionalCustomizers) {
Neo4jTransactionManager transactionManager = new Neo4jTransactionManager(driver, databaseNameProvider);
optionalCustomizers.ifAvailable((customizer) -> customizer.customize(transactionManager));
optionalCustomizers.ifAvailable((customizer) -> customizer.customize((TransactionManager) transactionManager));
return transactionManager;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ static class JdbcTransactionManagerConfiguration {
DataSourceTransactionManager transactionManager(Environment environment, DataSource dataSource,
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
DataSourceTransactionManager transactionManager = createTransactionManager(environment, dataSource);
transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
transactionManagerCustomizers
.ifAvailable((customizers) -> customizers.customize((TransactionManager) transactionManager));
return transactionManager;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ protected JpaBaseConfiguration(DataSource dataSource, JpaProperties properties,
public PlatformTransactionManager transactionManager(
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
transactionManagerCustomizers
.ifAvailable((customizers) -> customizers.customize((TransactionManager) transactionManager));
return transactionManager;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,12 @@
* @param <T> the transaction manager type
* @author Phillip Webb
* @since 1.5.0
* @deprecated since 3.2.0 for removal in 3.4.0 in favor of
* {@link TransactionManagerCustomizer}.
*/
@Deprecated(since = "3.2.0", forRemoval = true)
@FunctionalInterface
public interface PlatformTransactionManagerCustomizer<T extends PlatformTransactionManager> {

/**
* Customize the given transaction manager.
* @param transactionManager the transaction manager to customize
*/
void customize(T transactionManager);
public interface PlatformTransactionManagerCustomizer<T extends PlatformTransactionManager>
extends TransactionManagerCustomizer<T> {

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ public class TransactionManagerCustomizationAutoConfiguration {
@Bean
@ConditionalOnMissingBean
TransactionManagerCustomizers platformTransactionManagerCustomizers(
ObjectProvider<PlatformTransactionManagerCustomizer<?>> customizers) {
return new TransactionManagerCustomizers(customizers.orderedStream().toList());
ObjectProvider<TransactionManagerCustomizer<?>> customizers) {
return TransactionManagerCustomizers.of(customizers.orderedStream().toList());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.boot.autoconfigure.transaction;

import org.springframework.transaction.TransactionManager;

/**
* Callback interface that can be implemented by beans wishing to customize
* {@link TransactionManager TransactionManagers} while retaining default
* auto-configuration.
*
* @param <T> the transaction manager type
* @author Andy Wilkinson
* @since 3.2.0
*/
public interface TransactionManagerCustomizer<T extends TransactionManager> {

/**
* Customize the given transaction manager.
* @param transactionManager the transaction manager to customize
*/
void customize(T transactionManager);

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,69 @@

import org.springframework.boot.util.LambdaSafe;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionManager;

/**
* A collection of {@link PlatformTransactionManagerCustomizer}.
* A collection of {@link TransactionManagerCustomizer TransactionManagerCustomizers}.
*
* @author Phillip Webb
* @author Andy Wilkinson
* @since 1.5.0
*/
public class TransactionManagerCustomizers {

private final List<PlatformTransactionManagerCustomizer<?>> customizers;
private final List<? extends TransactionManagerCustomizer<?>> customizers;

/**
* Creates a new {@code TransactionManagerCustomizers} instance containing the given
* {@code customizers}.
* @param customizers the customizers
* @deprecated since 3.2.0 for removal in 3.4.0 in favor of {@link #of(Collection)}
*/
@SuppressWarnings("removal")
@Deprecated(since = "3.2.0", forRemoval = true)
public TransactionManagerCustomizers(Collection<? extends PlatformTransactionManagerCustomizer<?>> customizers) {
this.customizers = (customizers != null) ? new ArrayList<>(customizers) : Collections.emptyList();
this((customizers != null) ? new ArrayList<>(customizers)
: Collections.<TransactionManagerCustomizer<?>>emptyList());
}

private TransactionManagerCustomizers(List<? extends TransactionManagerCustomizer<?>> customizers) {
this.customizers = customizers;
}

/**
* Customize the given {@code platformTransactionManager}.
* @param platformTransactionManager the platform transaction manager to customize
* @deprecated since 3.2.0 for removal in 3.4.0 in favor of
* {@link #customize(TransactionManager)}
*/
@Deprecated(since = "3.2.0", forRemoval = true)
public void customize(PlatformTransactionManager platformTransactionManager) {
customize((TransactionManager) platformTransactionManager);
}

/**
* Customize the given {@code transactionManager}.
* @param transactionManager the transaction manager to customize
* @since 3.2.0
*/
@SuppressWarnings("unchecked")
public void customize(PlatformTransactionManager transactionManager) {
LambdaSafe.callbacks(PlatformTransactionManagerCustomizer.class, this.customizers, transactionManager)
public void customize(TransactionManager transactionManager) {
LambdaSafe.callbacks(TransactionManagerCustomizer.class, this.customizers, transactionManager)
.withLogger(TransactionManagerCustomizers.class)
.invoke((customizer) -> customizer.customize(transactionManager));
}

/**
* Returns a new {@code TransactionManagerCustomizers} instance containing the given
* {@code customizers}.
* @param customizers the customizers
* @return the new instance
* @since 3.2.0
*/
public static TransactionManagerCustomizers of(Collection<? extends TransactionManagerCustomizer<?>> customizers) {
return new TransactionManagerCustomizers((customizers != null) ? new ArrayList<>(customizers)
: Collections.<TransactionManagerCustomizer<?>>emptyList());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
* @since 1.5.0
*/
@ConfigurationProperties(prefix = "spring.transaction")
public class TransactionProperties implements PlatformTransactionManagerCustomizer<AbstractPlatformTransactionManager> {
public class TransactionProperties implements TransactionManagerCustomizer<AbstractPlatformTransactionManager> {

/**
* Default transaction timeout. If a duration suffix is not specified, seconds will be
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;

/**
Expand All @@ -43,7 +44,8 @@ class JndiJtaConfiguration {
JtaTransactionManager transactionManager(
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();
transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(jtaTransactionManager));
transactionManagerCustomizers
.ifAvailable((customizers) -> customizers.customize((TransactionManager) jtaTransactionManager));
return jtaTransactionManager;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
import org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy;
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.ManagedBeanSettings;
import org.hibernate.cfg.SchemaToolingSettings;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
Expand Down Expand Up @@ -129,7 +130,8 @@ void testDmlScript() {
void testDmlScriptRunsEarly() {
contextRunner().withUserConfiguration(TestInitializedJpaConfiguration.class)
.withClassLoader(new HideDataScriptClassLoader())
.withPropertyValues("spring.jpa.show-sql=true", "spring.jpa.hibernate.ddl-auto:create-drop",
.withPropertyValues("spring.jpa.show-sql=true", "spring.jpa.properties.hibernate.format_sql=true",
"spring.jpa.properties.hibernate.highlight_sql=true", "spring.jpa.hibernate.ddl-auto:create-drop",
"spring.sql.init.data-locations:/city.sql", "spring.jpa.defer-datasource-initialization=true")
.run((context) -> assertThat(context.getBean(TestInitializedJpaConfiguration.class).called).isTrue());
}
Expand Down Expand Up @@ -386,17 +388,17 @@ void hibernatePropertiesCustomizerCanDisableBeanContainer() {
@Test
void vendorPropertiesWithEmbeddedDatabaseAndNoDdlProperty() {
contextRunner().run(vendorProperties((vendorProperties) -> {
assertThat(vendorProperties).doesNotContainKeys(AvailableSettings.JAKARTA_HBM2DDL_DATABASE_ACTION);
assertThat(vendorProperties).containsEntry(AvailableSettings.HBM2DDL_AUTO, "create-drop");
assertThat(vendorProperties).doesNotContainKeys(SchemaToolingSettings.JAKARTA_HBM2DDL_DATABASE_ACTION);
assertThat(vendorProperties).containsEntry(SchemaToolingSettings.HBM2DDL_AUTO, "create-drop");
}));
}

@Test
void vendorPropertiesWhenDdlAutoPropertyIsSet() {
contextRunner().withPropertyValues("spring.jpa.hibernate.ddl-auto=update")
.run(vendorProperties((vendorProperties) -> {
assertThat(vendorProperties).doesNotContainKeys(AvailableSettings.JAKARTA_HBM2DDL_DATABASE_ACTION);
assertThat(vendorProperties).containsEntry(AvailableSettings.HBM2DDL_AUTO, "update");
assertThat(vendorProperties).doesNotContainKeys(SchemaToolingSettings.JAKARTA_HBM2DDL_DATABASE_ACTION);
assertThat(vendorProperties).containsEntry(SchemaToolingSettings.HBM2DDL_AUTO, "update");
}));
}

Expand All @@ -406,25 +408,26 @@ void vendorPropertiesWhenDdlAutoPropertyAndHibernatePropertiesAreSet() {
.withPropertyValues("spring.jpa.hibernate.ddl-auto=update",
"spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop")
.run(vendorProperties((vendorProperties) -> {
assertThat(vendorProperties).doesNotContainKeys(AvailableSettings.JAKARTA_HBM2DDL_DATABASE_ACTION);
assertThat(vendorProperties).containsEntry(AvailableSettings.HBM2DDL_AUTO, "create-drop");
assertThat(vendorProperties).doesNotContainKeys(SchemaToolingSettings.JAKARTA_HBM2DDL_DATABASE_ACTION);
assertThat(vendorProperties).containsEntry(SchemaToolingSettings.HBM2DDL_AUTO, "create-drop");
}));
}

@Test
void vendorPropertiesWhenDdlAutoPropertyIsSetToNone() {
contextRunner().withPropertyValues("spring.jpa.hibernate.ddl-auto=none")
.run(vendorProperties((vendorProperties) -> assertThat(vendorProperties).doesNotContainKeys(
AvailableSettings.JAKARTA_HBM2DDL_DATABASE_ACTION, AvailableSettings.HBM2DDL_AUTO)));
SchemaToolingSettings.JAKARTA_HBM2DDL_DATABASE_ACTION, SchemaToolingSettings.HBM2DDL_AUTO)));
}

@Test
void vendorPropertiesWhenJpaDdlActionIsSet() {
contextRunner()
.withPropertyValues("spring.jpa.properties.jakarta.persistence.schema-generation.database.action=create")
.run(vendorProperties((vendorProperties) -> {
assertThat(vendorProperties).containsEntry(AvailableSettings.JAKARTA_HBM2DDL_DATABASE_ACTION, "create");
assertThat(vendorProperties).doesNotContainKeys(AvailableSettings.HBM2DDL_AUTO);
assertThat(vendorProperties).containsEntry(SchemaToolingSettings.JAKARTA_HBM2DDL_DATABASE_ACTION,
"create");
assertThat(vendorProperties).doesNotContainKeys(SchemaToolingSettings.HBM2DDL_AUTO);
}));
}

Expand All @@ -434,8 +437,9 @@ void vendorPropertiesWhenBothDdlAutoPropertiesAreSet() {
.withPropertyValues("spring.jpa.properties.jakarta.persistence.schema-generation.database.action=create",
"spring.jpa.hibernate.ddl-auto=create-only")
.run(vendorProperties((vendorProperties) -> {
assertThat(vendorProperties).containsEntry(AvailableSettings.JAKARTA_HBM2DDL_DATABASE_ACTION, "create");
assertThat(vendorProperties).containsEntry(AvailableSettings.HBM2DDL_AUTO, "create-only");
assertThat(vendorProperties).containsEntry(SchemaToolingSettings.JAKARTA_HBM2DDL_DATABASE_ACTION,
"create");
assertThat(vendorProperties).containsEntry(SchemaToolingSettings.HBM2DDL_AUTO, "create-only");
}));
}

Expand Down Expand Up @@ -570,7 +574,7 @@ static class DisableBeanContainerConfiguration {

@Bean
HibernatePropertiesCustomizer disableBeanContainerHibernatePropertiesCustomizer() {
return (hibernateProperties) -> hibernateProperties.remove(AvailableSettings.BEAN_CONTAINER);
return (hibernateProperties) -> hibernateProperties.remove(ManagedBeanSettings.BEAN_CONTAINER);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ static class CustomTransactionManagerCustomizersConfiguration {

@Bean
TransactionManagerCustomizers customTransactionManagerCustomizers() {
return new TransactionManagerCustomizers(Collections.emptyList());
return TransactionManagerCustomizers.of(Collections.<TransactionManagerCustomizer<?>>emptyList());
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.junit.jupiter.api.Test;

import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;

import static org.assertj.core.api.Assertions.assertThat;
Expand All @@ -36,23 +37,22 @@ class TransactionManagerCustomizersTests {

@Test
void customizeWithNullCustomizersShouldDoNothing() {
new TransactionManagerCustomizers(null).customize(mock(PlatformTransactionManager.class));
TransactionManagerCustomizers.of(null).customize(mock(TransactionManager.class));
}

@Test
void customizeShouldCheckGeneric() {
List<TestCustomizer<?>> list = new ArrayList<>();
list.add(new TestCustomizer<>());
list.add(new TestJtaCustomizer());
TransactionManagerCustomizers customizers = new TransactionManagerCustomizers(list);
customizers.customize(mock(PlatformTransactionManager.class));
customizers.customize(mock(JtaTransactionManager.class));
TransactionManagerCustomizers customizers = TransactionManagerCustomizers.of(list);
customizers.customize((TransactionManager) mock(PlatformTransactionManager.class));
customizers.customize((TransactionManager) mock(JtaTransactionManager.class));
assertThat(list.get(0).getCount()).isEqualTo(2);
assertThat(list.get(1).getCount()).isOne();
}

static class TestCustomizer<T extends PlatformTransactionManager>
implements PlatformTransactionManagerCustomizer<T> {
static class TestCustomizer<T extends PlatformTransactionManager> implements TransactionManagerCustomizer<T> {

private int count;

Expand Down

0 comments on commit 1a22415

Please sign in to comment.