This repository contains the source code for the following libraries:
structurizr / java Goto Github PK
View Code? Open in Web Editor NEWStructurizr for Java
Home Page: https://docs.structurizr.com/java
License: Apache License 2.0
Structurizr for Java
Home Page: https://docs.structurizr.com/java
License: Apache License 2.0
This repository contains the source code for the following libraries:
For a quick test i just wanted to scan everything on a small pet project. So i did:
new NameSuffixComponentFinderStrategy("")
Unfortunately this results in
java.lang.NullPointerException at com.structurizr.componentfinder.ComponentFinder.foundComponent(ComponentFinder.java:39)
Its ok for me if an empty string does not return anything. It wasn't a valid regex or anything.
But a nullpointer seems less then ideal to me ;-)
But then i looked a little deeper and it seems that the nullpointer is the result of an anonymous inner class. The empty suffix is allowed. It matches everything. But matching the inner class results in an error due because type.getCanonicalName()
is null when type is an inner class.
Hello,
Not sure if this is as intended but I have for example an User that uses a container and I would expect that relationship would show up when displaying system diagram for the system that owns the container and same user. Currently I have to resort to adding that connection at both levels to achieve what I want.
I just exported a DynamicView from structurizr as plantuml and was surprised that this did not generate a plantuml sequence diagram. I wouldn't directly consider this a bug, but I definitely feel that it would be good if it could.
Was the choice to not export a sequence diagram intentional? I could probably contribute a fix that makes it generate sequence diagrams, but I'd first like to know if this is wanted behavior. Or maybe there should be an option?
I am trying to document an application that uses spring boot version 2.0.0.M7. But The problem am having is that when i use "structurizr-spring" dependency to auto scan components it fails to locate them. I can see from my logs that when the component finder tries to find files that are specified (as packageToScan parameter) it goes through all the files existing in classpath including the jar file for the application.
My project structure looks like this. I have application package and architecture package ( structurizr) gradle projects in the same level and in architecture's build.gradle i have added compile dependency to the application.
app
architecture
Here is code excerpt that shows how i am trying to find spring components
` ComponentFinder componentFinder = new ComponentFinder(
webApplication, "com.mypackage.name",
new SpringComponentFinderStrategy(
new ReferencedTypesSupportingTypesStrategy()
)
);
componentFinder.findComponents();
`
Hi.
When running ComponentFinder.componentFinder
I get my log littered with warnings, e.g:
2018-10-31 09:17:50.980 [main] WARN com.structurizr.analysis.AbstractComponentFinderStrategy - java.lang.IllegalArgumentException: A component type must be provided.
As far as I've debugged, the exception comes from here https://github.com/structurizr/java/blob/master/structurizr-core/src/com/structurizr/model/Container.java#L163
and is logged here
https://github.com/structurizr/java/blob/master/structurizr-analysis/src/com/structurizr/analysis/AbstractComponentFinderStrategy.java#L135
The problem are all the calls to Container.getComponentOfType
using Class.getCanonicalName()
as argument, since the latter can return null
in a number of cases, like anonymous and local classes. For instance, for class ch.qos.logback.core.subst.Tokenizer$1
.
So, you should null check getCanonicalName()
and ignore those classes or perhaps use the !isNestedClass(type)
check, which is used in another place in the file.
I cloned the repo yesterday and the Documentation tests all fail with:
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:86)
at org.junit.Assert.assertTrue(Assert.java:41)
at org.junit.Assert.assertTrue(Assert.java:52)
at com.structurizr.documentation.DocumentationTests.test_addImage_ThrowsAnException_WhenTheSpecifiedFileDoesNotExist(DocumentationTests.java:335)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:253)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
However if I change the test from:
@Test
public void test_addImage_ThrowsAnException_WhenTheSpecifiedFileIsNotAFile() throws IOException {
try {
documentation.addImage(new File(".//test/unit/com/structurizr/documentation/"));
} catch (IllegalArgumentException iae) {
assertTrue(iae.getMessage().endsWith("/structurizr-core/test/unit/com/structurizr/documentation is not a file."));
}
}
to :
@Test(expected = IllegalArgumentException.class)
public void test_addImage_ThrowsAnException_WhenTheSpecifiedFileIsNotAFile() throws IOException {
documentation.addImage(new File(".//test/unit/com/structurizr/documentation/"));
}
It runs fine, is there a reason not to use the @Test(expected = IllegalArgumentException.class)
construct? If not I will make a pull request for it.
I wondering whether or not it would be interesting to add a SpringWebserviceEndpointFinderStrategy, which will look for org.springframework.ws.server.endpoint.annotation.Endpoint annotations.
This would require org.springframework.ws:spring-ws-core:2.4.2.RELEASE to be added as a dependency.
For now I implemented that SpringWebserviceEndpointFinderStrategy as a util in my project, but I willing to contribute it back.
Or is using the AnnotationTypeMatcher the recommended approach?
It appears to my that SourceCodeComponentFinderStrategy only supports UTF-8 as file encoding.
As a default that's the right thing to do.
But it would be nice to be able to specify the encoding, for example we have a case where "iso-8859-1" is used in the project.
In the implementation of #runJavaDoc in SourceCodeComponentFinderStrategy, you could pass the configured file encoding via the "-encoding" command line parameter to the doclet.
Can you provide plantUML source code for all the pictures?thanks!
It is not possible to write code that creates relationships for elements of different types because the abstract class StaticStructureElement is not public. The alternative to make StaticStructureElement public would be an interface that contains the public "uses" methods.
There is also no uses method with a more common destination argument, for example of type StaticStructureElement...
PlantUMLWriter currently has a lot of private methods. Please consider making them protected instead, to allow tweaking the behaviour of the PlantUML export without having to duplicate the entire class.
Hi,
I am new to structurizr and I am unable to resolve the following issue:
Code
structurizrClient.putWorkspace(WORKSPACE_ID, workspace);
Error Message
Apr 17, 2018 11:04:07 AM com.structurizr.api.StructurizrClient putWorkspace
INFO: Putting workspace with ID 38873
Exception in thread "main" java.lang.NoClassDefFoundError: com/structurizr/io/json/JsonWriter
at com.structurizr.api.StructurizrClient.putWorkspace(StructurizrClient.java:188)
at com.structurizr.example.GettingStarted.main(GettingStarted.java:50)
Caused by: java.lang.ClassNotFoundException: com.structurizr.io.json.JsonWriter
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 2 more
I downloaded the file and followed all the steps. But, some files still seem to be missing.
Shouldn't the results of hashCode() be consistent with the notion of value equality as implemented by .equals()?
Disclaimer: I don't really consider myself a Java programmer. I'm analysing the Java code in the process of producing a Python port of Structurizr.
I added some components from 3rd party libraries that are used by a lot of spring controllers, and then i scan for the spring controllers. I expected the controllers to be linked the controller but while they all show up in the diagram there is no usage in between. Looking at the code of AbstractReflectionComponentFinderStrategy it seems it only will link components that reside in the scanned package. It would really be useful to allow it to add dependencies to all the already registered components. Or at least make it configurable.
so this if in the addEfferentDependencies is causing this behavior:
` if (referencedTypeName.startsWith(componentFinder.getPackageToScan())) {
Component destinationComponent = componentFinder.getContainer().getComponentOfType(referencedTypeName);
if (destinationComponent != null) {
if (component != destinationComponent) {
component.uses(destinationComponent, "");
}
} else if (!referencedTypeName.equals(implementationType) && depth < 10) {
addEfferentDependencies(component, referencedTypeName, ++depth);
}
}`
Greetings! I have a problem with defining component relationships. They are not shown in Deployment view.
Here is examplery code:
package test;
import com.structurizr.Workspace;
import com.structurizr.api.StructurizrClient;
import com.structurizr.model.Container;
import com.structurizr.model.DeploymentNode;
import com.structurizr.model.Model;
import com.structurizr.model.SoftwareSystem;
import com.structurizr.view.ContainerView;
import com.structurizr.view.DeploymentView;
import com.structurizr.view.ViewSet;
public class test {
private static final long WORKSPACE_ID = 2;
private static final String API_KEY = "8d30fcd5-1044-46f2-b9e4-e4c8b9881459";
private static final String API_SECRET = "29e6f7a1-f26e-4197-9bb3-9237e6a6cf01";
public static void main(String[] args) throws Exception {
Workspace workspace = new Workspace("test", "test");
Model model = workspace.getModel();
SoftwareSystem test = model.addSoftwareSystem("test", "test");
Container lb = test.addContainer("lb.domain.com", "Load-Balanser", "NGINX");
DeploymentNode lb_node = model.addDeploymentNode("lb.domain.com", "Load-Balanser", "Linux", 1);
lb_node.add(lb);
Container app = test.addContainer("app.domain.com", "App Server", "WebLogic");
DeploymentNode app_node = model.addDeploymentNode("app.domain.com", "App server", "Linux", 1);
app_node.add(app);
lb.uses(app, "Balancing load");
ViewSet views = workspace.getViews();
ContainerView containerView = views.createContainerView(test, "ContainerView", "test");
containerView.addAllContainers();
DeploymentView deploymentView = views.createDeploymentView(test, "DeploymentView", "test");
deploymentView.addAllDeploymentNodes();
StructurizrClient structurizrClient = new StructurizrClient("http://localhost:8880/api", API_KEY, API_SECRET);
structurizrClient.putWorkspace(WORKSPACE_ID, workspace);
}
}
Resulting Component View:
Resulting Deployment View:
What is going wrong?
Working with this strategy:
new ComponentFinder(
attackPath, "com.example.svc",
new SpringComponentFinderStrategy(
new ReferencedTypesSupportingTypesStrategy()
),
new SourceCodeComponentFinderStrategy(
sourceRoots.get("example-svc").toFile(),
150
)
).findComponents();
As it is running through the classes, it comes across one that looks like this:
@Component
public class SomethingUpdateDbConsumer implements Consumer<List<Some>> {
The AbstractSpringComponentFinderStrategy.findInterfacesForImplementationClassesWithAnnotation()
method sees the interface java.util.function.Consumer
and decides that this component should be represented as that.
However, a few loop iterations later, it finds this guy:
@Component
public class OtherthingUpdateDbConsumer implements Consumer<List<Other>> {
And going through the same logic as before, tries to add a second component named Consumer which blows up.
At the top of the loop, there is a check for whether the candidate component already exists in the components, but it is checking on the simple name, not the interface name, so it doesn't see a problem, and there isn't a check whether this interface name already exists prior to trying to insert it.
So.. a few questions:
Situation:
How to describe this situation in one Structurizr model?
I tried creating a module documentation
and adding dependencies on app1
and app2
, but since these are Spring Boot Applications, they are bundled into a single jar and component finding fails.
Other option could be finding components in each application individually and then putting them together somehow.
How would you solve this?
BTW ( #44 might be related)
I had an existing model (workspace 111), saved it on structurizr and then fetched it again with the client. Then I got the following exception:
Exception in thread "main" com.structurizr.io.StructurizrReaderException: Could not read JSON
at com.structurizr.io.json.JsonReader.read(JsonReader.java:23)
at com.structurizr.api.StructurizrClient.getWorkspace(StructurizrClient.java:104)
at com.structurizr.api.StructurizrClient.mergeWorkspace(StructurizrClient.java:152)
at at.gv.justiz.ju30.architecture.Target2015.main(Target2015.java:143)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: com.structurizr.Workspace["model"]->com.structurizr.model.Model["softwareSystems"]->com.structurizr.model.SoftwareSystem["relationships"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:232)
Hi,
Apologies if this is an uninformed question. I understand that you need to use java to construct a code model that structurizr can consume. However, is it possible to analyze code that is written in a different language, such as C or C++?
Feels to me like there's been significant progress & changes since September and so perhaps it's time for another release candidate or final release.
Is there any reason not to cut an RC5 release soon? (eta??)
If a full release is preferred then are there any blocking issues holding that up that I could help unblock?
After upgrading to structurizr 0.3.0, I'm getting the following debug message on structurizrClient.mergeWorkspace:
Mai 11, 2015 10:03:21 PM com.structurizr.api.StructurizrClient debugResponse
INFORMATION: HTTP/1.1 401 Unauthorized
Mai 11, 2015 10:03:21 PM com.structurizr.api.StructurizrClient putWorkspace
INFORMATION: {"message":"MD5 hash doesn't match content"}
API-Token is correct for sure, I'm using workspace ID 111
In case of PlantUML, the processor to image expects to receive one diagram at a time.
Current interface of writers doesn't allow returning multiple diagrams separately. I had to split the string on "@startuml" line and save as individual files.
Hi guys,
I'm like using Structurizr to create my architecture documentation.
But i have recently ran into a class not found exception:
Container apiBackend = company.addContainer("Backend API", "Provides and Receives company data via JSON/HTTPS API.", "js");
ComponentFinder serviceFinder = new ComponentFinder(apiMiddleware, "com.company.services", new SpringComponentFinderStrategy(
new ReferencedTypesSupportingTypesStrategy(false)
));
This package only contains @service annotations.
But when i run this i get:
Exception in thread "restartedMain" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: java.lang.NoClassDefFoundError: org/springframework/data/jpa/repository/JpaRepository
at com.structurizr.analysis.SpringRepositoryComponentFinderStrategy.findSpringRepositoryInterfaces(SpringRepositoryComponentFinderStrategy.java:41)
at com.structurizr.analysis.SpringRepositoryComponentFinderStrategy.doFindComponents(SpringRepositoryComponentFinderStrategy.java:28)
at com.structurizr.analysis.AbstractComponentFinderStrategy.findComponents(AbstractComponentFinderStrategy.java:57)
at com.structurizr.analysis.SpringComponentFinderStrategy.doFindComponents(SpringComponentFinderStrategy.java:61)
at com.structurizr.analysis.AbstractComponentFinderStrategy.findComponents(AbstractComponentFinderStrategy.java:57)
at com.structurizr.analysis.ComponentFinder.findComponents(ComponentFinder.java:74)
at com.neanex.MiddlewareApplication.main(MiddlewareApplication.java:79)
... 5 more
Caused by: java.lang.ClassNotFoundException: org.springframework.data.jpa.repository.JpaRepository
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 12 more```
Can you guys point me in the right direction?
Extra info: I'm only using 1 CrudRepository for redis and it's not situated in that package, but in a repositories package.
kind regards
Hi
Field/parameter "packageToScan" is now a String value, limiting packages to scan to one single package. As I do not want to scan the entire codebase, it would be convenient to be able to list multiple sub-packages to scan.
It seems like a quick fix in AbstractReflectionsComponentFinderStrategy
.filterInputsBy(new FilterBuilder().includePackage(componentFinder.getPackageToScan()))
the includePackage method in the reflections API takes a vararg of Strings, making it possible to easily refactor ComponentFinder to accept a list/array of packages to scan.
essentially changing this line to
.filterInputsBy(new FilterBuilder().includePackage(componentFinder.getPackagesToScan()))
that is, changing getPackageToScan to getPackagesToScan
This is also very relevant for multi-module builds.
E.g. when controllers depend upon services/repositories from other maven-modules.
The errors are a.o. about Spring Repositories.
I'm not familiar with the codebase, but I think that in method beforeFindComponents of SpringComponentFinderStrategy the setDuplicateComponentStrategy for each item of componentFinderStrategies ?
Originally posted by @FreeWillaert in #106 (comment)
By default the PlantUMLWriter writes the complete workspace into one single puml
file.
When using puml
file in asciidoctor, a single UML diagram is expected per file. Starting with @startuml en ending with @enduml.
To be able to write a single View, expose all write(? extends View view, Writer writer)
methods.
As far as i can tell, i can't find the "structurizr-dot" jar artifact published anywhere [*], could it be possible to activate the publication of this submodule for the next release ?
(i've seen that there are really not a lot of code in the module, but it would be cleaner to just re-use it)
[* : not found here http://jcenter.bintray.com/com/structurizr/ for example ]
Each time I create a diagram it is generating this json file, which is fine - however it is generating it in the base directory of my project. It should really be generated in the base directory of the module.
i.e. not in /ore
but inside /diagrams
Right now I have to append the projects .gitignore to stop these being committed but this means the project then knows about structurizer, I would much rather have edit the specific .gitignore inside of /diagrams
and keep everything to do with structurizer inside here.
Hi
I am trying to use a ComponentFinder based on a SourceCodeComponentFinderStrategy:
ComponentFinder componentFinder = new ComponentFinder( forceCFI, "instru", new SourceCodeComponentFinderStrategy(new File(sourceRoot, "/src/"), 150)); componentFinder.findComponents();
but I get the following exception:
Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/tools/javadoc/Main at com.structurizr.analysis.SourceCodeComponentFinderStrategy.runJavaDoc(SourceCodeComponentFinderStrategy.java:118) at com.structurizr.analysis.SourceCodeComponentFinderStrategy.afterFindComponents(SourceCodeComponentFinderStrategy.java:62) at com.structurizr.analysis.ComponentFinder.findComponents(ComponentFinder.java:76) at Test.main(Test.java:102) Caused by: java.lang.ClassNotFoundException: com.sun.tools.javadoc.Main at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 4 more
I tried to google search about the fail of the loading of the class but did not find anything usefull. I tried also to replace the OpenJDK by the Sun JDK but the error is still there. Is this a bug or I missed something ?
I was following tutorial at https://github.com/structurizr/java/blob/master/docs/spring-petclinic.md, but I was still getting component view without controllers, until I found that SpringComponentFinderStrategy
by default ignores non-public classes.
Since spring-projects/spring-petclinic@83ff9a5 controllers in pet clinic are not public which causes trouble following the tutorial for Pet Clinic.
Maybe referencing fixed revision in the tutorial could help.
I'm catching a bunch of components using the SpringAnnotations, but there are a few stragglers that I'm trying to catch using a RegexTypeMatcher.
I've run into a problem where one class that I'm trying to capture with the RegexTypeMatcher is also annotated with a Spring @component which causes the componentFinder to throw an IllegalArgumentException: A component named 'xxx' already exists for this container.
The scanning application continues on with the other scans, but it doesn't upload at the end. I was naively expecting that it would consolidate components found with more than one strategy within the same component. Do I have to manually try to avoid such a circumstance or am I maybe missing something?
Hello,
I am trying to use Structurizr with Maven, but unfortunately I can't import the "com.structurizr.api.StructurizrClient" class (version 0.6.0) even if I am following the tutorial you provided.
I ran the "./gradlew publishToMavenLocal" command and I added the dependencies to my pom file. Everything loads and works fine until I try to import the "com.structurizr.api.StructurizrClient" class. In fact in my dependencies (even if I have them in my pom file), I can't see any jar called "structuriz-client-0.6.0.jar".
I checked in my local Maven repository and I couldn't find the jar there. I can't manually download the jar file from Bintray, so I tried to find another solution to my problem.
Currently I made it work by downloading version 0.3.2 of Structurizr and then by manually adding to the build path of my project "structuriz-client-0.3.2.jar". This allows me to import (and use) the "com.structurizr.api.StructurizrClient" class.
It looks like that in the Bintray repository the client-0.6.0 jar file is not there, or am I doing anything wrong?
Thanks!
I have trouble using the method sePaperSize(). When reloading the Structurizr workspace, the paper_size seems to ignore the java calls I made:
` SystemContextView contextView = views.createSystemContextView(irma, "Overview", "Kharon architecture");
contextView.addAllSoftwareSystems();
contextView.add(user);
contextView.setPaperSize(PaperSize.A5_Landscape);
// Software view
SystemContextView contextView = views.createSystemContextView(irma, "Overview", "Kharon architecture");
contextView.addAllSoftwareSystems();
contextView.add(user);
contextView.setPaperSize(PaperSize.A5_Landscape);
// Who view
SystemContextView whoView = views.createSystemContextView(irma, "Who", "Kharon architecture");
whoView.addAllSoftwareSystems();
whoView.addAllPeople();
whoView.setPaperSize(PaperSize.A5_Landscape);`
and I always get an A4 Portrait on the website, except for the 1st diagram (SystemContext) that seems to take the call into account the A5 landscape call...
We have an application, which generates the diagrams, populates the documentation and parses the ADRs. When I run locally everything works fine, but when it runs on our build-server or at a co-workers computer. the application fails due to a IllegalArgumentException.
Caused by: java.lang.IllegalArgumentException: No enum constant com.structurizr.documentation.DecisionStatus.
at java.lang.Enum.valueOf(Enum.java:238)
at com.structurizr.documentation.DecisionStatus.valueOf(DecisionStatus.java:6)
at com.structurizr.documentation.AdrToolsImporter.extractStatus(AdrToolsImporter.java:142)
at com.structurizr.documentation.AdrToolsImporter.importArchitectureDecisionRecords(AdrToolsImporte/.java:83)
Based upon the stacktrace I concluded that actual name of the DecisionStatus does not get returned from the statusRegex matcher.group(1). I assume it return an emptyString.
The most apparent difference is that I use a Mac and the build-server and my co-worker run Windows as the OS. I will try to troubleshoot this some further.
Using: Structurizr 1.0.0-RC7
When you creates 2 containers with the same name, the second call returns null instead of throwing an exception, making it hard to debug.
I have the following code which generate a context
and container view
. Unfortunaly the objects distributor
and admin
type Person
doesn't appear inside the enterprise context of a container diagram but in a context diagram it does.
See my code snippet:
Workspace workspace = new Workspace("MyPlatform", "My online platform");
Model model = workspace.getModel();
Person distributor = model.addPerson(Location.Internal,"Distributor", "A distributor");
Person admin = model.addPerson(Location.Internal,"Admin", "An Admin");
SoftwareSystem platform = model.addSoftwareSystem(Location.Internal, "My Platform", "A platform.");
administrator.uses(platform, "Manage all accounts");
...
Container distributorApplication = platform.addContainer("Distrib. App", "A distributor mobile app" "Android");
distributor.uses(distributorApplication, "Uses", "JSON/HTTPS");
Container adminApplication = platform.addContainer("Admin App", "An admin web app", "React");
admin.uses(adminApplication, "Block an account", "JSON/HTTPS");
...
ViewSet views = workspace.getViews();
SystemContextView contextView = views.createSystemContextView(platform, "SystemContext", "A context diagram");
contextView.setPaperSize(A5_Landscape);
contextView.addAllSoftwareSystems();
contextView.addAllPeople();
ContainerView containerView = views.createContainerView(platform, "Container", "A container diagram");
containerView.setPaperSize(A4_Landscape);
containerView.addAllElements();
containerView.addAllSoftwareSystems();
containerView.addAllPeople();
...
Any idea how to solve this?
In my dynamic diagram i want to display an interaction between two persons. This is not yet possible.
All the SupportingTypesStrategy
implementations in structurizr-core seem to use Class::getCanonicalName
to convert Class
objects to String
s. Later these strings are converted back to classes via ClassLoader::loadClass
in TypeUtils.getVisibility
. Unfortunately this does not work for inner classes.
For the class Inner
in class Bar
in package foo
e.g.
Class::getCanonicalName = foo.Bar.Inner
Class::getName = foo.Bar$Inner
and in ClassLoader::loadClass
you must use foo.Bar$Inner
to load the inner class. foo.Bar.Inner
will lead to an exception like the one I see when running ComponentFinder on my project:
Exception in thread "main" java.lang.IllegalArgumentException: The specified type could not be found.
at com.structurizr.analysis.TypeUtils.getVisibility(TypeUtils.java:33)
at com.structurizr.analysis.AbstractComponentFinderStrategy.findSupportingTypes(AbstractComponentFinderStrategy.java:85)
at com.structurizr.analysis.AbstractComponentFinderStrategy.afterFindComponents(AbstractComponentFinderStrategy.java:70)
at com.structurizr.analysis.ComponentFinder.findComponents(ComponentFinder.java:76)
We have a potentially weird setup (although surely not that uncommon):
Our source repo contains com.example.ThingImpl
which implements a com.example.Thing
interface which we inherit from an dependency jar (it's generated from a swagger definition through ci). We religiously add relevant javadocs to the implementation but the generated interface has none.
Running some of the spring component finders manages to identify a component "Thing" with CodeElements for Thing (interface, primary) and ThingImpl (class, supporting). Then when trying to identify the Component description it considers the non-existent interface description but ignores ThingImpl's juicy javadocs because it's a "supporting" class.
Proposal: Modify SourceCodeComponentFinderStrategy
so that:
CodeElement
description.CodeElement
description.I'm slightly concerned about what might happen if multiple documented Primary CodeElement
s are found with javadocs - which will be picked? Similarly with multiple documented Secondary CodeElement
s are found. But I know this isn't the case for my code base so I'm ignoring it for now.
Any improvements to this approach?
Hi Simon,
I'm trying to updat a Structurizr workspace but failing for some reason. Just today was able to update.
WorkspaceID = 20371
I believe both key and secret are correct...
Exception I get:
Structurizr.Client.StructurizrClientException was unhandled
HResult=-2146233088
Message=There was an error putting the workspace: The remote server returned an error: (401) Unauthorized.
Source=Structurizr.Core
StackTrace:
at Structurizr.Client.StructurizrClient.PutWorkspace(Int64 workspaceId, Workspace workspace)
at ConsoleApplication1.Program.Main(String[] args) in C:\Users\XXX\documents\visual studio 2015\Projects\ConsoleApplication1\ConsoleApplication1\Program.cs:line 64
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
HResult=-2146233079
Message=The remote server returned an error: (401) Unauthorized.
Source=System
StackTrace:
at System.Net.WebClient.UploadDataInternal(Uri address, String method, Byte[] data, WebRequest& request)
at System.Net.WebClient.UploadString(Uri address, String method, String data)
at System.Net.WebClient.UploadString(String address, String method, String data)
at Structurizr.Client.StructurizrClient.PutWorkspace(Int64 workspaceId, Workspace workspace)
InnerException:
I would like to have a json schema to be generated from the current code to allow other implementations (.NET, ruby, php, etc.) to be able to keep up-to-date with the latest object model of the REST api for the Structurizr site.
I will issue a pull request for this issue with my first cut of this.
Thanks.
I decided to take a stab at C4 and work out a workspace. I was already using GraphViz and Dot for automatically generated graph visualizations and was hoping that a C4 workspace can visualized using Dot/GraphViz. I find that the DotWriter spits out dot content just fine, but that GraphViz cannot create a complete image for a more complex workspace... Is that your experience as well?
I was hoping for GraphViz to visualize all the defined views in the workspace in one image, but only the first digraph ends up in the image. Online GraphViz versions confirm the behavior.
Working with the .NET framework, I ported your Java DotWriter to C# (easy) and did a crude port of Java LivingDocumentation.DotDiagram to C# (harder). Then I used one of your example workspaces, Big Bank plc, to try out the ported DotWriter/DotDiagram and found that the dot content contains several digraphs, but GraphViz only visualizes the first one...
The method add(Relationship relationship) in DynamicView doesn't work as expected. The relationships don't get a sequence number. And the second attempt to upload the diagram results in an exception. If I use add(Element source, String description, Element destination) with the information from my relationship object instead all works well...
Hello,
I have an IndexController
mentioning a class Item
only in this form
private PageImpl<Item> createPageable(Pageable pageable)
Such mention is not sufficient to create a link in a diagram. On the other hand, adding a field of type Item
works just fine.
Is there any known way how to solve this issue?
Component
extends Element
and therefore has a hashCode()
based purely on Element.name
. Container
has a LinkedHashSet
of Component
and therefore is limited to one Component
of any given name. So it seems safe to assume that a Container is designed to only contain one Component of any given name.
Model.addComponent(..)
methods (unlike addPerson(..)
, addSoftwareSystem(..)
, addContainer(..)
) fails to check the component is new before adding it, thereby overrides the first Component
of that name with a second. When using SequentialIntegerIdGeneratorStrategy
both first and second instances get different ids and so both end up in the Model.elementsById
index (which is weird). When using MessageDigestIdGenerator
then the both get the same id, the first ends up in the index but the second ends up in the Container
(which is probelmatic).
A real world example of this can be found using the ComponentFinder
to find a component that happens to both implement CrudRepository
AND be annotated @Repository
.
Suggest that Model.addComponent(..)
methods are modified to block addition of duplicates in the first place, like their sibling add methods, and that callers are modified to avoid adding duplicates. Will put together a PR along these lines unless I hear objections.
Hello,
I really like your topics and the way you explain. I am a computer science student. I am developing an desktop app that would help farmers get to know the best seed for the area based on the database of experts. I did that well but I also wanted them to be updated on what to do every time there has to be an activity on their crops for instance weed, apply fertilizer etc. I have a table of timing which stores duration for a given crop and what my program does it subtract the starting date as the planting date from the current date and checks from the timing table if the differences in dates matches the duration stored for the crop it fetches the action. I have tried doing a thread but it is not fetching the action. Kindly this is the section of the code.
String selcted_crop = crop();
String selcted_place = activity_Area();
try {
String s = "Insert into activities(id_Number, f_Name, l_Name, phone_Number, start_Date, crop_ID, place_ID, farm_Size)values(?,?,?,?,?,?,?,?) ";
pst = conn.prepareStatement(s);
pst.setString(1, id_Number.getText());
pst.setString(2, f_Name.getText());
pst.setString(3, s_Name.getText());
pst.setString(4, phone_Number.getText());
pst.setString(5, ((JTextField) jDateChooser2.getDateEditor().getUiComponent()).getText());
pst.setString(6, selcted_crop);
pst.setString(7, selcted_place);
pst.setString(8, farm_Size.getText());
pst.executeUpdate();
JOptionPane.showMessageDialog(null, "Record Saved");
String plc1[] = new String[100];
String placeve = "";
Thread t = new Thread() {
public void run() {
for (;;) {
Calendar c = new GregorianCalendar();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int day = c.get(Calendar.DAY_OF_MONTH);
int hour = c.get(Calendar.HOUR);
int min = c.get((Calendar.MINUTE));
int sec = c.get(Calendar.SECOND);
CurrentDate = year + "-0" + month + day;
CurrentHour = "0" + hour + min + sec;
}
}
};
t.start();
for (int i = 0; i <= 3; i++) {
try {
String stl = "Select *from vendors where place_ID = '" + place_ComboBox.getSelectedItem().toString() + "'";
pst = conn.prepareStatement(stl);
rst = pst.executeQuery();
while (rst.next()) {
plc1[i] = rst.getString("vendor_Name");
JOptionPane.showMessageDialog(null, plc1[i]);
}
} catch (Exception e) {
}
}
String name = f_Name.getText();
try {
String g = "select *from activity where s_name=?";
pst = conn.prepareStatement(g);
pst.setString(1, name);
rst = pst.executeQuery();
if (rst.next()) {
name = rst.getString("s_Name");
}
} catch (Exception e) {
}
String crop1 = crop_ComboBox.getSelectedItem().toString();
String crop_ID = "";
try {
String l = "select *from crops where crop_Name=?";
pst = conn.prepareStatement(l);
pst.setString(1, crop1);
rst = pst.executeQuery();
if (rst.next()) {
crop_ID = rst.getString("crop_ID");
}
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e);
}
String plc = place_ComboBox.getSelectedItem().toString();
String place_ID = "";
try {
String re = "select *from places where place_Name=?";
pst = conn.prepareStatement(re);
pst.setString(1, plc);
rst = pst.executeQuery();
if (rst.next()) {
place_ID = rst.getString("place_ID");
}
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e);
}
String pie = "";
String pie1 = "";
try {
String b = "select * from seeds where crop_ID=? and place_ID=?";
pst = conn.prepareStatement(b);
pst.setString(1, crop_ID);
pst.setString(2, place_ID);
rst = pst.executeQuery();
if (rst.next()) {
pie = rst.getString("seed_Name");
pie1 = rst.getString("seed_ID");
JOptionPane.showMessageDialog(null, "Hujambo " + name + ", You are being informed that the best seed for you is " + pie + ". KIndly buy the seeds from a trusted vendor");
}
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e);
}
int uniqueid = 0;
String action = "";
String cp[] = new String[1000];
int diffDays[] = new int[100];
String pNumber = phone_Number.getText();
for (int i = 0; i < uniqueid; i++) {
try {
String str = "Select *from activities where phone_Number = '" + pNumber + "'";
pst = conn.prepareStatement(str);
rst = pst.executeQuery();
while (rst.next()) {
String dp = rst.getString("start_Date");
String kp = rst.getString("cropId");
}
} catch (Exception e) {
}
int dur = 0;
try {
String ke = "select from actions where seed_ID='" + pie1 + "'";
pst = conn.prepareStatement(ke);
rst = pst.executeQuery();
while (rst.next()) {
action = rst.getString("action");
if (rst.next()) {
dur = rst.getInt("Duration");
action = rst.getString("action");
if (diffDays[i] == dur) {
JOptionPane.showMessageDialog(null, "Kindly it has gone'" + dur + "' you are being informed to '" + action + "'");
}
}
}
} catch (Exception e) {
}
}
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e);
}
I have a maven multi-module application (see also #58),
Parts of the system:
SpringComponentFinderStrategy
and SourceCodeComponentFinderStrategy
In situation (A) calling the documentation main manually works well and finds controller from the App module.
In situation (B) let maven build invoke the main, the following error shows up:
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:294)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NoClassDefFoundError: com/sun/tools/javadoc/Main
at com.structurizr.analysis.SourceCodeComponentFinderStrategy.runJavaDoc(SourceCodeComponentFinderStrategy.java:118)
at com.structurizr.analysis.SourceCodeComponentFinderStrategy.afterFindComponents(SourceCodeComponentFinderStrategy.java:62)
at com.structurizr.analysis.ComponentFinder.findComponents(ComponentFinder.java:76)
Skipping the SourceCodeComponentFinderStrategy
results in "fixing" this errors, but doesn't return any found components.
./gradlew test fails:
java.lang.Exception: Unexpected exception, expected<javax.crypto.BadPaddingException> but was<java.security.InvalidKeyException>
at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:28)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:86)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:49)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:69)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:105)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:355)
at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.security.InvalidKeyException: Illegal key size
I notice that you've gone to the effort of having an IdGenerator interface as if it were pluggable, but in Model.java the implementation is hard coded to SequentialIdGeneratorStratergy:
Any objection to this becoming truly pluggable so that alternate implementations can be used?
For example, I repeatedly find myself speculating that it would be useful to have a stable IdGenerator such that as code evolves the same components generate the same ids each run. I'm hopeful that this could have value in linking / merging microservice models into bigger system models; or might have practical value in highlighting changes over time (deleted vs added components)
I'm wondering if there is a good way to model components and actors of which there may be replicas or multiple instances?
For example, if I have an Actor who is using a chat program front-end to communicate with another Actor who is using another instance of the front-end, how would I model this exchange? Both front-ends are instances of the same component, and both talk to the same back-end?
This sort of thing is especially useful in dynamic views to show how users interact with each other through the system.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.