Skip to content
This repository was archived by the owner on Mar 28, 2026. It is now read-only.

Commit b585eed

Browse files
Bug fixes to prevent parents and children to both be added to container/component views.
1 parent d8e6c88 commit b585eed

10 files changed

Lines changed: 187 additions & 12 deletions

File tree

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ subprojects { proj ->
1414

1515
description = 'Structurizr'
1616
group = 'com.structurizr'
17-
version = '1.9.3'
17+
version = '1.9.4'
1818

1919
repositories {
2020
mavenCentral()

docs/changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 1.9.4 (22nd May 2021)
4+
5+
- Bug fixes to prevent parents and children to both be added to container/component views.
6+
37
## 1.9.3 (11th May 2021)
48

59
- Added an `addTheme` method on `Configuration`.

structurizr-core/src/com/structurizr/view/ComponentView.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ protected void checkElementCanBeAdded(Element element) {
266266
if (element.equals(getContainer().getParent())) {
267267
throw new ElementNotPermittedInViewException("The software system in scope cannot be added to a component view.");
268268
} else {
269+
checkParentAndChildrenHaveNotAlreadyBeenAdded((SoftwareSystem)element);
269270
return;
270271
}
271272
}
@@ -274,11 +275,13 @@ protected void checkElementCanBeAdded(Element element) {
274275
if (element.equals(getContainer())) {
275276
throw new ElementNotPermittedInViewException("The container in scope cannot be added to a component view.");
276277
} else {
278+
checkParentAndChildrenHaveNotAlreadyBeenAdded((Container)element);
277279
return;
278280
}
279281
}
280282

281283
if (element instanceof Component) {
284+
checkParentAndChildrenHaveNotAlreadyBeenAdded((Component)element);
282285
return;
283286
}
284287

structurizr-core/src/com/structurizr/view/ContainerView.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,13 @@ protected void checkElementCanBeAdded(Element element) {
181181
if (element.equals(getSoftwareSystem())) {
182182
throw new ElementNotPermittedInViewException("The software system in scope cannot be added to a container view.");
183183
} else {
184+
checkParentAndChildrenHaveNotAlreadyBeenAdded((SoftwareSystem)element);
184185
return;
185186
}
186187
}
187188

188189
if (element instanceof Container) {
190+
checkParentAndChildrenHaveNotAlreadyBeenAdded((Container)element);
189191
return;
190192
}
191193

structurizr-core/src/com/structurizr/view/DeploymentView.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ protected void checkElementCanBeAdded(Element elementToBeAdded) {
314314
Set<String> softwareSystemIds = getElements().stream().map(ElementView::getElement).filter(e -> e instanceof SoftwareSystemInstance).map(e -> (SoftwareSystemInstance)e).map(SoftwareSystemInstance::getSoftwareSystemId).collect(Collectors.toSet());
315315

316316
if (softwareSystemIds.contains(containerInstanceToBeAdded.getContainer().getSoftwareSystem().getId())) {
317-
throw new ElementNotPermittedInViewException("The parent of " + elementToBeAdded.getName() + " is already in this view.");
317+
throw new ElementNotPermittedInViewException("A parent of " + elementToBeAdded.getName() + " is already in this view.");
318318
}
319319
}
320320
}

structurizr-core/src/com/structurizr/view/View.java

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -439,20 +439,31 @@ public ViewSet getViewSet() {
439439
protected abstract boolean canBeRemoved(Element element);
440440

441441
final void checkParentAndChildrenHaveNotAlreadyBeenAdded(StaticStructureElement elementToBeAdded) {
442-
// check the parent hasn't been added already
443-
Set<String> elementIds = getElements().stream().map(ElementView::getElement).map(Element::getId).collect(Collectors.toSet());
442+
// check a parent hasn't been added already
443+
Set<String> idsOfElementsInView = getElements().stream().map(ElementView::getElement).map(Element::getId).collect(Collectors.toSet());
444444

445-
if (elementToBeAdded.getParent() != null) {
446-
if (elementIds.contains(elementToBeAdded.getParent().getId())) {
447-
throw new ElementNotPermittedInViewException("The parent of " + elementToBeAdded.getName() + " is already in this view.");
445+
Element parent = elementToBeAdded.getParent();
446+
while (parent != null) {
447+
if (idsOfElementsInView.contains(parent.getId())) {
448+
throw new ElementNotPermittedInViewException("A parent of " + elementToBeAdded.getName() + " is already in this view.");
448449
}
450+
451+
parent = parent.getParent();
449452
}
450453

451454
// and now check a child hasn't been added already
452-
Set<String> elementParentIds = getElements().stream().map(ElementView::getElement).filter(e -> e.getParent() != null).map(e -> e.getParent().getId()).collect(Collectors.toSet());
455+
Set<String> elementParentIds = new HashSet<>();
456+
for (ElementView elementView : getElements()) {
457+
Element element = elementView.getElement();
458+
parent = element.getParent();
459+
while (parent != null) {
460+
elementParentIds.add(parent.getId());
461+
parent = parent.getParent();
462+
}
463+
}
453464

454465
if (elementParentIds.contains(elementToBeAdded.getId())) {
455-
throw new ElementNotPermittedInViewException("The child of " + elementToBeAdded.getName() + " is already in this view.");
466+
throw new ElementNotPermittedInViewException("A child of " + elementToBeAdded.getName() + " is already in this view.");
456467
}
457468
}
458469

structurizr-core/test/unit/com/structurizr/view/ComponentViewTests.java

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,4 +626,114 @@ public void test_addContainer_ThrowsAnException_WhenTheContainerIsTheScopeOfTheV
626626
}
627627
}
628628

629+
@Test
630+
public void test_addSoftwareSystem_ThrowsAnException_WhenAChildContainerIsAlreadyAdded() {
631+
try {
632+
SoftwareSystem softwareSystem1 = model.addSoftwareSystem("Software System 1");
633+
Container container1 = softwareSystem1.addContainer("Container 1");
634+
Component component1 = container1.addComponent("Component 1");
635+
636+
SoftwareSystem softwareSystem2 = model.addSoftwareSystem("Software System 2");
637+
Container container2 = softwareSystem2.addContainer("Container 2");
638+
Component component2 = container2.addComponent("Component 2");
639+
640+
ComponentView view = views.createComponentView(container1, "key", "Description");
641+
642+
view.add(container2);
643+
view.add(softwareSystem2);
644+
645+
fail();
646+
} catch (ElementNotPermittedInViewException e) {
647+
assertEquals("A child of Software System 2 is already in this view.", e.getMessage());
648+
}
649+
}
650+
651+
@Test
652+
public void test_addSoftwareSystem_ThrowsAnException_WhenAChildComponentIsAlreadyAdded() {
653+
try {
654+
SoftwareSystem softwareSystem1 = model.addSoftwareSystem("Software System 1");
655+
Container container1 = softwareSystem1.addContainer("Container 1");
656+
Component component1 = container1.addComponent("Component 1");
657+
658+
SoftwareSystem softwareSystem2 = model.addSoftwareSystem("Software System 2");
659+
Container container2 = softwareSystem2.addContainer("Container 2");
660+
Component component2 = container2.addComponent("Component 2");
661+
662+
ComponentView view = views.createComponentView(container1, "key", "Description");
663+
664+
view.add(component2);
665+
view.add(softwareSystem2);
666+
667+
fail();
668+
} catch (ElementNotPermittedInViewException e) {
669+
assertEquals("A child of Software System 2 is already in this view.", e.getMessage());
670+
}
671+
}
672+
673+
@Test
674+
public void test_addContainer_ThrowsAnException_WhenAChildComponentIsAlreadyAdded() {
675+
try {
676+
SoftwareSystem softwareSystem1 = model.addSoftwareSystem("Software System 1");
677+
Container container1 = softwareSystem1.addContainer("Container 1");
678+
Component component1 = container1.addComponent("Component 1");
679+
680+
SoftwareSystem softwareSystem2 = model.addSoftwareSystem("Software System 2");
681+
Container container2 = softwareSystem2.addContainer("Container 2");
682+
Component component2 = container2.addComponent("Component 2");
683+
684+
ComponentView view = views.createComponentView(container1, "key", "Description");
685+
686+
view.add(component2);
687+
view.add(container2);
688+
689+
fail();
690+
} catch (ElementNotPermittedInViewException e) {
691+
assertEquals("A child of Container 2 is already in this view.", e.getMessage());
692+
}
693+
}
694+
695+
@Test
696+
public void test_addContainer_ThrowsAnException_WhenTheParentIsAlreadyAdded() {
697+
try {
698+
SoftwareSystem softwareSystem1 = model.addSoftwareSystem("Software System 1");
699+
Container container1 = softwareSystem1.addContainer("Container 1");
700+
Component component1 = container1.addComponent("Component 1");
701+
702+
SoftwareSystem softwareSystem2 = model.addSoftwareSystem("Software System 2");
703+
Container container2 = softwareSystem2.addContainer("Container 2");
704+
Component component2 = container2.addComponent("Component 2");
705+
706+
ComponentView view = views.createComponentView(container1, "key", "Description");
707+
708+
view.add(softwareSystem2);
709+
view.add(container2);
710+
711+
fail();
712+
} catch (ElementNotPermittedInViewException e) {
713+
assertEquals("A parent of Container 2 is already in this view.", e.getMessage());
714+
}
715+
}
716+
717+
@Test
718+
public void test_addComponent_ThrowsAnException_WhenTheParentIsAlreadyAdded() {
719+
try {
720+
SoftwareSystem softwareSystem1 = model.addSoftwareSystem("Software System 1");
721+
Container container1 = softwareSystem1.addContainer("Container 1");
722+
Component component1 = container1.addComponent("Component 1");
723+
724+
SoftwareSystem softwareSystem2 = model.addSoftwareSystem("Software System 2");
725+
Container container2 = softwareSystem2.addContainer("Container 2");
726+
Component component2 = container2.addComponent("Component 2");
727+
728+
ComponentView view = views.createComponentView(container1, "key", "Description");
729+
730+
view.add(softwareSystem2);
731+
view.add(component2);
732+
733+
fail();
734+
} catch (ElementNotPermittedInViewException e) {
735+
assertEquals("A parent of Component 2 is already in this view.", e.getMessage());
736+
}
737+
}
738+
629739
}

structurizr-core/test/unit/com/structurizr/view/ContainerViewTests.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
import org.junit.Before;
77
import org.junit.Test;
88

9+
import java.util.HashMap;
10+
import java.util.Map;
11+
912
import static org.junit.Assert.*;
1013

1114
public class ContainerViewTests extends AbstractWorkspaceTestBase {
@@ -306,4 +309,46 @@ public void test_addSoftwareSystem_ThrowsAnException_WhenTheSoftwareSystemIsTheS
306309
}
307310
}
308311

312+
@Test
313+
public void test_addSoftwareSystem_ThrowsAnException_WhenAChildContainerIsAlreadyAdded() {
314+
try {
315+
SoftwareSystem softwareSystem1 = model.addSoftwareSystem("Software System 1");
316+
Container container1 = softwareSystem1.addContainer("Container 1");
317+
318+
SoftwareSystem softwareSystem2 = model.addSoftwareSystem("Software System 2");
319+
Container container2 = softwareSystem2.addContainer("Container 2");
320+
321+
ContainerView view = views.createContainerView(softwareSystem1, "key", "Description");
322+
323+
view.add(container1);
324+
view.add(container2);
325+
view.add(softwareSystem2);
326+
327+
fail();
328+
} catch (ElementNotPermittedInViewException e) {
329+
assertEquals("A child of Software System 2 is already in this view.", e.getMessage());
330+
}
331+
}
332+
333+
@Test
334+
public void test_addContainer_ThrowsAnException_WhenTheParentIsAlreadyAdded() {
335+
try {
336+
SoftwareSystem softwareSystem1 = model.addSoftwareSystem("Software System 1");
337+
Container container1 = softwareSystem1.addContainer("Container 1");
338+
339+
SoftwareSystem softwareSystem2 = model.addSoftwareSystem("Software System 2");
340+
Container container2 = softwareSystem2.addContainer("Container 2");
341+
342+
ContainerView view = views.createContainerView(softwareSystem1, "key", "Description");
343+
344+
view.add(container1);
345+
view.add(softwareSystem2);
346+
view.add(container2);
347+
348+
fail();
349+
} catch (ElementNotPermittedInViewException e) {
350+
assertEquals("A parent of Container 2 is already in this view.", e.getMessage());
351+
}
352+
}
353+
309354
}

