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); + + } + + + +}