#1119 - Avoid reference to spring-webmvc in configuration for RestTemplate.

RestTemplateHateoasConfiguration previously referred to HypermediaWebMvcConfigurer which is turn depending on WebMvcConfigurer, a type living in spring-webmvc. The very former would still get active in WebFlux as the web stack is selected based on the presence of either DispatcherServlet or DispatcherHandler. This is now resolved by using a WebMvcConverter indrection to handle the configuration tweaks avoiding the reference to interfaces from spring-webmvc.

Introduced an ArchUnit based test that Spring HATEOAS code only depends on Spring types containing references to reactive types from either the ….reactive package or classes starting with WebFlux.
This commit is contained in:
Oliver Drotbohm
2019-11-09 09:04:55 -06:00
parent 5444e14017
commit 5f016d6c9e
5 changed files with 250 additions and 38 deletions

View File

@@ -15,25 +15,36 @@
*/
package org.springframework.hateoas;
import org.junit.jupiter.api.Test;
import static com.tngtech.archunit.core.domain.JavaClass.Predicates.*;
import static org.springframework.hateoas.ArchitectureTest.Architecture.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.springframework.lang.Nullable;
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.Dependency;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.core.importer.ImportOption;
import com.tngtech.archunit.core.importer.ImportOptions;
import com.tngtech.archunit.lang.syntax.ArchRuleDefinition;
import com.tngtech.archunit.library.dependencies.SliceRule;
import com.tngtech.archunit.library.dependencies.SlicesRuleDefinition;
/**
* Tests to verify certain architectural assumptions.
*
* @author Oliver Gierke
* @author Oliver Drotbohm
*/
@TestInstance(Lifecycle.PER_CLASS)
class ArchitectureTest {
ImportOptions options = new ImportOptions().with(ImportOption.Predefined.DONT_INCLUDE_TESTS);
JavaClasses classes = new ClassFileImporter(options) //
.importPackages("org.springframework.hateoas");
.importPackages("org.springframework.hateoas", "org.springframework");
@Test
void assertNoCyclicPackageDependencies() {
@@ -44,4 +55,58 @@ class ArchitectureTest {
rule.check(classes);
}
@Test // #1119
void onlyReactivePackagesReferToReactiveTypesInSpringFramework() {
DescribedPredicate<JavaClass> areSpringFrameworkClassesWithReactiveDependency = JavaClass.Predicates
.resideInAnyPackage("org.springframework..") //
.and(JavaClass.Predicates.resideOutsideOfPackage("..hateoas..")) //
.and(dependsOn(reactiveType()));
ArchRuleDefinition.noClasses().that() //
.resideInAnyPackage("org.springframework.hateoas..") //
.and().resideOutsideOfPackages("..reactive") //
.and().haveSimpleNameNotStartingWith("WebFlux") //
.and().haveSimpleNameNotStartingWith("WebClient") //
.should().dependOnClassesThat(areSpringFrameworkClassesWithReactiveDependency) //
.check(classes);
}
static class Architecture {
public static DescribedPredicate<JavaClass> hasWebFluxPrefix() {
return simpleNameStartingWith("WebClient").or(simpleNameStartingWith("WebFlux"));
}
public static DescribedPredicate<JavaClass> reactorType() {
return resideInAPackage("reactor..");
}
public static DescribedPredicate<JavaClass> reactiveStreamsType() {
return resideInAPackage("org.reactivestreams..");
}
public static DescribedPredicate<JavaClass> reactiveType() {
return reactorType().or(reactiveStreamsType());
}
public static DescribedPredicate<JavaClass> dependsOn(DescribedPredicate<JavaClass> predicate) {
return new DescribedPredicate<JavaClass>("depends on reactive types") {
/*
* (non-Javadoc)
* @see com.tngtech.archunit.base.DescribedPredicate#apply(java.lang.Object)
*/
@Override
public boolean apply(@Nullable JavaClass input) {
return input != null && input.getDirectDependenciesFromSelf().stream() //
.map(Dependency::getTargetClass) //
.anyMatch(predicate::apply);
}
};
}
}
}