├── .github
└── workflows
│ └── build.yml
├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── docs
├── binaries.md
├── building.md
├── changelog.md
├── component-finder.md
├── dot.md
├── images
│ ├── graphviz-getting-started.png
│ ├── graphviz-spring-petclinic-components.png
│ ├── spring-petclinic-1.png
│ ├── spring-petclinic-plantuml.png
│ ├── structurizr-annotations-1.png
│ ├── structurizr-banner.png
│ ├── structurizr-logo.png
│ ├── supporting-types-1.png
│ ├── supporting-types-2.png
│ ├── supporting-types-3.png
│ ├── supporting-types-4.png
│ ├── supporting-types-5.png
│ ├── supporting-types-6.gif
│ ├── supporting-types-7.png
│ ├── supporting-types-8.png
│ └── websequencediagrams-1.png
├── spring-component-finder-strategies.md
├── spring-petclinic.md
├── structurizr-annotations.md
├── supplementing-from-source-code.md
├── supporting-types.md
└── type-matchers.md
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
├── structurizr-adr-tools
└── README.md
├── structurizr-analysis
├── build.gradle
├── src
│ └── com
│ │ └── structurizr
│ │ └── analysis
│ │ ├── AbstractComponentFinderStrategy.java
│ │ ├── AbstractTypeMatcher.java
│ │ ├── AnnotatedMethodComponentFinderStrategy.java
│ │ ├── AnnotationTypeMatcher.java
│ │ ├── ComponentFinder.java
│ │ ├── ComponentFinderStrategy.java
│ │ ├── DefaultTypeRepository.java
│ │ ├── DuplicateComponentException.java
│ │ ├── DuplicateComponentStrategy.java
│ │ ├── ExtendsClassTypeMatcher.java
│ │ ├── FirstImplementationOfInterfaceSupportingTypesStrategy.java
│ │ ├── IgnoreDuplicateComponentStrategy.java
│ │ ├── ImplementsInterfaceTypeMatcher.java
│ │ ├── JavadocCommentFilter.java
│ │ ├── NameSuffixTypeMatcher.java
│ │ ├── ReferencedTypesInSamePackageSupportingTypesStrategy.java
│ │ ├── ReferencedTypesSupportingTypesStrategy.java
│ │ ├── RegexTypeMatcher.java
│ │ ├── SourceCodeComponentFinderStrategy.java
│ │ ├── StructurizrAnnotationsComponentFinderStrategy.java
│ │ ├── SupportingTypesStrategy.java
│ │ ├── ThrowExceptionDuplicateComponentStrategy.java
│ │ ├── TypeCategory.java
│ │ ├── TypeMatcher.java
│ │ ├── TypeMatcherComponentFinderStrategy.java
│ │ ├── TypeRepository.java
│ │ ├── TypeUtils.java
│ │ └── TypeVisibility.java
└── test
│ └── unit
│ ├── com
│ └── structurizr
│ │ ├── AbstractWorkspaceTestBase.java
│ │ └── analysis
│ │ ├── AbstractComponentFinderStrategyTests.java
│ │ ├── AnnotatedMethodComponentFinderStrategyTest.java
│ │ ├── AnnotationTypeMatcherTests.java
│ │ ├── ComponentFinderTests.java
│ │ ├── DefaultTypeRepositoryTests.java
│ │ ├── ExtendsClassTypeMatcherTests.java
│ │ ├── ImplementsInterfaceTypeMatcherTests.java
│ │ ├── JavadocCommentFilterTests.java
│ │ ├── NameSuffixTypeMatcherTests.java
│ │ ├── RegexTypeMatcherTests.java
│ │ ├── SourceCodeComponentFinderStrategyTests.java
│ │ ├── StructurizrAnnotationsComponentFinderStrategyTests.java
│ │ ├── TypeMatcherComponentFinderStrategyTests.java
│ │ ├── TypeUtilsTests.java
│ │ └── reflections
│ │ ├── AbstractComponentFinderStrategyTests.java
│ │ ├── cyclicDependency
│ │ ├── AComponent.java
│ │ └── BComponent.java
│ │ ├── dependenciesFromSuperClass
│ │ ├── ComponentBase.java
│ │ ├── LoggingComponent.java
│ │ └── SomeComponent.java
│ │ ├── featureinterface
│ │ ├── FeatureInterface.java
│ │ ├── OtherComponent.java
│ │ └── SomeComponent.java
│ │ ├── multipleComponentFinders
│ │ ├── package1
│ │ │ └── MyController.java
│ │ └── package2
│ │ │ └── MyRepository.java
│ │ └── supportingTypes
│ │ └── myapp
│ │ ├── AbstractComponent.java
│ │ ├── data
│ │ ├── MyRepository.java
│ │ ├── MyRepositoryImpl.java
│ │ └── MyRepositoryRowMapper.java
│ │ ├── util
│ │ └── RowMapperHelper.java
│ │ └── web
│ │ └── MyController.java
│ └── test
│ ├── AnnotatedMethodComponentFinderStrategy
│ ├── main
│ │ ├── Bean.java
│ │ ├── Configuration.java
│ │ ├── FakeComponent.java
│ │ ├── FakeComponentImpl.java
│ │ ├── FakeConfiguration.java
│ │ ├── FakeEfferentComponentImpl.java
│ │ └── SecondFakeConfiguration.java
│ └── other
│ │ └── OtherConfiguration.java
│ ├── DefaultTypeRepository
│ ├── SomeAbstractClass.java
│ ├── SomeClass.java
│ ├── SomeEnum.java
│ └── SomeInterface.java
│ ├── MoreDefaultTypeRepository
│ └── AnotherClass.java
│ ├── SourceCodeComponentFinderStrategy
│ ├── SomeComponent.java
│ └── SomeComponentImpl.java
│ ├── StructurizrAnnotationsComponentFinderStrategy
│ ├── Controller.java
│ ├── Repository.java
│ └── RepositoryImpl.java
│ ├── TypeMatcherComponentFinderStrategy
│ ├── MyController.java
│ ├── MyRepository.java
│ └── MyRepositoryImpl.java
│ └── TypeUtils
│ ├── AnotherClass.java
│ ├── SomeAbstractClass.java
│ ├── SomeClass.java
│ ├── SomeEnum.java
│ └── SomeInterface.java
├── structurizr-annotations
├── build.gradle
└── src
│ └── com
│ └── structurizr
│ └── annotation
│ ├── Component.java
│ ├── UsedByContainer.java
│ ├── UsedByContainers.java
│ ├── UsedByPeople.java
│ ├── UsedByPerson.java
│ ├── UsedBySoftwareSystem.java
│ ├── UsedBySoftwareSystems.java
│ ├── UsesComponent.java
│ ├── UsesContainer.java
│ ├── UsesContainers.java
│ ├── UsesSoftwareSystem.java
│ └── UsesSoftwareSystems.java
├── structurizr-dot
├── README.md
├── build.gradle
├── docs
│ └── images
│ │ └── getting-started.png
├── etc
│ └── graphviz-dot.properties
├── src
│ └── com
│ │ └── structurizr
│ │ └── io
│ │ └── dot
│ │ ├── DOTDiagram.java
│ │ ├── DOTWriter.java
│ │ └── RankDirection.java
└── test
│ ├── structurizr-36141-workspace.json
│ ├── structurizr-54915-workspace.json
│ └── unit
│ └── com
│ └── structurizr
│ └── io
│ └── dot
│ └── DOTWriterTests.java
├── structurizr-examples
├── build.gradle
├── etc
│ └── logging.properties
└── src
│ └── com
│ └── structurizr
│ └── example
│ ├── SpringBootPetClinic.java
│ ├── SpringPetClinic.java
│ ├── StructurizrAnnotations.java
│ └── annotations
│ ├── HtmlController.java
│ ├── JdbcRepository.java
│ └── Repository.java
├── structurizr-export
└── README.md
├── structurizr-graphviz
└── README.md
├── structurizr-javaee
├── build.gradle
└── src
│ └── com
│ └── structurizr
│ └── analysis
│ └── JavaEEComponentFinderStrategy.java
├── structurizr-plantuml
├── README.md
├── build.gradle
├── docs
│ └── images
│ │ └── getting-started.png
├── src
│ └── com
│ │ └── structurizr
│ │ └── io
│ │ └── plantuml
│ │ ├── BasicPlantUMLWriter.java
│ │ ├── PlantUMLDiagram.java
│ │ ├── PlantUMLEncoder.java
│ │ └── PlantUMLWriter.java
└── test
│ ├── structurizr-36141-workspace.json
│ ├── structurizr-54915-workspace.json
│ └── unit
│ └── com
│ └── structurizr
│ └── io
│ └── plantuml
│ ├── AbstractPlantUMLWriterTests.java
│ ├── PlantUMLEncoderTests.java
│ └── PlantUMLWriterTests.java
└── structurizr-spring
├── build.gradle
├── src
└── com
│ └── structurizr
│ └── analysis
│ ├── AbstractSpringComponentFinderStrategy.java
│ ├── SpringComponentComponentFinderStrategy.java
│ ├── SpringComponentFinderStrategy.java
│ ├── SpringMvcControllerComponentFinderStrategy.java
│ ├── SpringRepositoryComponentFinderStrategy.java
│ ├── SpringRestControllerComponentFinderStrategy.java
│ ├── SpringServiceComponentFinderStrategy.java
│ └── SpringWebServiceEndpointComponentFinderStrategy.java
└── test
└── unit
├── com
└── structurizr
│ └── analysis
│ ├── AbstractSpringComponentFinderStrategyTests.java
│ ├── SpringComponentComponentFinderStrategyTests.java
│ ├── SpringComponentFinderStrategyTests.java
│ ├── SpringMvcControllerComponentFinderStrategyTests.java
│ ├── SpringRepositoryComponentFinderStrategyTests.java
│ ├── SpringRestControllerComponentFinderStrategyTests.java
│ ├── SpringServiceComponentFinderStrategyTests.java
│ ├── SpringWebServiceEndpointComponentFinderStrategyTests.java
│ └── myapp
│ ├── api
│ └── SomeApiController.java
│ ├── data
│ ├── JdbcSomeRepository.java
│ ├── SomeNonPublicRepository.java
│ ├── SomeOtherRepository.java
│ └── SomeRepository.java
│ ├── domain
│ └── Something.java
│ ├── service
│ ├── SomeService.java
│ └── SomeServiceImpl.java
│ └── web
│ └── SomeController.java
└── test
├── AbstractSpringComponentFinderStrategy
├── SomeController.java
├── SomeNonPublicRepository.java
└── SomePublicRepository.java
├── SpringComponentComponentFinderStrategy
├── SomeComponent.java
└── TheSomeComponentImpl.java
├── SpringMvcControllerComponentFinderStrategy
└── SomeController.java
├── SpringRepositoryComponentFinderStrategy
├── annotation
│ ├── JdbcSomeRepository.java
│ └── SomeRepository.java
├── crudRepository
│ └── SomeCrudRepository.java
└── jpaRepository
│ └── SomeJpaRepository.java
├── SpringRestControllerComponentFinderStrategy
└── SomeController.java
├── SpringServiceComponentFinderStrategy
├── SomeService.java
└── SomeServiceImpl.java
└── SpringWebServiceEndpointComponentFinderStrategy
└── SomeWebService.java
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Gradle
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
3 |
4 | name: Java CI with Gradle
5 | on:
6 | push:
7 | branches: [ master ]
8 | pull_request:
9 | branches: [ master ]
10 |
11 | jobs:
12 | build:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v2
16 | - name: Set up JDK 1.8
17 | uses: actions/setup-java@v1
18 | with:
19 | java-version: 1.8
20 | - name: Grant execute permission for gradlew
21 | run: chmod +x gradlew
22 | - name: Build with Gradle
23 | run: ./gradlew
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Gradle caches, etc
2 | **/.gradle
3 |
4 | # IntelliJ IDEA project files
5 | **/*.ipr
6 | **/*.iws
7 | **/*.iml
8 | .idea/*
9 | # !.idea/vcs.xml
10 | # !.idea/modules.xml
11 | # !.idea/encodings.xml
12 | # !.idea/codeStyleSettings.xml
13 | # !.idea/runConfigurations/
14 |
15 | # Eclipse project files
16 | .classpath
17 | .project
18 | .settings
19 | **/.settings
20 |
21 | # Compiled stuff
22 | build
23 | out
24 | bin
25 | **/bin/
26 |
27 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
28 | hs_err_pid*
29 |
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Structurizr for Java extensions
2 |
3 | This GitHub repository is a collection of extensions for the [Structurizr for Java](https://github.com/structurizr/java) library that provide a way to extract architectural information from Java code via reflection.
4 |
5 | Unfortunately:
6 |
7 | - The code in this library is incompatible with newer versions of the `structurizr-core` library.
8 | - The code in this library has some dependencies on Java 8.
9 | - There is very little interest in this library.
10 |
11 | Therefore this repo has been archived. The code remains open source, so you are more than welcome to fork it and make your own releases.
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | task wrapper(type: Wrapper) {
2 | gradleVersion = '4.0'
3 | }
4 |
5 | defaultTasks 'clean', 'compileJava', 'test'
6 |
7 | subprojects { proj ->
8 |
9 | apply plugin: 'idea'
10 | apply plugin: 'java'
11 | apply plugin: 'maven-publish'
12 | apply plugin: 'maven'
13 | apply plugin: 'signing'
14 |
15 | description = 'Structurizr'
16 | group = 'com.structurizr'
17 | version = '1.4.0'
18 |
19 | repositories {
20 | mavenCentral()
21 | }
22 |
23 | sourceSets {
24 | main {
25 | java {
26 | srcDir 'src'
27 | }
28 | }
29 | test {
30 | java {
31 | srcDir 'test/unit'
32 | }
33 | }
34 | }
35 |
36 | dependencies {
37 | compile 'com.google.code.findbugs:jsr305:3.0.2'
38 | }
39 |
40 | compileJava.options.encoding = 'UTF-8'
41 | compileTestJava.options.encoding = 'UTF-8'
42 |
43 | sourceCompatibility = 1.8
44 | targetCompatibility = 1.8
45 |
46 | jar {
47 | manifest {
48 | attributes(
49 | "Implementation-Title": "Structurizr for Java",
50 | "Implementation-Version": version
51 | )
52 | }
53 | }
54 |
55 | task sourcesJar(type: Jar) {
56 | classifier = 'sources'
57 | from sourceSets.main.allJava
58 | }
59 |
60 | task javadocJar(type: Jar) {
61 | classifier = 'javadoc'
62 | from javadoc
63 | }
64 |
65 | artifacts {
66 | archives javadocJar, sourcesJar
67 | }
68 |
69 | signing {
70 | sign configurations.archives
71 | }
72 |
73 | uploadArchives {
74 | repositories {
75 | mavenDeployer {
76 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
77 |
78 | repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
79 | authentication(userName: ossrhUsername, password: ossrhPassword)
80 | }
81 |
82 | snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
83 | authentication(userName: ossrhUsername, password: ossrhPassword)
84 | }
85 |
86 | pom.project {
87 | name 'Structurizr for Java'
88 | packaging 'jar'
89 | description 'Structurizr for Java'
90 | url 'https://github.com/structurizr/java'
91 |
92 | scm {
93 | connection 'scm:git:git://github.com/structurizr/structurizr-java.git'
94 | developerConnection 'scm:git:git@github.com:structurizr/structurizr-java.git'
95 | url 'https://github.com/structurizr/java'
96 | }
97 |
98 | licenses {
99 | license {
100 | name 'The Apache License, Version 2.0'
101 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
102 | }
103 | }
104 |
105 | developers {
106 | developer {
107 | id "simon"
108 | name "Simon Brown"
109 | email "simon@structurizr.com"
110 | }
111 | }
112 | }
113 | }
114 | }
115 | }
116 |
117 | def pomConfig = {
118 | licenses {
119 | license {
120 | name "The Apache Software License, Version 2.0"
121 | url "http://www.apache.org/licenses/LICENSE-2.0.txt"
122 | distribution "repo"
123 | }
124 | }
125 | developers {
126 | developer {
127 | id "simon"
128 | name "Simon Brown"
129 | email "simon@structurizr.com"
130 | }
131 | }
132 | }
133 |
134 | publishing {
135 | publications {
136 | mavenJava(MavenPublication) {
137 | from components.java
138 | artifact sourcesJar
139 | artifact javadocJar
140 | pom.withXml {
141 | def root = asNode()
142 | root.appendNode('description', 'Visualise, document and explore your software architecture with the C4 model.')
143 | root.appendNode('name', 'Structurizr for Java')
144 | root.appendNode('url', 'https://github.com/structurizr/java')
145 | root.children().last() + pomConfig
146 | }
147 | }
148 | }
149 |
150 | repositories {
151 | maven {
152 | url "$buildDir/repo"
153 | }
154 | }
155 | }
156 |
157 | }
--------------------------------------------------------------------------------
/docs/binaries.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/docs/binaries.md
--------------------------------------------------------------------------------
/docs/building.md:
--------------------------------------------------------------------------------
1 | # Building
2 |
3 | 
4 |
5 | To build the Structurizr for Java extensions, you'll need:
6 |
7 | - Java 8 or above
8 | - The ```JAVA_HOME``` environment needs to point to your JDK
9 |
10 | ```
11 | git clone https://github.com/structurizr/java-extensions.git
12 | cd java-extensions
13 | export JAVA_HOME=...
14 | ./gradlew
15 | ```
--------------------------------------------------------------------------------
/docs/changelog.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## 1.3.5 (8th April 2020)
4 |
5 | - Added the structurizr-graphviz library.
6 |
7 | ## 1.3.4 (29th February 2020)
8 |
9 | Bug fixes.
10 |
11 | ## 1.3.1 (29th October 2019)
12 |
13 | - The structurizr-annotations library can now be more easily used with OSGi applications.
14 | - Fixes a bug with the PlantUML and WebSequenceDiagram writers, where relationships were sorted incorrectly (alphabetically, rather than numerically).
--------------------------------------------------------------------------------
/docs/component-finder.md:
--------------------------------------------------------------------------------
1 | # Component finder
2 |
3 | The Structurizr for Java library includes a component finder and a number of prebuilt pluggable strategies that allow you to extract components from a codebase.
4 |
5 | ## Background
6 |
7 | The idea behind the [C4 model](https://c4model.com) and Structurizr is that there are a number of levels of abstraction sitting above the code.
8 | Although we write Java code using interfaces and classes in packages, it's often useful to think about how that code is organised into "components".
9 | In its simplest form, a "component" is just a grouping of classes and interfaces.
10 |
11 | If you reverse-engineer some Java code using a UML tool, you'll typically get a UML class diagram showing all of the classes and interfaces.
12 | The component diagram in the C4 model is about hiding some of this complexity and implementation detail.
13 | You can read more about this at [Components vs classes](https://structurizr.com/help/components-vs-classes).
14 |
15 | ## Purpose
16 |
17 | The purpose of the [component finder](https://github.com/structurizr/java-extensions/blob/master/structurizr-analysis/src/com/structurizr/analysis/ComponentFinder.java) is to find components in your codebase.
18 | Since every codebase is different (i.e. code structure, naming conventions, frameworks used, etc), different pluggable component finder strategies allow you to customize the rules that you use to find components.
19 | Some example rules that you might use to find components include:
20 |
21 | - All classes where the name ends with `Component`.
22 | - All classes where the name ends with `Controller`.
23 | - All classes that are annotated with the Spring `@Repository` annotation.
24 | - All classes that inherit from `AbstractComponent`.
25 | - etc
26 |
27 | ## Basic usage
28 |
29 | To use a component finder, simply create an instance of the `ComponentFinder` class and configure it as needed.
30 |
31 | ```java
32 | Container webApplication = mySoftwareSystem.addContainer("Web Application", "Description", "Apache Tomcat 7.x");
33 |
34 | ComponentFinder componentFinder = new ComponentFinder(
35 | webApplication, "com.mycompany.mysoftwaresystem",
36 | ... a number of component finder strategies ...);
37 | componentFinder.findComponents();
38 | ```
39 |
40 | In this case, we're going to find components and associate them with the `webApplication` container, and we're only going to find components that reside somewhere underneath the `com.mycompany.mysoftwaresystem` package to avoid accidentally finding components residing in frameworks that we might be using.
41 |
42 | We also need to plug in one or more component finder strategies, which actually implement the logic to find and extract components from a codebase.
43 |
44 | ## Component finder strategies
45 |
46 | The are a number of component finder strategies already implemented in this GitHub repository and, since the code is open source, you can build your own too.
47 | Some of the component finder strategies work using static analysis and reflection techniques against the compiled version of the code (you will need this on your classpath), others by parsing the source code.
48 |
49 | Name | Dependency | Description | Extracted from
50 | ---- | ---------- | ----------- | --------------
51 | [TypeMatcherComponentFinderStrategy](type-matchers.md) | structurizr-core | A component finder strategy that uses type information to find components, based upon a number of pluggable TypeMatcher implementations (e.g. [NameSuffixTypeMatcher](https://github.com/structurizr/java-extensions/blob/master/structurizr-analysis/src/com/structurizr/analysis/NameSuffixTypeMatcher.java), [ImplementsInterfaceTypeMatcher](https://github.com/structurizr/java-extensions/blob/master/structurizr-analysis/src/com/structurizr/analysis/ImplementsInterfaceTypeMatcher.java), [RegexTypeMatcher](https://github.com/structurizr/java-extensions/blob/master/structurizr-analysis/src/com/structurizr/analysis/RegexTypeMatcher.java) and [AnnotationTypeMatcher](https://github.com/structurizr/java-extensions/blob/master/structurizr-analysis/src/com/structurizr/analysis/AnnotationTypeMatcher.java)). | Compiled bytecode
52 | [SpringComponentFinderStrategy](spring-component-finder-strategies.md) | structurizr-spring | Finds types annotated `@Controller`, `@RestController`, `@Component`, `@Service` and `@Repository`, plus classes that extend `JpaRepository`. | Compiled bytecode
53 | [StructurizrAnnotationsComponentFinderStrategy](structurizr-annotations.md) | structurizr-core | Finds the Structurizr annotations `@Component`, `@UsedByPerson`, `@UsedBySoftwareSystem`, `@UsedByContainer`, `@UsesSoftwareSystem`, `@UsesContainer` and `@UsesComponent`. | Compiled bytecode
54 | [SourceCodeComponentFinderStrategy](supplementing-from-source-code.md) | structurizr-core | This component finder strategy doesn't really find components, it instead extracts the top-level Javadoc comment from the code so that this can be added to existing component definitions. It also calculates the size of components, based upon the number of lines of source code. | Source code
55 |
--------------------------------------------------------------------------------
/docs/dot.md:
--------------------------------------------------------------------------------
1 | # Graphviz and DOT
2 |
3 | Structurizr for Java also includes the ```structurizr-dot``` library, which in turn uses Cyrille Martraire's [dot-diagram library](https://github.com/LivingDocumentation/dot-diagram) to create DOT (graph description language) files that can be imported into the [Graphviz tool](http://www.graphviz.org).
4 |
5 | Simply create your software architecture model and views as usual, and use the [DotWriter](https://github.com/structurizr/java/blob/master/structurizr-dot/src/com/structurizr/io/dot/DotWriter.java) class to export the views. [For example](https://github.com/structurizr/java/blob/master/structurizr-dot/src/com/structurizr/io/dot/DotWriterExample.java):
6 |
7 | ```java
8 | Workspace workspace = new Workspace("Getting Started", "This is a model of my software system.");
9 | Model model = workspace.getModel();
10 |
11 | Person user = model.addPerson("User", "A user of my software system.");
12 | SoftwareSystem softwareSystem = model.addSoftwareSystem("Software System", "My software system.");
13 | user.uses(softwareSystem, "Uses");
14 |
15 | ViewSet views = workspace.getViews();
16 | SystemContextView contextView = views.createSystemContextView(softwareSystem, "SystemContext", "An example of a System Context diagram.");
17 | contextView.addAllSoftwareSystems();
18 | contextView.addAllPeople();
19 |
20 | StringWriter stringWriter = new StringWriter();
21 | DotWriter dotWriter = new DotWriter();
22 | dotWriter.write(workspace, stringWriter);
23 | System.out.println(stringWriter);
24 | ```
25 |
26 | > You will need Graphviz installed.
27 |
28 | This code will generate and output a DOT diagram definition that looks like this:
29 |
30 | ```
31 | digraph G {
32 | graph [labelloc=top,label="Software System - System Context",fontname="Verdana",fontsize=12];
33 | edge [fontname="Verdana",fontsize=9,labelfontname="Verdana",labelfontsize=9];
34 | node [fontname="Verdana",fontsize=9,shape=record];
35 | c0 [label="User"]
36 | c1 [label="Software System"]
37 | // null
38 | c0 -> c1 [label="Uses" , ];
39 | }
40 | ```
41 |
42 | Importing this graph definition into Graphviz (or [GraphvizFiddle](https://stamm-wilbrandt.de/GraphvizFiddle/)) gives you the following image:
43 |
44 | 
45 |
46 | ## Benefits of using Graphviz with Structurizr
47 |
48 | The key benefit of using Graphviz in conjunction with the Structurizr client library is that you can create diagrams from a __model__ of your software system. The model provides a set of rules that must be followed; related to elements, relationships, and how they are exposed using diagrams. This means:
49 |
50 | 1. Rather than looking after a collection of disjointed Graphviz diagram definitions, you can create many Graphviz diagrams from a single model and keep them all up to date easily, especially if integrated with your continuous build server and build pipeline.
51 | 1. The naming of elements and the definition of relationships between elements _remains consistent across diagrams_.
52 | 1. The software architecture model at the component level can be created by extracting components from a codebase, using _static analysis and reflection techniques_.
53 |
54 | ### Example
55 |
56 | Here is a Graphviz version of the Component diagram from the [Spring PetClinic example](https://structurizr.com/share/1#components).
57 |
58 | 
--------------------------------------------------------------------------------
/docs/images/graphviz-getting-started.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/docs/images/graphviz-getting-started.png
--------------------------------------------------------------------------------
/docs/images/graphviz-spring-petclinic-components.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/docs/images/graphviz-spring-petclinic-components.png
--------------------------------------------------------------------------------
/docs/images/spring-petclinic-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/docs/images/spring-petclinic-1.png
--------------------------------------------------------------------------------
/docs/images/spring-petclinic-plantuml.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/docs/images/spring-petclinic-plantuml.png
--------------------------------------------------------------------------------
/docs/images/structurizr-annotations-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/docs/images/structurizr-annotations-1.png
--------------------------------------------------------------------------------
/docs/images/structurizr-banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/docs/images/structurizr-banner.png
--------------------------------------------------------------------------------
/docs/images/structurizr-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/docs/images/structurizr-logo.png
--------------------------------------------------------------------------------
/docs/images/supporting-types-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/docs/images/supporting-types-1.png
--------------------------------------------------------------------------------
/docs/images/supporting-types-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/docs/images/supporting-types-2.png
--------------------------------------------------------------------------------
/docs/images/supporting-types-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/docs/images/supporting-types-3.png
--------------------------------------------------------------------------------
/docs/images/supporting-types-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/docs/images/supporting-types-4.png
--------------------------------------------------------------------------------
/docs/images/supporting-types-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/docs/images/supporting-types-5.png
--------------------------------------------------------------------------------
/docs/images/supporting-types-6.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/docs/images/supporting-types-6.gif
--------------------------------------------------------------------------------
/docs/images/supporting-types-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/docs/images/supporting-types-7.png
--------------------------------------------------------------------------------
/docs/images/supporting-types-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/docs/images/supporting-types-8.png
--------------------------------------------------------------------------------
/docs/images/websequencediagrams-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/docs/images/websequencediagrams-1.png
--------------------------------------------------------------------------------
/docs/spring-component-finder-strategies.md:
--------------------------------------------------------------------------------
1 | # Spring component finder strategies
2 |
3 | Included in the `structurizr-spring` library are a number of component finder strategies that help you identify components in Spring applications, including those built using Spring Boot.
4 |
5 | * __SpringMvcControllerComponentFinderStrategy__: A component finder strategy that finds Spring MVC controllers (classes annotated `@Controller`).
6 | * __SpringRestControllerComponentFinderStrategy__: A component finder strategy that finds Spring REST controllers (classes annotated `@RestController`).
7 | * __SpringServiceComponentFinderStrategy__: A component finder strategy that finds Spring services (classes annotated `@Service`).
8 | * __SpringComponentComponentFinderStrategy__: A component finder strategy that finds Spring components (classes annotated `@Component`).
9 | * __SpringRepositoryComponentFinderStrategy__: A component finder strategy for Spring repositories (classes annotated `@Repository`, plus those that extend `JpaRepository` or `CrudRepository`).
10 | * __SpringComponentFinderStrategy__: A combined component finder strategy that uses all of the individual strategies listed above.
11 |
12 | ## Spring naming conventions and interfaces vs implementation classes
13 |
14 | Some of the Spring annotations (e.g. `@Component`, `@Service` and `@Repository`) are typically used to annotate _implementation classes_.
15 | For example, a `JdbcCustomerRepository` class might be annotated `@Repository`, rather than the `CustomerRepository` interface.
16 | This component finder strategy tries to refer to interface types rather than implementation classes, based upon the following assumptions:
17 |
18 | 1. Having a component named `CustomerRepository` is preferable to `JdbcCustomerRespository`.
19 | 2. Other types in the codebase will likely have a dependency on the interface type (e.g. via dependency injection) rather than being coupled to the implementation class.
20 |
21 | Given that a class can implement any number of interfaces, for a given implementation class, the component finder strategies will try to find the interface where the name of that interface is included in the name of the implementation class (i.e. `*Interface`, `Interface*` and `*Interface*`).
22 | For example, the following implementation classes will match an interface named `CustomerRepository`:
23 |
24 | * `JdbcCustomerRepository`
25 | * `CustomerRepositoryImpl`
26 | * `JdbcCustomerRepositoryImpl`
27 |
28 | ## Public vs non-public types
29 |
30 | By default, non-public types will be ignored so that, for example, you can hide repository implementations behind services, as described at [Whoops! Where did my architecture go](http://olivergierke.de/2013/01/whoops-where-did-my-architecture-go/). Use the `setIncludePublicTypesOnly` method to change this behaviour.
31 |
32 | ## Example
33 |
34 | You can see an example of how to use the Spring component finder strategies in the [Spring PetClinic example](spring-petclinic.md).
35 |
--------------------------------------------------------------------------------
/docs/structurizr-annotations.md:
--------------------------------------------------------------------------------
1 | # Structurizr annotations
2 |
3 | Structurizr for Java includes some custom annotations that you can add to your code.
4 | These serve to either make it explicit how components should be extracted from your codebase, or they help supplement the software architecture model.
5 |
6 | The annotations can be found in the [structurizr-annotations](https://bintray.com/structurizr/maven/structurizr-java) artifact, which is a very small standalone JAR file containing only the Structurizr annotations.
7 | All annotations have a runtime retention policy, so they will be present in the compiled bytecode.
8 |
9 | ## @Component
10 |
11 | A type-level annotation that can be used to signify that the annotated type (an interface or class) can be considered to be a "component".
12 | The properties are as follows:
13 |
14 | - description: The description of the component (optional).
15 | - technology: The technology of component (optional).
16 |
17 | ## @UsedByPerson
18 |
19 | A type-level annotation that can be used to signify that the named person uses the component on which this annotation is placed, creating a relationship form the person to the component.
20 | The properties are as follows:
21 |
22 | - name: The name of the person (required).
23 | - description: The description of the relationship (optional).
24 | - technology: The technology of relationship (optional).
25 |
26 | ## @UsedBySoftwareSystem
27 |
28 | A type-level annotation that can be used to signify that the named software system uses the component on which this annotation is placed, creating a relationship from the software system to the component.
29 | The properties are as follows:
30 |
31 | - name: The name of the software system (required).
32 | - description: The description of the relationship (optional).
33 | - technology: The technology of relationship (optional).
34 |
35 | ## @UsedByContainer
36 |
37 | A type-level annotation that can be used to signify that the named container uses the component on which this annotation is placed, creating a relationship from the container to the component.
38 | The properties are as follows:
39 |
40 | - name: The name of the container (required).
41 | - description: The description of the relationship (optional).
42 | - technology: The technology of relationship (optional).
43 |
44 | If the container resides in the same software system as the component, the simple name can be used to identify the container (e.g. "Database").
45 | Otherwise, the full canonical name of the form "Software System/Container" must be used (e.g. "Some Other Software System/Database").
46 |
47 | ## @UsesSoftwareSystem
48 |
49 | A type-level annotation that can be used to signify that the component on which this annotation is placed has a relationship to the named software system, creating a relationship from the component to the software system.
50 | The properties are as follows:
51 |
52 | - name: The name of the software system (required).
53 | - description: The description of the relationship (optional).
54 | - technology: The technology of relationship (optional).
55 |
56 | ## @UsesContainer
57 |
58 | A type-level annotation that can be used to signify that the component on which this annotation is placed has a relationship to the named container, creating a relationship from the component to the container.
59 | The properties are as follows:
60 |
61 | - name: The name of the container (required).
62 | - description: The description of the relationship (optional).
63 | - technology: The technology of relationship (optional).
64 |
65 | If the container resides in the same software system as the component, the simple name can be used to identify the container (e.g. "Database").
66 | Otherwise, the full canonical name of the form "Software System/Container" must be used (e.g. "Some Other Software System/Database").
67 |
68 | ## @UsesComponent
69 |
70 | A field-level annotation that can be used to supplement the existing relationship (i.e. add a description and/or technology) between two components.
71 |
72 | When using the various component finder strategies, Structurizr for Java will identify components along with the relationships between those components.
73 | Since this is typically done using reflection against the compiled bytecode, you'll notice that the description and technology properties of the resulting relationships is always empty.
74 | The `@UsesComponent` annotation provides a simple way to ensure that such information is added into the model.
75 |
76 | The properties are as follows:
77 |
78 | - description: The description of the relationship (required).
79 | - technology: The technology of relationship (optional).
80 |
81 | ## Example
82 |
83 | Here are some examples of the annotations, which have been used to create the following diagram.
84 |
85 | 
86 |
87 | ```java
88 | @Component(description = "Serves HTML pages to users.", technology = "Java")
89 | @UsedByPerson(name = "User", description = "Uses", technology = "HTTPS")
90 | class HtmlController {
91 |
92 | @UsesComponent(description = "Gets data using")
93 | private Repository repository = new JdbcRepository();
94 |
95 | }
96 | ```
97 |
98 | ```java
99 | @Component(description = "Provides access to data stored in the database.", technology = "Java and JPA")
100 | public interface Repository {
101 |
102 | String getData(long id);
103 |
104 | }
105 | ```
106 |
107 | ```java
108 | @UsesContainer(name = "Database", description = "Reads from", technology = "JDBC")
109 | class JdbcRepository implements Repository {
110 |
111 | public String getData(long id) {
112 | return "...";
113 | }
114 |
115 | }
116 | ```
117 |
118 | See [StructurizrAnnotations.java](https://github.com/structurizr/java-extensions/blob/master/structurizr-examples/src/com/structurizr/example/StructurizrAnnotations.java) for the full source code illustrating how to use the various annotations in conjunction with the component finder.
119 | The resulting diagrams can be found at [https://structurizr.com/share/36571](https://structurizr.com/share/36571).
120 |
--------------------------------------------------------------------------------
/docs/supplementing-from-source-code.md:
--------------------------------------------------------------------------------
1 | # Supplementing the model from source code
2 |
3 | Most of the component finder strategies included in Structurizr for Java find components using reflection against the compiled bytecode.
4 | Some useful information exists in the source code though; including:
5 |
6 | * The type-level doc comment (`/** ... */`, typically extracted using the javadoc tool). This can be used to populate the description property of components.
7 | * The number of lines of source code. This can be a used to calculate the "size" of a component.
8 |
9 | A pre-built [SourceCodeComponentFinderStrategy](https://github.com/structurizr/java-extensions/blob/master/structurizr-analysis/src/com/structurizr/analysis/SourceCodeComponentFinderStrategy.java) is provided to do this, which uses the standard `javadoc` tool.
10 | You will need to include `JAVA_HOME/lib/tools.jar` on your classpath.
11 |
12 | ## Example
13 |
14 | Here's an example of how to use the `SourceCodeComponentFinderStrategy`, taken from the [Spring PetClinic example](spring-petclinic.md).
15 |
16 | ```java
17 | File sourceRoot = new File("/some/path");
18 |
19 | ComponentFinder componentFinder = new ComponentFinder(
20 | webApplication, "org.springframework.samples.petclinic",
21 | new SpringComponentFinderStrategy(
22 | new ReferencedTypesSupportingTypesStrategy(false)
23 | ),
24 | new SourceCodeComponentFinderStrategy(new File(sourceRoot, "/src/main/java/"), 150));
25 |
26 | componentFinder.findComponents();
27 | ```
28 |
29 | For every `CodeElement` that belongs to every `Component` in the `Container` passed to the `ComponentFinder`, the `SourceCodeComponentFinderStrategy` will:
30 |
31 | * Set the description property, based on the type-level doc comment. The doc comment will be truncated if necessary (e.g. to 150 characters in the example above).
32 | * Set the size property to be the number of lines of the file that the type was found in.
33 |
34 | Additionally, the description property of the `Component` will be set to be that of the primary `CodeElement`, if a description has not been set on the `Component` already.
35 |
--------------------------------------------------------------------------------
/docs/type-matchers.md:
--------------------------------------------------------------------------------
1 | # Type matchers
2 |
3 | Structurizr for Java includes a number "type matchers", which when used in conjunction with the [TypeMatcherComponentFinderStrategy](https://github.com/structurizr/java-extensions/blob/master/structurizr-analysis/src/com/structurizr/analysis/TypeMatcherComponentFinderStrategy.java), provides a simple way to find components in your codebase based upon specific types. The following pre-built type matchers are included.
4 |
5 | ## NameSuffixTypeMatcher
6 |
7 | Matches types where the (simple) name of the type ends with the specified suffix. For example, to find all types named `*Controller`:
8 |
9 | ```java
10 | new NameSuffixTypeMatcher("Controller", "", "");
11 | ```
12 |
13 | ## RegexTypeMatcher
14 |
15 | Matches types using a regex against the fully qualified type name. For example, to find all types with a fully qualified name of `*.web.*Controller`:
16 |
17 | ```java
18 | new RegexTypeMatcher(".*\.web\..*Controller", "", "");
19 | ```
20 |
21 | ## AnnotationTypeMatcher
22 |
23 | Matches types based upon the presence of a type-level annotation. For example, to find all types that are annotated with the Java EE `@Stateless` annotation:
24 |
25 | ```java
26 | new AnnotationTypeMatcher(javax.ejb.Stateless.class, "", "");
27 | ```
28 |
29 | ## ImplementsInterfaceTypeMatcher
30 |
31 | Matches types where the type implements the specified interface. For example, to find all types that implement the `Repository` interface:
32 |
33 | ```java
34 | new ImplementsInterfaceTypeMatcher(Repository.class, "", "");
35 | ```
36 |
37 | ## ExtendsClassTypeMatcher
38 |
39 | Matches types where the type extends the specified class. For example, to find all types that extend the `AbstractComponent` class:
40 |
41 | ```java
42 | new ExtendsClassTypeMatcher(AbstractComponent.class, "", "");
43 | ```
44 |
45 | ## Example
46 |
47 | Here is an example of how you might use the type matchers in conjunction with the component finder:
48 |
49 | ```java
50 | ComponentFinder componentFinder = new ComponentFinder(
51 | someContainer,
52 | "com.mycompany.myapp",
53 | new TypeMatcherComponentFinderStrategy(
54 | new NameSuffixTypeMatcher("Controller", "Controller description", "Controller technology"),
55 | new NameSuffixTypeMatcher("Repository", "Repository description", "Repository technology")
56 | )
57 | );
58 | componentFinder.findComponents();
59 | ```
60 |
61 | The description and technology properties specified on the type matchers will be used to set the corresponding properties on the `Component` instances that are created when matching types are found.
62 |
63 | ## Writing your own type matchers
64 |
65 | You can write your own type matchers by implementing the [TypeMatcher](https://github.com/structurizr/java-extensions/blob/master/structurizr-analysis/src/com/structurizr/analysis/TypeMatcher.java) interface, or by extending the [AbstractTypeMatcher](https://github.com/structurizr/java-extensions/blob/master/structurizr-analysis/src/com/structurizr/analysis/AbstractTypeMatcher.java) class.
66 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | signing.keyId=123456768
2 | signing.password=password
3 | signing.secretKeyRingFile=/some/path
4 |
5 | ossrhUsername=username
6 | ossrhPassword=password
7 |
8 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Nov 19 10:27:00 CET 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'structurizr'
2 |
3 | include 'structurizr-analysis'
4 | include 'structurizr-annotations'
5 | include 'structurizr-diff'
6 | include 'structurizr-examples'
7 | include 'structurizr-spring'
--------------------------------------------------------------------------------
/structurizr-adr-tools/README.md:
--------------------------------------------------------------------------------
1 | # structurizr-adr-tools
2 |
3 | __This module has moved to [https://github.com/structurizr/documentation](https://github.com/structurizr/documentation).__
--------------------------------------------------------------------------------
/structurizr-analysis/build.gradle:
--------------------------------------------------------------------------------
1 | dependencies {
2 |
3 | compile project(':structurizr-annotations')
4 | compile 'com.structurizr:structurizr-core:1.3.5'
5 |
6 | compile 'org.reflections:reflections:0.9.10'
7 | compile 'org.javassist:javassist:3.22.0-CR2'
8 |
9 | compile files("${System.getProperty('java.home')}/../lib/tools.jar")
10 |
11 | testCompile 'junit:junit:4.12'
12 | testCompile 'org.assertj:assertj-core:3.14.0'
13 | }
14 |
15 | sourceSets {
16 | main {
17 | java {
18 | srcDir 'src'
19 | }
20 | }
21 | test {
22 | java {
23 | srcDir 'test/unit'
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/AbstractTypeMatcher.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | /**
4 | * A superclass used for TypeMatcher implementations.
5 | */
6 | public abstract class AbstractTypeMatcher implements TypeMatcher {
7 |
8 | private String description;
9 | private String technology;
10 |
11 | public AbstractTypeMatcher(String description, String technology) {
12 | this.description = description;
13 | this.technology = technology;
14 | }
15 |
16 | @Override
17 | public String getDescription() {
18 | return description;
19 | }
20 |
21 | @Override
22 | public String getTechnology() {
23 | return technology;
24 | }
25 |
26 | }
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/AnnotatedMethodComponentFinderStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 | import com.structurizr.model.Container;
5 | import org.reflections.ReflectionUtils;
6 |
7 | import javax.annotation.Nonnull;
8 | import javax.annotation.Nullable;
9 | import java.lang.annotation.Annotation;
10 | import java.lang.reflect.Method;
11 | import java.util.AbstractMap.SimpleImmutableEntry;
12 | import java.util.HashSet;
13 | import java.util.Objects;
14 | import java.util.Set;
15 | import java.util.stream.Collectors;
16 |
17 | /**
18 | * A generic component finder strategy that finds components based on returned types of specifically annotated methods.
19 | * To filter scanned classes for specifically annotated methods specify classAnnotation as well.
20 | * This strategy uses first found implementation as a type property for a Component and
21 | * when component duplicates are found it behaves according to passed DuplicateComponentStrategy (by default it ignores duplicates if nothing is passed to constructor).
22 | *
23 | * With example below this strategy finds 2 components based on method annotation {@code @Bean},
24 | * e.g. component with name "SomeComponent" has efferent relation to "SomeEfferentComponent".
25 | *
26 | * {@code @Configuration}
27 | * public class SomeConfiguration {
28 | *
29 | * {@code @Bean}
30 | * public SomeComponent someComponent(SomeEfferentComponent someEfferentComponent) {
31 | * return new SomeComponentImpl(someEfferentComponent);
32 | * }
33 | *
34 | * {@code @Bean}
35 | * public SomeEfferentComponent someEfferentComponent() {
36 | * return new SomeEfferentComponentImpl();
37 | * }
38 | * }
39 | *
40 | */
41 | public class AnnotatedMethodComponentFinderStrategy extends AbstractComponentFinderStrategy {
42 | private final Class extends Annotation> classAnnotation;
43 | private final Class extends Annotation> methodAnnotation;
44 |
45 | /**
46 | * Construct strategy that finds components based on return type of methods annotated with {@code methodAnnotation}
47 | *
48 | * @param methodAnnotation the annotation to look for on methods
49 | */
50 | public AnnotatedMethodComponentFinderStrategy(Class extends Annotation> methodAnnotation) {
51 | this(methodAnnotation, null, new IgnoreDuplicateComponentStrategy());
52 | }
53 |
54 | public AnnotatedMethodComponentFinderStrategy(Class extends Annotation> methodAnnotation, DuplicateComponentStrategy duplicateComponentStrategy) {
55 | this(methodAnnotation, null, duplicateComponentStrategy);
56 | }
57 |
58 | /**
59 | * Construct strategy that finds components based on return type of methods annotated with {@code methodAnnotation}
60 | * which belong only to classes annotated with {@code classAnnotation}
61 | *
62 | * @param methodAnnotation the annotation to look for on methods
63 | * @param classAnnotation the annotation to look for on classes/interfaces
64 | */
65 | public AnnotatedMethodComponentFinderStrategy(Class extends Annotation> methodAnnotation, Class extends Annotation> classAnnotation) {
66 | this(methodAnnotation, classAnnotation, new IgnoreDuplicateComponentStrategy(), new ReferencedTypesSupportingTypesStrategy());
67 | }
68 |
69 | /**
70 | * Construct strategy that finds components based on return type of methods annotated with {@code methodAnnotation}
71 | * which belong only to classes annotated with {@code classAnnotation}.
72 | *
73 | * @param methodAnnotation the annotation to look for on methods
74 | * @param classAnnotation the annotation to look for on classes/interfaces to narrow scanned scope of methods
75 | * @param duplicateComponentStrategy strategy how to behave when component duplicates found
76 | * @param strategies strategies to look for supporting types for a component
77 | * (component hides all types which support defined in component functionality behind abstraction)
78 | */
79 | public AnnotatedMethodComponentFinderStrategy(
80 | @Nonnull Class extends Annotation> methodAnnotation,
81 | @Nullable Class extends Annotation> classAnnotation,
82 | @Nullable DuplicateComponentStrategy duplicateComponentStrategy,
83 | SupportingTypesStrategy... strategies
84 | ) {
85 | super(strategies);
86 | DuplicateComponentStrategy duplicateStrategy = duplicateComponentStrategy != null ? duplicateComponentStrategy : new IgnoreDuplicateComponentStrategy();
87 | this.setDuplicateComponentStrategy(duplicateStrategy);
88 | this.classAnnotation = classAnnotation;
89 | this.methodAnnotation = methodAnnotation;
90 | }
91 |
92 | @Override
93 | protected Set doFindComponents() {
94 | Set components = new HashSet<>();
95 | Container container = getComponentFinder().getContainer();
96 |
97 | Set> classes = new HashSet<>();
98 | if (classAnnotation != null) {
99 | classes.addAll(findTypesAnnotatedWith(classAnnotation));
100 | } else {
101 | classes.addAll(getComponentFinder().getTypeRepository().getAllTypes());
102 | }
103 | for (Class> clazz : classes) {
104 | Set> allMethods = ReflectionUtils.getAllMethods(clazz, m -> m.isAnnotationPresent(methodAnnotation))
105 | .stream().map(this::interfaceToImpReturnedFrom).filter(Objects::nonNull).collect(Collectors.toSet());
106 | for (SimpleImmutableEntry entry : allMethods) {
107 | Component component = addComponent(container, entry.getKey().getSimpleName(), entry.getValue().getName(), "", "");
108 | if (component != null) {
109 | components.add(component);
110 | }
111 | }
112 | }
113 | return components;
114 | }
115 |
116 | private SimpleImmutableEntry interfaceToImpReturnedFrom(Method method) {
117 | Class returnInterface = method.getReturnType();
118 | if (returnInterface.equals(Void.TYPE)) {
119 | return null;
120 | }
121 | Class returnFirstImpl = method.getReturnType();
122 | if (returnInterface.isInterface()) {
123 | Class firstImplementationOfInterface = TypeUtils.findFirstImplementationOfInterface(returnInterface, getTypeRepository().getAllTypes());
124 | //firstImplementationOfInterface could be null when bean is defined inside class of packageToScan but impl is located in non scan package
125 | if (firstImplementationOfInterface != null) {
126 | returnFirstImpl = firstImplementationOfInterface;
127 | }
128 | }
129 | return new SimpleImmutableEntry<>(returnInterface, returnFirstImpl);
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/AnnotationTypeMatcher.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import java.lang.annotation.Annotation;
4 |
5 | /**
6 | * Matches types based upon the presence of a type-level annotation.
7 | */
8 | public class AnnotationTypeMatcher extends AbstractTypeMatcher {
9 |
10 | private Class extends Annotation> annotation;
11 |
12 | public AnnotationTypeMatcher(Class extends Annotation> annotation, String description, String technology) {
13 | super(description, technology);
14 |
15 | if (annotation == null) {
16 | throw new IllegalArgumentException("An annotation must be supplied");
17 | }
18 |
19 | this.annotation = annotation;
20 | }
21 |
22 | @Override
23 | public boolean matches(Class type) {
24 | return type.getAnnotation(annotation) != null;
25 | }
26 |
27 | }
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/ComponentFinder.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 | import com.structurizr.model.Container;
5 |
6 | import java.net.URLClassLoader;
7 | import java.util.*;
8 | import java.util.regex.Pattern;
9 |
10 | import static com.structurizr.util.StringUtils.isNullOrEmpty;
11 |
12 | /**
13 | * This class allows you to find components in a Java codebase, when used in conjunction
14 | * with a number of pluggable component finder strategies.
15 | */
16 | public class ComponentFinder {
17 |
18 | private URLClassLoader urlClassLoader;
19 | private TypeRepository typeRepository;
20 | private Container container;
21 | private List packageNames = new ArrayList<>();
22 |
23 | // this is a default of regexes representing types we're probably not interested in */
24 | private Set exclusions = new HashSet<>(Arrays.asList(
25 | Pattern.compile("java\\..*"),
26 | Pattern.compile("javax\\..*"),
27 | Pattern.compile("sun\\..*")
28 | ));
29 |
30 | // the list of strategies, which will be executed in the order they are added
31 | private List componentFinderStrategies = new ArrayList<>();
32 |
33 | /**
34 | * Create a new component finder.
35 | *
36 | * @param container the Container that components will be added to
37 | * @param packageName the Java package name to be scanned (e.g. "com.mycompany.myapp")
38 | * @param componentFinderStrategies one or more ComponentFinderStrategy objects, describing how to find components
39 | */
40 | public ComponentFinder(Container container, String packageName, ComponentFinderStrategy... componentFinderStrategies) {
41 | if (container == null) {
42 | throw new IllegalArgumentException("A container must be specified.");
43 | }
44 |
45 | if (isNullOrEmpty(packageName)) {
46 | throw new IllegalArgumentException("A package name must be specified.");
47 | }
48 |
49 | if (componentFinderStrategies.length == 0) {
50 | throw new IllegalArgumentException("One or more ComponentFinderStrategy objects must be specified.");
51 | }
52 |
53 | this.container = container;
54 | this.packageNames.add(packageName);
55 |
56 | for (ComponentFinderStrategy componentFinderStrategy : componentFinderStrategies) {
57 | this.componentFinderStrategies.add(componentFinderStrategy);
58 | componentFinderStrategy.setComponentFinder(this);
59 | }
60 | }
61 |
62 | /**
63 | * Find components, using all of the configured component finder strategies
64 | * in the order they were added.
65 | *
66 | * @return the set of Components that were found
67 | * @throws Exception if something goes wrong
68 | */
69 | public Set findComponents() throws Exception {
70 | Set componentsFound = new HashSet<>();
71 |
72 | for (ComponentFinderStrategy componentFinderStrategy : componentFinderStrategies) {
73 | componentFinderStrategy.beforeFindComponents();
74 | }
75 |
76 | for (ComponentFinderStrategy componentFinderStrategy : componentFinderStrategies) {
77 | componentsFound.addAll(componentFinderStrategy.findComponents());
78 | }
79 |
80 | for (ComponentFinderStrategy componentFinderStrategy : componentFinderStrategies) {
81 | componentFinderStrategy.afterFindComponents();
82 | }
83 |
84 | return componentsFound;
85 | }
86 |
87 | /**
88 | * Gets the Container that components will be added to.
89 | *
90 | * @return a Container instance
91 | */
92 | public Container getContainer() {
93 | return this.container;
94 | }
95 |
96 | /**
97 | * Adds a package name to be scanned.
98 | *
99 | * @param packageName the package name as a String
100 | */
101 | public void addPackageName(String packageName) {
102 | if (isNullOrEmpty(packageName)) {
103 | throw new IllegalArgumentException("A package name must be specified.");
104 | }
105 |
106 | packageNames.add(packageName);
107 | }
108 |
109 | /**
110 | * Gets the names of the packages to be scanned.
111 | *
112 | * @return the package names, as a List of String
113 | */
114 | public List getPackageNames() {
115 | return new ArrayList<>(packageNames);
116 | }
117 |
118 | /**
119 | * Gets the set of regexes that define which types should be excluded during the component finding process.
120 | *
121 | * @return a set of Pattern (regex) instances
122 | */
123 | public Set getExclusions() {
124 | return new HashSet<>(exclusions);
125 | }
126 |
127 | /**
128 | * Adds one or more regexes to the set of regexes that define which types should be excluded during the component finding process.
129 | *
130 | * @param regexes one or more regular expressions, as Strings
131 | */
132 | public void exclude(String... regexes) {
133 | if (regexes != null) {
134 | for (String regex : regexes) {
135 | this.exclusions.add(Pattern.compile(regex));
136 | }
137 | }
138 | }
139 |
140 | /**
141 | * Clears the set of exclusions.
142 | */
143 | public void clearExclusions() {
144 | this.exclusions.clear();
145 | }
146 |
147 | /**
148 | * Sets a classloader to load classes from instead of the system classloader.
149 | *
150 | * @param urlClassLoader the classloader to use
151 | */
152 | public void setUrlClassLoader(URLClassLoader urlClassLoader) {
153 | this.urlClassLoader = urlClassLoader;
154 | }
155 |
156 | /**
157 | * Gets the classloader used to load classes.
158 | *
159 | * @return the classloader to use, or null if system classloader
160 | */
161 | public URLClassLoader getUrlClassLoader() {
162 | return urlClassLoader;
163 | }
164 |
165 | /**
166 | * Sets the type repository used to analyse java classes.
167 | *
168 | * @param typeRepository the type repository to use when analysing
169 | */
170 | public void setTypeRepository(TypeRepository typeRepository) {
171 | this.typeRepository = typeRepository;
172 | }
173 |
174 | /**
175 | * Gets the type repository used to analyse java classes.
176 | *
177 | * @return the type supplied type repository, or a default implementation
178 | */
179 | public TypeRepository getTypeRepository() {
180 | if (typeRepository == null) {
181 | typeRepository = new DefaultTypeRepository(getPackageNames(), getExclusions(), getUrlClassLoader());
182 | }
183 | return typeRepository;
184 | }
185 |
186 | }
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/ComponentFinderStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 |
5 | import java.util.Set;
6 |
7 | /**
8 | * The interface that all component finder strategies must implement.
9 | */
10 | public interface ComponentFinderStrategy {
11 |
12 | /**
13 | * Sets a reference to the parent component finder.
14 | *
15 | * @param componentFinder a ComponentFinder instance
16 | */
17 | void setComponentFinder(ComponentFinder componentFinder);
18 |
19 | /**
20 | * Called before all component finder strategies belonging to the
21 | * same component finder are asked to find components.
22 | *
23 | * @throws Exception if something goes wrong
24 | */
25 | void beforeFindComponents() throws Exception;
26 |
27 | /**
28 | * Finds components.
29 | *
30 | * @return the set of components found
31 | * @throws Exception if something goes wrong
32 | */
33 | Set findComponents() throws Exception;
34 |
35 | /**
36 | * Called after all component finder strategies belonging to the
37 | * same component finder have found components. This can be used
38 | * to supplement the component with more information, such as
39 | * dependencies.
40 | *
41 | * @throws Exception if something goes wrong
42 | */
43 | void afterFindComponents() throws Exception;
44 |
45 | }
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/DuplicateComponentException.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | public class DuplicateComponentException extends RuntimeException {
4 |
5 | DuplicateComponentException(String message) {
6 | super(message);
7 | }
8 |
9 | }
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/DuplicateComponentStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 |
5 | /**
6 | * Defines a strategy that should be called when a duplicate component is found.
7 | */
8 | public interface DuplicateComponentStrategy {
9 |
10 | /**
11 | * Called when a duplicate component is found.
12 | *
13 | * @param component the existing Component object
14 | * @param name the new component name
15 | * @param type the new component type
16 | * @param description the new description
17 | * @param technology the new technology
18 | *
19 | * @return a Component instance, or null if a new component should not be created
20 | */
21 | Component duplicateComponentFound(Component component, String name, String type, String description, String technology);
22 |
23 | }
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/ExtendsClassTypeMatcher.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | /**
4 | * Matches types where the type extends the specified class.
5 | */
6 | public class ExtendsClassTypeMatcher extends AbstractTypeMatcher {
7 |
8 | private Class classType;
9 |
10 | public ExtendsClassTypeMatcher(Class classType, String description, String technology) {
11 | super(description, technology);
12 |
13 | if (classType.isInterface() || classType.isEnum()) {
14 | throw new IllegalArgumentException(classType + " is not a class type");
15 | }
16 |
17 | this.classType = classType;
18 | }
19 |
20 | @Override
21 | public boolean matches(Class type) {
22 | return classType.isAssignableFrom(type);
23 | }
24 |
25 | }
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/FirstImplementationOfInterfaceSupportingTypesStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 | import org.apache.commons.logging.Log;
5 | import org.apache.commons.logging.LogFactory;
6 |
7 | import java.util.HashSet;
8 | import java.util.Set;
9 |
10 | /**
11 | * If the component type is an interface, this strategy finds the first implementation of that interface.
12 | */
13 | public class FirstImplementationOfInterfaceSupportingTypesStrategy extends SupportingTypesStrategy {
14 |
15 | private static final Log log = LogFactory.getLog(FirstImplementationOfInterfaceSupportingTypesStrategy.class);
16 |
17 | @Override
18 | public Set> findSupportingTypes(Component component) {
19 | Set> set = new HashSet<>();
20 |
21 | try {
22 | Class componentType = getTypeRepository().loadClass(component.getType().getType());
23 | if (componentType.isInterface()) {
24 | Class type = TypeUtils.findFirstImplementationOfInterface(componentType, getTypeRepository().getAllTypes());
25 | if (type != null) {
26 | set.add(type);
27 | }
28 | }
29 | } catch (ClassNotFoundException e) {
30 | log.warn("Could not load type " + component.getType().getType());
31 | }
32 |
33 | return set;
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/IgnoreDuplicateComponentStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 |
5 | public class IgnoreDuplicateComponentStrategy implements DuplicateComponentStrategy {
6 |
7 | /**
8 | * @param component the existing Component object
9 | * @param name the new component name
10 | * @param type the new component type
11 | * @param description the new description
12 | * @param technology the new technology
13 | * @return {@code null} means a new component should not be created
14 | */
15 | @Override
16 | public Component duplicateComponentFound(Component component, String name, String type, String description, String technology) {
17 | return null;
18 | }
19 | }
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/ImplementsInterfaceTypeMatcher.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | /**
4 | * Matches types where the type implements the specified interface.
5 | */
6 | public class ImplementsInterfaceTypeMatcher extends AbstractTypeMatcher {
7 |
8 | private Class interfaceType;
9 |
10 | public ImplementsInterfaceTypeMatcher(Class interfaceType, String description, String technology) {
11 | super(description, technology);
12 |
13 | if (!interfaceType.isInterface()) {
14 | throw new IllegalArgumentException(interfaceType + " is not an interface type");
15 | }
16 |
17 | this.interfaceType = interfaceType;
18 | }
19 |
20 | @Override
21 | public boolean matches(Class type) {
22 | return interfaceType.isAssignableFrom(type);
23 | }
24 |
25 | }
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/JavadocCommentFilter.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | /**
4 | * Cleans up Javadoc comments for inclusion in the software architecture model.
5 | */
6 | class JavadocCommentFilter {
7 |
8 | private Integer maxCommentLength;
9 |
10 | JavadocCommentFilter(Integer maxCommentLength) {
11 | if (maxCommentLength != null && maxCommentLength < 1) {
12 | throw new IllegalArgumentException("Maximum comment length must be greater than 0.");
13 | }
14 |
15 | this.maxCommentLength = maxCommentLength;
16 | }
17 |
18 | String filterAndTruncate(String s) {
19 | if (s == null) {
20 | return null;
21 | }
22 |
23 | s = s.replaceAll("\\n", " ");
24 | s = s.replaceAll("(?s)<.*?>", "");
25 | s = s.replaceAll("\\{@link (\\S*)\\}", "$1");
26 | s = s.replaceAll("\\{@link (\\S*) (.*?)\\}", "$2");
27 |
28 | if (maxCommentLength != null && s.length() > maxCommentLength) {
29 | return s.substring(0, maxCommentLength-3) + "...";
30 | } else {
31 | return s;
32 | }
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/NameSuffixTypeMatcher.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | /**
4 | * Matches types where the name of the type ends with the specified suffix.
5 | */
6 | public class NameSuffixTypeMatcher extends AbstractTypeMatcher {
7 |
8 | private String suffix;
9 |
10 | public NameSuffixTypeMatcher(String suffix, String description, String technology) {
11 | super(description, technology);
12 |
13 | if (suffix == null || suffix.trim().length() == 0) {
14 | throw new IllegalArgumentException("A suffix must be supplied");
15 | }
16 |
17 | this.suffix = suffix;
18 | }
19 |
20 | @Override
21 | public boolean matches(Class type) {
22 | return type.getSimpleName().endsWith(suffix);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/ReferencedTypesInSamePackageSupportingTypesStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.CodeElement;
4 | import com.structurizr.model.Component;
5 |
6 | import java.util.HashSet;
7 | import java.util.Set;
8 | import java.util.stream.Collectors;
9 |
10 | /**
11 | * This strategy finds all referenced types in the same package as the component type,
12 | * and is useful if each component resides in its own Java package.
13 | */
14 | public class ReferencedTypesInSamePackageSupportingTypesStrategy extends SupportingTypesStrategy {
15 |
16 | private boolean includeIndirectlyReferencedTypes;
17 |
18 | public ReferencedTypesInSamePackageSupportingTypesStrategy() {
19 | this(true);
20 | }
21 |
22 | public ReferencedTypesInSamePackageSupportingTypesStrategy(boolean includeIndirectlyReferencedTypes) {
23 | this.includeIndirectlyReferencedTypes = includeIndirectlyReferencedTypes;
24 | }
25 |
26 | @Override
27 | public Set> findSupportingTypes(Component component) {
28 | CodeElement codeElement = component.getType();
29 | if (codeElement != null) {
30 | ReferencedTypesSupportingTypesStrategy referencedTypesSupportingTypesStrategy = new ReferencedTypesSupportingTypesStrategy(includeIndirectlyReferencedTypes);
31 | referencedTypesSupportingTypesStrategy.setTypeRepository(getTypeRepository());
32 | Set> supportingTypes = referencedTypesSupportingTypesStrategy.findSupportingTypes(component);
33 |
34 | return supportingTypes.stream()
35 | .filter(type -> type.getPackage().getName().startsWith(codeElement.getPackage()))
36 | .collect(Collectors.toSet());
37 | } else {
38 | return new HashSet<>();
39 | }
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/ReferencedTypesSupportingTypesStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.CodeElement;
4 | import com.structurizr.model.Component;
5 |
6 | import java.util.HashSet;
7 | import java.util.Set;
8 |
9 | import static java.util.stream.Collectors.toSet;
10 |
11 | /**
12 | * This strategy finds all types that are referenced by the component type
13 | * and supporting types.
14 | */
15 | public class ReferencedTypesSupportingTypesStrategy extends SupportingTypesStrategy {
16 |
17 | private boolean includeIndirectlyReferencedTypes;
18 |
19 | public ReferencedTypesSupportingTypesStrategy() {
20 | this(true);
21 | }
22 |
23 | public ReferencedTypesSupportingTypesStrategy(boolean includeIndirectlyReferencedTypes) {
24 | this.includeIndirectlyReferencedTypes = includeIndirectlyReferencedTypes;
25 | }
26 |
27 | private Set> getReferencedTypesInPackage(String type) {
28 | return getTypeRepository()
29 | .findReferencedTypes(type)
30 | .stream()
31 | .filter(this::accepts)
32 | .collect(toSet());
33 | }
34 |
35 | private boolean accepts(final Class> clazz) {
36 | final String type = clazz.getCanonicalName();
37 |
38 | if (type != null) {
39 | for (final String packageName : getTypeRepository().getPackages()) {
40 | if (type.startsWith(packageName)) {
41 | return true;
42 | }
43 | }
44 | }
45 |
46 | return false;
47 | }
48 |
49 | @Override
50 | public Set> findSupportingTypes(Component component) {
51 | Set> referencedTypes = new HashSet<>();
52 | referencedTypes.addAll(getReferencedTypesInPackage(component.getType().getType()));
53 |
54 | for (CodeElement codeElement : component.getCode()) {
55 | referencedTypes.addAll(getReferencedTypesInPackage(codeElement.getType()));
56 | }
57 |
58 | if (includeIndirectlyReferencedTypes) {
59 | int numberOfTypes = referencedTypes.size();
60 | boolean foundMore = true;
61 | while (foundMore) {
62 | Set> indirectlyReferencedTypes = new HashSet<>();
63 | for (Class> type : referencedTypes) {
64 | indirectlyReferencedTypes.addAll(getReferencedTypesInPackage(type.getCanonicalName()));
65 | }
66 | referencedTypes.addAll(indirectlyReferencedTypes);
67 |
68 | if (referencedTypes.size() > numberOfTypes) {
69 | foundMore = true;
70 | numberOfTypes = referencedTypes.size();
71 | } else {
72 | foundMore = false;
73 | }
74 | }
75 | }
76 |
77 | return referencedTypes;
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/RegexTypeMatcher.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import java.util.regex.Pattern;
4 |
5 | /**
6 | * Matches types using a regex against the fully qualified type name.
7 | */
8 | public class RegexTypeMatcher extends AbstractTypeMatcher {
9 |
10 | private Pattern regex;
11 |
12 | public RegexTypeMatcher(String regex, String description, String technology) {
13 | super(description, technology);
14 |
15 | if (regex == null) {
16 | throw new IllegalArgumentException("A regex must be supplied");
17 | }
18 |
19 | this.regex = Pattern.compile(regex);
20 | }
21 |
22 | public RegexTypeMatcher(Pattern regex, String description, String technology) {
23 | super(description, technology);
24 |
25 | if (regex == null) {
26 | throw new IllegalArgumentException("A regex must be supplied");
27 | }
28 |
29 | this.regex = regex;
30 | }
31 |
32 | @Override
33 | public boolean matches(Class type) {
34 | if (type != null && type.getCanonicalName() != null) {
35 | return Pattern.matches(regex.pattern(), type.getCanonicalName());
36 | } else {
37 | return false;
38 | }
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/SourceCodeComponentFinderStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.CodeElement;
4 | import com.structurizr.model.CodeElementRole;
5 | import com.structurizr.model.Component;
6 | import com.sun.javadoc.ClassDoc;
7 | import com.sun.javadoc.RootDoc;
8 |
9 | import java.io.ByteArrayOutputStream;
10 | import java.io.File;
11 | import java.io.PrintStream;
12 | import java.nio.file.Files;
13 | import java.nio.file.Paths;
14 | import java.util.*;
15 |
16 | /**
17 | * This component finder strategy doesn't really find components, it instead:
18 | *
19 | * - Extracts the top-level Javadoc comment from the code so that this can be added to existing component definitions.
20 | * - Calculates the size of components based upon the number of lines of source code.
21 | *
22 | */
23 | public class SourceCodeComponentFinderStrategy implements ComponentFinderStrategy {
24 |
25 | private ComponentFinder componentFinder;
26 | private static RootDoc ROOTDOC;
27 |
28 | private File sourcePath;
29 | private Integer maxDescriptionLength = null;
30 | private String encoding = null;
31 |
32 | private Map typeToSourceFile = new HashMap<>();
33 | private Map typeToDescription = new HashMap<>();
34 |
35 | public SourceCodeComponentFinderStrategy(File sourcePath) {
36 | this.sourcePath = sourcePath;
37 | }
38 |
39 | public SourceCodeComponentFinderStrategy(File sourcePath, int maxDescriptionLength) {
40 | this.sourcePath = sourcePath;
41 | this.maxDescriptionLength = maxDescriptionLength;
42 | }
43 |
44 | @Override
45 | public void setComponentFinder(ComponentFinder componentFinder) {
46 | this.componentFinder = componentFinder;
47 | }
48 |
49 | public void setEncoding(String encoding) {
50 | this.encoding = encoding;
51 | }
52 |
53 | @Override
54 | public void beforeFindComponents() throws Exception {
55 | }
56 |
57 | @Override
58 | public Set findComponents() throws Exception {
59 | return new HashSet<>(); // this component finder doesn't find components
60 | }
61 |
62 | @Override
63 | public void afterFindComponents() throws Exception {
64 | runJavaDoc();
65 |
66 | JavadocCommentFilter filter = new JavadocCommentFilter(maxDescriptionLength);
67 | for (ClassDoc classDoc : ROOTDOC.classes()) {
68 | String type = classDoc.qualifiedTypeName();
69 | String comment = filter.filterAndTruncate(classDoc.commentText());
70 | String pathToSourceFile = classDoc.position().file().getCanonicalPath();
71 |
72 | typeToSourceFile.put(type, new File(pathToSourceFile));
73 | typeToDescription.put(type, comment);
74 | }
75 |
76 | for (Component component : componentFinder.getContainer().getComponents()) {
77 | long count = 0;
78 |
79 | for (CodeElement codeElement : component.getCode()) {
80 | if (typeToDescription.containsKey(codeElement.getType())) {
81 | codeElement.setDescription(typeToDescription.get(codeElement.getType()));
82 |
83 | // additionally set the description on the component, if it's not already been set
84 | if (codeElement.getRole() == CodeElementRole.Primary) {
85 | if (component.getDescription() == null || component.getDescription().trim().length() == 0) {
86 | component.setDescription(typeToDescription.get(component.getType().getType()));
87 | }
88 | }
89 | }
90 |
91 | File sourceFile = typeToSourceFile.get(codeElement.getType());
92 | if (sourceFile != null) {
93 | long numberOfLinesInFile = Files.lines(Paths.get(sourceFile.toURI())).count();
94 | codeElement.setUrl(sourceFile.toURI().toString());
95 | codeElement.setSize(numberOfLinesInFile);
96 | count += numberOfLinesInFile;
97 | }
98 | }
99 |
100 | if (count > 0) {
101 | component.setSize(count);
102 | }
103 | }
104 | }
105 |
106 | private void runJavaDoc() throws Exception {
107 | List parameters = new LinkedList<>();
108 | parameters.add("-sourcepath");
109 | parameters.add(sourcePath.getCanonicalPath());
110 | parameters.add("-subpackages");
111 | parameters.add(String.join(":", componentFinder.getPackageNames()));
112 |
113 | if (encoding != null) {
114 | parameters.add("-encoding");
115 | parameters.add(encoding);
116 | }
117 |
118 | parameters.add("-private");
119 |
120 | final PrintStream outOriginal = System.out;
121 | final PrintStream errOriginal = System.err;
122 | final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
123 | System.setOut(new PrintStream(bytes));
124 | System.setErr(System.out);
125 | try {
126 | com.sun.tools.javadoc.Main.execute(
127 | "StructurizrDoclet",
128 | this.getClass().getName(),
129 | parameters.toArray(new String[parameters.size()])
130 | );
131 | }
132 | catch (Throwable t) {
133 | outOriginal.write(bytes.toByteArray());
134 | outOriginal.flush();
135 | throw t;
136 | }
137 | finally {
138 | System.setOut(outOriginal);
139 | System.setErr(errOriginal);
140 | }
141 | }
142 |
143 | public static boolean start(RootDoc rootDoc) {
144 | ROOTDOC = rootDoc;
145 | return true;
146 | }
147 |
148 | }
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/SupportingTypesStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 |
5 | import java.util.Set;
6 |
7 | /**
8 | * Superclass for strategies used to find the types that support a component.
9 | */
10 | public abstract class SupportingTypesStrategy {
11 |
12 | private TypeRepository typeRepository;
13 |
14 | protected TypeRepository getTypeRepository() {
15 | return typeRepository;
16 | }
17 |
18 | void setTypeRepository(TypeRepository typeRepository) {
19 | this.typeRepository = typeRepository;
20 | }
21 |
22 | public abstract Set> findSupportingTypes(Component component);
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/ThrowExceptionDuplicateComponentStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 |
5 | /**
6 | * Throws an exception when a duplicate component is found.
7 | */
8 | public class ThrowExceptionDuplicateComponentStrategy implements DuplicateComponentStrategy {
9 |
10 | @Override
11 | public Component duplicateComponentFound(Component component, String name, String type, String description, String technology) {
12 | throw new DuplicateComponentException(String.format(
13 | "A component named \"%s\" already exists in the container named \"%s\".",
14 | component.getName(),
15 | component.getContainer().getName()));
16 | }
17 |
18 | }
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/TypeCategory.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | public final class TypeCategory {
4 |
5 | public static final TypeCategory CLASS = new TypeCategory("class");
6 | public static final TypeCategory INTERFACE = new TypeCategory("interface");
7 | public static final TypeCategory ABSTRACT_CLASS = new TypeCategory("abstract");
8 | public static final TypeCategory ENUM = new TypeCategory("enum");
9 |
10 | private String name;
11 |
12 | private TypeCategory(String name) {
13 | this.name = name;
14 | }
15 |
16 | public String getName() {
17 | return name;
18 | }
19 |
20 | @Override
21 | public String toString() {
22 | return name;
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/TypeMatcher.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | /**
4 | * Determines whether a given type implements the rules for being identified as a component.
5 | */
6 | public interface TypeMatcher {
7 |
8 | boolean matches(Class type);
9 |
10 | String getDescription();
11 |
12 | String getTechnology();
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/TypeMatcherComponentFinderStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 | import com.structurizr.model.Container;
5 |
6 | import java.util.*;
7 |
8 | /**
9 | * A component finder strategy that uses type information to find components, based upon a number
10 | * of pluggable {@link TypeMatcher} implementations.
11 | */
12 | public class TypeMatcherComponentFinderStrategy extends AbstractComponentFinderStrategy {
13 |
14 | private List typeMatchers = new LinkedList<>();
15 |
16 | public TypeMatcherComponentFinderStrategy(TypeMatcher... typeMatchers) {
17 | this.typeMatchers.addAll(Arrays.asList(typeMatchers));
18 | }
19 |
20 | @Override
21 | protected Set doFindComponents() {
22 | Set components = new HashSet<>();
23 |
24 | Set> types = getTypeRepository().getAllTypes();
25 | for (Class type : types) {
26 | for (TypeMatcher typeMatcher : typeMatchers) {
27 | if (typeMatcher.matches(type)) {
28 | final Container container = getComponentFinder().getContainer();
29 | Component newComponent = addComponent(
30 | container,
31 | type.getSimpleName(),
32 | type.getCanonicalName(),
33 | typeMatcher.getDescription(),
34 | typeMatcher.getTechnology());
35 |
36 | if (newComponent != null) {
37 | components.add(newComponent);
38 | }
39 | }
40 | }
41 | }
42 |
43 | return components;
44 | }
45 |
46 | }
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/TypeRepository.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import java.util.List;
4 | import java.util.Set;
5 |
6 | /**
7 | * This represents an abstraction for a repository of type information.
8 | */
9 | public interface TypeRepository {
10 |
11 | /**
12 | * Gets the packages that this type repository is associated with scanning.
13 | *
14 | * @return the fully qualified package names
15 | */
16 | List getPackages();
17 |
18 | /**
19 | * Gets all of the types found by this type repository.
20 | *
21 | * @return a Set of Class objects, or an empty set of no classes were found
22 | */
23 | Set> getAllTypes();
24 |
25 | /**
26 | * Finds the set of types referenced by the specified type.
27 | *
28 | * @param typeName the starting type
29 | * @return a Set of Class objects, or an empty set if none were found
30 | */
31 | Set> findReferencedTypes(String typeName);
32 |
33 | /**
34 | * Loads the specified type.
35 | * @param typeName the type to load
36 | * @return a Class object
37 | * @throws ClassNotFoundException if the class cannot be found and created
38 | */
39 | Class> loadClass(String typeName) throws ClassNotFoundException;
40 |
41 | }
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/TypeUtils.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import org.apache.commons.logging.Log;
4 | import org.apache.commons.logging.LogFactory;
5 |
6 | import java.lang.annotation.Annotation;
7 | import java.lang.reflect.Modifier;
8 | import java.util.Set;
9 | import java.util.stream.Collectors;
10 |
11 | /**
12 | * Some utility methods for working with types.
13 | */
14 | public class TypeUtils {
15 |
16 | private static final Log log = LogFactory.getLog(TypeUtils.class);
17 |
18 | /**
19 | * Finds the visibility of a given type.
20 | *
21 | * @param typeRepository the repository where types should be loaded from
22 | * @param typeName the fully qualified type name
23 | * @return a TypeVisibility object representing the visibility (e.g. public, package, etc)
24 | */
25 | public static TypeVisibility getVisibility(TypeRepository typeRepository, String typeName) {
26 | try {
27 | Class> type = typeRepository.loadClass(typeName);
28 | int modifiers = type.getModifiers();
29 | if (Modifier.isPrivate(modifiers)) {
30 | return TypeVisibility.PRIVATE;
31 | } else if (Modifier.isPublic(modifiers)) {
32 | return TypeVisibility.PUBLIC;
33 | } else if (Modifier.isProtected(modifiers)) {
34 | return TypeVisibility.PROTECTED;
35 | } else {
36 | return TypeVisibility.PACKAGE;
37 | }
38 | } catch (ClassNotFoundException e) {
39 | log.warn("Visibility for type " + typeName + " could not be found.");
40 | return null;
41 | }
42 | }
43 |
44 | /**
45 | * Finds the category of a given type.
46 | *
47 | * @param typeRepository the repository where types should be loaded from
48 | * @param typeName the fully qualified type name
49 | * @return a TypeCategory object representing the category (e.g. class, interface, enum, etc)
50 | */
51 | public static TypeCategory getCategory(TypeRepository typeRepository, String typeName) {
52 | try {
53 | Class> type = typeRepository.loadClass(typeName);
54 | if (type.isInterface()) {
55 | return TypeCategory.INTERFACE;
56 | } else if (type.isEnum()) {
57 | return TypeCategory.ENUM;
58 | } else {
59 | if (Modifier.isAbstract(type.getModifiers())) {
60 | return TypeCategory.ABSTRACT_CLASS;
61 | } else{
62 | return TypeCategory.CLASS;
63 | }
64 | }
65 | } catch (ClassNotFoundException e) {
66 | log.warn("Category for type " + typeName + " could not be found.");
67 | return null;
68 | }
69 | }
70 |
71 | /**
72 | * Finds the set of types that are annotated with the specified annotation.
73 | *
74 | * @param annotation the Annotation to find
75 | * @param types the set of Class objects to search through
76 | * @return a Set of Class objects, or an empty set of none could be found
77 | */
78 | public static Set> findTypesAnnotatedWith(Class extends Annotation> annotation, Set> types) {
79 | if (annotation == null) {
80 | throw new IllegalArgumentException("An annotation type must be specified.");
81 | }
82 |
83 | return types.stream().filter(c -> c.isAnnotationPresent(annotation)).collect(Collectors.toSet());
84 | }
85 |
86 | /**
87 | * Finds the first implementation of the given interface.
88 | *
89 | * @param interfaceType a Class object representing the interface type
90 | * @param types the set of Class objects to search through
91 | * @return the first concrete implementation class of the given interface,
92 | * or null if one can't be found
93 | */
94 | public static Class findFirstImplementationOfInterface(Class interfaceType, Set> types) {
95 | if (interfaceType == null) {
96 | throw new IllegalArgumentException("An interface type must be provided.");
97 | } else if (!interfaceType.isInterface()) {
98 | throw new IllegalArgumentException("The interface type must represent an interface.");
99 | }
100 |
101 | if (types == null) {
102 | throw new IllegalArgumentException("The set of types to search through must be provided.");
103 | }
104 |
105 | for (Class> type : types) {
106 | boolean isInterface = type.isInterface();
107 | boolean isAbstract = Modifier.isAbstract(type.getModifiers());
108 | boolean isAssignable = interfaceType.isAssignableFrom(type);
109 | if (!isInterface && !isAbstract && isAssignable) {
110 | return type;
111 | }
112 | }
113 |
114 | return null;
115 | }
116 |
117 | }
--------------------------------------------------------------------------------
/structurizr-analysis/src/com/structurizr/analysis/TypeVisibility.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | public final class TypeVisibility {
4 |
5 | public static final TypeVisibility PUBLIC = new TypeVisibility("public");
6 | public static final TypeVisibility PACKAGE = new TypeVisibility("package");
7 | public static final TypeVisibility PROTECTED = new TypeVisibility("protected");
8 | public static final TypeVisibility PRIVATE = new TypeVisibility("private");
9 |
10 | private String name;
11 |
12 | private TypeVisibility(String name) {
13 | this.name = name;
14 | }
15 |
16 | public String getName() {
17 | return name;
18 | }
19 |
20 | @Override
21 | public String toString() {
22 | return name;
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/AbstractWorkspaceTestBase.java:
--------------------------------------------------------------------------------
1 | package com.structurizr;
2 |
3 | import com.structurizr.model.Model;
4 | import com.structurizr.view.ViewSet;
5 |
6 | public class AbstractWorkspaceTestBase {
7 |
8 | protected Workspace workspace = new Workspace("Name", "Description");
9 | protected Model model = workspace.getModel();
10 | protected ViewSet views = workspace.getViews();
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/AbstractComponentFinderStrategyTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertEquals;
6 | import static org.junit.Assert.fail;
7 |
8 | public class AbstractComponentFinderStrategyTests {
9 |
10 | private AbstractComponentFinderStrategy strategy = new TypeMatcherComponentFinderStrategy();
11 |
12 | @Test
13 | public void test_addSupportingTypesStrategy_ThrowsAnException_WhenANullSupportingTypesStrategyIsSpecified() {
14 | try {
15 | strategy.addSupportingTypesStrategy(null);
16 | fail();
17 | } catch (IllegalArgumentException iae) {
18 | assertEquals("A supporting types strategy must be provided.", iae.getMessage());
19 | }
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/AnnotatedMethodComponentFinderStrategyTest.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.Workspace;
4 | import com.structurizr.model.Component;
5 | import com.structurizr.model.Container;
6 | import com.structurizr.model.Relationship;
7 | import org.junit.Test;
8 | import test.AnnotatedMethodComponentFinderStrategy.main.Bean;
9 | import test.AnnotatedMethodComponentFinderStrategy.main.Configuration;
10 | import test.AnnotatedMethodComponentFinderStrategy.main.FakeComponent;
11 | import test.AnnotatedMethodComponentFinderStrategy.main.FakeComponentImpl;
12 | import test.AnnotatedMethodComponentFinderStrategy.main.FakeEfferentComponentImpl;
13 |
14 | import java.util.Set;
15 |
16 | import static org.assertj.core.api.Assertions.assertThatThrownBy;
17 | import static org.assertj.core.api.Assertions.from;
18 | import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
19 |
20 | public class AnnotatedMethodComponentFinderStrategyTest {
21 |
22 | private ComponentFinder componentFinder;
23 | private Container fakeContainer = new Workspace("Fake Workspace", "")
24 | .getModel()
25 | .addSoftwareSystem("Fake System", "")
26 | .addContainer("Fake Container", "", "");
27 | private String rootPackageToScan = "test.AnnotatedMethodComponentFinderStrategy";
28 | private String mainPackageToScan = "test.AnnotatedMethodComponentFinderStrategy.main";
29 |
30 | @Test
31 | public void test_findComponentsFromAnnotatedMethodsOnlyFromSpecifiedClassesIgnoringDuplicatesOfSameImplType() throws Exception {
32 | componentFinder = new ComponentFinder(fakeContainer, mainPackageToScan, new AnnotatedMethodComponentFinderStrategy(Bean.class, Configuration.class));
33 |
34 | Set components = componentFinder.findComponents();
35 | assertThat(components).hasSize(2);
36 |
37 | Component fakeComponent = fakeContainer.getComponentWithName(FakeComponent.class.getSimpleName());
38 | assertThat(fakeComponent)
39 | .returns(FakeComponentImpl.class.getName(), from(c -> c.getType().getType()))
40 | .returns("", from(Component::getDescription))
41 | .returns("", from(Component::getTechnology));
42 |
43 | Component fakeEfferentComponent = fakeContainer.getComponentWithName(FakeEfferentComponentImpl.class.getSimpleName());
44 | assertThat(fakeComponent.getRelationships()).hasOnlyOneElementSatisfying(relationship ->
45 | assertThat(relationship)
46 | .returns(fakeComponent, Relationship::getSource)
47 | .returns(fakeEfferentComponent, Relationship::getDestination)
48 | );
49 | }
50 |
51 | @Test
52 | public void test_findComponentsFromAllAnnotatedMethodsIgnoreDuplicatesOfSameImplType() throws Exception {
53 | componentFinder = new ComponentFinder(fakeContainer, mainPackageToScan, new AnnotatedMethodComponentFinderStrategy(Bean.class));
54 |
55 | Set components = componentFinder.findComponents();
56 |
57 | assertThat(components).hasSize(3);
58 | }
59 |
60 | @Test
61 | public void test_findComponentsFromAllAnnotatedMethodsIgnoringAllDuplicates_WhenIgnoreStrategyPassed() throws Exception {
62 | componentFinder = new ComponentFinder(fakeContainer, rootPackageToScan, new AnnotatedMethodComponentFinderStrategy(Bean.class, new IgnoreDuplicateComponentStrategy()));
63 |
64 | Set components = componentFinder.findComponents();
65 |
66 | assertThat(components).hasSize(3);
67 | }
68 |
69 | @Test
70 | public void test_findComponentsFromAllAnnotatedMethodsIgnoringAllDuplicates_WhenNullAsDuplicateStrategyPassed() throws Exception {
71 | componentFinder = new ComponentFinder(fakeContainer, rootPackageToScan, new AnnotatedMethodComponentFinderStrategy(Bean.class, null, null));
72 |
73 | Set components = componentFinder.findComponents();
74 |
75 | assertThat(components).hasSize(3);
76 | }
77 |
78 | @Test
79 | public void test_findComponents_ThrowsDuplicateComponentException_WhenThrowStrategyPassed() {
80 | componentFinder = new ComponentFinder(fakeContainer, rootPackageToScan, new AnnotatedMethodComponentFinderStrategy(Bean.class, new ThrowExceptionDuplicateComponentStrategy()));
81 |
82 | assertThatThrownBy(() -> componentFinder.findComponents()).isInstanceOf(DuplicateComponentException.class);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/AnnotationTypeMatcherTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.annotation.Component;
4 | import org.junit.Test;
5 |
6 | import static org.junit.Assert.assertFalse;
7 | import static org.junit.Assert.assertTrue;
8 |
9 | public class AnnotationTypeMatcherTests {
10 |
11 | @Test(expected = IllegalArgumentException.class)
12 | public void test_construction_ThrowsAnExceptionWhenANullAnnotationClassIsSupplied()
13 | {
14 | new AnnotationTypeMatcher(null, "", "");
15 | }
16 |
17 | @Test
18 | public void test_matches_ReturnsFalse_WhenTheGivenTypeDoesNotHaveTheAnnotation()
19 | {
20 | AnnotationTypeMatcher matcher = new AnnotationTypeMatcher(Component.class, "", "");
21 | assertFalse(matcher.matches(MyService.class));
22 | }
23 |
24 | @Test
25 | public void test_matches_ReturnsTrue_WhenTheGivenTypeDoesHaveTheAnnotation()
26 | {
27 | AnnotationTypeMatcher matcher = new AnnotationTypeMatcher(Component.class, "", "");
28 | assertTrue(matcher.matches(MyController.class));
29 | }
30 |
31 | @Component
32 | private class MyController {
33 | }
34 |
35 | private class MyService {
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/ComponentFinderTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.AbstractWorkspaceTestBase;
4 | import com.structurizr.model.Container;
5 | import org.junit.Test;
6 |
7 | import static org.junit.Assert.assertEquals;
8 | import static org.junit.Assert.fail;
9 |
10 | public class ComponentFinderTests extends AbstractWorkspaceTestBase {
11 |
12 | @Test
13 | public void test_construction_ThrowsAnException_WhenANullContainerIsSpecified() {
14 | try {
15 | new ComponentFinder(null, null);
16 | fail();
17 | } catch (IllegalArgumentException iae) {
18 | assertEquals("A container must be specified.", iae.getMessage());
19 | }
20 | }
21 |
22 | @Test
23 | public void test_construction_ThrowsAnException_WhenANullPackageNameIsSpecified() {
24 | try {
25 | Container container = model.addSoftwareSystem("Software System", "").addContainer("Container", "", "");
26 | new ComponentFinder(container, null);
27 | fail();
28 | } catch (IllegalArgumentException iae) {
29 | assertEquals("A package name must be specified.", iae.getMessage());
30 | }
31 | }
32 |
33 | @Test
34 | public void test_construction_ThrowsAnException_WhenNoComponentFinderStrategiesAreSpecified() {
35 | try {
36 | Container container = model.addSoftwareSystem("Software System", "").addContainer("Container", "", "");
37 | new ComponentFinder(container, "com.mycompany.myapp");
38 | fail();
39 | } catch (IllegalArgumentException iae) {
40 | assertEquals("One or more ComponentFinderStrategy objects must be specified.", iae.getMessage());
41 | }
42 | }
43 |
44 | @Test
45 | public void test_addPackageName_ThrowsAnException_WhenANullPackageNameIsSpecified() {
46 | try {
47 | Container container = model.addSoftwareSystem("Software System", "").addContainer("Container", "", "");
48 | ComponentFinder componentFinder = new ComponentFinder(container, "com.mycompany.myapp", new TypeMatcherComponentFinderStrategy(new NameSuffixTypeMatcher("Component", "", "")));
49 | componentFinder.addPackageName(null);
50 | fail();
51 | } catch (IllegalArgumentException iae) {
52 | assertEquals("A package name must be specified.", iae.getMessage());
53 | }
54 | }
55 |
56 | @Test
57 | public void test_addPackageName_ThrowsAnException_WhenAnEmptyPackageNameIsSpecified() {
58 | try {
59 | Container container = model.addSoftwareSystem("Software System", "").addContainer("Container", "", "");
60 | ComponentFinder componentFinder = new ComponentFinder(container, "com.mycompany.myapp", new TypeMatcherComponentFinderStrategy(new NameSuffixTypeMatcher("Component", "", "")));
61 | componentFinder.addPackageName(" ");
62 | fail();
63 | } catch (IllegalArgumentException iae) {
64 | assertEquals("A package name must be specified.", iae.getMessage());
65 | }
66 | }
67 |
68 | }
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/DefaultTypeRepositoryTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.HashSet;
6 | import java.util.Set;
7 | import java.util.regex.Pattern;
8 | import java.util.stream.Collectors;
9 |
10 | import static java.util.Arrays.asList;
11 | import static org.junit.Assert.assertEquals;
12 | import static org.junit.Assert.assertTrue;
13 |
14 | public class DefaultTypeRepositoryTests {
15 |
16 | private DefaultTypeRepository typeRepository;
17 |
18 | @Test
19 | public void test_getAllTypes_ReturnsAnEmptySet_WhenNoTypesWereFound() {
20 | typeRepository = new DefaultTypeRepository("com.structurizr.analysis.foo", new HashSet<>(), null);
21 | Set> types = typeRepository.getAllTypes();
22 | assertTrue(types.isEmpty());
23 | }
24 |
25 | @Test
26 | public void test_getAllTypes_ReturnsANonEmptySet_WhenTypesWereFound() {
27 | typeRepository = new DefaultTypeRepository("test.DefaultTypeRepository", new HashSet<>(), null);
28 | Set types = typeRepository.getAllTypes().stream().map(Class::getCanonicalName).collect(Collectors.toSet());
29 | assertEquals(4, types.size());
30 |
31 | assertTrue(types.contains("test.DefaultTypeRepository.SomeAbstractClass"));
32 | assertTrue(types.contains("test.DefaultTypeRepository.SomeClass"));
33 | assertTrue(types.contains("test.DefaultTypeRepository.SomeEnum"));
34 | assertTrue(types.contains("test.DefaultTypeRepository.SomeInterface"));
35 | }
36 |
37 | @Test
38 | public void test_getAllTypes_ReturnsANonEmptySet_WhenTypesAreFoundAndExclusionsHaveBeenSpecified() {
39 | Set exclusions = new HashSet<>();
40 | exclusions.add(Pattern.compile(".*Abstract.*"));
41 | typeRepository = new DefaultTypeRepository("test.DefaultTypeRepository", exclusions, null);
42 | Set types = typeRepository.getAllTypes().stream().map(Class::getCanonicalName).collect(Collectors.toSet());
43 | assertEquals(3, types.size());
44 |
45 | assertTrue(types.contains("test.DefaultTypeRepository.SomeEnum"));
46 | assertTrue(types.contains("test.DefaultTypeRepository.SomeClass"));
47 | assertTrue(types.contains("test.DefaultTypeRepository.SomeInterface"));
48 | }
49 |
50 | @Test
51 | public void test_getAllTypes_ReturnsCompleteSet_WhenThereAreMultiplePackages() throws Exception {
52 | typeRepository = new DefaultTypeRepository(asList("test.DefaultTypeRepository","test.MoreDefaultTypeRepository"), new HashSet<>(), null);
53 |
54 | Set types = typeRepository.getAllTypes().stream().map(Class::getCanonicalName).collect(Collectors.toSet());
55 | assertEquals(4+1, types.size());
56 |
57 | assertTrue(types.contains("test.DefaultTypeRepository.SomeAbstractClass"));
58 | assertTrue(types.contains("test.DefaultTypeRepository.SomeClass"));
59 | assertTrue(types.contains("test.DefaultTypeRepository.SomeEnum"));
60 | assertTrue(types.contains("test.DefaultTypeRepository.SomeInterface"));
61 |
62 | assertTrue(types.contains("test.MoreDefaultTypeRepository.AnotherClass"));
63 | }
64 |
65 | @Test
66 | public void test_findReferencedTypes_ReturnsASetOnlyContainingJavaLangObject_WhenThereAreNoTypesReferenced() throws Exception {
67 | typeRepository = new DefaultTypeRepository("test.DefaultTypeRepository", new HashSet<>(), null);
68 | Set types = typeRepository.findReferencedTypes("test.DefaultTypeRepository.SomeInterface").stream().map(Class::getCanonicalName).collect(Collectors.toSet());
69 | assertEquals(1, types.size());
70 |
71 | assertTrue(types.contains("java.lang.Object"));
72 | }
73 |
74 | @Test
75 | public void test_findReferencedTypes_ReturnsANonEmptySet_WhenThereAreTypesReferenced() throws Exception {
76 | typeRepository = new DefaultTypeRepository("test.DefaultTypeRepository", new HashSet<>(), null);
77 | Set types = typeRepository.findReferencedTypes("test.DefaultTypeRepository.SomeClass").stream().map(Class::getCanonicalName).collect(Collectors.toSet());
78 | assertEquals(3, types.size());
79 |
80 | assertTrue(types.contains("test.DefaultTypeRepository.SomeEnum"));
81 | assertTrue(types.contains("test.DefaultTypeRepository.SomeAbstractClass"));
82 | assertTrue(types.contains("com.structurizr.annotation.Component"));
83 | }
84 |
85 | }
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/ExtendsClassTypeMatcherTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertFalse;
6 | import static org.junit.Assert.assertTrue;
7 |
8 | public class ExtendsClassTypeMatcherTests {
9 |
10 | @Test(expected = IllegalArgumentException.class)
11 | public void test_construction_ThrowsAnExceptionWhenAnInterfaceTypeIsSupplied()
12 | {
13 | new ExtendsClassTypeMatcher(MyRepository.class, "", "");
14 | }
15 |
16 | @Test(expected = IllegalArgumentException.class)
17 | public void test_construction_ThrowsAnExceptionWhenAnEnumTypeIsSupplied()
18 | {
19 | new ExtendsClassTypeMatcher(MyEnum.class, "", "");
20 | }
21 |
22 | @Test
23 | public void test_matches_ReturnsFalse_WhenTheGivenTypeDoesNotExtendTheClass()
24 | {
25 | ExtendsClassTypeMatcher matcher = new ExtendsClassTypeMatcher(AbstractComponent.class, "", "");
26 | assertFalse(matcher.matches(MyOtherClass.class));
27 | }
28 |
29 | @Test
30 | public void test_matches_ReturnsTrue_WhenTheGivenTypeDoesExtendTheClass()
31 | {
32 | ExtendsClassTypeMatcher matcher = new ExtendsClassTypeMatcher(AbstractComponent.class, "", "");
33 | assertTrue(matcher.matches(MyController.class));
34 | assertTrue(matcher.matches(MyRepositoryImpl.class));
35 | }
36 |
37 | private abstract class AbstractComponent {
38 | }
39 |
40 | private class MyController extends AbstractComponent {
41 | }
42 |
43 | private interface MyRepository {
44 | }
45 |
46 | private class MyRepositoryImpl extends AbstractComponent implements MyRepository {
47 | }
48 |
49 | private class MyOtherClass {
50 | }
51 |
52 | private enum MyEnum {
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/ImplementsInterfaceTypeMatcherTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertFalse;
6 | import static org.junit.Assert.assertTrue;
7 |
8 | public class ImplementsInterfaceTypeMatcherTests {
9 |
10 | @Test(expected = IllegalArgumentException.class)
11 | public void test_construction_ThrowsAnExceptionWhenANonInterfaceTypeIsSupplied()
12 | {
13 | new ImplementsInterfaceTypeMatcher(MyRepositoryImpl.class, "", "");
14 | }
15 |
16 | @Test
17 | public void test_matches_ReturnsFalse_WhenTheGivenTypeDoesNotImplementTheInterface()
18 | {
19 | ImplementsInterfaceTypeMatcher matcher = new ImplementsInterfaceTypeMatcher(MyRepository.class, "", "");
20 | assertFalse(matcher.matches(MyController.class));
21 | }
22 |
23 | @Test
24 | public void test_matches_ReturnsTrue_WhenTheGivenTypeDoesImplementTheInterface()
25 | {
26 | ImplementsInterfaceTypeMatcher matcher = new ImplementsInterfaceTypeMatcher(MyRepository.class, "", "");
27 | assertTrue(matcher.matches(MyRepositoryImpl.class));
28 | }
29 |
30 | private class MyController {
31 | }
32 |
33 | private interface MyRepository {
34 | }
35 |
36 | private class MyRepositoryImpl implements MyRepository {
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/JavadocCommentFilterTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertEquals;
6 | import static org.junit.Assert.assertNull;
7 |
8 | public class JavadocCommentFilterTests {
9 |
10 | @Test(expected = IllegalArgumentException.class)
11 | public void test_construction_ThrowsAnIllegalArgumentException_WhenZeroIsSpecified() {
12 | new JavadocCommentFilter(0);
13 | }
14 |
15 | @Test(expected = IllegalArgumentException.class)
16 | public void test_construction_ThrowsAnIllegalArgumentException_WhenANegativeNumberIsSpecified() {
17 | new JavadocCommentFilter(-1);
18 | }
19 |
20 | @Test
21 | public void test_filterAndTruncate_ReturnsNull_WhenGivenNull() {
22 | assertNull(new JavadocCommentFilter(null).filterAndTruncate(null));
23 | }
24 |
25 | @Test
26 | public void test_filterAndTruncate_ReturnsTheOriginalText_WhenNoMaxLengthHasBeenSpecified()
27 | {
28 | assertEquals("Here is some text.", new JavadocCommentFilter(null).filterAndTruncate("Here is some text."));
29 | }
30 |
31 | @Test
32 | public void test_filterAndTruncate_TruncatesTheTextWhenAMaxLengthHasBeenSpecified()
33 | {
34 | assertEquals("Here...", new JavadocCommentFilter(7).filterAndTruncate("Here is some text."));
35 | }
36 |
37 | @Test
38 | public void test_filterAndTruncate_FiltersJavadocLinkTags()
39 | {
40 | assertEquals("Uses SomeClass and AnotherClass to do some work.", new JavadocCommentFilter(null).filterAndTruncate("Uses {@link SomeClass} and {@link AnotherClass} to do some work."));
41 | }
42 |
43 | @Test
44 | public void test_filterAndTruncate_FiltersJavadocLinkTagsWithLabels()
45 | {
46 | assertEquals("Uses some class and another class to do some work.", new JavadocCommentFilter(null).filterAndTruncate("Uses {@link SomeClass some class} and {@link AnotherClass another class} to do some work."));
47 | }
48 |
49 | @Test
50 | public void test_filterAndTruncate_FiltersHtml()
51 | {
52 | assertEquals("Uses SomeClass and AnotherClass to do some work.", new JavadocCommentFilter(null).filterAndTruncate("Uses SomeClass and AnotherClass to do some work."));
53 | }
54 |
55 | @Test
56 | public void test_filterAndTruncate_FiltersLineBreaks()
57 | {
58 | assertEquals("Uses SomeClass and AnotherClass to do some work.", new JavadocCommentFilter(null).filterAndTruncate("Uses SomeClass and AnotherClass\nto do some work."));
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/NameSuffixTypeMatcherTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertFalse;
6 | import static org.junit.Assert.assertTrue;
7 |
8 | public class NameSuffixTypeMatcherTests {
9 |
10 | @Test(expected = IllegalArgumentException.class)
11 | public void test_construction_ThrowsAnExceptionWhenANullSuffixIsSupplied()
12 | {
13 | new NameSuffixTypeMatcher(null, "", "");
14 | }
15 |
16 | @Test(expected = IllegalArgumentException.class)
17 | public void test_construction_ThrowsAnExceptionWhenAnEmptyStringSuffixIsSupplied()
18 | {
19 | new NameSuffixTypeMatcher(" ", "", "");
20 | }
21 |
22 | @Test
23 | public void test_matches_ReturnsFalse_WhenTheNameOfTheGivenTypeDoesNotHaveTheSuffix()
24 | {
25 | NameSuffixTypeMatcher matcher = new NameSuffixTypeMatcher("Component", "", "");
26 | assertFalse(matcher.matches(MyController.class));
27 | }
28 |
29 | @Test
30 | public void Ttest_matches_ReturnsTrue_WhenTheNameOfTheGivenTypeDoesHaveTheSuffix()
31 | {
32 | NameSuffixTypeMatcher matcher = new NameSuffixTypeMatcher("Controller", "", "");
33 | assertTrue(matcher.matches(MyController.class));
34 | }
35 |
36 | private class MyController {
37 | }
38 |
39 | }
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/RegexTypeMatcherTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.regex.Pattern;
6 |
7 | import static org.junit.Assert.assertFalse;
8 | import static org.junit.Assert.assertTrue;
9 |
10 | public class RegexTypeMatcherTests {
11 |
12 | @Test(expected = IllegalArgumentException.class)
13 | public void test_construction_ThrowsAnExceptionWhenANullRegexAsAStringIsSupplied()
14 | {
15 | new RegexTypeMatcher((String)null, "", "");
16 | }
17 |
18 | @Test(expected = IllegalArgumentException.class)
19 | public void test_construction_ThrowsAnExceptionWhenANullRegexAsAPatternIsSupplied()
20 | {
21 | new RegexTypeMatcher((Pattern)null, "", "");
22 | }
23 |
24 | @Test
25 | public void test_matches_ReturnsFalse_WhenTheNameOfTheGivenTypeDoesNotMatchTheRegex()
26 | {
27 | RegexTypeMatcher matcher = new RegexTypeMatcher(Pattern.compile("MyController"), "", "");
28 | assertFalse(matcher.matches(MyController.class));
29 |
30 | matcher = new RegexTypeMatcher("MyController", "", "");
31 | assertFalse(matcher.matches(MyController.class));
32 | }
33 |
34 | @Test
35 | public void test_matches_ReturnsTrue_WhenTheNameOfTheGivenTypeDoesMatchTheRegex()
36 | {
37 | String regex = ".*\\.analysis\\..*Controller";
38 |
39 | RegexTypeMatcher matcher = new RegexTypeMatcher(Pattern.compile(regex), "", "");
40 | assertTrue(matcher.matches(MyController.class));
41 |
42 | matcher = new RegexTypeMatcher(regex, "", "");
43 | assertTrue(matcher.matches(MyController.class));
44 | }
45 |
46 | @Test
47 | public void test_matches_ReturnsFalse_WhenPassedANullType() {
48 | String regex = ".*\\.analysis\\..*Controller";
49 |
50 | RegexTypeMatcher matcher = new RegexTypeMatcher(Pattern.compile(regex), "", "");
51 | assertFalse(matcher.matches(null));
52 | }
53 |
54 | private class MyController {
55 | }
56 |
57 | }
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/SourceCodeComponentFinderStrategyTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.Workspace;
4 | import com.structurizr.model.Component;
5 | import com.structurizr.model.Container;
6 | import com.structurizr.model.Model;
7 | import com.structurizr.model.SoftwareSystem;
8 | import org.junit.Before;
9 | import org.junit.Test;
10 |
11 | import java.io.File;
12 |
13 | import static org.junit.Assert.assertEquals;
14 |
15 | public class SourceCodeComponentFinderStrategyTests {
16 |
17 | private Container webApplication;
18 | private Component someComponent;
19 | private File sourcePath = new File("test/unit");
20 |
21 | @Before
22 | public void setUp() {
23 | Workspace workspace = new Workspace("Name", "Description");
24 | Model model = workspace.getModel();
25 |
26 | SoftwareSystem softwareSystem = model.addSoftwareSystem("Name", "Description");
27 | webApplication = softwareSystem.addContainer("Name", "Description", "Technology");
28 |
29 | someComponent = webApplication.addComponent(
30 | "SomeComponent",
31 | "test.SourceCodeComponentFinderStrategy.SomeComponent",
32 | "", "");
33 | someComponent.addSupportingType("test.SourceCodeComponentFinderStrategy.SomeComponentImpl");
34 | }
35 |
36 | @Test
37 | public void test_findComponents() throws Exception {
38 | ComponentFinder componentFinder = new ComponentFinder(
39 | webApplication,
40 | "test.SourceCodeComponentFinderStrategy",
41 | new SourceCodeComponentFinderStrategy(sourcePath)
42 | );
43 | componentFinder.findComponents();
44 |
45 | assertEquals("A component that does something.", someComponent.getDescription());
46 | assertEquals(20, someComponent.getSize());
47 | }
48 |
49 | @Test
50 | public void test_findComponents_TruncatesComponentDescriptions_WhenComponentDescriptionsAreTooLong() throws Exception {
51 | ComponentFinder componentFinder = new ComponentFinder(
52 | webApplication,
53 | "test.SourceCodeComponentFinderStrategy",
54 | new SourceCodeComponentFinderStrategy(sourcePath, 10)
55 | );
56 | componentFinder.findComponents();
57 |
58 | assertEquals("A compo...", someComponent.getDescription());
59 | }
60 |
61 | @Test
62 | public void test_findComponents_DoesNotSetTheComponentDescription_WhenTheComponentAlreadyHasADescription() throws Exception {
63 | someComponent.setDescription("An existing description.");
64 | ComponentFinder componentFinder = new ComponentFinder(
65 | webApplication,
66 | "test.SourceCodeComponentFinderStrategy",
67 | new SourceCodeComponentFinderStrategy(sourcePath, 10)
68 | );
69 | componentFinder.findComponents();
70 |
71 | assertEquals("An existing description.", someComponent.getDescription());
72 | }
73 |
74 | }
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/TypeMatcherComponentFinderStrategyTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.Workspace;
4 | import com.structurizr.model.Component;
5 | import com.structurizr.model.Container;
6 | import com.structurizr.model.Model;
7 | import com.structurizr.model.SoftwareSystem;
8 | import org.junit.Before;
9 | import org.junit.Test;
10 |
11 | import static org.junit.Assert.*;
12 | import static org.junit.Assert.assertTrue;
13 |
14 | public class TypeMatcherComponentFinderStrategyTests {
15 |
16 | private Container container;
17 | private ComponentFinder componentFinder;
18 |
19 | @Before
20 | public void setUp() throws Exception {
21 | Workspace workspace = new Workspace("Name", "Description");
22 | Model model = workspace.getModel();
23 |
24 | SoftwareSystem softwareSystem = model.addSoftwareSystem("Name", "Description");
25 | container = softwareSystem.addContainer("Name", "Description", "Technology");
26 |
27 | componentFinder = new ComponentFinder(
28 | container,
29 | "test.TypeMatcherComponentFinderStrategy",
30 | new TypeMatcherComponentFinderStrategy(
31 | new NameSuffixTypeMatcher("Controller", "Controller description", "Controller technology"),
32 | new NameSuffixTypeMatcher("Repository", "Repository description", "Repository technology")
33 | )
34 | );
35 | componentFinder.findComponents();
36 | }
37 |
38 | @Test
39 | public void test_basicUsage() throws Exception {
40 | assertEquals(2, container.getComponents().size());
41 |
42 | Component myController = container.getComponentWithName("MyController");
43 | assertNotNull(myController);
44 | assertEquals("MyController", myController.getName());
45 | assertEquals("test.TypeMatcherComponentFinderStrategy.MyController", myController.getType().getType());
46 | assertEquals("Controller description", myController.getDescription());
47 | assertEquals("Controller technology", myController.getTechnology());
48 |
49 | Component myRepository = container.getComponentWithName("MyRepository");
50 | assertNotNull(myRepository);
51 | assertEquals("MyRepository", myRepository.getName());
52 | assertEquals("test.TypeMatcherComponentFinderStrategy.MyRepository", myRepository.getType().getType());
53 | assertEquals("Repository description", myRepository.getDescription());
54 | assertEquals("Repository technology", myRepository.getTechnology());
55 |
56 | assertEquals(1, myController.getRelationships().size());
57 | assertNotNull(myController.getRelationships().stream().filter(r -> r.getDestination() == myRepository).findFirst().get());
58 | }
59 |
60 | @Test
61 | public void test_findingDuplicateComponentsThrowsAnException() throws Exception {
62 | try {
63 | componentFinder.findComponents();
64 | fail();
65 | } catch (DuplicateComponentException dce) {
66 | assertTrue(dce.getMessage().startsWith("A component named \""));
67 | assertTrue(dce.getMessage().endsWith("\" already exists in the container named \"Name\"."));
68 | }
69 | }
70 |
71 |
72 | }
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/reflections/cyclicDependency/AComponent.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.reflections.cyclicDependency;
2 |
3 | public class AComponent {
4 |
5 | private BComponent bComponent = new BComponent();
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/reflections/cyclicDependency/BComponent.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.reflections.cyclicDependency;
2 |
3 | public class BComponent {
4 |
5 | private AComponent aComponent = new AComponent();
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/reflections/dependenciesFromSuperClass/ComponentBase.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.reflections.dependenciesFromSuperClass;
2 |
3 | public abstract class ComponentBase {
4 |
5 | private LoggingComponent loggingComponent = new LoggingComponent();
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/reflections/dependenciesFromSuperClass/LoggingComponent.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.reflections.dependenciesFromSuperClass;
2 |
3 | public class LoggingComponent {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/reflections/dependenciesFromSuperClass/SomeComponent.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.reflections.dependenciesFromSuperClass;
2 |
3 | public class SomeComponent extends ComponentBase {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/reflections/featureinterface/FeatureInterface.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.reflections.featureinterface;
2 |
3 | public interface FeatureInterface {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/reflections/featureinterface/OtherComponent.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.reflections.featureinterface;
2 |
3 | public class OtherComponent implements FeatureInterface {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/reflections/featureinterface/SomeComponent.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.reflections.featureinterface;
2 |
3 | public class SomeComponent implements FeatureInterface {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/reflections/multipleComponentFinders/package1/MyController.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.reflections.multipleComponentFinders.package1;
2 |
3 | import com.structurizr.analysis.reflections.multipleComponentFinders.package2.MyRepository;
4 |
5 | public class MyController {
6 |
7 | private MyRepository myRepository;
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/reflections/multipleComponentFinders/package2/MyRepository.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.reflections.multipleComponentFinders.package2;
2 |
3 | public interface MyRepository {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/reflections/supportingTypes/myapp/AbstractComponent.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.reflections.supportingTypes.myapp;
2 |
3 | public abstract class AbstractComponent {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/reflections/supportingTypes/myapp/data/MyRepository.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.reflections.supportingTypes.myapp.data;
2 |
3 | import com.structurizr.annotation.Component;
4 |
5 | @Component
6 | public interface MyRepository {
7 | }
8 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/reflections/supportingTypes/myapp/data/MyRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.reflections.supportingTypes.myapp.data;
2 |
3 | import com.structurizr.analysis.reflections.supportingTypes.myapp.AbstractComponent;
4 |
5 | class MyRepositoryImpl extends AbstractComponent implements MyRepository {
6 |
7 | private MyRepositoryRowMapper rowMapper;
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/reflections/supportingTypes/myapp/data/MyRepositoryRowMapper.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.reflections.supportingTypes.myapp.data;
2 |
3 | import com.structurizr.analysis.reflections.supportingTypes.myapp.util.RowMapperHelper;
4 |
5 | class MyRepositoryRowMapper {
6 |
7 | private RowMapperHelper helper;
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/reflections/supportingTypes/myapp/util/RowMapperHelper.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.reflections.supportingTypes.myapp.util;
2 |
3 | public class RowMapperHelper {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/com/structurizr/analysis/reflections/supportingTypes/myapp/web/MyController.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.reflections.supportingTypes.myapp.web;
2 |
3 | import com.structurizr.analysis.reflections.supportingTypes.myapp.AbstractComponent;
4 | import com.structurizr.analysis.reflections.supportingTypes.myapp.data.MyRepository;
5 | import com.structurizr.annotation.Component;
6 |
7 | @Component
8 | class MyController extends AbstractComponent {
9 |
10 | private MyRepository myRepository;
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/AnnotatedMethodComponentFinderStrategy/main/Bean.java:
--------------------------------------------------------------------------------
1 | package test.AnnotatedMethodComponentFinderStrategy.main;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
9 | @Retention(RetentionPolicy.RUNTIME)
10 | public @interface Bean {
11 | }
12 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/AnnotatedMethodComponentFinderStrategy/main/Configuration.java:
--------------------------------------------------------------------------------
1 | package test.AnnotatedMethodComponentFinderStrategy.main;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Target(ElementType.TYPE)
9 | @Retention(RetentionPolicy.RUNTIME)
10 | public @interface Configuration {
11 | }
12 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/AnnotatedMethodComponentFinderStrategy/main/FakeComponent.java:
--------------------------------------------------------------------------------
1 | package test.AnnotatedMethodComponentFinderStrategy.main;
2 |
3 | public interface FakeComponent {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/AnnotatedMethodComponentFinderStrategy/main/FakeComponentImpl.java:
--------------------------------------------------------------------------------
1 | package test.AnnotatedMethodComponentFinderStrategy.main;
2 |
3 | public class FakeComponentImpl implements FakeComponent {
4 | private final FakeEfferentComponentImpl someEfferentComponent;
5 |
6 | FakeComponentImpl(FakeEfferentComponentImpl someEfferentComponent) {
7 | this.someEfferentComponent = someEfferentComponent;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/AnnotatedMethodComponentFinderStrategy/main/FakeConfiguration.java:
--------------------------------------------------------------------------------
1 | package test.AnnotatedMethodComponentFinderStrategy.main;
2 |
3 | @Configuration
4 | class FakeConfiguration {
5 |
6 | @Bean
7 | FakeComponent fakeComponent(FakeEfferentComponentImpl someEfferentComponent) {
8 | return new FakeComponentImpl(someEfferentComponent);
9 | }
10 |
11 | @Bean
12 | FakeEfferentComponentImpl fakeEfferentComponent() {
13 | return new FakeEfferentComponentImpl();
14 | }
15 |
16 | @Bean
17 | FakeComponent secondFakeComponent() {
18 | return new FakeComponentImpl(fakeEfferentComponent());
19 | }
20 |
21 | @Bean
22 | void notComponent() {
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/AnnotatedMethodComponentFinderStrategy/main/FakeEfferentComponentImpl.java:
--------------------------------------------------------------------------------
1 | package test.AnnotatedMethodComponentFinderStrategy.main;
2 |
3 | public class FakeEfferentComponentImpl {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/AnnotatedMethodComponentFinderStrategy/main/SecondFakeConfiguration.java:
--------------------------------------------------------------------------------
1 | package test.AnnotatedMethodComponentFinderStrategy.main;
2 |
3 | class SecondFakeConfiguration {
4 |
5 | @Bean
6 | SecondFakeComponent secondFakeComponent() {
7 | return new SecondFakeComponent();
8 | }
9 |
10 | static class SecondFakeComponent {
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/AnnotatedMethodComponentFinderStrategy/other/OtherConfiguration.java:
--------------------------------------------------------------------------------
1 | package test.AnnotatedMethodComponentFinderStrategy.other;
2 |
3 | import test.AnnotatedMethodComponentFinderStrategy.main.Bean;
4 | import test.AnnotatedMethodComponentFinderStrategy.main.FakeComponent;
5 |
6 | class OtherConfiguration {
7 |
8 | @Bean
9 | FakeComponent otherFakeComponent() {
10 | return new OtherFakeComponentImpl();
11 | }
12 |
13 | class OtherFakeComponentImpl implements FakeComponent {
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/DefaultTypeRepository/SomeAbstractClass.java:
--------------------------------------------------------------------------------
1 | package test.DefaultTypeRepository;
2 |
3 | abstract class SomeAbstractClass implements SomeInterface {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/DefaultTypeRepository/SomeClass.java:
--------------------------------------------------------------------------------
1 | package test.DefaultTypeRepository;
2 |
3 | import com.structurizr.annotation.Component;
4 |
5 | @Component
6 | class SomeClass extends SomeAbstractClass {
7 |
8 | private SomeEnum someEnum;
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/DefaultTypeRepository/SomeEnum.java:
--------------------------------------------------------------------------------
1 | package test.DefaultTypeRepository;
2 |
3 | public enum SomeEnum {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/DefaultTypeRepository/SomeInterface.java:
--------------------------------------------------------------------------------
1 | package test.DefaultTypeRepository;
2 |
3 | public interface SomeInterface {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/MoreDefaultTypeRepository/AnotherClass.java:
--------------------------------------------------------------------------------
1 | package test.MoreDefaultTypeRepository;
2 |
3 | public class AnotherClass {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/SourceCodeComponentFinderStrategy/SomeComponent.java:
--------------------------------------------------------------------------------
1 | package test.SourceCodeComponentFinderStrategy;
2 |
3 | /**
4 | * A component that does something.
5 | */
6 | public interface SomeComponent {
7 |
8 | void doSomething();
9 |
10 | }
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/SourceCodeComponentFinderStrategy/SomeComponentImpl.java:
--------------------------------------------------------------------------------
1 | package test.SourceCodeComponentFinderStrategy;
2 |
3 | class SomeComponentImpl implements SomeComponent {
4 |
5 | @Override
6 | public void doSomething() {
7 | System.out.println("Doing something");
8 | }
9 |
10 | }
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/StructurizrAnnotationsComponentFinderStrategy/Controller.java:
--------------------------------------------------------------------------------
1 | package test.StructurizrAnnotationsComponentFinderStrategy;
2 |
3 | import com.structurizr.annotation.*;
4 |
5 | @Component(description = "Does something.")
6 | @UsedByPerson(name = "Anonymous User", description = "Uses to do something", technology = "HTTPS")
7 | @UsedByPerson(name = "Authenticated User", description = "Uses to do something too")
8 | @UsedBySoftwareSystem(name = "External 1", description = "Uses to do something", technology = "HTTPS")
9 | @UsedBySoftwareSystem(name = "External 2", description = "Uses to do something too")
10 | @UsedByContainer(name = "Software System/Web Browser", description = "Makes calls to", technology = "HTTPS") // an example of using a canonical name
11 | @UsedByContainer(name = "API Client", description = "Makes API calls to", technology = "HTTPS") // an example of not using a canonical name
12 | @UsesSoftwareSystem(name = "External 1", description = "Sends information to", technology = "HTTPS")
13 | public class Controller {
14 |
15 | @UsesComponent(description = "Reads from and writes to", technology = "Just a method call")
16 | protected Repository repository;
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/StructurizrAnnotationsComponentFinderStrategy/Repository.java:
--------------------------------------------------------------------------------
1 | package test.StructurizrAnnotationsComponentFinderStrategy;
2 |
3 | import com.structurizr.annotation.Component;
4 |
5 | @Component(description = "Manages some data.")
6 | public interface Repository {
7 |
8 | void getData();
9 |
10 | }
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/StructurizrAnnotationsComponentFinderStrategy/RepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package test.StructurizrAnnotationsComponentFinderStrategy;
2 |
3 | import com.structurizr.annotation.UsesContainer;
4 |
5 | @UsesContainer(name = "Database", description = "Reads from and writes to", technology = "JDBC")
6 | class RepositoryImpl implements Repository {
7 |
8 | @Override
9 | public void getData() {
10 | }
11 |
12 | }
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/TypeMatcherComponentFinderStrategy/MyController.java:
--------------------------------------------------------------------------------
1 | package test.TypeMatcherComponentFinderStrategy;
2 |
3 | public class MyController {
4 |
5 | private MyRepository myRepository = new MyRepositoryImpl();
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/TypeMatcherComponentFinderStrategy/MyRepository.java:
--------------------------------------------------------------------------------
1 | package test.TypeMatcherComponentFinderStrategy;
2 |
3 | public interface MyRepository {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/TypeMatcherComponentFinderStrategy/MyRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package test.TypeMatcherComponentFinderStrategy;
2 |
3 | public class MyRepositoryImpl implements MyRepository {
4 |
5 | public void doSomething() {
6 | // make a reference to an inner class
7 | throw new RuntimeException() {
8 | @Override
9 | public String getMessage() {
10 | return "I'm an inner class.";
11 | }
12 | };
13 | }
14 |
15 | }
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/TypeUtils/AnotherClass.java:
--------------------------------------------------------------------------------
1 | package test.TypeUtils;
2 |
3 | public class AnotherClass {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/TypeUtils/SomeAbstractClass.java:
--------------------------------------------------------------------------------
1 | package test.TypeUtils;
2 |
3 | abstract class SomeAbstractClass implements SomeInterface {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/TypeUtils/SomeClass.java:
--------------------------------------------------------------------------------
1 | package test.TypeUtils;
2 |
3 | import com.structurizr.annotation.Component;
4 |
5 | @Component
6 | class SomeClass extends SomeAbstractClass {
7 |
8 | private SomeEnum someEnum;
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/TypeUtils/SomeEnum.java:
--------------------------------------------------------------------------------
1 | package test.TypeUtils;
2 |
3 | public enum SomeEnum {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-analysis/test/unit/test/TypeUtils/SomeInterface.java:
--------------------------------------------------------------------------------
1 | package test.TypeUtils;
2 |
3 | public interface SomeInterface {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-annotations/build.gradle:
--------------------------------------------------------------------------------
1 | jar {
2 | manifest {
3 | attributes(
4 | 'Bundle-ManifestVersion': "2",
5 | 'Bundle-Name': "Structurizr for Java",
6 | 'Bundle-SymbolicName': "com.structurizr.annotations",
7 | 'Bundle-Version': version,
8 | 'Export-Package': "com.structurizr.annotation;version=\"$version\""
9 | )
10 | }
11 | }
--------------------------------------------------------------------------------
/structurizr-annotations/src/com/structurizr/annotation/Component.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * A type-level annotation that can be used to signify that the annotated type
7 | * (an interface or class) can be considered to be a "component".
8 | */
9 | @Documented
10 | @Target(ElementType.TYPE)
11 | @Retention(RetentionPolicy.RUNTIME)
12 | public @interface Component {
13 |
14 | String description() default "";
15 | String technology() default "";
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/structurizr-annotations/src/com/structurizr/annotation/UsedByContainer.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * A type-level annotation that can be used to signify that the named
7 | * container uses the component on which this annotation is placed,
8 | * creating a relationship from the container to the component.
9 | */
10 | @Documented
11 | @Target({ElementType.TYPE})
12 | @Retention(RetentionPolicy.RUNTIME)
13 | @Repeatable(UsedByContainers.class)
14 | public @interface UsedByContainer {
15 |
16 | String name();
17 | String description() default "";
18 | String technology() default "";
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/structurizr-annotations/src/com/structurizr/annotation/UsedByContainers.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * A wrapper for multiple @UsedByContainer annotations.
7 | */
8 | @Documented
9 | @Target({ElementType.TYPE})
10 | @Retention(RetentionPolicy.RUNTIME)
11 | public @interface UsedByContainers {
12 |
13 | UsedByContainer[] value();
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/structurizr-annotations/src/com/structurizr/annotation/UsedByPeople.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * A wrapper for multiple @UsedByPerson annotations.
7 | */
8 | @Documented
9 | @Target({ElementType.TYPE})
10 | @Retention(RetentionPolicy.RUNTIME)
11 | public @interface UsedByPeople {
12 |
13 | UsedByPerson[] value();
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/structurizr-annotations/src/com/structurizr/annotation/UsedByPerson.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * A type-level annotation that can be used to signify that the named
7 | * person uses the component on which this annotation is placed,
8 | * creating a relationship from the person to the component.
9 | */
10 | @Documented
11 | @Target({ElementType.TYPE})
12 | @Retention(RetentionPolicy.RUNTIME)
13 | @Repeatable(UsedByPeople.class)
14 | public @interface UsedByPerson {
15 |
16 | String name();
17 | String description() default "";
18 | String technology() default "";
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/structurizr-annotations/src/com/structurizr/annotation/UsedBySoftwareSystem.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * A type-level annotation that can be used to signify that the named
7 | * software system uses the component on which this annotation is placed,
8 | * creating a relationship from the software system to the component.
9 | */
10 | @Documented
11 | @Target({ElementType.TYPE})
12 | @Retention(RetentionPolicy.RUNTIME)
13 | @Repeatable(UsedBySoftwareSystems.class)
14 | public @interface UsedBySoftwareSystem {
15 |
16 | String name();
17 | String description() default "";
18 | String technology() default "";
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/structurizr-annotations/src/com/structurizr/annotation/UsedBySoftwareSystems.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * A wrapper for multiple @UsedBySoftwareSystem annotations.
7 | */
8 | @Documented
9 | @Target({ElementType.TYPE})
10 | @Retention(RetentionPolicy.RUNTIME)
11 | public @interface UsedBySoftwareSystems {
12 |
13 | UsedBySoftwareSystem[] value();
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/structurizr-annotations/src/com/structurizr/annotation/UsesComponent.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * A field-level annotation that can be used to supplement the existing relationship
7 | * (i.e. add a description and/or technology) between two components.
8 | */
9 | @Documented
10 | @Target({ElementType.FIELD})
11 | @Retention(RetentionPolicy.RUNTIME)
12 | public @interface UsesComponent {
13 |
14 | String description();
15 | String technology() default "";
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/structurizr-annotations/src/com/structurizr/annotation/UsesContainer.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * A type-level annotation that can be used to signify that the component
7 | * on which this annotation is placed has a relationship to the named container,
8 | * creating a relationship from the component to the container.
9 | */
10 | @Documented
11 | @Target({ElementType.TYPE})
12 | @Retention(RetentionPolicy.RUNTIME)
13 | @Repeatable(UsesContainers.class)
14 | public @interface UsesContainer {
15 |
16 | String name();
17 | String description() default "";
18 | String technology() default "";
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/structurizr-annotations/src/com/structurizr/annotation/UsesContainers.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * A wrapper for multiple @UsesContainer annotations.
7 | */
8 | @Documented
9 | @Target({ElementType.TYPE})
10 | @Retention(RetentionPolicy.RUNTIME)
11 | public @interface UsesContainers {
12 |
13 | UsesContainer[] value();
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/structurizr-annotations/src/com/structurizr/annotation/UsesSoftwareSystem.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * A type-level annotation that can be used to signify that the component
7 | * on which this annotation is placed has a relationship to the named software system,
8 | * creating a relationship from the component to the software system.
9 | */
10 | @Documented
11 | @Target({ElementType.TYPE})
12 | @Retention(RetentionPolicy.RUNTIME)
13 | @Repeatable(UsesSoftwareSystems.class)
14 | public @interface UsesSoftwareSystem {
15 |
16 | String name();
17 | String description() default "";
18 | String technology() default "";
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/structurizr-annotations/src/com/structurizr/annotation/UsesSoftwareSystems.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * A wrapper for multiple @UsesSoftwareSystem annotations.
7 | */
8 | @Documented
9 | @Target({ElementType.TYPE})
10 | @Retention(RetentionPolicy.RUNTIME)
11 | public @interface UsesSoftwareSystems {
12 |
13 | UsesSoftwareSystem[] value();
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/structurizr-dot/README.md:
--------------------------------------------------------------------------------
1 | # structurizr-dot
2 |
3 | __This module is deprecated - please use [structurizr-export](../structurizr-export) instead.__
4 |
5 | structurizr-dot can export the views in a Structurizr workspace to DOT diagram definitions that are compatible with Graphviz. The following diagram types are supported:
6 |
7 | - System Landscape
8 | - System Context
9 | - Container
10 | - Component
11 | - Dynamic
12 | - Deployment
13 |
14 | Create your software architecture model and views as usual, and use the [DOTWriter](https://github.com/structurizr/java-extensions/blob/master/structurizr-dot/src/com/structurizr/io/dot/DOTWriter.java) class to export the views. [For example](https://github.com/structurizr/java-extensions/blob/master/structurizr-examples/src/com/structurizr/example/DOT.java):
15 |
16 | ```java
17 | Workspace workspace = new Workspace("Getting Started", "This is a model of my software system.");
18 | Model model = workspace.getModel();
19 |
20 | Person user = model.addPerson("User", "A user of my software system.");
21 | SoftwareSystem softwareSystem = model.addSoftwareSystem("Software System", "My software system.");
22 | user.uses(softwareSystem, "Uses");
23 |
24 | ViewSet views = workspace.getViews();
25 | SystemContextView contextView = views.createSystemContextView(softwareSystem, "SystemContext", "An example of a System Context diagram.");
26 | contextView.addAllSoftwareSystems();
27 | contextView.addAllPeople();
28 |
29 | Styles styles = views.getConfiguration().getStyles();
30 | styles.addElementStyle(Tags.SOFTWARE_SYSTEM).background("#1168bd").color("#ffffff");
31 | styles.addElementStyle(Tags.PERSON).background("#08427b").color("#ffffff").shape(Shape.Person);
32 |
33 | DOTWriter dotWriter = new DOTWriter();
34 | System.out.println(dotWriter.toString(contextView));
35 | ```
36 |
37 | This code will generate and output a DOT diagram definition that looks like this:
38 |
39 | ```
40 | digraph {
41 | compound=true
42 | graph [fontname="Arial", rankdir=TB, ranksep=1.0, nodesep=1.0]
43 | node [fontname="Arial", shape=box, margin="0.4,0.3"]
44 | edge [fontname="Arial"]
45 | label=<
Software System - System Context
An example of a System Context diagram.>
46 | subgraph cluster_enterprise {
47 | margin=25
48 | label=<
Enterprise
[Enterprise]>
49 | labelloc=b
50 | color="#444444"
51 | fontcolor="#444444"
52 | fillcolor="#ffffff"
53 | }
54 |
55 | 1 [id=1,shape=rect, label=<User
[Person]
A user of my software
system.>, style=filled, color="#052e56", fillcolor="#08427b", fontcolor="#ffffff"]
56 | 2 [id=2,shape=rect, label=<Software System
[Software System]
My software system.>, style=filled, color="#0b4884", fillcolor="#1168bd", fontcolor="#ffffff"]
57 |
58 | 1 -> 2 [id=3, label=<Uses>, style="dashed", color="#707070", fontcolor="#707070"]
59 | }
60 | ```
61 |
62 | If you render this with Graphviz, you will get something like this:
63 |
64 | 
65 |
66 | ## Changelog
67 |
68 | ### 1.0.0 (unreleased)
69 |
70 | - Initial version.
--------------------------------------------------------------------------------
/structurizr-dot/build.gradle:
--------------------------------------------------------------------------------
1 | version = '1.0.0'
2 |
3 | dependencies {
4 |
5 | compile 'com.structurizr:structurizr-core:1.9.1'
6 |
7 | testCompile 'junit:junit:4.12'
8 | testCompile 'com.structurizr:structurizr-client:1.9.1'
9 |
10 | }
11 |
12 | sourceSets {
13 | main {
14 | java {
15 | srcDir 'src'
16 | }
17 | }
18 | test {
19 | java {
20 | srcDir 'test/unit'
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/structurizr-dot/docs/images/getting-started.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/structurizr-dot/docs/images/getting-started.png
--------------------------------------------------------------------------------
/structurizr-dot/etc/graphviz-dot.properties:
--------------------------------------------------------------------------------
1 | # The path where to output generated documentation, with ending slash
2 | outpath=
3 |
4 | # The path to the dot tool (Graphviz), with ending slash
5 | dotpath=/usr/local/bin/
6 |
7 | # The image extension, with the leading dot
8 | imageextension=.png
9 |
10 |
11 | # $0: outpath
12 | # $1: outpath+filename
13 | commandline={0}dot -Tpng {1}.dot -o {1}.png -Gdpi=72 -Gsize="6,8.5"
--------------------------------------------------------------------------------
/structurizr-dot/src/com/structurizr/io/dot/DOTDiagram.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.io.dot;
2 |
3 | public class DOTDiagram {
4 |
5 | private String key;
6 | private String name;
7 | private String definition;
8 |
9 | DOTDiagram(String key, String name, String definition) {
10 | this.key = key;
11 | this.name = name;
12 | this.definition = definition;
13 | }
14 |
15 | public String getKey() {
16 | return key;
17 | }
18 |
19 | public String getName() {
20 | return name;
21 | }
22 |
23 | public String getDefinition() {
24 | return definition;
25 | }
26 |
27 | }
--------------------------------------------------------------------------------
/structurizr-dot/src/com/structurizr/io/dot/RankDirection.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.io.dot;
2 |
3 | /**
4 | * The various rank directions used by Graphviz.
5 | */
6 | enum RankDirection {
7 |
8 | TopBottom("TB"),
9 | BottomTop("BT"),
10 | LeftRight("LR"),
11 | RightLeft("RL");
12 |
13 | private String code;
14 |
15 | RankDirection(String code) {
16 | this.code = code;
17 | }
18 |
19 | String getCode() {
20 | return code;
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/structurizr-examples/build.gradle:
--------------------------------------------------------------------------------
1 | dependencies {
2 | compile project(':structurizr-annotations')
3 | compile project(':structurizr-spring')
4 |
5 | compile 'com.structurizr:structurizr-client:1.9.6'
6 |
7 | compile 'org.slf4j:slf4j-api:1.7.21'
8 | compile 'org.slf4j:slf4j-simple:1.7.21'
9 | }
10 |
11 | task springPetClinic(type:JavaExec) {
12 | main = "com.structurizr.example.spring.petclinic.SpringPetClinic"
13 | classpath(
14 | sourceSets.main.runtimeClasspath,
15 | '/Users/structurizr/Documents/spring-petclinic/target/spring-petclinic-1.0.0-SNAPSHOT/WEB-INF/classes',
16 | fileTree(dir: '/Users/structurizr/Documents/spring-petclinic/target/spring-petclinic-1.0.0-SNAPSHOT/WEB-INF/lib', include: '*.jar')
17 | )
18 | args '/Users/structurizr/Documents/spring-petclinic'
19 | }
--------------------------------------------------------------------------------
/structurizr-examples/etc/logging.properties:
--------------------------------------------------------------------------------
1 | handlers=java.util.logging.ConsoleHandler
2 | java.util.logging.ConsoleHandler.level=ALL
3 |
4 | com.structurizr.level=ALL
--------------------------------------------------------------------------------
/structurizr-examples/src/com/structurizr/example/StructurizrAnnotations.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.example;
2 |
3 | import com.structurizr.Workspace;
4 | import com.structurizr.analysis.ComponentFinder;
5 | import com.structurizr.analysis.StructurizrAnnotationsComponentFinderStrategy;
6 | import com.structurizr.api.StructurizrClient;
7 | import com.structurizr.model.*;
8 | import com.structurizr.view.*;
9 |
10 | /**
11 | * An small example that illustrates how to use the Structurizr annotations
12 | * in conjunction with the StructurizrAnnotationsComponentFinderStrategy.
13 | *
14 | * The live workspace is available to view at https://structurizr.com/share/36571
15 | */
16 | public class StructurizrAnnotations {
17 |
18 | private static final String DATABASE_TAG = "Database";
19 |
20 | private static final long WORKSPACE_ID = 36571;
21 | private static final String API_KEY = "";
22 | private static final String API_SECRET = "";
23 |
24 | public static void main(String[] args) throws Exception {
25 | Workspace workspace = new Workspace("Structurizr for Java Annotations", "This is a model of my software system.");
26 | Model model = workspace.getModel();
27 | model.setImpliedRelationshipsStrategy(new CreateImpliedRelationshipsUnlessAnyRelationshipExistsStrategy());
28 |
29 | Person user = model.addPerson("User", "A user of my software system.");
30 | SoftwareSystem softwareSystem = model.addSoftwareSystem("Software System", "My software system.");
31 |
32 | Container webApplication = softwareSystem.addContainer("Web Application", "Provides users with information.", "Java");
33 | Container database = softwareSystem.addContainer("Database", "Stores information.", "Relational database schema");
34 | database.addTags(DATABASE_TAG);
35 |
36 | ComponentFinder componentFinder = new ComponentFinder(
37 | webApplication,
38 | "com.structurizr.example.annotations",
39 | new StructurizrAnnotationsComponentFinderStrategy()
40 | );
41 | componentFinder.findComponents();
42 |
43 | ViewSet views = workspace.getViews();
44 | SystemContextView contextView = views.createSystemContextView(softwareSystem, "SystemContext", "An example of a System Context diagram.");
45 | contextView.addAllElements();
46 |
47 | ContainerView containerView = views.createContainerView(softwareSystem, "Containers", "The container diagram from my software system.");
48 | containerView.addAllElements();
49 |
50 | ComponentView componentView = views.createComponentView(webApplication, "Components", "The component diagram for the web application.");
51 | componentView.addAllElements();
52 |
53 | Styles styles = views.getConfiguration().getStyles();
54 | styles.addElementStyle(Tags.ELEMENT).color("#ffffff");
55 | styles.addElementStyle(Tags.SOFTWARE_SYSTEM).background("#1168bd");
56 | styles.addElementStyle(Tags.CONTAINER).background("#438dd5");
57 | styles.addElementStyle(Tags.COMPONENT).background("#85bbf0").color("#000000");
58 | styles.addElementStyle(Tags.PERSON).background("#08427b").shape(Shape.Person);
59 | styles.addElementStyle(DATABASE_TAG).shape(Shape.Cylinder);
60 |
61 | StructurizrClient structurizrClient = new StructurizrClient(API_KEY, API_SECRET);
62 | structurizrClient.putWorkspace(WORKSPACE_ID, workspace);
63 | }
64 |
65 | }
--------------------------------------------------------------------------------
/structurizr-examples/src/com/structurizr/example/annotations/HtmlController.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.example.annotations;
2 |
3 | import com.structurizr.annotation.Component;
4 | import com.structurizr.annotation.UsedByPerson;
5 | import com.structurizr.annotation.UsesComponent;
6 |
7 | @Component(description = "Serves HTML pages to users.", technology = "Java")
8 | @UsedByPerson(name = "User", description = "Uses", technology = "HTTPS")
9 | class HtmlController {
10 |
11 | @UsesComponent(description = "Gets data using")
12 | private Repository repository = new JdbcRepository();
13 |
14 | }
--------------------------------------------------------------------------------
/structurizr-examples/src/com/structurizr/example/annotations/JdbcRepository.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.example.annotations;
2 |
3 | import com.structurizr.annotation.UsesContainer;
4 |
5 | @UsesContainer(name = "Database", description = "Reads from", technology = "JDBC")
6 | class JdbcRepository implements Repository {
7 |
8 | public String getData(long id) {
9 | return "...";
10 | }
11 |
12 | }
--------------------------------------------------------------------------------
/structurizr-examples/src/com/structurizr/example/annotations/Repository.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.example.annotations;
2 |
3 | import com.structurizr.annotation.Component;
4 |
5 | @Component(description = "Provides access to data stored in the database.", technology = "Java and JPA")
6 | public interface Repository {
7 |
8 | String getData(long id);
9 |
10 | }
--------------------------------------------------------------------------------
/structurizr-export/README.md:
--------------------------------------------------------------------------------
1 | # structurizr-export
2 |
3 | __This module has moved to [https://github.com/structurizr/export](https://github.com/structurizr/export).__
--------------------------------------------------------------------------------
/structurizr-graphviz/README.md:
--------------------------------------------------------------------------------
1 | # structurizr-graphviz
2 |
3 | __This module has moved to [https://github.com/structurizr/graphviz](https://github.com/structurizr/graphviz).__
--------------------------------------------------------------------------------
/structurizr-javaee/build.gradle:
--------------------------------------------------------------------------------
1 | dependencies {
2 | compile 'com.structurizr:structurizr-core:1.3.5'
3 |
4 | compile 'javax:javaee-api:7.0'
5 | }
6 |
--------------------------------------------------------------------------------
/structurizr-javaee/src/com/structurizr/analysis/JavaEEComponentFinderStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 |
5 | import javax.ejb.Singleton;
6 | import javax.ejb.Stateful;
7 | import javax.ejb.Stateless;
8 | import javax.inject.Named;
9 | import javax.websocket.server.ServerEndpoint;
10 | import javax.ws.rs.Path;
11 | import java.util.HashSet;
12 | import java.util.Set;
13 |
14 | public class JavaEEComponentFinderStrategy extends AbstractComponentFinderStrategy {
15 |
16 | public JavaEEComponentFinderStrategy() {
17 | super(new FirstImplementationOfInterfaceSupportingTypesStrategy());
18 | }
19 |
20 | public JavaEEComponentFinderStrategy(SupportingTypesStrategy... strategies) {
21 | super(strategies);
22 | }
23 |
24 | @Override
25 | protected Set doFindComponents() {
26 | Set components = new HashSet<>();
27 |
28 | components.addAll(findClassesWithAnnotation(Path.class, "JAX-RS web service"));
29 | components.addAll(findClassesWithAnnotation(ServerEndpoint.class, "Websocket endpoint"));
30 | components.addAll(findClassesWithAnnotation(Stateless.class, "Stateless session bean"));
31 | components.addAll(findClassesWithAnnotation(Stateful.class, "Stateful session bean"));
32 | components.addAll(findClassesWithAnnotation(Singleton.class, "Singleton session bean"));
33 | components.addAll(findClassesWithAnnotation(Named.class, "Named bean"));
34 |
35 | return components;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/structurizr-plantuml/README.md:
--------------------------------------------------------------------------------
1 | # structurizr-plantuml
2 |
3 | __This module is deprecated - please use [structurizr-export](https://github.com/structurizr/export) instead.__
--------------------------------------------------------------------------------
/structurizr-plantuml/build.gradle:
--------------------------------------------------------------------------------
1 | version = '1.6.4'
2 |
3 | dependencies {
4 |
5 | compile 'com.structurizr:structurizr-core:1.9.1'
6 |
7 | testCompile 'junit:junit:4.12'
8 | testCompile 'org.assertj:assertj-core:3.4.0'
9 | testCompile 'com.structurizr:structurizr-client:1.9.1'
10 |
11 | }
12 |
13 | sourceSets {
14 | main {
15 | java {
16 | srcDir 'src'
17 | }
18 | }
19 | test {
20 | java {
21 | srcDir 'test/unit'
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/structurizr-plantuml/docs/images/getting-started.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/structurizr/java-extensions/468228ce69801cb542e2a9d065d2f447506e9498/structurizr-plantuml/docs/images/getting-started.png
--------------------------------------------------------------------------------
/structurizr-plantuml/src/com/structurizr/io/plantuml/PlantUMLDiagram.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.io.plantuml;
2 |
3 | public class PlantUMLDiagram {
4 |
5 | private String key;
6 | private String name;
7 | private String definition;
8 |
9 | PlantUMLDiagram(String key, String name, String definition) {
10 | this.key = key;
11 | this.name = name;
12 | this.definition = definition;
13 | }
14 |
15 | public String getKey() {
16 | return key;
17 | }
18 |
19 | public String getName() {
20 | return name;
21 | }
22 |
23 | public String getDefinition() {
24 | return definition;
25 | }
26 |
27 | }
--------------------------------------------------------------------------------
/structurizr-plantuml/src/com/structurizr/io/plantuml/PlantUMLEncoder.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.io.plantuml;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.nio.charset.StandardCharsets;
5 | import java.util.zip.Deflater;
6 | import java.util.zip.DeflaterOutputStream;
7 |
8 | /**
9 | * A Java implementation of http://plantuml.com/code-javascript-synchronous
10 | * that uses Java's built-in Deflate algorithm.
11 | */
12 | public class PlantUMLEncoder {
13 |
14 | public String encode(String plantUMLDefinition) throws Exception {
15 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
16 | Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION, true);
17 |
18 | DeflaterOutputStream dos = new DeflaterOutputStream(baos, deflater, true);
19 | dos.write(plantUMLDefinition.getBytes(StandardCharsets.UTF_8));
20 | dos.finish();
21 |
22 | return encode(baos.toByteArray());
23 | }
24 |
25 | private String encode(byte[] bytes) {
26 | StringBuilder buf = new StringBuilder();
27 | for (int i = 0; i < bytes.length; i += 3) {
28 | int b1 = (bytes[i]) & 0xFF;
29 | int b2 = (i + 1 < bytes.length ? bytes[i + 1] : (byte)0) & 0xFF;
30 | int b3 = (i + 2 < bytes.length ? bytes[i + 2] : (byte)0) & 0xFF;
31 |
32 | append3bytes(buf, b1, b2, b3);
33 | }
34 |
35 | return buf.toString();
36 | }
37 |
38 | private char encode6bit(byte b) {
39 | if (b < 10) {
40 | return (char) ('0' + b);
41 | }
42 | b -= 10;
43 | if (b < 26) {
44 | return (char) ('A' + b);
45 | }
46 | b -= 26;
47 | if (b < 26) {
48 | return (char) ('a' + b);
49 | }
50 | b -= 26;
51 | if (b == 0) {
52 | return '-';
53 | }
54 | if (b == 1) {
55 | return '_';
56 | }
57 |
58 | return '?';
59 | }
60 |
61 | private void append3bytes(StringBuilder buf, int b1, int b2, int b3) {
62 | int c1 = b1 >> 2;
63 | int c2 = (b1 & 0x3) << 4 | b2 >> 4;
64 | int c3 = (b2 & 0xF) << 2 | b3 >> 6;
65 | int c4 = b3 & 0x3F;
66 |
67 | buf.append(encode6bit((byte)(c1 & 0x3F)));
68 | buf.append(encode6bit((byte)(c2 & 0x3F)));
69 | buf.append(encode6bit((byte)(c3 & 0x3F)));
70 | buf.append(encode6bit((byte)(c4 & 0x3F)));
71 | }
72 |
73 | }
--------------------------------------------------------------------------------
/structurizr-plantuml/test/unit/com/structurizr/io/plantuml/AbstractPlantUMLWriterTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.io.plantuml;
2 |
3 | import com.structurizr.Workspace;
4 | import com.structurizr.view.View;
5 | import org.junit.Test;
6 |
7 | import static org.junit.Assert.assertEquals;
8 | import static org.junit.Assert.fail;
9 |
10 | public class AbstractPlantUMLWriterTests {
11 |
12 | @Test
13 | public void test_writeWorkspace_ThrowsAnExceptionWhenPassedANullWorkspace() throws Exception {
14 | BasicPlantUMLWriter plantUMLWriter = new BasicPlantUMLWriter();
15 | try {
16 | plantUMLWriter.write((Workspace)null, null);
17 | fail();
18 | } catch (Exception e) {
19 | assertEquals("A workspace must be provided.", e.getMessage());
20 | }
21 | }
22 |
23 | @Test
24 | public void test_writeWorkspace_ThrowsAnExceptionWhenPassedANullWriter() throws Exception {
25 | BasicPlantUMLWriter plantUMLWriter = new BasicPlantUMLWriter();
26 | Workspace workspace = new Workspace("Name", "Description");
27 | try {
28 | plantUMLWriter.write(workspace, null);
29 | fail();
30 | } catch (Exception e) {
31 | assertEquals("A writer must be provided.", e.getMessage());
32 | }
33 | }
34 |
35 | @Test
36 | public void test_writeView_ThrowsAnExceptionWhenPassedANullView() throws Exception {
37 | BasicPlantUMLWriter plantUMLWriter = new BasicPlantUMLWriter();
38 | try {
39 | plantUMLWriter.write((View)null, null);
40 | fail();
41 | } catch (Exception e) {
42 | assertEquals("A view must be provided.", e.getMessage());
43 | }
44 | }
45 |
46 | }
--------------------------------------------------------------------------------
/structurizr-plantuml/test/unit/com/structurizr/io/plantuml/PlantUMLEncoderTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.io.plantuml;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertEquals;
6 |
7 | public class PlantUMLEncoderTests {
8 |
9 | @Test
10 | public void test() throws Exception {
11 | assertEquals("SyfFqhLppCbCJbMmKiX8pSd91m00", new PlantUMLEncoder().encode("Bob->Alice : hello"));
12 | }
13 |
14 | }
--------------------------------------------------------------------------------
/structurizr-spring/build.gradle:
--------------------------------------------------------------------------------
1 | dependencies {
2 | compile project(':structurizr-analysis')
3 |
4 | compile 'com.structurizr:structurizr-core:1.3.5'
5 |
6 | compile 'org.springframework:spring-web:4.2.9.RELEASE'
7 | compile 'org.springframework.data:spring-data-jpa:1.9.4.RELEASE'
8 | compile 'org.springframework.ws:spring-ws-core:2.4.2.RELEASE'
9 |
10 | testCompile 'junit:junit:4.12'
11 |
12 | }
--------------------------------------------------------------------------------
/structurizr-spring/src/com/structurizr/analysis/AbstractSpringComponentFinderStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 | import com.structurizr.model.Container;
5 |
6 | import java.lang.annotation.Annotation;
7 | import java.lang.reflect.Modifier;
8 | import java.util.HashSet;
9 | import java.util.Set;
10 |
11 | public abstract class AbstractSpringComponentFinderStrategy extends AbstractComponentFinderStrategy {
12 |
13 | public static final String SPRING_MVC_CONTROLLER = "Spring MVC Controller";
14 | public static final String SPRING_SERVICE = "Spring Service";
15 | public static final String SPRING_REPOSITORY = "Spring Repository";
16 | public static final String SPRING_COMPONENT = "Spring Component";
17 | public static final String SPRING_REST_CONTROLLER = "Spring REST Controller";
18 | public static final String SPRING_WEB_SERVICE_ENDPOINT = "Spring Web Service";
19 |
20 | protected boolean includePublicTypesOnly = true;
21 |
22 | public AbstractSpringComponentFinderStrategy(SupportingTypesStrategy... strategies) {
23 | super(strategies);
24 | }
25 |
26 | protected Set findInterfacesForImplementationClassesWithAnnotation(Class extends Annotation> type, String technology) {
27 | Set components = new HashSet<>();
28 |
29 | Container container = getComponentFinder().getContainer();
30 | Set> annotatedTypes = findTypesAnnotatedWith(type);
31 | for (Class> annotatedType : annotatedTypes) {
32 | if (container.getComponentWithName(annotatedType.getSimpleName()) != null) {
33 | continue;
34 | } else if (annotatedType.isInterface()) {
35 | // the annotated type is an interface, so we're done
36 | Component newComponent = addComponent(container, annotatedType.getSimpleName(), annotatedType.getCanonicalName(), "", technology);
37 |
38 | if (newComponent != null) {
39 | components.add(newComponent);
40 | }
41 | } else {
42 | // The Spring @Component, @Service and @Repository annotations are typically used to annotate implementation
43 | // classes, but we really want to find the interface type and use that to represent the component. Why?
44 | // Well, for example, a Spring MVC controller may have a dependency on a "SomeRepository" interface, but
45 | // it's the "JdbcSomeRepositoryImpl" implementation class that gets annotated with @Repository.
46 | //
47 | // This next bit of code tries to find the "SomeRepository" interface...
48 | String componentName = annotatedType.getSimpleName(); // e.g. JdbcSomeRepositoryImpl
49 | Class> componentType = annotatedType;
50 | boolean foundInterface = false;
51 |
52 | if (annotatedType.getInterfaces().length > 0) {
53 | for (Class interfaceType : annotatedType.getInterfaces()) {
54 | String interfaceName = interfaceType.getSimpleName();
55 | if (componentName.startsWith(interfaceName) || // <***>
56 | componentName.endsWith(interfaceName) || // <***>
57 | componentName.contains(interfaceName)) { // <***><***>
58 | componentName = interfaceName;
59 | componentType = interfaceType;
60 | foundInterface = true;
61 | break;
62 | }
63 | }
64 | }
65 |
66 | if (!includePublicTypesOnly || Modifier.isPublic(componentType.getModifiers())) {
67 | Component newComponent = addComponent(container, componentName, componentType.getCanonicalName(), "", technology);
68 | if (newComponent != null) {
69 | components.add(newComponent);
70 |
71 | if (foundInterface) {
72 | // the primary component type is now an interface, so add the type we originally found as a supporting type
73 | newComponent.addSupportingType(annotatedType.getCanonicalName());
74 | }
75 | }
76 | }
77 | }
78 | }
79 |
80 | return components;
81 | }
82 |
83 | /**
84 | * Sets whether this component finder strategy only finds components that are based upon public types.
85 | *
86 | * @param includePublicTypesOnly true for public types only, false otherwise
87 | */
88 | public void setIncludePublicTypesOnly(boolean includePublicTypesOnly) {
89 | this.includePublicTypesOnly = includePublicTypesOnly;
90 | }
91 |
92 | }
--------------------------------------------------------------------------------
/structurizr-spring/src/com/structurizr/analysis/SpringComponentComponentFinderStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 |
5 | import java.util.Set;
6 |
7 | /**
8 | * A component finder strategy that finds Spring components (classes annotated @Component).
9 | */
10 | public final class SpringComponentComponentFinderStrategy extends AbstractSpringComponentFinderStrategy {
11 |
12 | public SpringComponentComponentFinderStrategy(SupportingTypesStrategy... strategies) {
13 | super(strategies);
14 | }
15 |
16 | @Override
17 | protected Set doFindComponents() {
18 | return findInterfacesForImplementationClassesWithAnnotation(
19 | org.springframework.stereotype.Component.class,
20 | SPRING_COMPONENT
21 | );
22 | }
23 |
24 | }
--------------------------------------------------------------------------------
/structurizr-spring/src/com/structurizr/analysis/SpringComponentFinderStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 |
5 | import java.util.HashSet;
6 | import java.util.LinkedList;
7 | import java.util.List;
8 | import java.util.Set;
9 |
10 | /**
11 | *
12 | * This component finder strategy knows how to find the following Spring components:
13 | *
14 | *
15 | *
16 | * - Spring MVC controllers (classes annotated @Controller)
17 | * - Spring REST controllers (classes annotated @RestController)
18 | * - Spring services (classes annotated @Service)
19 | * - Spring components (classes annotated @Component)
20 | * - Spring repositories (classes annotated @Repository, plus those that extend JpaRepository or CrudRepository)
21 | *
22 | *
23 | *
24 | * By default, non-public types will be ignored so that, for example, you can
25 | * hide repository implementations behind services, as described at
26 | * Whoops! Where did my architecture go.
27 | * You can change this behaviour by passing false to {@link #setIncludePublicTypesOnly(boolean)}.
28 | *
29 | */
30 | public class SpringComponentFinderStrategy extends AbstractSpringComponentFinderStrategy {
31 |
32 | private List componentFinderStrategies = new LinkedList<>();
33 |
34 | public SpringComponentFinderStrategy(SupportingTypesStrategy... strategies) {
35 | super(strategies);
36 | }
37 |
38 | @Override
39 | public void beforeFindComponents() {
40 | super.beforeFindComponents();
41 |
42 | componentFinderStrategies.add(new SpringRestControllerComponentFinderStrategy());
43 | componentFinderStrategies.add(new SpringMvcControllerComponentFinderStrategy());
44 | componentFinderStrategies.add(new SpringServiceComponentFinderStrategy());
45 | componentFinderStrategies.add(new SpringComponentComponentFinderStrategy());
46 | componentFinderStrategies.add(new SpringRepositoryComponentFinderStrategy());
47 |
48 | for (AbstractSpringComponentFinderStrategy componentFinderStrategy : componentFinderStrategies) {
49 | componentFinderStrategy.setIncludePublicTypesOnly(includePublicTypesOnly);
50 | componentFinderStrategy.setComponentFinder(getComponentFinder());
51 | supportingTypesStrategies.forEach(componentFinderStrategy::addSupportingTypesStrategy);
52 | componentFinderStrategy.setDuplicateComponentStrategy(getDuplicateComponentStrategy());
53 | componentFinderStrategy.beforeFindComponents();
54 | }
55 | }
56 |
57 | @Override
58 | protected Set doFindComponents() {
59 | Set components = new HashSet<>();
60 |
61 | for (AbstractComponentFinderStrategy componentFinderStrategy : componentFinderStrategies) {
62 | components.addAll(componentFinderStrategy.findComponents());
63 | }
64 |
65 | return components;
66 | }
67 |
68 | }
--------------------------------------------------------------------------------
/structurizr-spring/src/com/structurizr/analysis/SpringMvcControllerComponentFinderStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 |
5 | import java.util.Set;
6 |
7 | /**
8 | * A component finder strategy that finds Spring MVC controllers (classes annotated @Controller).
9 | */
10 | public final class SpringMvcControllerComponentFinderStrategy extends AbstractSpringComponentFinderStrategy {
11 |
12 | public SpringMvcControllerComponentFinderStrategy(SupportingTypesStrategy... strategies) {
13 | super(strategies);
14 | }
15 |
16 | @Override
17 | protected Set doFindComponents() {
18 | return findClassesWithAnnotation(
19 | org.springframework.stereotype.Controller.class,
20 | SPRING_MVC_CONTROLLER,
21 | includePublicTypesOnly
22 | );
23 | }
24 |
25 | }
--------------------------------------------------------------------------------
/structurizr-spring/src/com/structurizr/analysis/SpringRepositoryComponentFinderStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 | import com.structurizr.model.Container;
5 | import org.springframework.data.jpa.repository.JpaRepository;
6 | import org.springframework.data.repository.CrudRepository;
7 | import org.springframework.data.repository.Repository;
8 |
9 | import java.lang.reflect.Modifier;
10 | import java.util.HashSet;
11 | import java.util.Set;
12 |
13 | /**
14 | * A component finder strategy for Spring repositories (classes annotated @Repository,
15 | * plus those that extend JpaRepository or CrudRepository).
16 | */
17 | public final class SpringRepositoryComponentFinderStrategy extends AbstractSpringComponentFinderStrategy {
18 |
19 | public SpringRepositoryComponentFinderStrategy(SupportingTypesStrategy... strategies) {
20 | super(strategies);
21 | }
22 |
23 | @Override
24 | protected Set doFindComponents() {
25 | Set components = new HashSet<>();
26 |
27 | components.addAll(findAnnotatedSpringRepositories());
28 | components.addAll(findSpringRepositoryInterfaces());
29 |
30 | return components;
31 | }
32 |
33 | private Set findSpringRepositoryInterfaces() {
34 | Set componentsFound = new HashSet<>();
35 | Set> componentTypes = new HashSet<>();
36 |
37 | Set> types = getTypeRepository().getAllTypes();
38 | for (Class> type : types) {
39 | if (type.isInterface()) {
40 | if (
41 | Repository.class.isAssignableFrom(type) ||
42 | JpaRepository.class.isAssignableFrom(type) ||
43 | CrudRepository.class.isAssignableFrom(type)
44 | ) {
45 | componentTypes.add(type);
46 | }
47 | }
48 | }
49 |
50 | for (Class> componentType : componentTypes) {
51 | if (!includePublicTypesOnly || Modifier.isPublic(componentType.getModifiers())) {
52 | final Container container = getComponentFinder().getContainer();
53 | Component newComponent = addComponent(
54 | container,
55 | componentType.getSimpleName(),
56 | componentType.getCanonicalName(),
57 | "",
58 | SPRING_REPOSITORY);
59 |
60 |
61 | if (newComponent != null) {
62 | componentsFound.add(newComponent);
63 | }
64 | }
65 | }
66 |
67 | return componentsFound;
68 | }
69 |
70 | private Set findAnnotatedSpringRepositories() {
71 | return findInterfacesForImplementationClassesWithAnnotation(
72 | org.springframework.stereotype.Repository.class, SPRING_REPOSITORY);
73 | }
74 |
75 | }
--------------------------------------------------------------------------------
/structurizr-spring/src/com/structurizr/analysis/SpringRestControllerComponentFinderStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 |
5 | import java.util.Set;
6 |
7 | /**
8 | * A component finder strategy that finds Spring REST controllers (classes annotated @RestController).
9 | */
10 | public final class SpringRestControllerComponentFinderStrategy extends AbstractSpringComponentFinderStrategy {
11 |
12 | public SpringRestControllerComponentFinderStrategy(SupportingTypesStrategy... strategies) {
13 | super(strategies);
14 | }
15 |
16 | @Override
17 | protected Set doFindComponents() {
18 | return findClassesWithAnnotation(
19 | org.springframework.web.bind.annotation.RestController.class,
20 | SPRING_REST_CONTROLLER,
21 | includePublicTypesOnly
22 | );
23 | }
24 |
25 | }
--------------------------------------------------------------------------------
/structurizr-spring/src/com/structurizr/analysis/SpringServiceComponentFinderStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 |
5 | import java.util.Set;
6 |
7 | /**
8 | * A component finder strategy that finds Spring Services (classes annotated @Service).
9 | */
10 | public final class SpringServiceComponentFinderStrategy extends AbstractSpringComponentFinderStrategy {
11 |
12 | public SpringServiceComponentFinderStrategy(SupportingTypesStrategy... strategies) {
13 | super(strategies);
14 | }
15 |
16 | @Override
17 | protected Set doFindComponents() {
18 | return findInterfacesForImplementationClassesWithAnnotation(
19 | org.springframework.stereotype.Service.class,
20 | SPRING_SERVICE
21 | );
22 | }
23 |
24 | }
--------------------------------------------------------------------------------
/structurizr-spring/src/com/structurizr/analysis/SpringWebServiceEndpointComponentFinderStrategy.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.model.Component;
4 |
5 | import java.util.Set;
6 |
7 | /**
8 | * A component finder strategy that finds Spring web service endpoints (classes annotated @Endpoint).
9 | */
10 | public final class SpringWebServiceEndpointComponentFinderStrategy extends AbstractSpringComponentFinderStrategy {
11 |
12 | public SpringWebServiceEndpointComponentFinderStrategy(SupportingTypesStrategy... strategies) {
13 | super(strategies);
14 | }
15 |
16 | @Override
17 | protected Set doFindComponents() {
18 | return findClassesWithAnnotation(
19 | org.springframework.ws.server.endpoint.annotation.Endpoint.class,
20 | SPRING_WEB_SERVICE_ENDPOINT,
21 | includePublicTypesOnly
22 | );
23 | }
24 |
25 | }
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/com/structurizr/analysis/AbstractSpringComponentFinderStrategyTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.Workspace;
4 | import com.structurizr.model.Component;
5 | import com.structurizr.model.Container;
6 | import com.structurizr.model.Model;
7 | import com.structurizr.model.SoftwareSystem;
8 | import org.junit.Test;
9 |
10 | import static org.junit.Assert.assertEquals;
11 |
12 | public class AbstractSpringComponentFinderStrategyTests {
13 |
14 | @Test
15 | public void test_findComponents_IgnoresNonPublicTypesByDefault() throws Exception {
16 | Workspace workspace = new Workspace("Name", "Description");
17 | Model model = workspace.getModel();
18 | SoftwareSystem softwareSystem = model.addSoftwareSystem("Name", "Description");
19 | Container container = softwareSystem.addContainer("Name", "Description", "Technology");
20 |
21 | ComponentFinder componentFinder = new ComponentFinder(
22 | container,
23 | "test.AbstractSpringComponentFinderStrategy",
24 | new SpringComponentFinderStrategy()
25 | );
26 | componentFinder.findComponents();
27 |
28 | assertEquals(2, container.getComponents().size());
29 |
30 | Component component = container.getComponentWithName("SomeController");
31 | assertEquals("test.AbstractSpringComponentFinderStrategy.SomeController", component.getType().getType());
32 |
33 | component = container.getComponentWithName("SomePublicRepository");
34 | assertEquals("test.AbstractSpringComponentFinderStrategy.SomePublicRepository", component.getType().getType());
35 | }
36 |
37 | @Test
38 | public void test_findComponents_DoesNotIgnoreNonPublicTypes_WhenConfiguredToIncludeNonPublicTypes() throws Exception {
39 | Workspace workspace = new Workspace("Name", "Description");
40 | Model model = workspace.getModel();
41 | SoftwareSystem softwareSystem = model.addSoftwareSystem("Name", "Description");
42 | Container container = softwareSystem.addContainer("Name", "Description", "Technology");
43 |
44 | SpringComponentFinderStrategy springComponentFinderStrategy = new SpringComponentFinderStrategy();
45 | springComponentFinderStrategy.setIncludePublicTypesOnly(false);
46 | ComponentFinder componentFinder = new ComponentFinder(
47 | container,
48 | "test.AbstractSpringComponentFinderStrategy",
49 | springComponentFinderStrategy
50 | );
51 | componentFinder.findComponents();
52 |
53 | assertEquals(3, container.getComponents().size());
54 |
55 | Component component = container.getComponentWithName("SomeController");
56 | assertEquals("test.AbstractSpringComponentFinderStrategy.SomeController", component.getType().getType());
57 |
58 | component = container.getComponentWithName("SomePublicRepository");
59 | assertEquals("test.AbstractSpringComponentFinderStrategy.SomePublicRepository", component.getType().getType());
60 |
61 | component = container.getComponentWithName("SomeNonPublicRepository");
62 | assertEquals("test.AbstractSpringComponentFinderStrategy.SomeNonPublicRepository", component.getType().getType());
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/com/structurizr/analysis/SpringComponentComponentFinderStrategyTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.Workspace;
4 | import com.structurizr.model.Component;
5 | import com.structurizr.model.Container;
6 | import com.structurizr.model.Model;
7 | import com.structurizr.model.SoftwareSystem;
8 | import org.junit.Test;
9 |
10 | import static org.junit.Assert.assertEquals;
11 |
12 | public class SpringComponentComponentFinderStrategyTests {
13 |
14 | @Test
15 | public void test_findComponents_FindsSpringComponents() throws Exception {
16 | Workspace workspace = new Workspace("Name", "Description");
17 | Model model = workspace.getModel();
18 | SoftwareSystem softwareSystem = model.addSoftwareSystem("Name", "Description");
19 | Container container = softwareSystem.addContainer("Name", "Description", "Technology");
20 |
21 | ComponentFinder componentFinder = new ComponentFinder(
22 | container,
23 | "test.SpringComponentComponentFinderStrategy",
24 | new SpringComponentComponentFinderStrategy()
25 | );
26 | componentFinder.findComponents();
27 |
28 | assertEquals(1, container.getComponents().size());
29 | Component component = container.getComponentWithName("SomeComponent");
30 | assertEquals("test.SpringComponentComponentFinderStrategy.SomeComponent", component.getType().getType());
31 | assertEquals("", component.getDescription());
32 | assertEquals("Spring Component", component.getTechnology());
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/com/structurizr/analysis/SpringComponentFinderStrategyTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.Workspace;
4 | import com.structurizr.model.*;
5 | import org.junit.Before;
6 | import org.junit.Test;
7 |
8 | import java.util.Set;
9 |
10 | import static org.junit.Assert.assertEquals;
11 | import static org.junit.Assert.assertNotNull;
12 | import static org.junit.Assert.fail;
13 |
14 | public class SpringComponentFinderStrategyTests {
15 |
16 | private Container webApplication;
17 |
18 | @Before
19 | public void setUp() {
20 | Workspace workspace = new Workspace("Name", "Description");
21 | Model model = workspace.getModel();
22 | SoftwareSystem softwareSystem = model.addSoftwareSystem("Name", "Description");
23 | webApplication = softwareSystem.addContainer("Name", "Description", "Technology");
24 | }
25 |
26 | @Test
27 | public void test_findComponents() throws Exception {
28 | ComponentFinder componentFinder = new ComponentFinder(
29 | webApplication,
30 | "com.structurizr.analysis.myapp",
31 | new SpringComponentFinderStrategy()
32 | );
33 | componentFinder.findComponents();
34 |
35 | assertEquals(5, webApplication.getComponents().size());
36 | assertEquals(0, webApplication.getComponents().stream().filter(c -> "SomeNonPublicRepository".equals(c.getName())).count());
37 |
38 | Component someMvcController = webApplication.getComponentWithName("SomeController");
39 | assertNotNull(someMvcController);
40 | assertEquals("SomeController", someMvcController.getName());
41 | assertEquals("com.structurizr.analysis.myapp.web.SomeController", someMvcController.getType().getType());
42 | assertEquals(1, someMvcController.getCode().size());
43 |
44 | Component someRestController = webApplication.getComponentWithName("SomeApiController");
45 | assertNotNull(someRestController);
46 | assertEquals("SomeApiController", someRestController.getName());
47 | assertEquals("com.structurizr.analysis.myapp.api.SomeApiController", someRestController.getType().getType());
48 | assertEquals(1, someRestController.getCode().size());
49 |
50 | Component someService = webApplication.getComponentWithName("SomeService");
51 | assertNotNull(someService);
52 | assertEquals("SomeService", someService.getName());
53 | assertEquals("com.structurizr.analysis.myapp.service.SomeService", someService.getType().getType());
54 | assertEquals(2, someService.getCode().size());
55 | assertCodeElementInComponent(someService, "com.structurizr.analysis.myapp.service.SomeService", CodeElementRole.Primary);
56 | assertCodeElementInComponent(someService, "com.structurizr.analysis.myapp.service.SomeServiceImpl", CodeElementRole.Supporting);
57 |
58 | Component someRepository = webApplication.getComponentWithName("SomeRepository");
59 | assertNotNull(someRepository);
60 | assertEquals("SomeRepository", someRepository.getName());
61 | assertEquals("com.structurizr.analysis.myapp.data.SomeRepository", someRepository.getType().getType());
62 | assertEquals(2, someRepository.getCode().size());
63 | assertCodeElementInComponent(someRepository, "com.structurizr.analysis.myapp.data.SomeRepository", CodeElementRole.Primary);
64 | assertCodeElementInComponent(someRepository, "com.structurizr.analysis.myapp.data.JdbcSomeRepository", CodeElementRole.Supporting);
65 |
66 |
67 | Component someOtherRepository = webApplication.getComponentWithName("SomeOtherRepository");
68 | assertNotNull(someOtherRepository);
69 | assertEquals("SomeOtherRepository", someOtherRepository.getName());
70 | assertEquals("com.structurizr.analysis.myapp.data.SomeOtherRepository", someOtherRepository.getType().getType());
71 |
72 | assertEquals(1, someMvcController.getRelationships().size());
73 | Relationship relationship = someMvcController.getRelationships().iterator().next();
74 | assertEquals(someMvcController, relationship.getSource());
75 | assertEquals(someService, relationship.getDestination());
76 |
77 | assertEquals(1, someRestController.getRelationships().size());
78 | relationship = someRestController.getRelationships().iterator().next();
79 | assertEquals(someRestController, relationship.getSource());
80 | assertEquals(someService, relationship.getDestination());
81 |
82 | assertEquals(2, someService.getRelationships().size());
83 |
84 | Set relationships = someService.getRelationships();
85 | assertNotNull(relationships.stream().filter(r -> r.getDestination() == someRepository).findFirst().get());
86 | assertNotNull(relationships.stream().filter(r -> r.getDestination() == someOtherRepository).findFirst().get());
87 | }
88 |
89 | private void assertCodeElementInComponent(Component component, String type, CodeElementRole role) {
90 | for (CodeElement codeElement : component.getCode()) {
91 | if (codeElement.getType().equals(type) && codeElement.getRole() == role) {
92 | return;
93 | }
94 | }
95 |
96 | fail("Component " + component.getName() + " does not have a " + role + " code element of type " + type);
97 | }
98 |
99 | @Test
100 | public void test_findComponents_UsesTheConfiguredDuplicateComponentFinderStrategy() throws Exception {
101 | try {
102 | SpringComponentFinderStrategy springComponentFinderStrategy = new SpringComponentFinderStrategy();
103 | springComponentFinderStrategy.setDuplicateComponentStrategy(new DuplicateComponentStrategy() {
104 | @Override
105 | public Component duplicateComponentFound(Component component, String name, String type, String description, String technology) {
106 | return null;
107 | }
108 | });
109 |
110 | ComponentFinder componentFinder = new ComponentFinder(
111 | webApplication,
112 | "com.structurizr.analysis.myapp",
113 | springComponentFinderStrategy
114 | );
115 |
116 | componentFinder.findComponents();
117 | componentFinder.findComponents();
118 | } catch (DuplicateComponentException dce) {
119 | fail();
120 | }
121 | }
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/com/structurizr/analysis/SpringMvcControllerComponentFinderStrategyTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.Workspace;
4 | import com.structurizr.model.Component;
5 | import com.structurizr.model.Container;
6 | import com.structurizr.model.Model;
7 | import com.structurizr.model.SoftwareSystem;
8 | import org.junit.Test;
9 |
10 | import static org.junit.Assert.assertEquals;
11 |
12 | public class SpringMvcControllerComponentFinderStrategyTests {
13 |
14 | @Test
15 | public void test_findComponents_FindsSpringMvcControllers() throws Exception {
16 | Workspace workspace = new Workspace("Name", "Description");
17 | Model model = workspace.getModel();
18 | SoftwareSystem softwareSystem = model.addSoftwareSystem("Name", "Description");
19 | Container container = softwareSystem.addContainer("Name", "Description", "Technology");
20 |
21 | ComponentFinder componentFinder = new ComponentFinder(
22 | container,
23 | "test.SpringMvcControllerComponentFinderStrategy",
24 | new SpringMvcControllerComponentFinderStrategy()
25 | );
26 | componentFinder.findComponents();
27 |
28 | assertEquals(1, container.getComponents().size());
29 | Component component = container.getComponentWithName("SomeController");
30 | assertEquals("test.SpringMvcControllerComponentFinderStrategy.SomeController", component.getType().getType());
31 | assertEquals("", component.getDescription());
32 | assertEquals("Spring MVC Controller", component.getTechnology());
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/com/structurizr/analysis/SpringRepositoryComponentFinderStrategyTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.Workspace;
4 | import com.structurizr.model.Component;
5 | import com.structurizr.model.Container;
6 | import com.structurizr.model.Model;
7 | import com.structurizr.model.SoftwareSystem;
8 | import org.junit.Test;
9 |
10 | import static org.junit.Assert.assertEquals;
11 |
12 | public class SpringRepositoryComponentFinderStrategyTests {
13 |
14 | @Test
15 | public void test_findComponents_FindsSpringRepositoriesDefinedWithAnAnnotation() throws Exception {
16 | Workspace workspace = new Workspace("Name", "Description");
17 | Model model = workspace.getModel();
18 | SoftwareSystem softwareSystem = model.addSoftwareSystem("Name", "Description");
19 | Container container = softwareSystem.addContainer("Name", "Description", "Technology");
20 |
21 | ComponentFinder componentFinder = new ComponentFinder(
22 | container,
23 | "test.SpringRepositoryComponentFinderStrategy.annotation",
24 | new SpringRepositoryComponentFinderStrategy()
25 | );
26 | componentFinder.findComponents();
27 |
28 | // finding the components again should be idempotent
29 | componentFinder.findComponents();
30 |
31 | assertEquals(1, container.getComponents().size());
32 | Component component = container.getComponentWithName("SomeRepository");
33 | assertEquals("test.SpringRepositoryComponentFinderStrategy.annotation.SomeRepository", component.getType().getType());
34 | assertEquals("", component.getDescription());
35 | assertEquals("Spring Repository", component.getTechnology());
36 | }
37 |
38 | @Test
39 | public void test_findComponents_FindsSpringRepositoriesThatExtendJpaRepository() throws Exception {
40 | Workspace workspace = new Workspace("Name", "Description");
41 | Model model = workspace.getModel();
42 | SoftwareSystem softwareSystem = model.addSoftwareSystem("Name", "Description");
43 | Container container = softwareSystem.addContainer("Name", "Description", "Technology");
44 |
45 | ComponentFinder componentFinder = new ComponentFinder(
46 | container,
47 | "test.SpringRepositoryComponentFinderStrategy.jpaRepository",
48 | new SpringRepositoryComponentFinderStrategy()
49 | );
50 | componentFinder.findComponents();
51 |
52 | assertEquals(1, container.getComponents().size());
53 | Component component = container.getComponentWithName("SomeJpaRepository");
54 | assertEquals("test.SpringRepositoryComponentFinderStrategy.jpaRepository.SomeJpaRepository", component.getType().getType());
55 | assertEquals("", component.getDescription());
56 | assertEquals("Spring Repository", component.getTechnology());
57 | }
58 |
59 | @Test
60 | public void test_findComponents_FindsSpringRepositoriesThatExtendCrudRepository() throws Exception {
61 | Workspace workspace = new Workspace("Name", "Description");
62 | Model model = workspace.getModel();
63 | SoftwareSystem softwareSystem = model.addSoftwareSystem("Name", "Description");
64 | Container container = softwareSystem.addContainer("Name", "Description", "Technology");
65 |
66 | ComponentFinder componentFinder = new ComponentFinder(
67 | container,
68 | "test.SpringRepositoryComponentFinderStrategy.crudRepository",
69 | new SpringRepositoryComponentFinderStrategy()
70 | );
71 | componentFinder.findComponents();
72 |
73 | assertEquals(1, container.getComponents().size());
74 | Component component = container.getComponentWithName("SomeCrudRepository");
75 | assertEquals("test.SpringRepositoryComponentFinderStrategy.crudRepository.SomeCrudRepository", component.getType().getType());
76 | assertEquals("", component.getDescription());
77 | assertEquals("Spring Repository", component.getTechnology());
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/com/structurizr/analysis/SpringRestControllerComponentFinderStrategyTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.Workspace;
4 | import com.structurizr.model.Component;
5 | import com.structurizr.model.Container;
6 | import com.structurizr.model.Model;
7 | import com.structurizr.model.SoftwareSystem;
8 | import org.junit.Test;
9 |
10 | import static org.junit.Assert.assertEquals;
11 |
12 | public class SpringRestControllerComponentFinderStrategyTests {
13 |
14 | @Test
15 | public void test_findComponents_FindsSpringRestControllers() throws Exception {
16 | Workspace workspace = new Workspace("Name", "Description");
17 | Model model = workspace.getModel();
18 | SoftwareSystem softwareSystem = model.addSoftwareSystem("Name", "Description");
19 | Container container = softwareSystem.addContainer("Name", "Description", "Technology");
20 |
21 | ComponentFinder componentFinder = new ComponentFinder(
22 | container,
23 | "test.SpringRestControllerComponentFinderStrategy",
24 | new SpringRestControllerComponentFinderStrategy()
25 | );
26 | componentFinder.findComponents();
27 |
28 | assertEquals(1, container.getComponents().size());
29 | Component component = container.getComponentWithName("SomeController");
30 | assertEquals("test.SpringRestControllerComponentFinderStrategy.SomeController", component.getType().getType());
31 | assertEquals("", component.getDescription());
32 | assertEquals("Spring REST Controller", component.getTechnology());
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/com/structurizr/analysis/SpringServiceComponentFinderStrategyTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.Workspace;
4 | import com.structurizr.model.Component;
5 | import com.structurizr.model.Container;
6 | import com.structurizr.model.Model;
7 | import com.structurizr.model.SoftwareSystem;
8 | import org.junit.Test;
9 |
10 | import static org.junit.Assert.assertEquals;
11 |
12 | public class SpringServiceComponentFinderStrategyTests {
13 |
14 | @Test
15 | public void test_findComponents_FindsSpringServices() throws Exception {
16 | Workspace workspace = new Workspace("Name", "Description");
17 | Model model = workspace.getModel();
18 | SoftwareSystem softwareSystem = model.addSoftwareSystem("Name", "Description");
19 | Container container = softwareSystem.addContainer("Name", "Description", "Technology");
20 |
21 | ComponentFinder componentFinder = new ComponentFinder(
22 | container,
23 | "test.SpringServiceComponentFinderStrategy",
24 | new SpringServiceComponentFinderStrategy()
25 | );
26 | componentFinder.findComponents();
27 |
28 | assertEquals(1, container.getComponents().size());
29 | Component component = container.getComponentWithName("SomeService");
30 | assertEquals("test.SpringServiceComponentFinderStrategy.SomeService", component.getType().getType());
31 | assertEquals("", component.getDescription());
32 | assertEquals("Spring Service", component.getTechnology());
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/com/structurizr/analysis/SpringWebServiceEndpointComponentFinderStrategyTests.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis;
2 |
3 | import com.structurizr.Workspace;
4 | import com.structurizr.model.Component;
5 | import com.structurizr.model.Container;
6 | import com.structurizr.model.Model;
7 | import com.structurizr.model.SoftwareSystem;
8 | import org.junit.Test;
9 |
10 | import static org.junit.Assert.assertEquals;
11 |
12 | public class SpringWebServiceEndpointComponentFinderStrategyTests {
13 |
14 | @Test
15 | public void test_findComponents_FindsSpringWebServiceEndpoints() throws Exception {
16 | Workspace workspace = new Workspace("Name", "Description");
17 | Model model = workspace.getModel();
18 | SoftwareSystem softwareSystem = model.addSoftwareSystem("Name", "Description");
19 | Container container = softwareSystem.addContainer("Name", "Description", "Technology");
20 |
21 | ComponentFinder componentFinder = new ComponentFinder(
22 | container,
23 | "test.SpringWebServiceEndpointComponentFinderStrategy",
24 | new SpringWebServiceEndpointComponentFinderStrategy()
25 | );
26 | componentFinder.findComponents();
27 |
28 | assertEquals(1, container.getComponents().size());
29 | Component component = container.getComponentWithName("SomeWebService");
30 | assertEquals("test.SpringWebServiceEndpointComponentFinderStrategy.SomeWebService", component.getType().getType());
31 | assertEquals("", component.getDescription());
32 | assertEquals("Spring Web Service", component.getTechnology());
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/com/structurizr/analysis/myapp/api/SomeApiController.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.myapp.api;
2 |
3 | import com.structurizr.analysis.myapp.service.SomeService;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.web.bind.annotation.RestController;
6 |
7 | @RestController
8 | public class SomeApiController {
9 |
10 | @Autowired
11 | private SomeService someService;
12 |
13 | //@RequestMapping(value = "/do/something") - commenting this out removes a dependency on Spring MVC
14 | public String findSomething() {
15 | someService.doSomething();
16 |
17 | return "{some json}";
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/com/structurizr/analysis/myapp/data/JdbcSomeRepository.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.myapp.data;
2 |
3 | import com.structurizr.analysis.myapp.domain.Something;
4 | import org.springframework.stereotype.Repository;
5 |
6 | @Repository
7 | public class JdbcSomeRepository implements SomeRepository {
8 |
9 | @Override
10 | public Something findSomething() {
11 | return new Something();
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/com/structurizr/analysis/myapp/data/SomeNonPublicRepository.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.myapp.data;
2 |
3 | import org.springframework.data.jpa.repository.JpaRepository;
4 |
5 | interface SomeNonPublicRepository extends JpaRepository {
6 | }
7 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/com/structurizr/analysis/myapp/data/SomeOtherRepository.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.myapp.data;
2 |
3 | import org.springframework.data.jpa.repository.JpaRepository;
4 |
5 | public interface SomeOtherRepository extends JpaRepository {
6 | }
7 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/com/structurizr/analysis/myapp/data/SomeRepository.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.myapp.data;
2 |
3 | import com.structurizr.analysis.myapp.domain.Something;
4 |
5 | public interface SomeRepository {
6 |
7 | Something findSomething();
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/com/structurizr/analysis/myapp/domain/Something.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.myapp.domain;
2 |
3 | /**
4 | * Created by structurizr on 15/03/16.
5 | */
6 | public class Something {
7 | }
8 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/com/structurizr/analysis/myapp/service/SomeService.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.myapp.service;
2 |
3 | public interface SomeService {
4 |
5 | void doSomething();
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/com/structurizr/analysis/myapp/service/SomeServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.myapp.service;
2 |
3 | import com.structurizr.analysis.myapp.data.SomeOtherRepository;
4 | import com.structurizr.analysis.myapp.data.SomeRepository;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Service;
7 |
8 | @Service
9 | public class SomeServiceImpl implements SomeService {
10 |
11 | @Autowired
12 | private SomeRepository someRepository;
13 |
14 | @Autowired
15 | private SomeOtherRepository someOtherRepository;
16 |
17 | public void doSomething() {
18 | someRepository.findSomething();
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/com/structurizr/analysis/myapp/web/SomeController.java:
--------------------------------------------------------------------------------
1 | package com.structurizr.analysis.myapp.web;
2 |
3 | import com.structurizr.analysis.myapp.service.SomeService;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.stereotype.Controller;
6 |
7 | @Controller
8 | public class SomeController {
9 |
10 | @Autowired
11 | private SomeService someService;
12 |
13 | //@RequestMapping(value = "/do/something") - commenting this out removes a dependency on Spring MVC
14 | public String showHomePage() {
15 | someService.doSomething();
16 |
17 | return "/did/something";
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/test/AbstractSpringComponentFinderStrategy/SomeController.java:
--------------------------------------------------------------------------------
1 | package test.AbstractSpringComponentFinderStrategy;
2 |
3 | import org.springframework.stereotype.Controller;
4 |
5 | @Controller
6 | public class SomeController {
7 | }
8 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/test/AbstractSpringComponentFinderStrategy/SomeNonPublicRepository.java:
--------------------------------------------------------------------------------
1 | package test.AbstractSpringComponentFinderStrategy;
2 |
3 | import org.springframework.data.jpa.repository.JpaRepository;
4 |
5 | interface SomeNonPublicRepository extends JpaRepository {
6 | }
7 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/test/AbstractSpringComponentFinderStrategy/SomePublicRepository.java:
--------------------------------------------------------------------------------
1 | package test.AbstractSpringComponentFinderStrategy;
2 |
3 | import org.springframework.data.jpa.repository.JpaRepository;
4 |
5 | public interface SomePublicRepository extends JpaRepository {
6 | }
7 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/test/SpringComponentComponentFinderStrategy/SomeComponent.java:
--------------------------------------------------------------------------------
1 | package test.SpringComponentComponentFinderStrategy;
2 |
3 | public interface SomeComponent {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/test/SpringComponentComponentFinderStrategy/TheSomeComponentImpl.java:
--------------------------------------------------------------------------------
1 | package test.SpringComponentComponentFinderStrategy;
2 |
3 | import org.springframework.stereotype.Component;
4 |
5 | @Component
6 | public class TheSomeComponentImpl implements SomeComponent {
7 | }
8 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/test/SpringMvcControllerComponentFinderStrategy/SomeController.java:
--------------------------------------------------------------------------------
1 | package test.SpringMvcControllerComponentFinderStrategy;
2 |
3 | import org.springframework.stereotype.Controller;
4 |
5 | @Controller
6 | public class SomeController {
7 | }
8 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/test/SpringRepositoryComponentFinderStrategy/annotation/JdbcSomeRepository.java:
--------------------------------------------------------------------------------
1 | package test.SpringRepositoryComponentFinderStrategy.annotation;
2 |
3 | public class JdbcSomeRepository implements SomeRepository {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/test/SpringRepositoryComponentFinderStrategy/annotation/SomeRepository.java:
--------------------------------------------------------------------------------
1 | package test.SpringRepositoryComponentFinderStrategy.annotation;
2 |
3 | import org.springframework.stereotype.Repository;
4 |
5 | @Repository
6 | public interface SomeRepository {
7 | }
8 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/test/SpringRepositoryComponentFinderStrategy/crudRepository/SomeCrudRepository.java:
--------------------------------------------------------------------------------
1 | package test.SpringRepositoryComponentFinderStrategy.crudRepository;
2 |
3 | import org.springframework.data.repository.CrudRepository;
4 |
5 | public interface SomeCrudRepository extends CrudRepository {
6 | }
7 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/test/SpringRepositoryComponentFinderStrategy/jpaRepository/SomeJpaRepository.java:
--------------------------------------------------------------------------------
1 | package test.SpringRepositoryComponentFinderStrategy.jpaRepository;
2 |
3 | import org.springframework.data.jpa.repository.JpaRepository;
4 |
5 | public interface SomeJpaRepository extends JpaRepository {
6 | }
7 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/test/SpringRestControllerComponentFinderStrategy/SomeController.java:
--------------------------------------------------------------------------------
1 | package test.SpringRestControllerComponentFinderStrategy;
2 |
3 | import org.springframework.web.bind.annotation.RestController;
4 |
5 | @RestController
6 | public class SomeController {
7 | }
8 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/test/SpringServiceComponentFinderStrategy/SomeService.java:
--------------------------------------------------------------------------------
1 | package test.SpringServiceComponentFinderStrategy;
2 |
3 | public interface SomeService {
4 | }
5 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/test/SpringServiceComponentFinderStrategy/SomeServiceImpl.java:
--------------------------------------------------------------------------------
1 | package test.SpringServiceComponentFinderStrategy;
2 |
3 | import org.springframework.stereotype.Service;
4 |
5 | @Service
6 | public class SomeServiceImpl implements SomeService {
7 | }
8 |
--------------------------------------------------------------------------------
/structurizr-spring/test/unit/test/SpringWebServiceEndpointComponentFinderStrategy/SomeWebService.java:
--------------------------------------------------------------------------------
1 | package test.SpringWebServiceEndpointComponentFinderStrategy;
2 |
3 | import org.springframework.ws.server.endpoint.annotation.Endpoint;
4 |
5 | @Endpoint
6 | public class SomeWebService {
7 | }
--------------------------------------------------------------------------------