diff --git a/pom.xml b/pom.xml
index b2d4b1d1a..1399a7fc4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -41,7 +41,7 @@
4.2.0
- 0.23.1
+ 1.0.0
2017
diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/DependencyTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/DependencyTests.java
index e5e0c5625..cdd296a69 100644
--- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/DependencyTests.java
+++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/DependencyTests.java
@@ -16,7 +16,6 @@
package org.springframework.data.jdbc;
import org.assertj.core.api.SoftAssertions;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.data.auditing.config.AuditingHandlerBeanDefinitionParser;
@@ -43,10 +42,9 @@ public class DependencyTests {
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.jdbc")
- .that( //
- onlySpringData() //
- );
+ .importPackages("org.springframework.data.jdbc").that( //
+ onlySpringData() //
+ );
ArchRule rule = SlicesRuleDefinition.slices() //
.matching("org.springframework.data.jdbc.(**)") //
@@ -57,17 +55,17 @@ public class DependencyTests {
}
@Test
- @Disabled("Cycle in Spring Data Commons")
void acrossModules() {
- JavaClasses importedClasses = new ClassFileImporter()
- .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
+ JavaClasses importedClasses = new ClassFileImporter().withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
.importPackages( //
"org.springframework.data.jdbc", // Spring Data Relational
"org.springframework.data.relational", // Spring Data Relational
"org.springframework.data" // Spring Data Commons
).that(onlySpringData()) //
- .that(ignore(AuditingHandlerBeanDefinitionParser.class));
+ .that(ignore(AuditingHandlerBeanDefinitionParser.class)) //
+ .that(ignorePackage("org.springframework.data.aot.hint")) // ignoring aot, since it causes cycles in commons
+ .that(ignorePackage("org.springframework.data.aot")); // ignoring aot, since it causes cycles in commons
ArchRule rule = SlicesRuleDefinition.slices() //
.assignedFrom(subModuleSlicing()) //
@@ -99,7 +97,7 @@ public class DependencyTests {
return new DescribedPredicate<>("Spring Data Classes") {
@Override
- public boolean apply(JavaClass input) {
+ public boolean test(JavaClass input) {
return input.getPackageName().startsWith("org.springframework.data");
}
};
@@ -109,12 +107,22 @@ public class DependencyTests {
return new DescribedPredicate<>("ignored class " + type.getName()) {
@Override
- public boolean apply(JavaClass input) {
+ 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(".");
diff --git a/spring-data-r2dbc/pom.xml b/spring-data-r2dbc/pom.xml
index 14d7909d7..9bd821ef3 100644
--- a/spring-data-r2dbc/pom.xml
+++ b/spring-data-r2dbc/pom.xml
@@ -306,6 +306,12 @@
test
+
+ com.tngtech.archunit
+ archunit
+ ${archunit.version}
+ test
+
diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/DependencyTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/DependencyTests.java
index 51a0006e2..aaa399fd7 100644
--- a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/DependencyTests.java
+++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/DependencyTests.java
@@ -15,17 +15,20 @@
*/
package org.springframework.data.r2dbc;
-import static de.schauderhaft.degraph.check.JCheck.*;
-import static org.junit.Assert.*;
-
-import de.schauderhaft.degraph.check.JCheck;
-import de.schauderhaft.degraph.configuration.NamedPattern;
-import scala.runtime.AbstractFunction1;
-
-import org.junit.Assume;
+import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
+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.SliceAssignment;
+import com.tngtech.archunit.library.dependencies.SliceIdentifier;
+import com.tngtech.archunit.library.dependencies.SlicesRuleDefinition;
+
/**
* Test package dependencies for violations.
*
@@ -35,40 +38,131 @@ import org.junit.jupiter.api.Test;
public class DependencyTests {
@Test // DATAJDBC-114
- public void cycleFree() {
-
- Assume.assumeThat( //
- classpath() //
- .noJars() //
- .including("org.springframework.data.jdbc.**") //
- .including("org.springframework.data.relational.**") //
- .including("org.springframework.data.r2dbc.**") //
- .filterClasspath("*target/classes") // exclude test code
- .withSlicing("modules", "org.springframework.data.(*).**").printOnFailure("degraph.graphml"),
- JCheck.violationFree());
+ void cycleFree() {
+
+ 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.r2dbc").that( //
+ onlySpringData() //
+ );
+
+ ArchRule rule = SlicesRuleDefinition.slices() //
+ .matching("org.springframework.data.r2dbc.(**)") //
+ .should() //
+ .beFreeOfCycles();
+
+ rule.check(importedClasses);
}
@Test // DATAJDBC-220
- public void acrossModules() {
-
- assertThat( //
- classpath() //
- // include only Spring Data related classes (for example no JDK code)
- .including("org.springframework.data.**") //
- .filterClasspath(new AbstractFunction1() {
- @Override
- public Object apply(String s) { //
- // only the current module + commons
- return s.endsWith("target/classes") || s.contains("spring-data-commons");
- }
- }) // exclude test code
- .withSlicing("sub-modules", // sub-modules are defined by any of the following pattern.
- "org.springframework.data.jdbc.(**).*", //
- "org.springframework.data.relational.(**).*", //
- new NamedPattern("org.springframework.data.r2dbc.**", "repository.reactive"), //
- "org.springframework.data.(**).*") //
- .printTo("degraph-across-modules.graphml"), // writes a graphml to this location
- JCheck.violationFree());
+ void acrossModules() {
+
+ JavaClasses importedClasses = new ClassFileImporter().withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
+ .importPackages( //
+ "org.springframework.data.r2dbc", // Spring Data Relational
+ "org.springframework.data.relational", // Spring Data Relational
+ "org.springframework.data" // Spring Data Commons
+ ).that(onlySpringData()) //
+ .that(ignorePackage("org.springframework.data.aot.hint")) // ignoring aot, since it causes cycles in commons
+ .that(ignorePackage("org.springframework.data.aot")); // ignoring aot, since it causes cycles in commons
+
+ ArchRule rule = SlicesRuleDefinition.slices() //
+ .assignedFrom(subModuleSlicing()) //
+ .should().beFreeOfCycles();
+
+ rule.check(importedClasses);
+ }
+
+ @Test // GH-1058
+ void testGetFirstPackagePart() {
+
+ SoftAssertions.assertSoftly(softly -> {
+ softly.assertThat(getFirstPackagePart("a.b.c")).isEqualTo("a");
+ softly.assertThat(getFirstPackagePart("a")).isEqualTo("a");
+ });
+ }
+
+ 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 "";
+ }
+
+ private SliceAssignment subModuleSlicing() {
+ return new SliceAssignment() {
+
+ @Override
+ public SliceIdentifier getIdentifierOf(JavaClass javaClass) {
+
+ String packageName = javaClass.getPackageName();
+
+ String subModule = subModule("org.springframework.data.jdbc", packageName);
+ if (!subModule.isEmpty()) {
+ return SliceIdentifier.of(subModule);
+ }
+
+ subModule = subModule("org.springframework.data.relational", packageName);
+ if (!subModule.isEmpty()) {
+ return SliceIdentifier.of(subModule);
+ }
+
+ subModule = subModule("org.springframework.data", packageName);
+ if (!subModule.isEmpty()) {
+ return SliceIdentifier.of(subModule);
+ }
+
+ return SliceIdentifier.ignore();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Submodule";
+ }
+ };
+ }
}
diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/DependencyTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/DependencyTests.java
index a98b24423..716d1a5eb 100644
--- a/spring-data-relational/src/test/java/org/springframework/data/relational/DependencyTests.java
+++ b/spring-data-relational/src/test/java/org/springframework/data/relational/DependencyTests.java
@@ -16,7 +16,6 @@
package org.springframework.data.relational;
import org.assertj.core.api.SoftAssertions;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.data.relational.core.dialect.RenderContextFactory;
import org.springframework.data.relational.core.sql.render.SelectRenderContext;
@@ -59,7 +58,6 @@ public class DependencyTests {
}
@Test
- @Disabled("Cycle in Spring Data Commons")
void acrossModules() {
JavaClasses importedClasses = new ClassFileImporter() //
@@ -67,8 +65,9 @@ public class DependencyTests {
.importPackages( //
"org.springframework.data.relational", // Spring Data Relational
"org.springframework.data" // Spring Data Commons
- ).that(onlySpringData());
-
+ ).that(onlySpringData()) //
+ .that(ignorePackage("org.springframework.data.aot.hint")) // ignoring aot, since it causes cycles in commons
+ .that(ignorePackage("org.springframework.data.aot")); // ignoring aot, since it causes cycles in commons;
ArchRule rule = SlicesRuleDefinition.slices() //
.assignedFrom(subModuleSlicing()) //
@@ -100,7 +99,7 @@ public class DependencyTests {
return new DescribedPredicate<>("Spring Data Classes") {
@Override
- public boolean apply(JavaClass input) {
+ public boolean test(JavaClass input) {
return input.getPackageName().startsWith("org.springframework.data");
}
};
@@ -110,12 +109,22 @@ public class DependencyTests {
return new DescribedPredicate<>("ignored class " + type.getName()) {
@Override
- public boolean apply(JavaClass input) {
+ 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(".");