-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add rule SpringBootRules.AllTypesInApplicationPackage
- Loading branch information
1 parent
567bd2b
commit b7cf1dc
Showing
8 changed files
with
177 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
src/main/java/de/rweisleder/archunit/spring/SpringBootRules.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package de.rweisleder.archunit.spring; | ||
|
||
import com.tngtech.archunit.core.domain.JavaClass; | ||
import com.tngtech.archunit.lang.ArchCondition; | ||
import com.tngtech.archunit.lang.ArchRule; | ||
import com.tngtech.archunit.lang.ConditionEvents; | ||
import com.tngtech.archunit.lang.conditions.ArchConditions; | ||
import org.springframework.boot.SpringBootConfiguration; | ||
|
||
import java.util.Collection; | ||
import java.util.List; | ||
|
||
import static com.tngtech.archunit.lang.conditions.ArchConditions.resideInAnyPackage; | ||
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; | ||
import static de.rweisleder.archunit.spring.MergedAnnotationPredicates.springAnnotatedWith; | ||
import static java.util.stream.Collectors.toList; | ||
|
||
/** | ||
* Collection of {@link ArchRule rules} that can be used to check the structure of Spring Boot applications. | ||
* | ||
* @author Roland Weisleder | ||
*/ | ||
public class SpringBootRules { | ||
|
||
/** | ||
* A rule that checks that all classes are located in the same package or a sub-package of the application class. | ||
* The application class is the one annotated with {@code @SpringBootApplication} or {@code @SpringBootConfiguration} | ||
* and must be within the given classes. | ||
* | ||
* @see #beInApplicationPackage() | ||
*/ | ||
public static final ArchRule AllTypesInApplicationPackage = classes() | ||
.should(beInApplicationPackage()) | ||
.as("all types of a Spring Boot application should be located in the same package or a sub-package of the application class"); | ||
|
||
/** | ||
* A condition that checks that the given classes are located in the same package or a sub-package of the application class. | ||
* The application class is the one annotated with {@code @SpringBootApplication} or {@code @SpringBootConfiguration} | ||
* and must be within the given classes. | ||
* <p> | ||
* In case the application class is not within the given classes, consider using {@link ArchConditions#resideInAnyPackage(String...)} directly. | ||
* | ||
* @see #AllTypesInApplicationPackage | ||
*/ | ||
public static ArchCondition<JavaClass> beInApplicationPackage() { | ||
return new ArchCondition<JavaClass>("be located in the same package or a sub-package of the application class") { | ||
|
||
private ArchCondition<JavaClass> inApplicationPackageCondition; | ||
|
||
@Override | ||
public void init(Collection<JavaClass> javaClasses) { | ||
List<JavaClass> springBootApplicationClasses = javaClasses.stream() | ||
.filter(springAnnotatedWith(SpringBootConfiguration.class)) | ||
.collect(toList()); | ||
|
||
if (springBootApplicationClasses.isEmpty()) { | ||
throw new AssertionError("Could not locate a class annotated with @SpringBootApplication or @SpringBootConfiguration"); | ||
} | ||
|
||
String[] applicationPackageIdentifiers = springBootApplicationClasses.stream() | ||
.map(javaClass -> javaClass.getPackageName() + "..") | ||
.distinct().toArray(String[]::new); | ||
inApplicationPackageCondition = resideInAnyPackage(applicationPackageIdentifiers); | ||
} | ||
|
||
@Override | ||
public void check(JavaClass javaClass, ConditionEvents events) { | ||
inApplicationPackageCondition.check(javaClass, events); | ||
} | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
src/test/java/de/rweisleder/archunit/spring/SpringBootRulesTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package de.rweisleder.archunit.spring; | ||
|
||
import com.tngtech.archunit.core.domain.JavaClasses; | ||
import com.tngtech.archunit.lang.EvaluationResult; | ||
import de.rweisleder.archunit.spring.testclasses.boot.app1.FirstSpringBootApplication; | ||
import de.rweisleder.archunit.spring.testclasses.boot.app1.subpackage.FirstAppClassInSubpackage; | ||
import de.rweisleder.archunit.spring.testclasses.boot.app2.SecondSpringBootApplication; | ||
import org.junit.jupiter.api.Nested; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static de.rweisleder.archunit.spring.TestUtils.importClasses; | ||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
|
||
class SpringBootRulesTest { | ||
|
||
@Nested | ||
class Rule_AllTypesInApplicationPackage { | ||
|
||
@Test | ||
void provides_a_description() { | ||
String description = SpringBootRules.AllTypesInApplicationPackage.getDescription(); | ||
assertThat(description).isEqualTo("all types of a Spring Boot application should be located in the same package or a sub-package of the application class"); | ||
} | ||
|
||
@Test | ||
void has_no_violation_if_all_classes_are_in_application_package_or_subpackage() { | ||
JavaClasses classes = importClasses(FirstSpringBootApplication.class, FirstAppClassInSubpackage.class); | ||
EvaluationResult evaluationResult = SpringBootRules.AllTypesInApplicationPackage.evaluate(classes); | ||
assertThat(evaluationResult.hasViolation()).isFalse(); | ||
} | ||
|
||
@Test | ||
void has_violation_for_class_outside_application_package() { | ||
Class<?> classOutsideApplicationPackage = String.class; | ||
JavaClasses classes = importClasses(FirstSpringBootApplication.class, classOutsideApplicationPackage); | ||
EvaluationResult evaluationResult = SpringBootRules.AllTypesInApplicationPackage.evaluate(classes); | ||
assertThat(evaluationResult.hasViolation()).isTrue(); | ||
assertThat(evaluationResult.getFailureReport().getDetails()).anySatisfy(detail -> { | ||
assertThat(detail).contains(classOutsideApplicationPackage.getName(), "does not reside in any package"); | ||
}); | ||
} | ||
|
||
@Test | ||
void fails_if_classes_do_not_contain_a_Spring_Boot_application() { | ||
JavaClasses classes = importClasses(String.class); | ||
assertThatThrownBy(() -> SpringBootRules.AllTypesInApplicationPackage.evaluate(classes)) | ||
.isInstanceOf(AssertionError.class) | ||
.hasMessageContaining("Could not locate a class annotated with @SpringBootApplication or @SpringBootConfiguration"); | ||
} | ||
|
||
@Test | ||
void has_no_violation_if_classes_contain_multiple_distinct_Spring_Boot_applications() { | ||
JavaClasses classes = importClasses(FirstSpringBootApplication.class, SecondSpringBootApplication.class); | ||
EvaluationResult evaluationResult = SpringBootRules.AllTypesInApplicationPackage.evaluate(classes); | ||
assertThat(evaluationResult.hasViolation()).isFalse(); | ||
} | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
src/test/java/de/rweisleder/archunit/spring/TestUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package de.rweisleder.archunit.spring; | ||
|
||
import com.tngtech.archunit.core.domain.JavaClass; | ||
import com.tngtech.archunit.core.domain.JavaClasses; | ||
import com.tngtech.archunit.core.importer.ClassFileImporter; | ||
|
||
public class TestUtils { | ||
|
||
public static JavaClasses importClasses(Class<?>... classes) { | ||
return new ClassFileImporter().importClasses(classes); | ||
} | ||
|
||
public static JavaClass importClass(Class<?> classToImport) { | ||
return new ClassFileImporter().importClass(classToImport); | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
.../java/de/rweisleder/archunit/spring/testclasses/boot/app1/FirstSpringBootApplication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package de.rweisleder.archunit.spring.testclasses.boot.app1; | ||
|
||
import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
|
||
@SpringBootApplication | ||
public class FirstSpringBootApplication { | ||
} |
4 changes: 4 additions & 0 deletions
4
...weisleder/archunit/spring/testclasses/boot/app1/subpackage/FirstAppClassInSubpackage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package de.rweisleder.archunit.spring.testclasses.boot.app1.subpackage; | ||
|
||
public class FirstAppClassInSubpackage { | ||
} |
7 changes: 7 additions & 0 deletions
7
...java/de/rweisleder/archunit/spring/testclasses/boot/app2/SecondSpringBootApplication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package de.rweisleder.archunit.spring.testclasses.boot.app2; | ||
|
||
import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
|
||
@SpringBootApplication | ||
public class SecondSpringBootApplication { | ||
} |