mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 20:19:06 +00:00
Refine Spring Data JPA background bootstrapping mode support
Update `spring.data.jpa.repositories.bootstrap-mode` logic so that: - A value of `lazy` no longer sets a bootstrap executor. - A value of `deferred` requires that a bootstrap executor is ultimately set, and fails with a meaningful message if it is not. The logic used to find the AsyncTaskExecutor has now moved to the `JpaBaseConfiguration` and is triggered by the `EntityManagerFactoryBuilder` only when background bootstrapping is required. Closes gh-49688
This commit is contained in:
+3
@@ -19,6 +19,8 @@ package org.springframework.boot.data.jpa.test.autoconfigure;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.repository.config.BootstrapMode;
|
||||
|
||||
@@ -31,6 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@DataJpaTest(properties = "spring.profiles.active=test", bootstrapMode = BootstrapMode.DEFERRED)
|
||||
@ImportAutoConfiguration(TaskExecutionAutoConfiguration.class)
|
||||
class DataJpaTestAttributesIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
|
||||
+4
-27
@@ -25,7 +25,6 @@ import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.boot.LazyInitializationExcludeFilter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
@@ -35,8 +34,8 @@ import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguratio
|
||||
import org.springframework.boot.data.jpa.autoconfigure.DataJpaRepositoriesAutoConfiguration.JpaRepositoriesImportSelector;
|
||||
import org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration;
|
||||
import org.springframework.boot.jpa.autoconfigure.EntityManagerFactoryBuilderCustomizer;
|
||||
import org.springframework.boot.jpa.autoconfigure.PropertyBasedRequiredBackgroundBootstrapping;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.ImportSelector;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
@@ -83,15 +82,11 @@ import org.springframework.util.ClassUtils;
|
||||
public final class DataJpaRepositoriesAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@Conditional(BootstrapExecutorCondition.class)
|
||||
@ConditionalOnProperty(name = "spring.data.jpa.repositories.bootstrap-mode", havingValue = "deferred")
|
||||
EntityManagerFactoryBuilderCustomizer entityManagerFactoryBootstrapExecutorCustomizer(
|
||||
Map<String, AsyncTaskExecutor> taskExecutors) {
|
||||
return (builder) -> {
|
||||
AsyncTaskExecutor bootstrapExecutor = determineBootstrapExecutor(taskExecutors);
|
||||
if (bootstrapExecutor != null) {
|
||||
builder.setBootstrapExecutor(bootstrapExecutor);
|
||||
}
|
||||
};
|
||||
return (builder) -> builder.requireBootstrapExecutor(new PropertyBasedRequiredBackgroundBootstrapping(
|
||||
"spring.data.jpa.repositories.bootstrap-mode", "deferred"));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -106,24 +101,6 @@ public final class DataJpaRepositoriesAutoConfiguration {
|
||||
return taskExecutors.get(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME);
|
||||
}
|
||||
|
||||
private static final class BootstrapExecutorCondition extends AnyNestedCondition {
|
||||
|
||||
BootstrapExecutorCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(name = "spring.data.jpa.repositories.bootstrap-mode", havingValue = "deferred")
|
||||
static class DeferredBootstrapMode {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(name = "spring.data.jpa.repositories.bootstrap-mode", havingValue = "lazy")
|
||||
static class LazyBootstrapMode {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class JpaRepositoriesImportSelector implements ImportSelector {
|
||||
|
||||
private static final boolean ENVERS_AVAILABLE = ClassUtils.isPresent(
|
||||
|
||||
+2
-13
@@ -88,23 +88,12 @@ abstract class AbstractDataJpaRepositoriesAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenBootstrapModeIsLazyWithMultipleAsyncExecutorBootstrapExecutorIsConfigured() {
|
||||
this.contextRunner.withUserConfiguration(MultipleAsyncTaskExecutorConfiguration.class)
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(TaskExecutionAutoConfiguration.class, TaskSchedulingAutoConfiguration.class))
|
||||
.withPropertyValues("spring.data.jpa.repositories.bootstrap-mode=lazy")
|
||||
.run((context) -> assertThat(
|
||||
context.getBean(LocalContainerEntityManagerFactoryBean.class).getBootstrapExecutor())
|
||||
.isEqualTo(context.getBean("applicationTaskExecutor")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenBootstrapModeIsLazyWithSingleAsyncExecutorBootstrapExecutorIsConfigured() {
|
||||
void whenBootstrapModeDoesNotUseFallbackBootstrapExecutor() {
|
||||
this.contextRunner.withUserConfiguration(SingleAsyncTaskExecutorConfiguration.class)
|
||||
.withPropertyValues("spring.data.jpa.repositories.bootstrap-mode=lazy")
|
||||
.run((context) -> assertThat(
|
||||
context.getBean(LocalContainerEntityManagerFactoryBean.class).getBootstrapExecutor())
|
||||
.isEqualTo(context.getBean("testAsyncTaskExecutor")));
|
||||
.isNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ import static org.assertj.core.api.Assertions.entry;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Base for JPA tests and tests for {@link JpaBaseConfiguration}.
|
||||
* Test for {@link HibernateJpaAutoConfiguration} and {@link JpaBaseConfiguration}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Dave Syer
|
||||
|
||||
+58
-1
@@ -26,6 +26,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@@ -35,9 +36,11 @@ import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.orm.jpa.JpaVendorAdapter;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.orm.jpa.LocalEntityManagerFactoryBean;
|
||||
import org.springframework.orm.jpa.persistenceunit.PersistenceManagedTypes;
|
||||
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager;
|
||||
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -65,10 +68,14 @@ public class EntityManagerFactoryBuilder {
|
||||
|
||||
private final @Nullable URL persistenceUnitRootLocation;
|
||||
|
||||
private final @Nullable AsyncTaskExecutor fallbackBootstrapExecutor;
|
||||
|
||||
private @Nullable AsyncTaskExecutor bootstrapExecutor;
|
||||
|
||||
private @Nullable List<PersistenceUnitPostProcessor> persistenceUnitPostProcessors;
|
||||
|
||||
private @Nullable Supplier<? extends RuntimeException> requireBootstrapExecutorExceptionSupplier;
|
||||
|
||||
/**
|
||||
* Create a new instance passing in the common pieces that will be shared if multiple
|
||||
* EntityManagerFactory instances are created.
|
||||
@@ -98,10 +105,32 @@ public class EntityManagerFactoryBuilder {
|
||||
public EntityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter,
|
||||
Function<DataSource, Map<String, ?>> jpaPropertiesFactory,
|
||||
@Nullable PersistenceUnitManager persistenceUnitManager, @Nullable URL persistenceUnitRootLocation) {
|
||||
this(jpaVendorAdapter, jpaPropertiesFactory, persistenceUnitManager, persistenceUnitRootLocation, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance passing in the common pieces that will be shared if multiple
|
||||
* EntityManagerFactory instances are created.
|
||||
* @param jpaVendorAdapter a vendor adapter
|
||||
* @param jpaPropertiesFactory the JPA properties to be passed to the persistence
|
||||
* provider, based on the {@linkplain #dataSource(DataSource) configured data source}
|
||||
* @param persistenceUnitManager optional source of persistence unit information (can
|
||||
* be null)
|
||||
* @param persistenceUnitRootLocation the persistence unit root location to use as a
|
||||
* fallback or {@code null}
|
||||
* @param fallbackBootstrapExecutor the fallback executor to use when background
|
||||
* bootstrapping is required but no explicit executor has been set
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public EntityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter,
|
||||
Function<DataSource, Map<String, ?>> jpaPropertiesFactory,
|
||||
@Nullable PersistenceUnitManager persistenceUnitManager, @Nullable URL persistenceUnitRootLocation,
|
||||
@Nullable AsyncTaskExecutor fallbackBootstrapExecutor) {
|
||||
this.jpaVendorAdapter = jpaVendorAdapter;
|
||||
this.persistenceUnitManager = persistenceUnitManager;
|
||||
this.jpaPropertiesFactory = jpaPropertiesFactory;
|
||||
this.persistenceUnitRootLocation = persistenceUnitRootLocation;
|
||||
this.fallbackBootstrapExecutor = fallbackBootstrapExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,6 +152,20 @@ public class EntityManagerFactoryBuilder {
|
||||
this.bootstrapExecutor = bootstrapExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require a bootstrap executor to be configured when the
|
||||
* {@link LocalEntityManagerFactoryBean} is built. If no bootstrap executor is
|
||||
* {@link #setBootstrapExecutor(AsyncTaskExecutor) explicitly set} and no
|
||||
* {@link #EntityManagerFactoryBuilder(JpaVendorAdapter, Function, PersistenceUnitManager, URL, AsyncTaskExecutor)
|
||||
* fallbackBootstrapExecutor} is available then the supplied exception is thrown.
|
||||
* @param exceptionSupplier a supplier providing the exception to throw
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public void requireBootstrapExecutor(Supplier<? extends RuntimeException> exceptionSupplier) {
|
||||
Assert.notNull(exceptionSupplier, "'exceptionSupplier' must not be null");
|
||||
this.requireBootstrapExecutorExceptionSupplier = exceptionSupplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@linkplain PersistenceUnitPostProcessor persistence unit post processors}
|
||||
* to be applied to the PersistenceUnitInfo used for creating the
|
||||
@@ -281,7 +324,7 @@ public class EntityManagerFactoryBuilder {
|
||||
map.from(EntityManagerFactoryBuilder.this.persistenceUnitRootLocation)
|
||||
.as(Object::toString)
|
||||
.to(factory::setPersistenceUnitRootLocation);
|
||||
map.from(EntityManagerFactoryBuilder.this.bootstrapExecutor).to(factory::setBootstrapExecutor);
|
||||
map.from(this::bootstrapExecutor).to(factory::setBootstrapExecutor);
|
||||
map.from(EntityManagerFactoryBuilder.this.persistenceUnitPostProcessors)
|
||||
.as((postProcessors) -> postProcessors.toArray(PersistenceUnitPostProcessor[]::new))
|
||||
.to(factory::setPersistenceUnitPostProcessors);
|
||||
@@ -295,6 +338,20 @@ public class EntityManagerFactoryBuilder {
|
||||
return jpaPropertyMap;
|
||||
}
|
||||
|
||||
private @Nullable AsyncTaskExecutor bootstrapExecutor() {
|
||||
if (EntityManagerFactoryBuilder.this.bootstrapExecutor != null) {
|
||||
return EntityManagerFactoryBuilder.this.bootstrapExecutor;
|
||||
}
|
||||
if (EntityManagerFactoryBuilder.this.requireBootstrapExecutorExceptionSupplier != null) {
|
||||
if (EntityManagerFactoryBuilder.this.fallbackBootstrapExecutor != null) {
|
||||
return EntityManagerFactoryBuilder.this.fallbackBootstrapExecutor;
|
||||
}
|
||||
RuntimeException ex = EntityManagerFactoryBuilder.this.requireBootstrapExecutorExceptionSupplier.get();
|
||||
throw (ex != null) ? ex : new IllegalStateException("A bootstrap executor is required");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-2
@@ -37,6 +37,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingFilterBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.jpa.EntityManagerFactoryBuilder;
|
||||
import org.springframework.boot.persistence.autoconfigure.EntityScanPackages;
|
||||
@@ -45,6 +46,7 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.JpaVendorAdapter;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
@@ -120,13 +122,20 @@ public abstract class JpaBaseConfiguration {
|
||||
@ConditionalOnMissingBean
|
||||
public EntityManagerFactoryBuilder entityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter,
|
||||
ObjectProvider<PersistenceUnitManager> persistenceUnitManager,
|
||||
ObjectProvider<EntityManagerFactoryBuilderCustomizer> customizers) {
|
||||
ObjectProvider<EntityManagerFactoryBuilderCustomizer> customizers,
|
||||
Map<String, AsyncTaskExecutor> taskExecutors) {
|
||||
@Nullable AsyncTaskExecutor bootstrapExecutor = determineBootstrapExecutor(taskExecutors);
|
||||
EntityManagerFactoryBuilder builder = new EntityManagerFactoryBuilder(jpaVendorAdapter,
|
||||
this::buildJpaProperties, persistenceUnitManager.getIfAvailable());
|
||||
this::buildJpaProperties, persistenceUnitManager.getIfAvailable(), null, bootstrapExecutor);
|
||||
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return builder;
|
||||
}
|
||||
|
||||
private @Nullable AsyncTaskExecutor determineBootstrapExecutor(Map<String, AsyncTaskExecutor> taskExecutors) {
|
||||
return (taskExecutors.size() == 1) ? taskExecutors.values().iterator().next()
|
||||
: taskExecutors.get(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME);
|
||||
}
|
||||
|
||||
private Map<String, ?> buildJpaProperties(DataSource dataSource) {
|
||||
Map<String, Object> properties = new HashMap<>(this.properties.getProperties());
|
||||
Map<String, Object> vendorProperties = getVendorProperties(dataSource);
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2012-present 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.jpa.autoconfigure;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.boot.diagnostics.FailureAnalyzedException;
|
||||
import org.springframework.boot.jpa.EntityManagerFactoryBuilder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Supplier} to use with
|
||||
* {@link EntityManagerFactoryBuilder#requireBootstrapExecutor} when a property indicates
|
||||
* background bootstrapping is required.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public class PropertyBasedRequiredBackgroundBootstrapping implements Supplier<RuntimeException> {
|
||||
|
||||
private final String propertyName;
|
||||
|
||||
private final String propertyValue;
|
||||
|
||||
public PropertyBasedRequiredBackgroundBootstrapping(String propertyName, String propertyValue) {
|
||||
Assert.notNull(propertyName, "'propertyName' must not be null");
|
||||
Assert.notNull(propertyValue, "'propertyValue' must not be null");
|
||||
this.propertyName = propertyName;
|
||||
this.propertyValue = propertyValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuntimeException get() {
|
||||
String description = "A LocalContainerEntityManagerFactoryBean bootstrap executor is required when '%s' is set to '%s'"
|
||||
.formatted(this.propertyName, this.propertyValue);
|
||||
StringBuilder action = new StringBuilder();
|
||||
action.append("Use a different '%s' or provide a bootstrap executor using one of the following methods:\n"
|
||||
.formatted(this.propertyName));
|
||||
action.append("\tWith an auto-configured task executor "
|
||||
+ "(you may need to set 'spring.task.execution.mode' to 'force').");
|
||||
action.append("\tWith an AsyncTaskExecutor bean named 'applicationTaskExecutor.'");
|
||||
action.append("\tUsing a EntityManagerFactoryBuilderCustomizer.");
|
||||
return new FailureAnalyzedException(description, action.toString());
|
||||
}
|
||||
|
||||
}
|
||||
+45
-1
@@ -24,12 +24,17 @@ import javax.sql.DataSource;
|
||||
|
||||
import jakarta.persistence.spi.PersistenceProvider;
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;
|
||||
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
@@ -86,9 +91,48 @@ class EntityManagerFactoryBuilderTests {
|
||||
.containsExactly(postProcessor, postProcessor2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void requireBootstrapExecutorWhenExecutorProvidedDoesNotThrow() {
|
||||
EntityManagerFactoryBuilder builder = createEmptyBuilder();
|
||||
builder.requireBootstrapExecutor(() -> new IllegalStateException("BAD"));
|
||||
builder.setBootstrapExecutor(new SimpleAsyncTaskExecutor());
|
||||
DataSource dataSource = mock();
|
||||
assertThatNoException().isThrownBy(builder.dataSource(dataSource)::build);
|
||||
}
|
||||
|
||||
@Test
|
||||
void requireBootstrapExecutorWhenFallbackExecutorProvidesExecutorDoesNotThrow() {
|
||||
EntityManagerFactoryBuilder builder = createEmptyBuilder(new SimpleAsyncTaskExecutor());
|
||||
builder.requireBootstrapExecutor(() -> new IllegalStateException("BAD"));
|
||||
DataSource dataSource = mock();
|
||||
assertThatNoException().isThrownBy(builder.dataSource(dataSource)::build);
|
||||
}
|
||||
|
||||
@Test
|
||||
void requireBootstrapExecutorWhenExecutorAndNoFallbackExecutorThrowsException() {
|
||||
EntityManagerFactoryBuilder builder = createEmptyBuilder();
|
||||
builder.requireBootstrapExecutor(() -> new IllegalStateException("BAD"));
|
||||
DataSource dataSource = mock();
|
||||
assertThatIllegalStateException().isThrownBy(builder.dataSource(dataSource)::build).withMessage("BAD");
|
||||
}
|
||||
|
||||
@Test
|
||||
void requireBootstrapExecutorWhenSupplierReturnsNullExecutorAndNoFallbackExecutorThrowsException() {
|
||||
EntityManagerFactoryBuilder builder = createEmptyBuilder();
|
||||
builder.requireBootstrapExecutor(() -> null);
|
||||
DataSource dataSource = mock();
|
||||
assertThatIllegalStateException().isThrownBy(builder.dataSource(dataSource)::build)
|
||||
.withMessage("A bootstrap executor is required");
|
||||
}
|
||||
|
||||
private EntityManagerFactoryBuilder createEmptyBuilder() {
|
||||
return createEmptyBuilder(null);
|
||||
}
|
||||
|
||||
private EntityManagerFactoryBuilder createEmptyBuilder(@Nullable AsyncTaskExecutor fallbackBootstrapExecutor) {
|
||||
Function<DataSource, Map<String, ?>> jpaPropertiesFactory = (dataSource) -> Collections.emptyMap();
|
||||
return new EntityManagerFactoryBuilder(new TestJpaVendorAdapter(), jpaPropertiesFactory, null);
|
||||
return new EntityManagerFactoryBuilder(new TestJpaVendorAdapter(), jpaPropertiesFactory, null, null,
|
||||
fallbackBootstrapExecutor);
|
||||
}
|
||||
|
||||
static class TestJpaVendorAdapter extends AbstractJpaVendorAdapter {
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2012-present 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.jpa.autoconfigure;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.diagnostics.FailureAnalyzedException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link PropertyBasedRequiredBackgroundBootstrapping}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class PropertyBasedRequiredBackgroundBootstrappingTests {
|
||||
|
||||
@Test
|
||||
void getReturnsFailureAnalyzableException() {
|
||||
RuntimeException exception = new PropertyBasedRequiredBackgroundBootstrapping("test.bootstrap", "true").get();
|
||||
assertThat(exception).isInstanceOf(FailureAnalyzedException.class)
|
||||
.hasMessage("A LocalContainerEntityManagerFactoryBean bootstrap executor is required "
|
||||
+ "when 'test.bootstrap' is set to 'true'");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user