Browse Source
Replace `PropertyBasedRequiredBackgroundBootstrapping` with a simpler `BootstrapExecutorRequiredException` and use a regular failure analyzer to provide help. See gh-49733 See gh-49688pull/49787/head
9 changed files with 196 additions and 107 deletions
@ -0,0 +1,69 @@
@@ -0,0 +1,69 @@
|
||||
/* |
||||
* 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.jspecify.annotations.Nullable; |
||||
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* Exception thrown then the auto-configured |
||||
* {@link LocalContainerEntityManagerFactoryBean} is missing a required bootstrap |
||||
* executor. |
||||
* |
||||
* @author Phillip Webb |
||||
* @since 4.1.0 |
||||
*/ |
||||
public class BootstrapExecutorRequiredException extends IllegalStateException { |
||||
|
||||
private final @Nullable String propertyName; |
||||
|
||||
private final @Nullable String propertyValue; |
||||
|
||||
public BootstrapExecutorRequiredException(String message) { |
||||
this(message, null); |
||||
} |
||||
|
||||
public BootstrapExecutorRequiredException(String message, @Nullable Throwable cause) { |
||||
this(message, null, null, cause); |
||||
} |
||||
|
||||
private BootstrapExecutorRequiredException(String message, @Nullable String propertyName, |
||||
@Nullable String propertyValue, @Nullable Throwable cause) { |
||||
super(message, cause); |
||||
this.propertyName = propertyName; |
||||
this.propertyValue = propertyValue; |
||||
} |
||||
|
||||
@Nullable String getPropertyName() { |
||||
return this.propertyName; |
||||
} |
||||
|
||||
@Nullable String getPropertyValue() { |
||||
return this.propertyValue; |
||||
} |
||||
|
||||
public static BootstrapExecutorRequiredException ofProperty(String name, String value) { |
||||
Assert.hasText(name, "'name' must not be empty"); |
||||
Assert.hasText(value, "'value' must not be empty"); |
||||
String message = "An EntityManagerFactoryBean bootstrap executor is required when '%s' is set to '%s'" |
||||
.formatted(name, value); |
||||
return new BootstrapExecutorRequiredException(message, name, value, null); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
/* |
||||
* 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.jspecify.annotations.Nullable; |
||||
|
||||
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; |
||||
import org.springframework.boot.diagnostics.FailureAnalysis; |
||||
import org.springframework.boot.diagnostics.FailureAnalyzer; |
||||
|
||||
/** |
||||
* {@link FailureAnalyzer} for {@link BootstrapExecutorRequiredException}. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
class BootstrapExecutorRequiredFailureAnalyzer extends AbstractFailureAnalyzer<BootstrapExecutorRequiredException> { |
||||
|
||||
@Override |
||||
protected @Nullable FailureAnalysis analyze(Throwable rootFailure, BootstrapExecutorRequiredException cause) { |
||||
StringBuilder action = new StringBuilder(); |
||||
action.append(actionPreamble(cause.getPropertyName())); |
||||
action.append("\t- With an auto-configured task executor " |
||||
+ "(you may need to set 'spring.task.execution.mode' to 'force').\n"); |
||||
action.append("\t- With an AsyncTaskExecutor bean named 'applicationTaskExecutor'.\n"); |
||||
action.append("\t- Using a EntityManagerFactoryBuilderCustomizer.\n"); |
||||
return new FailureAnalysis(cause.getMessage(), action.toString(), cause); |
||||
} |
||||
|
||||
private String actionPreamble(@Nullable String propertyName) { |
||||
return (propertyName != null) |
||||
? "Use a different '%s' value or provide a bootstrap executor using one of the following methods:\n" |
||||
.formatted(propertyName) |
||||
: "Provide a bootstrap executor using one of the following methods:\n"; |
||||
} |
||||
|
||||
} |
||||
@ -1,60 +0,0 @@
@@ -1,60 +0,0 @@
|
||||
/* |
||||
* 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()); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,66 @@
@@ -0,0 +1,66 @@
|
||||
/* |
||||
* 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.FailureAnalysis; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link BootstrapExecutorRequiredFailureAnalyzer}. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
class BootstrapExecutorRequiredFailureAnalyzerTests { |
||||
|
||||
private final BootstrapExecutorRequiredFailureAnalyzer analyzer = new BootstrapExecutorRequiredFailureAnalyzer(); |
||||
|
||||
@Test |
||||
void analyzeWhenBootstrapExecutorRequiredExceptionWithProperties() { |
||||
BootstrapExecutorRequiredException exception = BootstrapExecutorRequiredException.ofProperty("testname", |
||||
"testvalue"); |
||||
FailureAnalysis result = this.analyzer.analyze(exception); |
||||
assertThat(result).isNotNull(); |
||||
assertThat(result.getDescription()).isEqualTo( |
||||
"An EntityManagerFactoryBean bootstrap executor is required when 'testname' is set to 'testvalue'"); |
||||
assertThat(result.getAction()).isEqualTo( |
||||
""" |
||||
Use a different 'testname' value or provide a bootstrap executor using one of the following methods: |
||||
- With an auto-configured task executor (you may need to set 'spring.task.execution.mode' to 'force'). |
||||
- With an AsyncTaskExecutor bean named 'applicationTaskExecutor'. |
||||
- Using a EntityManagerFactoryBuilderCustomizer. |
||||
"""); |
||||
} |
||||
|
||||
@Test |
||||
void analyzeWhenBootstrapExecutorRequiredExceptionWithMessage() { |
||||
BootstrapExecutorRequiredException exception = new BootstrapExecutorRequiredException("A custom message"); |
||||
FailureAnalysis result = this.analyzer.analyze(exception); |
||||
assertThat(result).isNotNull(); |
||||
assertThat(result.getDescription()).isEqualTo("A custom message"); |
||||
assertThat(result.getAction()).isEqualTo( |
||||
""" |
||||
Provide a bootstrap executor using one of the following methods: |
||||
- With an auto-configured task executor (you may need to set 'spring.task.execution.mode' to 'force'). |
||||
- With an AsyncTaskExecutor bean named 'applicationTaskExecutor'. |
||||
- Using a EntityManagerFactoryBuilderCustomizer. |
||||
"""); |
||||
} |
||||
|
||||
} |
||||
@ -1,40 +0,0 @@
@@ -1,40 +0,0 @@
|
||||
/* |
||||
* 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'"); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue