Commit ce728222 authored by René Schöne's avatar René Schöne
Browse files

Merge branch '9-show-null-children-in-tree' into 'dev'

Resolve "Show "null" children in tree"

Closes #9

See merge request jastadd/relast2uml!5
parents f8512ae0 7fa94991
Pipeline #12748 passed with stages
in 3 minutes and 25 seconds
DumpAst ::= DumpNode* <PackageName> BuildConfig PrintConfig ;
rel DumpAst.RootNode -> DumpNode ;
BuildConfig ::= GlobalPatternCollection:PatternCollection StyleInformation ExcludeTypePattern:TypePatternCollectionMapping* IncludeTypePattern:TypePatternCollectionMapping* <TypeIgnorePattern> <IncludeEmptyString:boolean> <Debug:boolean>;
BuildConfig ::= StyleInformation GlobalPatternCollection:PatternCollection
ExcludeTypePattern:TypePatternCollectionMapping* IncludeTypePattern:TypePatternCollectionMapping*
<TypeIgnorePattern> <IncludeEmptyString:boolean> <ExcludeNullNodes:boolean> <Debug:boolean>;
TypePatternCollectionMapping ::= <TypeRegex> PatternCollection ;
PatternCollection ::= <TokenPattern> <ChildPattern> <RelationPattern> <AttributePattern> <NonterminalAttributePattern> ;
StyleInformation ::= <NameMethod:StyleMethod> <BackgroundColorMethod:StyleMethod> <TextColorMethod:StyleMethod>;
......@@ -9,7 +11,9 @@ StyleInformation ::= <NameMethod:StyleMethod> <BackgroundColorMethod:StyleMethod
PrintConfig ::= <Scale:double> <Version> <OrderChildren:boolean> Header* ;
Header ::= <Value> ;
DumpNode ::= <Name> <Label> <BackgroundColor> <TextColor> <Object:Object> <Invisible:boolean> DumpChildNode* DumpToken* DumpRelation* /InvisiblePath/ ;
DumpNode ::= DumpChildNode* DumpToken* DumpRelation*
<Name> <Label> <BackgroundColor> <TextColor> <Object:Object> <Invisible:boolean>
/InvisiblePath/ ;
InnerDumpNode ;
rel InnerDumpNode.DumpNode <-> DumpNode.ContainerOfInner ;
......
......@@ -26,11 +26,23 @@ aspect GenerationBackend {
}
protected DumpNode DumpAst.transform(TransformationTransferInformation tti, Object obj, Source source)
throws java.lang.reflect.InvocationTargetException, IllegalAccessException, NoSuchMethodException {
if (obj == null) {
return transform(tti, obj, source, false);
}
protected DumpNode DumpAst.transform(
TransformationTransferInformation tti, Object obj, Source source, boolean allowNullObj)
throws java.lang.reflect.InvocationTargetException, IllegalAccessException, NoSuchMethodException {
if (obj == null && !allowNullObj) {
return null;
}
DumpNode node = tti.transformed.get(obj);
String objClassName = obj.getClass().getSimpleName();
DumpNode node;
String objClassName;
if (obj == null) {
node = null;
objClassName = "null";
} else {
node = tti.transformed.get(obj);
objClassName = obj.getClass().getSimpleName();
}
if (node != null) {
if (source == Source.RELATION) {
return node;
......@@ -47,9 +59,7 @@ aspect GenerationBackend {
if (!node.isAstNode()) {
return node;
}
node.setLabel(getBuildConfig().getStyleInformation().getNameMethod().get(obj));
node.setBackgroundColor(getBuildConfig().getStyleInformation().getBackgroundColorMethod().get(obj));
node.setTextColor(getBuildConfig().getStyleInformation().getTextColorMethod().get(obj));
applyStyle(node);
// do not process node further if coming from a relation
if (source == Source.RELATION) {
tti.relationTargetsUnprocessed.put(node, true);
......@@ -58,13 +68,17 @@ aspect GenerationBackend {
if (source == Source.INVISIBLE_PARENT || !isTypeEnabled(objClassName)) {
node.setInvisible(true);
}
if (obj == null) {
// for a null object, we do not need any further analysis
return node;
}
final ClassAnalysisResult car = analyzeClass(obj.getClass());
// -- singleChild --
for (SingleChildMethod singleChildMethod : car.singleChildMethods()) {
Object target = singleChildMethod.getMethod().invoke(obj);
String childName = singleChildMethod.getName();
DumpNode targetNode = transform(tti, target, nextSource(source, !isChildEnabled(objClassName, childName)));
if (target != null && targetNode != null) {
DumpNode targetNode = transform(tti, target, nextSource(source, !isChildEnabled(objClassName, childName)), !getBuildConfig().getExcludeNullNodes());
if (targetNode != null) {
DumpNormalChildNode normalChild = new DumpNormalChildNode();
normalChild.setName(childName);
normalChild.setDumpNode(targetNode);
......@@ -143,6 +157,13 @@ aspect GenerationBackend {
return node;
}
private void DumpAst.applyStyle(DumpNode node) {
Object obj = node.getObject();
node.setLabel(getBuildConfig().getStyleInformation().getNameMethod().get(obj));
node.setBackgroundColor(getBuildConfig().getStyleInformation().getBackgroundColorMethod().get(obj));
node.setTextColor(getBuildConfig().getStyleInformation().getTextColorMethod().get(obj));
}
private Source DumpAst.nextSource(Source currentSource, boolean shouldBeInvisible) {
return currentSource == Source.INVISIBLE_PARENT ? Source.INVISIBLE_PARENT :
(shouldBeInvisible ? Source.INVISIBLE_PARENT : Source.PARENT);
......@@ -415,6 +436,10 @@ aspect GenerationBackend {
// --- isAstNode ---
syn boolean DumpNode.isAstNode() {
if (getObject() == null) {
// this is only possible for normal child nodes, and they are ast nodes
return true;
}
Class<?> clazz = getObject().getClass();
for (java.lang.reflect.Method method : clazz.getMethods()) {
if ("init$Children".equals(method.getName()) && method.getParameterCount() == 0) {
......@@ -462,7 +487,6 @@ aspect GenerationBackend {
}
}
// --- myChildren ---
syn java.util.List<DumpNode> DumpNode.myChildren() {
java.util.List<DumpNode> result = new java.util.ArrayList<>();
......@@ -579,7 +603,7 @@ aspect GenerationBackend {
static StyleInformation StyleInformation.createDefault() {
StyleInformation result = new StyleInformation();
result.setNameMethod(n -> n.getClass().getSimpleName() + "@" + Integer.toHexString(n.hashCode()));
result.setNameMethod(n -> n == null ? "null" : n.getClass().getSimpleName() + "@" + Integer.toHexString(n.hashCode()));
result.setBackgroundColorMethod(n -> "");
result.setTextColorMethod(n -> "");
return result;
......
......@@ -308,6 +308,16 @@ public class DumpBuilder {
}
}
public DumpBuilder excludeNullNodes() {
buildConfig.setExcludeNullNodes(true);
return this;
}
public DumpBuilder includeNullNodes() {
buildConfig.setExcludeNullNodes(false);
return this;
}
public DumpBuilder customPreamble(String option) {
printConfig.addHeader(new Header(option));
return this;
......
......@@ -35,7 +35,7 @@ public class TestDumperMain {
builder.includeAttributes("simpleAttr")
.orderChildren()
.includeNonterminalAttributes("getCalculated")
.setNameMethod(n -> n.getClass().getSimpleName());
.setNameMethod(n -> n == null ? "null" : n.getClass().getSimpleName());
System.out.println(">> PlantUml");
DumpAst dumpAst = builder.build();
......
......@@ -31,9 +31,9 @@ public class TestSimple {
@Test void testChildlessNonterminal() {
Root root = createRoot(createA(A_NAME, a -> a.setD(new D())), null);
List<DumpNode> nodes = TestUtils.dumpModel(root);
Optional<DumpNode> optionalCDumpNode = nodes.stream().filter(n -> n.getObject() instanceof D).findFirst();
assertTrue(optionalCDumpNode.isPresent());
assertTrue(optionalCDumpNode.get().isAstNode());
Optional<DumpNode> actualD = nodes.stream().filter(n -> n.getObject() instanceof D).findFirst();
assertTrue(actualD.isPresent());
assertTrue(actualD.get().isAstNode());
}
@Test
......@@ -49,6 +49,22 @@ public class TestSimple {
assertThatMapOf(normalChildren(actualRoot)).containsExactlyInAnyOrder(tuple("A", A_NAME));
}
@Test
public void testOneNormalChildIncludeNullNodes() {
Root root = createRoot(createA(A_NAME), null);
List<DumpNode> nodes = TestUtils.dumpModel(root, DumpBuilder::includeNullNodes);
assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(
ROOT_NAME, A_NAME, null, null, null, null);
DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME);
assertEquals(1, actualRoot.getNumDumpToken());
assertEquals(2, actualRoot.getNumDumpChildNode());
assertEquals(0, actualRoot.getNumDumpRelation());
DumpNode actualA = TestUtils.findByName(nodes, A_NAME);
assertEquals(3, actualA.getNumDumpChildNode());
}
@Test
public void testListChildren() {
Root root = createRoot(null, null, createB(B1_NAME), createB(B2_NAME), createB(B3_NAME));
......
......@@ -156,6 +156,7 @@ public class TestUtils {
public static List<DumpNode> dumpModel(Object target, Consumer<DumpBuilder> options) {
ExposingDumpBuilder builder = new ExposingDumpBuilder(target);
builder.excludeNullNodes();
options.accept(builder);
DumpAst dumpAst = builder.build();
// let mustache run, but ignore result
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment