diff --git a/libraries-testing/article-resources/archunit/figure1.drawio b/libraries-testing/article-resources/archunit/figure1.drawio
new file mode 100644
index 0000000000..859d9946a1
--- /dev/null
+++ b/libraries-testing/article-resources/archunit/figure1.drawio
@@ -0,0 +1 @@
+7VjbctowEP0aP9LBNgb3sSa3BzJNJ+2kk5eMsBdbrax1ZUEgX1/Jlm84YWgbKL3wwFhHa3l99pyVwHKn6fpSkCy5xgiY5QyjteWeWY7jj331rYFNCXjOsARiQaMSshvglj6BAauwJY0g7wRKRCZp1gVD5BxC2cGIEPjYDVsg6z41IzH0gNuQsD56RyOZGNQev20mroDGiXm070zKiTkJv8YCl9w8jyOHciYl1TLmHfOERPjYgtxzy50KRFlepespMM1qxVh538ULs3XKArjc54YrsrkffLj+Bp8ePr+/GTw409XdwKyyImxpqEg3JMsYDYmkyE3mclMRpV4i05eaYRCWGyyQy1szb6txnpGQ8vgjZhoYKkSSecXpyIxrKu1RCdxgTovnuWcMFmomSGTKzJIrEFLlw94xGusIqdcOiBmZeJ3HBUkp0wqcLUMaEZX5FHmOOreAkTmwoK7WFBmK4pXcRfHRS1DGWvhF8VF4n+iKNZUYrFuQIf4SMAUpNiqkmvWMCIw/7EoUj43aJr7BkpbQRq4BiVF4XK/dlFpdmGr/QOUnvcpbzpikmlomi7dujyLIgEd5DcadEDPa0gpEymNmiEImGCMn7LxBg6IUoLPUwmhiZljKR4FfQMqNaRhkKbErjYjkSXG//ToSeLHUOS5FCDvodE3XIiIGuSPOK+M0NzuFI4ApB666/enVReD2RJCDWNEQTsL4bUMWjbXn+udbwyGFsL/nPX/L837f8874Gc/bB/P8+N/26GhPj7on5VH/KI16ponvFq7yWqiILiy/7baURlGpEcjpE5kX62mVZEi5LHjwAss7O1Tdd2m859P68Gjy7JzCnvPvYPhG7dOmX+9darPcjWagtf9POq1gYHvdFXCxyJUkt6VSJ/Xz6hn11JOpaikKT+d892e3eXuyR5v3jtrmvX7NQeQ0l8BPZGc/Vn0PeKTf3t5Hw9++vVe/pk/Z7P+d/UsV7v9eP6UD+19o64Oe2tWw+f+n3PGbv9fc8+8=
\ No newline at end of file
diff --git a/libraries-testing/article-resources/archunit/figure1.png b/libraries-testing/article-resources/archunit/figure1.png
new file mode 100644
index 0000000000..8bd8e9647b
Binary files /dev/null and b/libraries-testing/article-resources/archunit/figure1.png differ
diff --git a/libraries-testing/pom.xml b/libraries-testing/pom.xml
index 5a5cb99238..8052680ea5 100644
--- a/libraries-testing/pom.xml
+++ b/libraries-testing/pom.xml
@@ -1,7 +1,7 @@
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
libraries-testing
libraries-testing
@@ -158,6 +158,13 @@
test
+
+ com.tngtech.archunit
+ archunit-junit5
+ ${archunit.version}
+ test
+
+
@@ -193,7 +200,7 @@
1.5.7.1
- 1.9.9
+ 1.9.9
1.9.0
1.9.0
1.9.27
@@ -210,6 +217,7 @@
1.8
1.8
3.8.1
+ 0.14.1
diff --git a/libraries-testing/src/main/java/com/baldung/archunit/smurfs/persistence/SmurfsRepository.java b/libraries-testing/src/main/java/com/baldung/archunit/smurfs/persistence/SmurfsRepository.java
new file mode 100644
index 0000000000..8107e6317a
--- /dev/null
+++ b/libraries-testing/src/main/java/com/baldung/archunit/smurfs/persistence/SmurfsRepository.java
@@ -0,0 +1,49 @@
+/**
+ *
+ */
+package com.baldung.archunit.smurfs.persistence;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.TreeMap;
+
+import com.baldung.archunit.smurfs.persistence.domain.Smurf;
+
+import static java.util.stream.Collectors.toList;
+
+/**
+ * @author Philippe
+ *
+ */
+public class SmurfsRepository {
+
+ private static Map smurfs = Collections.synchronizedMap(new TreeMap<>());
+
+ static {
+ // Just a few here. A full list can be found
+ // at https://smurfs.fandom.com/wiki/List_of_Smurf_characters
+ smurfs.put("Papa", new Smurf("Papa", true, true));
+ smurfs.put("Actor", new Smurf("Actor", true, true));
+ smurfs.put("Alchemist", new Smurf("Alchemist", true, true));
+ smurfs.put("Archeologist", new Smurf("Archeologist", true, true));
+ smurfs.put("Architect", new Smurf("Architect", true, true));
+ smurfs.put("Baby", new Smurf("Baby", true, true));
+ smurfs.put("Baker", new Smurf("Baker", true, true));
+ smurfs.put("Baker", new Smurf("Baker", true, true));
+ }
+
+ public SmurfsRepository() {
+
+ }
+
+ public List findAll() {
+ return Collections.unmodifiableList(smurfs.values().stream().collect(toList()));
+ }
+
+ public Optional findByName(String name) {
+ return Optional.of(smurfs.get(name));
+ }
+
+}
diff --git a/libraries-testing/src/main/java/com/baldung/archunit/smurfs/persistence/domain/Smurf.java b/libraries-testing/src/main/java/com/baldung/archunit/smurfs/persistence/domain/Smurf.java
new file mode 100644
index 0000000000..468266cf9a
--- /dev/null
+++ b/libraries-testing/src/main/java/com/baldung/archunit/smurfs/persistence/domain/Smurf.java
@@ -0,0 +1,64 @@
+/**
+ *
+ */
+package com.baldung.archunit.smurfs.persistence.domain;
+
+/**
+ * @author Philippe
+ *
+ */
+public class Smurf {
+ private String name;
+ private boolean comic;
+ private boolean cartoon;
+
+ public Smurf() {}
+
+ public Smurf(String name, boolean comic, boolean cartoon) {
+ this.name = name;
+ this.comic = comic;
+ this.cartoon = cartoon;
+ }
+
+ /**
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @param name the name to set
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return the commic
+ */
+ public boolean isComic() {
+ return comic;
+ }
+
+ /**
+ * @param commic the commic to set
+ */
+ public void setCommic(boolean comic) {
+ this.comic = comic;
+ }
+
+ /**
+ * @return the cartoon
+ */
+ public boolean isCartoon() {
+ return cartoon;
+ }
+
+ /**
+ * @param cartoon the cartoon to set
+ */
+ public void setCartoon(boolean cartoon) {
+ this.cartoon = cartoon;
+ }
+}
diff --git a/libraries-testing/src/main/java/com/baldung/archunit/smurfs/presentation/SmurfsController.java b/libraries-testing/src/main/java/com/baldung/archunit/smurfs/presentation/SmurfsController.java
new file mode 100644
index 0000000000..c0aff4ec03
--- /dev/null
+++ b/libraries-testing/src/main/java/com/baldung/archunit/smurfs/presentation/SmurfsController.java
@@ -0,0 +1,27 @@
+package com.baldung.archunit.smurfs.presentation;
+
+import java.util.List;
+
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baldung.archunit.smurfs.service.SmurfsService;
+import com.baldung.archunit.smurfs.service.dto.SmurfDTO;
+
+@RequestMapping(value = "/smurfs", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+@RestController
+public class SmurfsController {
+
+ private SmurfsService smurfs;
+
+ public SmurfsController(SmurfsService smurfs) {
+ this.smurfs = smurfs;
+ }
+
+ @GetMapping
+ public List getSmurfs() {
+ return smurfs.findAll();
+ }
+}
diff --git a/libraries-testing/src/main/java/com/baldung/archunit/smurfs/service/SmurfsService.java b/libraries-testing/src/main/java/com/baldung/archunit/smurfs/service/SmurfsService.java
new file mode 100644
index 0000000000..40ffcc955c
--- /dev/null
+++ b/libraries-testing/src/main/java/com/baldung/archunit/smurfs/service/SmurfsService.java
@@ -0,0 +1,41 @@
+/**
+ *
+ */
+package com.baldung.archunit.smurfs.service;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.springframework.stereotype.Component;
+
+import com.baldung.archunit.smurfs.persistence.SmurfsRepository;
+import com.baldung.archunit.smurfs.persistence.domain.Smurf;
+import com.baldung.archunit.smurfs.service.dto.SmurfDTO;
+
+/**
+ * @author Philippe
+ *
+ */
+@Component
+public class SmurfsService {
+
+ private SmurfsRepository repository;
+
+ public SmurfsService(SmurfsRepository repository) {
+ this.repository = repository;
+ }
+
+ public List findAll() {
+
+ return repository.findAll()
+ .stream()
+ .map(SmurfsService::toDTO)
+ .collect(Collectors.toList());
+ }
+
+
+ public static SmurfDTO toDTO(Smurf smurf) {
+ return new SmurfDTO(smurf.getName(),smurf.isComic(), smurf.isCartoon());
+ }
+
+}
diff --git a/libraries-testing/src/main/java/com/baldung/archunit/smurfs/service/dto/SmurfDTO.java b/libraries-testing/src/main/java/com/baldung/archunit/smurfs/service/dto/SmurfDTO.java
new file mode 100644
index 0000000000..3c49262f9d
--- /dev/null
+++ b/libraries-testing/src/main/java/com/baldung/archunit/smurfs/service/dto/SmurfDTO.java
@@ -0,0 +1,64 @@
+/**
+ *
+ */
+package com.baldung.archunit.smurfs.service.dto;
+
+import com.baldung.archunit.smurfs.persistence.domain.Smurf;
+
+/**
+ * @author Philippe
+ *
+ */
+public class SmurfDTO {
+ private String name;
+ private boolean comic;
+ private boolean cartoon;
+
+ public SmurfDTO() {}
+
+ public SmurfDTO(String name, boolean comic, boolean cartoon) {
+ this.name = name;
+ this.comic = comic;
+ this.cartoon = cartoon;
+ }
+
+
+ /**
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+ /**
+ * @param name the name to set
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+ /**
+ * @return the commic
+ */
+ public boolean isComic() {
+ return comic;
+ }
+ /**
+ * @param commic the commic to set
+ */
+ public void setCommic(boolean comic) {
+ this.comic = comic;
+ }
+ /**
+ * @return the cartoon
+ */
+ public boolean isCartoon() {
+ return cartoon;
+ }
+ /**
+ * @param cartoon the cartoon to set
+ */
+ public void setCartoon(boolean cartoon) {
+ this.cartoon = cartoon;
+ }
+
+
+}
diff --git a/libraries-testing/src/test/java/com/baeldung/archunit/smurfs/SmurfsArchUnitTest.java b/libraries-testing/src/test/java/com/baeldung/archunit/smurfs/SmurfsArchUnitTest.java
new file mode 100644
index 0000000000..b0c4397794
--- /dev/null
+++ b/libraries-testing/src/test/java/com/baeldung/archunit/smurfs/SmurfsArchUnitTest.java
@@ -0,0 +1,92 @@
+/**
+ *
+ */
+package com.baeldung.archunit.smurfs;
+
+
+import com.tngtech.archunit.core.domain.JavaClasses;
+import com.tngtech.archunit.core.importer.ClassFileImporter;
+import com.tngtech.archunit.lang.ArchRule;
+import com.tngtech.archunit.library.Architectures.LayeredArchitecture;
+
+import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
+import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
+import static com.tngtech.archunit.library.Architectures.layeredArchitecture;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * @author Philippe
+ *
+ */
+public class SmurfsArchUnitTest {
+
+ @Test
+ public void givenPresentationLayerClasses_thenWrongCheckFails() {
+ JavaClasses jc = new ClassFileImporter().importPackages("com.baldung.archunit.smurfs");
+
+ ArchRule r1 = classes()
+ .that()
+ .resideInAPackage("..presentation..")
+ .should()
+ .onlyDependOnClassesThat()
+ .resideInAPackage("..service..");
+
+ assertThrows(AssertionError.class, ()-> r1.check(jc)) ;
+ }
+
+
+ @Test
+ public void givenPresentationLayerClasses_thenCheckWithFrameworkDependenciesSuccess() {
+ JavaClasses jc = new ClassFileImporter().importPackages("com.baldung.archunit.smurfs");
+
+ ArchRule r1 = classes()
+ .that()
+ .resideInAPackage("..presentation..")
+ .should()
+ .onlyDependOnClassesThat()
+ .resideInAnyPackage("..service..", "java..", "javax..", "org.springframework..");
+
+ r1.check(jc);
+ }
+
+ @Test
+ public void givenPresentationLayerClasses_thenNoPersistenceLayerAccess() {
+ JavaClasses jc = new ClassFileImporter().importPackages("com.baldung.archunit.smurfs");
+
+ ArchRule r1 = noClasses()
+ .that()
+ .resideInAPackage("..presentation..")
+ .should()
+ .dependOnClassesThat()
+ .resideInAPackage("..persistence..");
+
+
+ r1.check(jc);
+ }
+
+ @Test
+ public void givenApplicationClasses_thenNoLayerViolationsShouldExist() {
+
+ JavaClasses jc = new ClassFileImporter().importPackages("com.baldung.archunit.smurfs");
+
+ LayeredArchitecture arch = layeredArchitecture()
+ // Define layers
+ .layer("Presentation").definedBy("..presentation..")
+ .layer("Service").definedBy("..service..")
+ .layer("Persistence").definedBy("..persistence..")
+ // Add constraints
+ .whereLayer("Presentation").mayNotBeAccessedByAnyLayer()
+ .whereLayer("Service").mayOnlyBeAccessedByLayers("Presentation")
+ .whereLayer("Persistence").mayOnlyBeAccessedByLayers("Service");
+
+
+ arch.check(jc);
+
+ }
+
+
+
+}