diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/AbstractArchiveIntegrationTests.java b/build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/AbstractArchiveIntegrationTests.java index 4b9e7657906..0bfe5a0fbf4 100644 --- a/build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/AbstractArchiveIntegrationTests.java +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/AbstractArchiveIntegrationTests.java @@ -38,6 +38,8 @@ import org.assertj.core.api.AssertProvider; import org.assertj.core.api.ListAssert; import org.jspecify.annotations.Nullable; +import org.springframework.lang.CheckReturnValue; + import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.contentOf; @@ -172,6 +174,7 @@ abstract class AbstractArchiveIntegrationTests { return this; } + @CheckReturnValue ListAssert entryNamesInPath(String path) { List matches = new ArrayList<>(); withJarFile((jarFile) -> withEntries(jarFile, diff --git a/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java b/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java index fa46cb9edf2..8eb6e91c6bd 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java @@ -70,6 +70,7 @@ import org.gradle.api.tasks.VerificationException; * @author Phillip Webb * @author Dmytro Nosan * @author Moritz Halbritter + * @author Stefano Cordio */ public abstract class ArchitectureCheck extends DefaultTask { @@ -93,6 +94,8 @@ public abstract class ArchitectureCheck extends DefaultTask { getRules().addAll(whenMainSources( () -> ArchitectureRules.configurationPropertiesDeprecation(ArchitectureCheckAnnotation.classFor( getAnnotationClasses().get(), ArchitectureCheckAnnotation.DEPRECATED_CONFIGURATION_PROPERTY)))); + getRules().addAll(whenMainSources(() -> Collections.singletonList( + ArchitectureRules.allCustomAssertionMethodsNotReturningSelfShouldBeAnnotatedWithCheckReturnValue()))); getRules().addAll(and(getNullMarkedEnabled(), isMainSourceSet()).map(whenTrue(() -> Collections.singletonList( ArchitectureRules.packagesShouldBeAnnotatedWithNullMarked(getNullMarkedIgnoredPackages().get()))))); getRuleDescriptions().set(getRules().map(this::asDescriptions)); diff --git a/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureRules.java b/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureRules.java index e41cbaf73c5..15e6221e7bd 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureRules.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureRules.java @@ -63,6 +63,7 @@ import com.tngtech.archunit.library.dependencies.SlicesRuleDefinition; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Role; +import org.springframework.lang.CheckReturnValue; import org.springframework.util.ResourceUtils; /** @@ -75,6 +76,7 @@ import org.springframework.util.ResourceUtils; * @author Phillip Webb * @author Ngoc Nhan * @author Moritz Halbritter + * @author Stefano Cordio */ final class ArchitectureRules { @@ -158,6 +160,26 @@ final class ArchitectureRules { .allowEmptyShould(true); } + static ArchRule allCustomAssertionMethodsNotReturningSelfShouldBeAnnotatedWithCheckReturnValue() { + return ArchRuleDefinition.methods() + .that() + .areDeclaredInClassesThat() + .implement("org.assertj.core.api.Assert") + .and() + .arePublic() + .and() + .doNotHaveModifier(JavaModifier.BRIDGE) + .and(doNotReturnSelfType()) + .should() + .beAnnotatedWith(CheckReturnValue.class) + .allowEmptyShould(true); + } + + private static DescribedPredicate doNotReturnSelfType() { + return DescribedPredicate.describe("do not return self type", + (method) -> !method.getRawReturnType().equals(method.getOwner())); + } + private static ArchRule allPackagesShouldBeFreeOfTangles() { return SlicesRuleDefinition.slices() .matching("(**)") diff --git a/buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java b/buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java index 7acae3a1693..b0ab7be6dcb 100644 --- a/buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java +++ b/buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java @@ -62,13 +62,18 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Scott Frederick * @author Ivan Malutin * @author Dmytro Nosan + * @author Stefano Cordio */ class ArchitectureCheckTests { - private static final String SPRING_CONTEXT = "org.springframework:spring-context:6.2.9"; + private static final String ASSERTJ_CORE = "org.assertj:assertj-core:3.27.4"; private static final String JUNIT_JUPITER = "org.junit.jupiter:junit-jupiter:5.12.0"; + private static final String SPRING_CONTEXT = "org.springframework:spring-context:6.2.9"; + + private static final String SPRING_CORE = "org.springframework:spring-core:6.2.9"; + private static final String SPRING_INTEGRATION_JMX = "org.springframework.integration:spring-integration-jmx:6.5.1"; private GradleBuild gradleBuild; @@ -452,6 +457,23 @@ class ArchitectureCheckTests { "DeprecatedConfigurationPropertySince.getProperty"); } + @Test + void whenCustomAssertionMethodNotReturningSelfIsAnnotatedWithCheckReturnValueShouldSucceedAndWriteEmptyReport() + throws IOException { + prepareTask(Task.CHECK_ARCHITECTURE_MAIN, "assertj/checkReturnValue"); + build(this.gradleBuild.withDependencies(ASSERTJ_CORE, SPRING_CORE), Task.CHECK_ARCHITECTURE_MAIN); + } + + @Test + void whenCustomAssertionMethodNotReturningSelfIsNotAnnotatedWithCheckReturnValueShouldFailAndWriteReport() + throws IOException { + prepareTask(Task.CHECK_ARCHITECTURE_MAIN, "assertj/noCheckReturnValue"); + buildAndFail(this.gradleBuild.withDependencies(ASSERTJ_CORE), Task.CHECK_ARCHITECTURE_MAIN, + "methods that are declared in classes that implement org.assertj.core.api.Assert and " + + "are public and do not have modifier BRIDGE and do not return self type should be annotated " + + "with @CheckReturnValue"); + } + private void prepareTask(Task task, String... sourceDirectories) throws IOException { for (String sourceDirectory : sourceDirectories) { FileSystemUtils.copyRecursively( diff --git a/buildSrc/src/test/java/org/springframework/boot/build/architecture/assertj/checkReturnValue/WithCheckReturnValue.java b/buildSrc/src/test/java/org/springframework/boot/build/architecture/assertj/checkReturnValue/WithCheckReturnValue.java new file mode 100644 index 00000000000..74845f9dbd8 --- /dev/null +++ b/buildSrc/src/test/java/org/springframework/boot/build/architecture/assertj/checkReturnValue/WithCheckReturnValue.java @@ -0,0 +1,39 @@ +/* + * 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.build.architecture.assertj.checkReturnValue; + +import org.assertj.core.api.AbstractAssert; + +import org.springframework.lang.CheckReturnValue; + +public class WithCheckReturnValue extends AbstractAssert { + + WithCheckReturnValue() { + super(null, WithCheckReturnValue.class); + } + + @CheckReturnValue + public Object notReturningSelf() { + return new Object(); + } + + @Override + public WithCheckReturnValue isEqualTo(Object expected) { + return super.isEqualTo(expected); + } + +} diff --git a/buildSrc/src/test/java/org/springframework/boot/build/architecture/assertj/noCheckReturnValue/NoCheckReturnValue.java b/buildSrc/src/test/java/org/springframework/boot/build/architecture/assertj/noCheckReturnValue/NoCheckReturnValue.java new file mode 100644 index 00000000000..70e4be97c7d --- /dev/null +++ b/buildSrc/src/test/java/org/springframework/boot/build/architecture/assertj/noCheckReturnValue/NoCheckReturnValue.java @@ -0,0 +1,31 @@ +/* + * 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.build.architecture.assertj.noCheckReturnValue; + +import org.assertj.core.api.AbstractAssert; + +public class NoCheckReturnValue extends AbstractAssert { + + NoCheckReturnValue() { + super(null, NoCheckReturnValue.class); + } + + public Object notReturningSelf() { + return new Object(); + } + +} diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index 2d591aaaa22..575b993240e 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -6,6 +6,9 @@ + + + diff --git a/core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java b/core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java index 6f5be5b15ae..f39319f6d75 100644 --- a/core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java +++ b/core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java @@ -26,7 +26,6 @@ import org.assertj.core.api.AbstractAssert; import org.assertj.core.api.AbstractObjectArrayAssert; import org.assertj.core.api.AbstractObjectAssert; import org.assertj.core.api.AbstractThrowableAssert; -import org.assertj.core.api.Assertions; import org.assertj.core.api.MapAssert; import org.assertj.core.error.BasicErrorMessageFactory; import org.jspecify.annotations.Nullable; @@ -37,6 +36,7 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.lang.CheckReturnValue; import org.springframework.util.Assert; import static org.assertj.core.api.Assertions.assertThat; @@ -224,13 +224,14 @@ public class ApplicationContextAssert * @return array assertions for the bean names * @throws AssertionError if the application context did not start */ + @CheckReturnValue public AbstractObjectArrayAssert getBeanNames(Class type) { if (this.startupFailure != null) { throwAssertionError(contextFailedToStartWhenExpecting(this.startupFailure, "to get beans names with type:%n <%s>", type)); } - return Assertions.assertThat(getApplicationContext().getBeanNamesForType(type)) - .as("Bean names of type <%s> from <%s>", type, getApplicationContext()); + return assertThat(getApplicationContext().getBeanNamesForType(type)).as("Bean names of type <%s> from <%s>", + type, getApplicationContext()); } /** @@ -249,6 +250,7 @@ public class ApplicationContextAssert * @throws AssertionError if the application context contains multiple beans of the * given type */ + @CheckReturnValue public AbstractObjectAssert getBean(Class type) { return getBean(type, Scope.INCLUDE_ANCESTORS); } @@ -270,6 +272,7 @@ public class ApplicationContextAssert * @throws AssertionError if the application context contains multiple beans of the * given type */ + @CheckReturnValue public AbstractObjectAssert getBean(Class type, Scope scope) { Assert.notNull(scope, "'scope' must not be null"); if (this.startupFailure != null) { @@ -284,7 +287,7 @@ public class ApplicationContextAssert getApplicationContext(), type, names)); } T bean = (name != null) ? getApplicationContext().getBean(name, type) : null; - return Assertions.assertThat(bean).as("Bean of type <%s> from <%s>", type, getApplicationContext()); + return assertThat(bean).as("Bean of type <%s> from <%s>", type, getApplicationContext()); } private @Nullable String getPrimary(String[] names, Scope scope) { @@ -330,13 +333,14 @@ public class ApplicationContextAssert * is found * @throws AssertionError if the application context did not start */ + @CheckReturnValue public AbstractObjectAssert getBean(String name) { if (this.startupFailure != null) { throwAssertionError( contextFailedToStartWhenExpecting(this.startupFailure, "to contain a bean of name:%n <%s>", name)); } Object bean = findBean(name); - return Assertions.assertThat(bean).as("Bean of name <%s> from <%s>", name, getApplicationContext()); + return assertThat(bean).as("Bean of name <%s> from <%s>", name, getApplicationContext()); } /** @@ -357,6 +361,7 @@ public class ApplicationContextAssert * name but a different type */ @SuppressWarnings("unchecked") + @CheckReturnValue public AbstractObjectAssert getBean(String name, Class type) { if (this.startupFailure != null) { throwAssertionError(contextFailedToStartWhenExpecting(this.startupFailure, @@ -368,8 +373,8 @@ public class ApplicationContextAssert "%nExpecting:%n <%s>%nto contain a bean of name:%n <%s> (%s)%nbut found:%n <%s> of type <%s>", getApplicationContext(), name, type, bean, bean.getClass())); } - return Assertions.assertThat((T) bean) - .as("Bean of name <%s> and type <%s> from <%s>", name, type, getApplicationContext()); + return assertThat((T) bean).as("Bean of name <%s> and type <%s> from <%s>", name, type, + getApplicationContext()); } private @Nullable Object findBean(String name) { @@ -395,6 +400,7 @@ public class ApplicationContextAssert * no beans are found * @throws AssertionError if the application context did not start */ + @CheckReturnValue public MapAssert getBeans(Class type) { return getBeans(type, Scope.INCLUDE_ANCESTORS); } @@ -414,14 +420,15 @@ public class ApplicationContextAssert * no beans are found * @throws AssertionError if the application context did not start */ + @CheckReturnValue public MapAssert getBeans(Class type, Scope scope) { Assert.notNull(scope, "'scope' must not be null"); if (this.startupFailure != null) { throwAssertionError( contextFailedToStartWhenExpecting(this.startupFailure, "to get beans of type:%n <%s>", type)); } - return Assertions.assertThat(scope.getBeansOfType(getApplicationContext(), type)) - .as("Beans of type <%s> from <%s>", type, getApplicationContext()); + return assertThat(scope.getBeansOfType(getApplicationContext(), type)).as("Beans of type <%s> from <%s>", type, + getApplicationContext()); } /** @@ -434,6 +441,7 @@ public class ApplicationContextAssert * @return assertions on the cause of the failure * @throws AssertionError if the application context started without a failure */ + @CheckReturnValue public AbstractThrowableAssert getFailure() { hasFailed(); return assertThat(this.startupFailure); diff --git a/core/spring-boot-test/src/main/java/org/springframework/boot/test/json/JsonContentAssert.java b/core/spring-boot-test/src/main/java/org/springframework/boot/test/json/JsonContentAssert.java index 93ce0da1ef1..262f33f7aa8 100644 --- a/core/spring-boot-test/src/main/java/org/springframework/boot/test/json/JsonContentAssert.java +++ b/core/spring-boot-test/src/main/java/org/springframework/boot/test/json/JsonContentAssert.java @@ -40,6 +40,7 @@ import org.skyscreamer.jsonassert.JSONCompareResult; import org.skyscreamer.jsonassert.comparator.JSONComparator; import org.springframework.core.io.Resource; +import org.springframework.lang.CheckReturnValue; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.util.function.ThrowingFunction; @@ -917,6 +918,7 @@ public class JsonContentAssert extends AbstractAssert extractingJsonPathValue(CharSequence expression, Object... args) { return Assertions.assertThat(new JsonPathValue(expression, args).getValue(false)); } @@ -929,6 +931,7 @@ public class JsonContentAssert extends AbstractAssert extractingJsonPathStringValue(CharSequence expression, Object... args) { return Assertions.assertThat(extractingJsonPathValue(expression, args, String.class, "a string")); @@ -942,6 +945,7 @@ public class JsonContentAssert extends AbstractAssert extractingJsonPathNumberValue(CharSequence expression, Object... args) { return Assertions.assertThat(extractingJsonPathValue(expression, args, Number.class, "a number")); } @@ -954,6 +958,7 @@ public class JsonContentAssert extends AbstractAssert extractingJsonPathBooleanValue(CharSequence expression, Object... args) { return Assertions.assertThat(extractingJsonPathValue(expression, args, Boolean.class, "a boolean")); } @@ -968,6 +973,7 @@ public class JsonContentAssert extends AbstractAssert ListAssert extractingJsonPathArrayValue(CharSequence expression, Object... args) { return Assertions.assertThat(extractingJsonPathValue(expression, args, List.class, "an array")); } @@ -983,6 +989,7 @@ public class JsonContentAssert extends AbstractAssert MapAssert extractingJsonPathMapValue(CharSequence expression, Object... args) { return Assertions.assertThat(extractingJsonPathValue(expression, args, Map.class, "a map")); } diff --git a/core/spring-boot-test/src/main/java/org/springframework/boot/test/json/ObjectContentAssert.java b/core/spring-boot-test/src/main/java/org/springframework/boot/test/json/ObjectContentAssert.java index d58612f8595..d406ee93c21 100644 --- a/core/spring-boot-test/src/main/java/org/springframework/boot/test/json/ObjectContentAssert.java +++ b/core/spring-boot-test/src/main/java/org/springframework/boot/test/json/ObjectContentAssert.java @@ -22,6 +22,8 @@ import org.assertj.core.api.AbstractObjectAssert; import org.assertj.core.api.Assert; import org.assertj.core.api.InstanceOfAssertFactories; +import org.springframework.lang.CheckReturnValue; + /** * AssertJ {@link Assert} for {@link ObjectContent}. * @@ -41,6 +43,7 @@ public class ObjectContentAssert extends AbstractObjectAssert asArray() { return asInstanceOf(InstanceOfAssertFactories.ARRAY); } @@ -50,6 +53,7 @@ public class ObjectContentAssert extends AbstractObjectAssert asMap() { return asInstanceOf(InstanceOfAssertFactories.MAP); } diff --git a/system-test/spring-boot-image-system-tests/src/systemTest/java/org/springframework/boot/image/assertions/ContainerConfigAssert.java b/system-test/spring-boot-image-system-tests/src/systemTest/java/org/springframework/boot/image/assertions/ContainerConfigAssert.java index dbf5dcea437..1ec1cdc42d9 100644 --- a/system-test/spring-boot-image-system-tests/src/systemTest/java/org/springframework/boot/image/assertions/ContainerConfigAssert.java +++ b/system-test/spring-boot-image-system-tests/src/systemTest/java/org/springframework/boot/image/assertions/ContainerConfigAssert.java @@ -32,6 +32,7 @@ import org.assertj.core.api.ListAssert; import org.assertj.core.api.ObjectAssert; import org.springframework.boot.test.json.JsonContentAssert; +import org.springframework.lang.CheckReturnValue; /** * AssertJ {@link org.assertj.core.api.Assert} for Docker image container configuration. @@ -99,10 +100,12 @@ public class ContainerConfigAssert extends AbstractAssert buildpacks() { return this.actual.extractingJsonPathArrayValue("$.buildpacks[*].id"); } + @CheckReturnValue public AbstractListAssert, String, ObjectAssert> processOfType(String type) { return this.actual.extractingJsonPathArrayValue("$.processes[?(@.type=='%s')]", type) .singleElement() @@ -132,14 +135,17 @@ public class ContainerConfigAssert extends AbstractAssert buildpackLayers(String buildpackId) { return this.actual.extractingJsonPathArrayValue("$.buildpacks[?(@.key=='%s')].layers", buildpackId); } + @CheckReturnValue public AbstractListAssert, Object, ObjectAssert> appLayerShas() { return this.actual.extractingJsonPathArrayValue("$.app").extracting("sha"); } + @CheckReturnValue public AbstractObjectAssert sbomLayerSha() { return this.actual.extractingJsonPathValue("$.sbom.sha"); } diff --git a/system-test/spring-boot-image-system-tests/src/systemTest/java/org/springframework/boot/image/assertions/ImageAssert.java b/system-test/spring-boot-image-system-tests/src/systemTest/java/org/springframework/boot/image/assertions/ImageAssert.java index fbc242a647d..78afc1764b9 100644 --- a/system-test/spring-boot-image-system-tests/src/systemTest/java/org/springframework/boot/image/assertions/ImageAssert.java +++ b/system-test/spring-boot-image-system-tests/src/systemTest/java/org/springframework/boot/image/assertions/ImageAssert.java @@ -34,6 +34,7 @@ import org.springframework.boot.buildpack.platform.docker.DockerApi; import org.springframework.boot.buildpack.platform.docker.type.ImageReference; import org.springframework.boot.buildpack.platform.docker.type.Layer; import org.springframework.boot.test.json.JsonContentAssert; +import org.springframework.lang.CheckReturnValue; import org.springframework.util.StreamUtils; /** @@ -73,6 +74,7 @@ public class ImageAssert extends AbstractAssert { super(layer, LayerContentAssert.class); } + @CheckReturnValue public ListAssert entries() { List entryNames = new ArrayList<>(); try { diff --git a/test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/ScheduledExecutorServiceAssert.java b/test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/ScheduledExecutorServiceAssert.java index b9e5b075ef6..65155facd61 100644 --- a/test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/ScheduledExecutorServiceAssert.java +++ b/test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/ScheduledExecutorServiceAssert.java @@ -24,6 +24,7 @@ import java.util.concurrent.TimeUnit; import org.assertj.core.api.AbstractAssert; import org.assertj.core.api.Assert; +import org.springframework.lang.CheckReturnValue; import org.springframework.util.ReflectionUtils; /** @@ -85,6 +86,7 @@ public final class ScheduledExecutorServiceAssert * @param actual the {@link ScheduledExecutorService} * @return the assertion instance */ + @CheckReturnValue public static ScheduledExecutorServiceAssert assertThat(ScheduledExecutorService actual) { return new ScheduledExecutorServiceAssert(actual); } diff --git a/test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/SimpleAsyncTaskExecutorAssert.java b/test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/SimpleAsyncTaskExecutorAssert.java index 14a5685aec7..5104d438811 100644 --- a/test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/SimpleAsyncTaskExecutorAssert.java +++ b/test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/SimpleAsyncTaskExecutorAssert.java @@ -22,6 +22,7 @@ import org.assertj.core.api.AbstractAssert; import org.assertj.core.api.Assert; import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.lang.CheckReturnValue; import org.springframework.util.ReflectionUtils; /** @@ -77,6 +78,7 @@ public final class SimpleAsyncTaskExecutorAssert * @param actual the {@link SimpleAsyncTaskExecutor} * @return the assertion instance */ + @CheckReturnValue public static SimpleAsyncTaskExecutorAssert assertThat(SimpleAsyncTaskExecutor actual) { return new SimpleAsyncTaskExecutorAssert(actual); }