diff --git a/pom.xml b/pom.xml index 7ec86c87a..17e9520f2 100644 --- a/pom.xml +++ b/pom.xml @@ -335,9 +335,9 @@ - de.schauderhaft.degraph - degraph-check - 0.1.4 + com.tngtech.archunit + archunit + ${archunit} test diff --git a/src/main/java/org/springframework/data/repository/config/AotRepositoryInformation.java b/src/main/java/org/springframework/data/repository/config/AotRepositoryInformation.java index e9ba3ad70..b2faf62e4 100644 --- a/src/main/java/org/springframework/data/repository/config/AotRepositoryInformation.java +++ b/src/main/java/org/springframework/data/repository/config/AotRepositoryInformation.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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, diff --git a/src/main/java/org/springframework/data/repository/config/DefaultAotRepositoryContext.java b/src/main/java/org/springframework/data/repository/config/DefaultAotRepositoryContext.java index f9769fd09..74e8ad1c1 100644 --- a/src/main/java/org/springframework/data/repository/config/DefaultAotRepositoryContext.java +++ b/src/main/java/org/springframework/data/repository/config/DefaultAotRepositoryContext.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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, diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionReader.java b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionReader.java index 89d52970e..ff4c6a001 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionReader.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionReader.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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, diff --git a/src/test/java/org/springframework/data/DependencyTests.java b/src/test/java/org/springframework/data/DependencyTests.java index 8a3e7a511..fd1eaf0bf 100644 --- a/src/test/java/org/springframework/data/DependencyTests.java +++ b/src/test/java/org/springframework/data/DependencyTests.java @@ -15,29 +15,122 @@ */ package org.springframework.data; -import static de.schauderhaft.degraph.check.JCheck.*; -import static org.junit.Assert.*; +import static org.assertj.core.api.Assertions.*; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.springframework.data.repository.core.RepositoryMetadata; + +import com.tngtech.archunit.base.DescribedPredicate; +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.lang.ArchRule; +import com.tngtech.archunit.library.dependencies.SlicesRuleDefinition; /** + * Tests for package and slice cycles. All packages that have the same start including the part after {@literal data} + * are considered one slice. For example {@literal org.springframework.data.repository} and + * {@literal org.springframework.data.repository.support} are part of the same slice {@literal repository}. + * * @author Jens Schauder */ -@Disabled("Requires newer version of ASM 5.1") public class DependencyTests { - @Test - public void noInternalPackageCycles() { + JavaClasses importedClasses = new ClassFileImporter() // + .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS) // + .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_JARS) // we just analyze the code of this module. + .importPackages("org.springframework.data") // + .that(onlySpringData()) // - assertThat( - classpath() // - .noJars() // - .including("org.springframework.data.**") // - .filterClasspath("*target/classes") // - .printOnFailure("degraph.graphml"), // - violationFree() // - ); + // new cycle + .that(ignore(RepositoryMetadata.class)); + + @Test + void cycleFreeSlices() { + + ArchRule rule = SlicesRuleDefinition.slices() // + .matching("org.springframework.data.(*)..") // + .should() // + .beFreeOfCycles(); + + rule.check(importedClasses); + } + + @Test + void cycleFreePackages() { + + ArchRule rule = SlicesRuleDefinition.slices() // + .matching("org.springframework.data.(**)") // + .should() // + .beFreeOfCycles(); + + rule.check(importedClasses); + } + + @Test + void testGetFirstPackagePart() { + + assertThat(getFirstPackagePart("a.b.c")).isEqualTo("a"); + assertThat(getFirstPackagePart("a")).isEqualTo("a"); + } + + @Test + void testSubModule() { + + assertThat(subModule("a.b", "a.b.c.d")).isEqualTo("c"); + assertThat(subModule("a.b", "a.b.c")).isEqualTo("c"); + assertThat(subModule("a.b", "a.b")).isEqualTo(""); + } + + private DescribedPredicate onlySpringData() { + + return new DescribedPredicate<>("Spring Data Classes") { + @Override + public boolean test(JavaClass input) { + return input.getPackageName().startsWith("org.springframework.data"); + } + }; + } + + private DescribedPredicate ignore(Class type) { + + return new DescribedPredicate<>("ignored class " + type.getName()) { + @Override + public boolean test(JavaClass input) { + return !input.getFullName().startsWith(type.getName()); + } + }; + } + + private DescribedPredicate ignorePackage(String type) { + + return new DescribedPredicate<>("ignored class " + type) { + @Override + public boolean test(JavaClass input) { + return !input.getPackageName().equals(type); + } + }; + } + + private String getFirstPackagePart(String subpackage) { + + int index = subpackage.indexOf("."); + if (index < 0) { + return subpackage; + } + return subpackage.substring(0, index); + } + + private String subModule(String basePackage, String packageName) { + + if (packageName.startsWith(basePackage) && packageName.length() > basePackage.length()) { + + final int index = basePackage.length() + 1; + String subpackage = packageName.substring(index); + return getFirstPackagePart(subpackage); + } + return ""; } }