structurizr-core/test/unit/com/structurizr/view/DeploymentViewTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ public void test_addContainerInstance_ThrowsAnException_WhenTheParentSoftwareSys
532532
deploymentView.add(containerInstance);
533533
fail();
534534
} catch (ElementNotPermittedInViewException e) {
535-
assertEquals("The parent of Container is already in this view.", e.getMessage());
535+
assertEquals("A parent of Container is already in this view.", e.getMessage());
536536
}
537537
}
538538

structurizr-core/test/unit/com/structurizr/view/DynamicViewTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ public void test_add_ThrowsAnException_WhenTheParentOfAnElementHasAlreadyBeenAdd
149149
dynamicView.add(component1, component2);
150150
fail();
151151
} catch (Exception e) {
152-
assertEquals("The parent of Component 2 is already in this view.", e.getMessage());
152+
assertEquals("A parent of Component 2 is already in this view.", e.getMessage());
153153
}
154154
}
155155

@@ -171,7 +171,7 @@ public void test_add_ThrowsAnException_WhenTheChildOfAnElementHasAlreadyBeenAdde
171171
dynamicView.add(component1, container2);
172172
fail();
173173
} catch (Exception e) {
174-
assertEquals("The child of Container 2 is already in this view.", e.getMessage());
174+
assertEquals("A child of Container 2 is already in this view.", e.getMessage());
175175
}
176176
}
177177

0 commit comments

Comments
 (0)