summaryrefslogtreecommitdiffstats
path: root/configgen
diff options
context:
space:
mode:
authorOlli Virtanen <olli.virtanen@oath.com>2018-05-24 16:53:17 +0200
committerOlli Virtanen <olli.virtanen@oath.com>2018-05-24 16:53:17 +0200
commit882407b5ed793f24fbd8b53334eb84e3548c1131 (patch)
tree3479808b9203cdb2cc76dcd1ad41f3a8a51bf639 /configgen
parent7a5eb504b4ce7b6bdcd0e0e613bcb2287fd358f1 (diff)
Scala code replaced with Java equivalent
Diffstat (limited to 'configgen')
-rw-r--r--configgen/pom.xml34
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java351
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/ConfigGenerator.java444
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/ConfiggenUtil.java2
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/JavaClassBuilder.java170
-rw-r--r--configgen/src/main/scala/com/yahoo/config/codegen/BuilderGenerator.scala350
-rw-r--r--configgen/src/main/scala/com/yahoo/config/codegen/ConfigGenerator.scala423
-rw-r--r--configgen/src/main/scala/com/yahoo/config/codegen/JavaClassBuilder.scala186
-rw-r--r--configgen/src/test/java/com/yahoo/config/codegen/JavaClassBuilderTest.java116
-rw-r--r--configgen/src/test/resources/allfeatures.reference1983
-rw-r--r--configgen/src/test/scala/com/yahoo/config/codegen/JavaClassBuilderTest.scala97
11 files changed, 3065 insertions, 1091 deletions
diff --git a/configgen/pom.xml b/configgen/pom.xml
index e8de114f8d5..be9cd733601 100644
--- a/configgen/pom.xml
+++ b/configgen/pom.xml
@@ -19,14 +19,6 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-library</artifactId>
- </dependency>
- <dependency>
- <groupId>org.scala-lang.modules</groupId>
- <artifactId>scala-xml_${scala.major-version}</artifactId>
- </dependency>
</dependencies>
<build>
<plugins>
@@ -63,32 +55,6 @@
<updateReleaseInfo>true</updateReleaseInfo>
</configuration>
</plugin>
- <plugin>
- <groupId>net.alchim31.maven</groupId>
- <artifactId>scala-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>compile</id>
- <goals>
- <goal>compile</goal>
- </goals>
- <phase>compile</phase>
- </execution>
- <execution>
- <id>test-compile</id>
- <goals>
- <goal>testCompile</goal>
- </goals>
- <phase>test-compile</phase>
- </execution>
- <execution>
- <phase>process-resources</phase>
- <goals>
- <goal>compile</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
</plugins>
</build>
</project>
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java b/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java
new file mode 100644
index 00000000000..bf3fc2902a1
--- /dev/null
+++ b/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java
@@ -0,0 +1,351 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.codegen;
+
+import com.yahoo.config.codegen.LeafCNode.FileLeaf;
+import com.yahoo.config.codegen.LeafCNode.PathLeaf;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.yahoo.config.codegen.ConfigGenerator.boxedDataType;
+import static com.yahoo.config.codegen.ConfigGenerator.indentCode;
+import static com.yahoo.config.codegen.ConfigGenerator.nodeClass;
+import static com.yahoo.config.codegen.ConfigGenerator.userDataType;
+import static com.yahoo.config.codegen.JavaClassBuilder.INDENTATION;
+import static com.yahoo.config.codegen.JavaClassBuilder.createUniqueSymbol;
+import static com.yahoo.config.codegen.ReservedWords.INTERNAL_PREFIX;
+import static java.util.Arrays.stream;
+
+/**
+ * @author gjoranv
+ * @author ollivir
+ */
+
+public class BuilderGenerator {
+ public static String getBuilder(InnerCNode node) {
+ return getDeclaration(node) + "\n" + //
+ indentCode(INDENTATION, getUninitializedScalars(node) + "\n\n" + //
+ stream(node.getChildren()).map(BuilderGenerator::getBuilderFieldDefinition).collect(Collectors.joining("\n"))
+ + "\n\n" + //
+ getBuilderConstructors(node, nodeClass(node)) + "\n\n" + //
+ getOverrideMethod(node) + "\n\n" + //
+ getBuilderSetters(node) + "\n" + //
+ getSpecialRootBuilderCode(node))
+ + "}";
+ }
+
+ private static String getDeclaration(InnerCNode node) {
+ String getInterfaces = (node.getParent() == null) ? "implements ConfigInstance.Builder" : "implements ConfigBuilder";
+
+ return "public static class Builder " + getInterfaces + " {";
+ }
+
+ private static String getSpecialRootBuilderCode(InnerCNode node) {
+ return (node.getParent() == null) ? "\n" + getDispatchCode() + "\n" : "";
+ }
+
+ private static String getDispatchCode() {
+ // Use full path to @Override, as users are free to define an inner node called
+ // 'override'. (summarymap.def does)
+ // The generated inner 'Override' class would otherwise be mistaken for the
+ // annotation.
+ return "@java.lang.Override\n" + //
+ "public final boolean dispatchGetConfig(ConfigInstance.Producer producer) {\n" + //
+ " if (producer instanceof Producer) {\n" + //
+ " ((Producer)producer).getConfig(this);\n" + //
+ " return true;\n" + //
+ " }\n" + //
+ " return false;\n" + //
+ "}\n" + //
+ "\n" + //
+ "@java.lang.Override\n" + //
+ "public final String getDefMd5() { return CONFIG_DEF_MD5; }\n" + //
+ "@java.lang.Override\n" + //
+ "public final String getDefName() { return CONFIG_DEF_NAME; }\n" + //
+ "@java.lang.Override\n" + //
+ "public final String getDefNamespace() { return CONFIG_DEF_NAMESPACE; }";
+ }
+
+ private static String getUninitializedScalars(InnerCNode node) {
+ List<String> scalarsWithoutDefault = new ArrayList<>();
+ for (CNode child : node.getChildren()) {
+ if (child instanceof LeafCNode && (!child.isArray && !child.isMap && ((LeafCNode) child).getDefaultValue() == null)) {
+ scalarsWithoutDefault.add("\"" + child.getName() + "\"");
+ }
+ }
+
+ String uninitializedList = (scalarsWithoutDefault.size() > 0)
+ ? "Arrays.asList(\n" + indentCode(INDENTATION, String.join(",\n", scalarsWithoutDefault) + "\n)")
+ : "";
+
+ return "private Set<String> " + INTERNAL_PREFIX + "uninitialized = new HashSet<String>(" + uninitializedList + ");";
+ }
+
+ private static String getBuilderFieldDefinition(CNode node) {
+ if (node.isArray) {
+ return String.format("public List<%s> %s = new ArrayList<>();", builderType(node), node.getName());
+ } else if (node.isMap) {
+ return String.format("public Map<String, %s> %s = new LinkedHashMap<>();", builderType(node), node.getName());
+ } else if (node instanceof InnerCNode) {
+ return String.format("public %s %s = new %s();", builderType(node), node.getName(), builderType(node));
+ } else if (node instanceof LeafCNode) {
+ return String.format("private %s %s = null;", boxedBuilderType((LeafCNode) node), node.getName());
+ } else {
+ throw new IllegalStateException("Cannot produce builder field definition for node"); // Should not happen
+ }
+ }
+
+ private static String getBuilderSetters(CNode node) {
+ List<String> elem = new ArrayList<>();
+ CNode[] children = node.getChildren();
+
+ for (CNode child : children) {
+ if (child instanceof InnerCNode && child.isArray) {
+ elem.add(BuilderSetters.innerArraySetters((InnerCNode) child));
+ } else if (child instanceof InnerCNode && child.isMap) {
+ elem.add(BuilderSetters.innerMapSetters(child));
+ } else if (child instanceof LeafCNode && child.isArray) {
+ elem.add(BuilderSetters.leafArraySetters((LeafCNode) child));
+ } else if (child instanceof LeafCNode && child.isMap) {
+ elem.add(BuilderSetters.leafMapSetters(child));
+ } else if (child instanceof InnerCNode) {
+ elem.add(BuilderSetters.structSetter((InnerCNode) child));
+ } else if (child instanceof LeafCNode) {
+ elem.add(BuilderSetters.scalarSetters((LeafCNode) child));
+ }
+ }
+ return String.join("\n\n", elem);
+ }
+
+ private static class BuilderSetters {
+ private static String structSetter(InnerCNode n) {
+ return "public Builder " + n.getName() + "(" + builderType(n) + " " + INTERNAL_PREFIX + "builder) {\n" + //
+ " " + n.getName() + " = " + INTERNAL_PREFIX + "builder;\n" + //
+ " return this;\n" + //
+ "}";
+ }
+
+ private static String innerArraySetters(InnerCNode n) {
+ return "/**\n" + //
+ " * Add the given builder to this builder's list of " + nodeClass(n) + " builders\n" + //
+ " * @param " + INTERNAL_PREFIX + "builder a builder\n" + //
+ " * @return this builder\n" + //
+ " */\n" + //
+ "public Builder " + n.getName() + "(" + builderType(n) + " " + INTERNAL_PREFIX + "builder) {\n" + //
+ " " + n.getName() + ".add(" + INTERNAL_PREFIX + "builder);\n" + //
+ " return this;\n" + //
+ "}\n" + //
+ "\n" + //
+ "/**\n" + //
+ " * Set the given list as this builder's list of " + nodeClass(n) + " builders\n" + //
+ " * @param __builders a list of builders\n" + //
+ " * @return this builder\n" + //
+ " */\n" + //
+ "public Builder " + n.getName() + "(List<" + builderType(n) + "> __builders) {\n" + //
+ " " + n.getName() + " = __builders;\n" + //
+ " return this;\n" + //
+ "}";
+ }
+
+ private static String publicLeafNodeSetters(LeafCNode n) {
+ return "public Builder " + n.getName() + "(" + builderType(n) + " " + INTERNAL_PREFIX + "value) {\n" + //
+ " " + n.getName() + ".add(" + INTERNAL_PREFIX + "value);\n" + //
+ " return this;\n" + //
+ "}\n" + //
+ "\n" + //
+ "public Builder " + n.getName() + "(Collection<" + builderType(n) + "> " + INTERNAL_PREFIX + "values) {\n" + //
+ " " + n.getName() + ".addAll(" + INTERNAL_PREFIX + "values);\n" + //
+ " return this;\n" + //
+ "}";
+ }
+
+ private static String privateLeafNodeSetter(LeafCNode n) {
+ if ("String".equals(builderType(n)) || "FileReference".equals(builderType(n))) {
+ return "";
+ } else {
+ return "\n\n" + //
+ "private Builder " + n.getName() + "(String " + INTERNAL_PREFIX + "value) {\n" + //
+ " return " + n.getName() + "(" + builderType(n) + ".valueOf(" + INTERNAL_PREFIX + "value));\n" + //
+ "}";
+ }
+ }
+
+ private static String leafArraySetters(LeafCNode n) {
+ return publicLeafNodeSetters(n) + privateLeafNodeSetter(n);
+ }
+
+ private static String innerMapSetters(CNode n) {
+ return "public Builder " + n.getName() + "(String " + INTERNAL_PREFIX + "key, " + builderType(n) + " " + INTERNAL_PREFIX
+ + "value) {\n" + //
+ " " + n.getName() + ".put(" + INTERNAL_PREFIX + "key, " + INTERNAL_PREFIX + "value);\n" + //
+ " return this;\n" + //
+ "}\n" + //
+ "\n" + //
+ "public Builder " + n.getName() + "(Map<String, " + builderType(n) + "> " + INTERNAL_PREFIX + "values) {\n" + //
+ " " + n.getName() + ".putAll(" + INTERNAL_PREFIX + "values);\n" + //
+ " return this;\n" + //
+ "}";
+ }
+
+ private static String privateLeafMapSetter(CNode n) {
+ if ("String".equals(builderType(n)) || "FileReference".equals(builderType(n))) {
+ return "";
+ } else {
+ return "\n\n" + //
+ "private Builder " + n.getName() + "(String " + INTERNAL_PREFIX + "key, String " + INTERNAL_PREFIX + "value) {\n" + //
+ " return " + n.getName() + "(" + INTERNAL_PREFIX + "key, " + builderType(n) + ".valueOf(" + INTERNAL_PREFIX
+ + "value));\n" + //
+ "}";
+ }
+ }
+
+ private static String leafMapSetters(CNode n) {
+ return innerMapSetters(n) + privateLeafMapSetter(n);
+ }
+
+ private static String scalarSetters(LeafCNode n) {
+ String name = n.getName();
+
+ String signalInitialized = (n.getDefaultValue() == null) ? " " + INTERNAL_PREFIX + "uninitialized.remove(\"" + name + "\");\n"
+ : "";
+
+ String bType = builderType(n);
+ String stringSetter = "String".equals(bType) || "FileReference".equals(bType) ? ""
+ : String.format("\nprivate Builder %s(String %svalue) {\n" + //
+ " return %s(%s.valueOf(%svalue));\n" + //
+ "}", name, INTERNAL_PREFIX, name, boxedDataType(n), INTERNAL_PREFIX);
+
+ String getNullGuard = bType.equals(boxedBuilderType(n)) ? String.format(
+ "\nif (%svalue == null) throw new IllegalArgumentException(\"Null value is not allowed.\");", INTERNAL_PREFIX) : "";
+
+ return String.format("public Builder %s(%s %svalue) {%s\n" + //
+ " %s = %svalue;\n" + //
+ "%s", name, bType, INTERNAL_PREFIX, getNullGuard, name, INTERNAL_PREFIX, signalInitialized) + //
+ " return this;" + "\n}\n" + stringSetter;
+ }
+ }
+
+ private static String setBuilderValueFromConfig(CNode child, CNode node) {
+ final String name = child.getName();
+ final boolean isArray = child.isArray;
+ final boolean isMap = child.isMap;
+
+ if (child instanceof FileLeaf && isArray) {
+ return name + "(" + userDataType(child) + ".toValues(config." + name + "()));";
+ } else if (child instanceof FileLeaf && isMap) {
+ return name + "(" + userDataType(child) + ".toValueMap(config." + name + "()));";
+ } else if (child instanceof FileLeaf) {
+ return name + "(config." + name + "().value());";
+ } else if (child instanceof PathLeaf && isArray) {
+ return name + "(" + nodeClass(child) + ".toFileReferences(config." + name + "));";
+ } else if (child instanceof PathLeaf && isMap) {
+ return name + "(" + nodeClass(child) + ".toFileReferenceMap(config." + name + "));";
+ } else if (child instanceof PathLeaf) {
+ return name + "(config." + name + ".getFileReference());";
+ } else if (child instanceof LeafCNode) {
+ return name + "(config." + name + "());";
+ } else if (child instanceof InnerCNode && isArray) {
+ return setInnerArrayBuildersFromConfig((InnerCNode) child, node);
+ } else if (child instanceof InnerCNode && isMap) {
+ return setInnerMapBuildersFromConfig((InnerCNode) child);
+ } else {
+ return name + "(new " + builderType(child) + "(config." + name + "()));";
+ }
+ }
+
+ private static String setInnerArrayBuildersFromConfig(InnerCNode innerArr, CNode node) {
+ final String elemName = createUniqueSymbol(node, innerArr.getName());
+
+ return "for (" + userDataType(innerArr) + " " + elemName + " : config." + innerArr.getName() + "()) {\n" + //
+ " " + innerArr.getName() + "(new " + builderType(innerArr) + "(" + elemName + "));\n" + //
+ "}";
+ }
+
+ private static String setInnerMapBuildersFromConfig(InnerCNode innerMap) {
+ final String entryName = INTERNAL_PREFIX + "entry";
+ return "for (Map.Entry<String, " + userDataType(innerMap) + "> " + entryName + " : config." + innerMap.getName()
+ + "().entrySet()) {\n" + //
+ " " + innerMap.getName() + "(" + entryName + ".getKey(), new " + userDataType(innerMap) + ".Builder(" + entryName
+ + ".getValue()));\n" + //
+ "}";
+ }
+
+ private static String getBuilderConstructors(CNode node, String className) {
+ return "public Builder() { }\n" + //
+ "\n" + //
+ "public Builder(" + className + " config) {\n" + //
+ indentCode(INDENTATION,
+ stream(node.getChildren()).map(child -> setBuilderValueFromConfig(child, node)).collect(Collectors.joining("\n")))
+ + //
+ "\n}";
+ }
+
+ private static String conditionStatement(CNode child) {
+ final String superior = INTERNAL_PREFIX + "superior";
+
+ if (child.isArray) {
+ return "if (!" + superior + "." + child.getName() + ".isEmpty())";
+ } else if (child.isMap) {
+ return "";
+ } else if (child instanceof LeafCNode) {
+ return "if (" + superior + "." + child.getName() + " != null)";
+ } else {
+ return "";
+ }
+ }
+
+ private static String overrideBuilderValue(CNode child) {
+ final String superior = INTERNAL_PREFIX + "superior";
+ final String method = "override";
+ final String name = child.getName();
+ final String callSetter = name + "(" + superior + "." + name + ");";
+
+ if (child.isArray) {
+ String arrayOverride = INDENTATION + name + ".addAll(" + superior + "." + name + ");";
+ return conditionStatement(child) + "\n" + arrayOverride;
+ } else if (child instanceof InnerCNode && !child.isArray && !child.isMap) {
+ return name + "(" + name + "." + method + "(" + superior + "." + name + "));";
+ } else if (child.isMap) {
+ return callSetter;
+ } else {
+ return conditionStatement(child) + "\n" + INDENTATION + callSetter;
+ }
+ }
+
+ private static String getOverrideMethod(CNode node) {
+ final String superior = INTERNAL_PREFIX + "superior";
+ final String method = "override";
+
+ return "private Builder " + method + "(Builder " + superior + ") {\n" + //
+ indentCode(INDENTATION,
+ stream(node.getChildren()).map(BuilderGenerator::overrideBuilderValue).collect(Collectors.joining("\n")))
+ + "\n" + //
+ " return this;\n" + //
+ "}";
+ }
+
+ private static String builderType(CNode node) {
+ if (node instanceof InnerCNode) {
+ return boxedDataType(node) + ".Builder";
+ } else if (node instanceof FileLeaf) {
+ return "String";
+ } else if (node instanceof PathLeaf) {
+ return "FileReference";
+ } else if (node instanceof LeafCNode && (node.isArray || node.isMap)) {
+ return boxedDataType(node);
+ } else {
+ return userDataType(node);
+ }
+ }
+
+ private static String boxedBuilderType(LeafCNode node) {
+ if (node instanceof FileLeaf) {
+ return "String";
+ } else if (node instanceof PathLeaf) {
+ return "FileReference";
+ } else {
+ return boxedDataType(node);
+ }
+ }
+}
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/ConfigGenerator.java b/configgen/src/main/java/com/yahoo/config/codegen/ConfigGenerator.java
new file mode 100644
index 00000000000..9980cf565b1
--- /dev/null
+++ b/configgen/src/main/java/com/yahoo/config/codegen/ConfigGenerator.java
@@ -0,0 +1,444 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.codegen;
+
+import com.yahoo.config.codegen.LeafCNode.BooleanLeaf;
+import com.yahoo.config.codegen.LeafCNode.DoubleLeaf;
+import com.yahoo.config.codegen.LeafCNode.EnumLeaf;
+import com.yahoo.config.codegen.LeafCNode.FileLeaf;
+import com.yahoo.config.codegen.LeafCNode.IntegerLeaf;
+import com.yahoo.config.codegen.LeafCNode.LongLeaf;
+import com.yahoo.config.codegen.LeafCNode.PathLeaf;
+import com.yahoo.config.codegen.LeafCNode.ReferenceLeaf;
+import com.yahoo.config.codegen.LeafCNode.StringLeaf;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.yahoo.config.codegen.BuilderGenerator.getBuilder;
+import static com.yahoo.config.codegen.JavaClassBuilder.INDENTATION;
+import static com.yahoo.config.codegen.ReservedWords.INTERNAL_PREFIX;
+import static java.util.Arrays.stream;
+
+/**
+ * @author gjoranv
+ * @author Tony Vaagenes
+ * @author ollivir
+ */
+public class ConfigGenerator {
+ // TODO: don't take indent as method param - the caller should indent
+ public static String generateContent(String indent, InnerCNode node, boolean isOuter) {
+ CNode[] children = node.getChildren();
+
+ return indentCode(indent,
+ getBuilder(node) + "\n\n" +
+ stream(children).map(ConfigGenerator::getFieldDefinition).collect(Collectors.joining("\n")) + "\n\n" +
+ getConstructors(node) + "\n\n" +
+ getAccessors(children) + "\n\n" +
+ getGetChangesRequiringRestart(node) + "\n\n" +
+ getContainsFieldsFlaggedWithRestart(node, isOuter) +
+ getStaticMethods(node) +
+ generateCodeForChildren(children, indent)
+ );
+ }
+
+ private static String generateCodeForChildren(CNode[] children, String indent) {
+ List<String> pieces = new LinkedList<>();
+ for (CNode child : children) {
+ if (child instanceof EnumLeaf) {
+ pieces.add(getEnumCode((EnumLeaf) child) + "\n");
+ } else if (child instanceof InnerCNode) {
+ pieces.add(getInnerDefinition((InnerCNode) child, indent) + "\n");
+ }
+ }
+ return String.join("\n", pieces);
+ }
+
+ private static String getInnerDefinition(InnerCNode inner, String indent) {
+ return (getClassDoc(inner) + "\n" +//
+ getClassDeclaration(inner) + "\n" +//
+ generateContent(indent, inner, false)).trim() + "\n}";
+ }
+
+ private static String getClassDeclaration(CNode node) {
+ return "public final static class " + nodeClass(node) + " extends InnerNode { \n";
+ }
+
+ private static String getFieldDefinition(CNode node) {
+ String fieldDef;
+ if (node instanceof LeafCNode && node.isArray) {
+ fieldDef = String.format("LeafNodeVector<%s, %s> %s;", boxedDataType(node), nodeClass(node), node.getName());
+ } else if (node instanceof InnerCNode && node.isArray) {
+ fieldDef = String.format("InnerNodeVector<%s> %s;", nodeClass(node), node.getName());
+ } else if (node.isMap) {
+ fieldDef = String.format("Map<String, %s> %s;", nodeClass(node), node.getName());
+ } else {
+ fieldDef = String.format("%s %s;", nodeClass(node), node.getName());
+ }
+ return node.getCommentBlock("//") + "private final " + fieldDef;
+ }
+
+ private static String getStaticMethods(InnerCNode node) {
+ if (node.isArray) {
+ return getStaticMethodsForInnerArray(node) + "\n\n";
+ } else if (node.isMap) {
+ return getStaticMethodsForInnerMap(node) + "\n\n";
+ } else {
+ return "";
+ }
+ }
+
+ private static String getContainsFieldsFlaggedWithRestart(CNode node, boolean isOuter) {
+ if (isOuter) {
+ return String.format("private static boolean containsFieldsFlaggedWithRestart() {\n" +//
+ " return %b;\n" +//
+ "}\n\n", node.needRestart());
+ } else {
+ return "";
+ }
+ }
+
+ private static String getGetChangesRequiringRestart(InnerCNode node) {
+ List<String> comparisons = new LinkedList<>();
+ for (CNode child : node.getChildren()) {
+ if (child.needRestart()) {
+ comparisons.add("\n " + getComparison(child));
+ }
+ }
+
+ return "private ChangesRequiringRestart getChangesRequiringRestart(" + nodeClass(node) + " newConfig) {\n" +//
+ " ChangesRequiringRestart changes = new ChangesRequiringRestart(\"" + node.getName() + "\");" + String.join("", comparisons) + "\n" +//
+ " return changes;\n" +//
+ "}";
+ }
+
+ private static String quotedComment(CNode node) {
+ return node.getComment().replace("\n", "\\n").replace("\"", "\\\"");
+ }
+
+ private static String getComparison(CNode node) {
+ if (node instanceof InnerCNode && node.isArray) {
+ return " changes.compareArray(this." + node.getName() + ", newConfig." + node.getName() + ", \"" + node.getName() + "\", \"" + quotedComment(node) + "\",\n" +//
+ " (a,b) -> ((" + nodeClass(node) + ")a).getChangesRequiringRestart((" + nodeClass(node) + ")b));";
+ } else if (node instanceof InnerCNode && node.isMap) {
+ return " changes.compareMap(this." + node.getName() + ", newConfig." + node.getName() + ", \"" + node.getName() + "\", \"" + quotedComment(node) + "\",\n" +//
+ " (a,b) -> ((" + nodeClass(node) + ")a).getChangesRequiringRestart((" + nodeClass(node) + ")b));";
+ } else if (node instanceof InnerCNode) {
+ return " changes.mergeChanges(\"" + node.getName() + "\", this." + node.getName() + ".getChangesRequiringRestart(newConfig." + node.getName() + "));";
+ } else if (node.isArray) {
+ return " changes.compareArray(this." + node.getName() + ", newConfig." + node.getName() + ", \"" + node.getName() + "\", \"" + quotedComment(node) + "\",\n" +//
+ " (a,b) -> new ChangesRequiringRestart(\"" + node.getName() + "\").compare(a,b,\"\",\"" + quotedComment(node) + "\"));";
+ } else if (node.isMap) {
+ return " changes.compareMap(this." + node.getName() + ", newConfig." + node.getName() + ", \"" + node.getName() + "\", \"" + quotedComment(node) + "\",\n" +//
+ " (a,b) -> new ChangesRequiringRestart(\"" + node.getName() + "\").compare(a,b,\"\",\"" + quotedComment(node) + "\"));";
+ } else {
+ return " changes.compare(this." + node.getName() + ", newConfig." + node.getName() + ", \"" + node.getName() + "\", \"" + quotedComment(node) + "\");";
+ }
+ }
+
+ private static String scalarDefault(LeafCNode scalar) {
+ if (scalar.getDefaultValue() == null) {
+ return "";
+ } else if (scalar instanceof EnumLeaf && scalar.getDefaultValue().getValue() == null) {
+ return "";
+ } else if (scalar instanceof EnumLeaf) {
+ return nodeClass(scalar) + "." + scalar.getDefaultValue().getStringRepresentation();
+ } else if (scalar instanceof LongLeaf) {
+ return scalar.getDefaultValue().getStringRepresentation() + "L";
+ } else if (scalar instanceof DoubleLeaf) {
+ return scalar.getDefaultValue().getStringRepresentation() + "D";
+ } else {
+ return scalar.getDefaultValue().getStringRepresentation();
+ }
+ }
+
+ private static String assignFromBuilder(CNode child) {
+ final String name = child.getName();
+ final String className = nodeClass(child);
+ final boolean isArray = child.isArray;
+ final boolean isMap = child.isMap;
+
+ if (child instanceof FileLeaf && isArray) {
+ return name + " = LeafNodeVector.createFileNodeVector(builder." + name + ");";
+ } else if (child instanceof PathLeaf && isArray) {
+ return name + " = LeafNodeVector.createPathNodeVector(builder." + name + ");";
+ } else if (child instanceof LeafCNode && isArray) {
+ return name + " = new LeafNodeVector<>(builder." + name + ", new " + className + "());";
+ } else if (child instanceof FileLeaf && isMap) {
+ return name + " = LeafNodeMaps.asFileNodeMap(builder." + name + ");";
+ } else if (child instanceof PathLeaf && isMap) {
+ return name + " = LeafNodeMaps.asPathNodeMap(builder." + name + ");";
+ } else if (child instanceof LeafCNode && isMap) {
+ return name + " = LeafNodeMaps.asNodeMap(builder." + name + ", new " + className + "());";
+ } else if (child instanceof InnerCNode && isArray) {
+ return name + " = " + className + ".createVector(builder." + name + ");";
+ } else if (child instanceof InnerCNode && isMap) {
+ return name + " = " + className + ".createMap(builder." + name + ");";
+ } else if (child instanceof InnerCNode) {
+ return name + " = new " + className + "(builder." + name + ", throwIfUninitialized);";
+ } else if (child instanceof LeafCNode) {
+ return name + " = (builder." + name + " == null) ?\n" +//
+ " new " + className + "(" + scalarDefault((LeafCNode) child) + ") : new " + className + "(builder." + name + ");";
+ } else {
+ throw new IllegalStateException("Cannot create assignment for node"); // should not happen
+ }
+ }
+
+ private static String getConstructors(InnerCNode inner) {
+ // TODO: merge these two constructors into one when the config library uses builders to set values from payload.
+ return "public " + nodeClass(inner) + "(Builder builder) {\n" +//
+ " this(builder, true);\n" +//
+ "}\n" +//
+ "\n" +//
+ "private " + nodeClass(inner) + "(Builder builder, boolean throwIfUninitialized) {\n" +//
+ " if (throwIfUninitialized && ! builder." + INTERNAL_PREFIX + "uninitialized.isEmpty())\n" +//
+ " throw new IllegalArgumentException(\"The following builder parameters for \" +\n" +//
+ " \"" + inner.getFullName() + " must be initialized: \" + builder." + INTERNAL_PREFIX + "uninitialized);\n" +//
+ "\n" +//
+ indentCode(INDENTATION, stream(inner.getChildren()).map(ConfigGenerator::assignFromBuilder).collect(Collectors.joining("\n"))) + "\n" +//
+ "}";
+ }
+
+ private static String getAccessorCode(CNode node) {
+ if (node.isArray) {
+ return accessorsForArray(node);
+ } else if (node.isMap) {
+ return accessorsForMap(node);
+ } else {
+ return accessorForStructOrScalar(node);
+ }
+ }
+
+ private static String valueAccessor(CNode node) {
+ if (node instanceof LeafCNode) {
+ return ".value()";
+ } else {
+ return "";
+ }
+ }
+
+ private static String listAccessor(CNode node) {
+ if (node instanceof LeafCNode) {
+ return node.getName() + ".asList()";
+ } else {
+ return node.getName();
+ }
+ }
+
+ private static String mapAccessor(CNode node) {
+ if (node instanceof LeafCNode) {
+ return "LeafNodeMaps.asValueMap(" + node.getName() + ")";
+ } else {
+ return "Collections.unmodifiableMap(" + node.getName() + ")";
+ }
+ }
+
+ private static String accessorsForArray(CNode node) {
+ final String name = node.getName();
+ final String fullName = node.getFullName();
+ return "/**\n" +//
+ " * @return " + fullName + "\n" +//
+ " */\n" +//
+ "public List<" + boxedDataType(node) + "> " + name + "() {\n" +//
+ " return " + listAccessor(node) + ";\n" +//
+ "}\n" +//
+ "\n" +//
+ "/**\n" +//
+ " * @param i the index of the value to return\n" +//
+ " * @return " + fullName + "\n" +//
+ " */\n" +//
+ "public " + userDataType(node) + " " + name + "(int i) {\n" +//
+ " return " + name + ".get(i)" + valueAccessor(node) + ";\n" +//
+ "}";
+ }
+
+ private static String accessorsForMap(CNode node) {
+ final String name = node.getName();
+ final String fullName = node.getFullName();
+
+ return "/**\n" +//
+ " * @return " + fullName + "\n" +//
+ " */\n" +//
+ "public Map<String, " + boxedDataType(node) + "> " + name + "() {\n" +//
+ " return " + mapAccessor(node) + ";\n" +//
+ "}\n" +//
+ "\n" +//
+ "/**\n" +//
+ " * @param key the key of the value to return\n" +//
+ " * @return " + fullName + "\n" +//
+ " */\n" +//
+ "public " + userDataType(node) + " " + name + "(String key) {\n" +//
+ " return " + name + ".get(key)" + valueAccessor(node) + ";\n" +//
+ "}";
+ }
+
+ private static String accessorForStructOrScalar(CNode node) {
+ return "/**\n" +//
+ " * @return " + node.getFullName() + "\n" +//
+ " */\n" +//
+ "public " + userDataType(node) + " " + node.getName() + "() {\n" +//
+ " return " + node.getName() + valueAccessor(node) + ";\n" +//
+ "}";
+ }
+
+ private static String getAccessors(CNode[] children) {
+ List<String> accessors = new LinkedList<>();
+ for (CNode child : children) {
+ String accessor = getAccessorCode(child);
+ if (accessor.isEmpty() == false) {
+ accessors.add(accessor);
+ }
+ }
+ return String.join("\n\n", accessors);
+ }
+
+ private static String getStaticMethodsForInnerArray(InnerCNode inner) {
+ final String nc = nodeClass(inner);
+ return String.format("private static InnerNodeVector<%s> createVector(List<Builder> builders) {\n" +//
+ " List<%s> elems = new ArrayList<>();\n" +//
+ " for (Builder b : builders) {\n" +//
+ " elems.add(new %s(b));\n" +//
+ " }\n" +//
+ " return new InnerNodeVector<%s>(elems);\n" +//
+ "}", nc, nc, nc, nc);
+ }
+
+ private static String getStaticMethodsForInnerMap(InnerCNode inner) {
+ final String nc = nodeClass(inner);
+ return String.format(
+ "private static Map<String, %s> createMap(Map<String, Builder> builders) {\n" +//
+ " Map<String, %s> ret = new LinkedHashMap<>();\n" +//
+ " for(String key : builders.keySet()) {\n" +//
+ " ret.put(key, new %s(builders.get(key)));\n" +//
+ " }\n" +//
+ " return Collections.unmodifiableMap(ret);\n" +//
+ "}", nc, nc, nc);
+ }
+
+ private static String getEnumCode(EnumLeaf en) {
+ String enumValues = stream(en.getLegalValues()).map(e -> String.format(" public final static Enum %s = Enum.%s;", e, e)).collect(Collectors.joining("\n"));
+
+ String code = String.format("%s\n" +//
+ "public final static class %s extends EnumNode<%s> {\n" +//
+ "\n" +//
+ " public %s(){\n" +//
+ " this.value = null;\n" +//
+ " }\n" +//
+ "\n" +//
+ " public %s(Enum enumValue) {\n" +//
+ " super(enumValue != null);\n" +//
+ " this.value = enumValue;\n" +//
+ " }\n" +//
+ "\n" +//
+ " public enum Enum {%s}\n" +//
+ "%s\n" +//
+ "\n" +//
+ " @Override\n" +//
+ " protected boolean doSetValue(@NonNull String name) {\n" +//
+ " try {\n" +//
+ " value = Enum.valueOf(name);\n" +//
+ " return true;\n" +//
+ " } catch (IllegalArgumentException e) {\n" +//
+ " }\n" +//
+ " return false;\n" +//
+ " }\n" +//
+ "}", getClassDoc(en),
+ nodeClass(en),
+ nodeClass(en) + ".Enum",
+ nodeClass(en),
+ nodeClass(en),
+ String.join(", ", en.getLegalValues()),
+ enumValues);
+
+ return indentCode("", code);
+ }
+
+ private static String getClassDoc(CNode node) {
+ String header = "/**\n" + " * This class represents " + node.getFullName();
+ String nodeComment = node.getCommentBlock(" *");
+ if (nodeComment.isEmpty()) {
+ return header + "\n */";
+ } else {
+ if (nodeComment.endsWith("\n")) {
+ nodeComment = nodeComment.substring(0, nodeComment.length() - 1);
+ }
+ return header + "\n * \n" + nodeComment + "\n */";
+ }
+ }
+
+ static String indentCode(String indent, String code) {
+ List<String> indented = new LinkedList<>();
+ for (String line : code.split("\n", -1)) {
+ indented.add(line.length() > 0 ? indent + line : line);
+ }
+ return String.join("\n", indented);
+ }
+
+ /**
+ * @return the name of the class that is generated by this node.
+ */
+ static String nodeClass(CNode node) {
+ if (node.getName().length() == 0) {
+ throw new CodegenRuntimeException("Node with empty name, under parent " + node.getParent().getName());
+ } else if (node instanceof InnerCNode && node.getParent() == null) {
+ return ConfiggenUtil.createClassName(node.getName());
+ } else if (node instanceof BooleanLeaf) {
+ return "BooleanNode";
+ } else if (node instanceof DoubleLeaf) {
+ return "DoubleNode";
+ } else if (node instanceof FileLeaf) {
+ return "FileNode";
+ } else if (node instanceof PathLeaf) {
+ return "PathNode";
+ } else if (node instanceof IntegerLeaf) {
+ return "IntegerNode";
+ } else if (node instanceof LongLeaf) {
+ return "LongNode";
+ } else if (node instanceof ReferenceLeaf) {
+ return "ReferenceNode";
+ } else if (node instanceof StringLeaf) {
+ return "StringNode";
+ } else {
+ return ConfiggenUtil.capitalize(node.getName());
+ }
+ }
+
+ static String userDataType(CNode node) {
+ if (node instanceof InnerCNode) {
+ return nodeClass(node);
+ } else if (node instanceof EnumLeaf) {
+ return nodeClass(node) + ".Enum";
+ } else if (node instanceof BooleanLeaf) {
+ return "boolean";
+ } else if (node instanceof DoubleLeaf) {
+ return "double";
+ } else if (node instanceof FileLeaf) {
+ return "FileReference";
+ } else if (node instanceof PathLeaf) {
+ return "Path";
+ } else if (node instanceof IntegerLeaf) {
+ return "int";
+ } else if (node instanceof LongLeaf) {
+ return "long";
+ } else if (node instanceof StringLeaf) {
+ return "String";
+ } else {
+ throw new IllegalStateException("Cannot determine user data type for node"); // should not occur
+ }
+ }
+
+ /**
+ * @return the boxed java data type, e.g. Integer for int
+ */
+ static String boxedDataType(CNode node) {
+ String rawType = userDataType(node);
+
+ if ("int".equals(rawType)) {
+ return "Integer";
+ } else if (rawType.toLowerCase().equals(rawType)) {
+ return ConfiggenUtil.capitalize(rawType);
+ } else {
+ return rawType;
+ }
+ }
+}
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/ConfiggenUtil.java b/configgen/src/main/java/com/yahoo/config/codegen/ConfiggenUtil.java
index 299a5540098..995ef419f30 100644
--- a/configgen/src/main/java/com/yahoo/config/codegen/ConfiggenUtil.java
+++ b/configgen/src/main/java/com/yahoo/config/codegen/ConfiggenUtil.java
@@ -26,7 +26,7 @@ public class ConfiggenUtil {
return className;
}
- private static String capitalize(String in) {
+ static String capitalize(String in) {
StringBuilder sb = new StringBuilder(in);
sb.setCharAt(0, Character.toTitleCase(in.charAt(0)));
return sb.toString();
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/JavaClassBuilder.java b/configgen/src/main/java/com/yahoo/config/codegen/JavaClassBuilder.java
new file mode 100644
index 00000000000..00498094db5
--- /dev/null
+++ b/configgen/src/main/java/com/yahoo/config/codegen/JavaClassBuilder.java
@@ -0,0 +1,170 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.codegen;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.Random;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.yahoo.config.codegen.ConfigGenerator.indentCode;
+import static com.yahoo.config.codegen.ConfiggenUtil.createClassName;
+import static com.yahoo.config.codegen.DefParser.DEFAULT_PACKAGE_PREFIX;
+
+/**
+ * Builds one Java class based on the given CNode tree.
+ *
+ * @author gjoranv
+ * @author Tony Vaagenes
+ * @author ollivir
+ */
+public class JavaClassBuilder implements ClassBuilder {
+ public static final String INDENTATION = " ";
+
+ private final InnerCNode root;
+ private final NormalizedDefinition nd;
+ private final String packagePrefix;
+ private final String javaPackage;
+ private final String className;
+ private final File destDir;
+
+ public JavaClassBuilder(InnerCNode root, NormalizedDefinition nd, File destDir, String rawPackagePrefix) {
+ this.root = root;
+ this.nd = nd;
+ this.packagePrefix = (rawPackagePrefix != null) ? rawPackagePrefix : DEFAULT_PACKAGE_PREFIX;
+ this.javaPackage = (root.getPackage() != null) ? root.getPackage() : packagePrefix + root.getNamespace();
+ this.className = createClassName(root.getName());
+ this.destDir = destDir;
+ }
+
+ @Override
+ public void createConfigClasses() {
+ try {
+ File outFile = new File(getDestPath(destDir, javaPackage), className + ".java");
+ try (PrintStream out = new PrintStream(new FileOutputStream(outFile))) {
+ out.print(getConfigClass(className));
+ }
+ System.err.println(outFile.getPath() + " successfully written.");
+ } catch (FileNotFoundException e) {
+ throw new CodegenRuntimeException(e);
+ }
+ }
+
+ public String getConfigClass(String className) {
+ return getHeader() + "\n\n" + //
+ getRootClassDeclaration(root, className) + "\n\n" + //
+ indentCode(INDENTATION, getFrameworkCode()) + "\n\n" + //
+ ConfigGenerator.generateContent(INDENTATION, root, true) + "\n" + //
+ "}\n";
+ }
+
+ private String getHeader() {
+ return "/**\n" + //
+ " * This file is generated from a config definition file.\n" + //
+ " * ------------ D O N O T E D I T ! ------------\n" + //
+ " */\n" + //
+ "\n" + //
+ "package " + javaPackage + ";\n" + //
+ "\n" + //
+ "import java.util.*;\n" + //
+ "import java.nio.file.Path;\n" + //
+ "import edu.umd.cs.findbugs.annotations.NonNull;\n" + //
+ getImportFrameworkClasses(root.getNamespace());
+ }
+
+ private String getImportFrameworkClasses(String namespace) {
+ if (CNode.DEFAULT_NAMESPACE.equals(namespace) == false) {
+ return "import " + packagePrefix + CNode.DEFAULT_NAMESPACE + ".*;";
+ } else {
+ return "";
+ }
+ }
+
+ // TODO: remove the extra comment line " *" if root.getCommentBlock is empty
+ private String getRootClassDeclaration(InnerCNode root, String className) {
+ return "/**\n" + //
+ " * This class represents the root node of " + root.getFullName() + "\n" + //
+ " *\n" + //
+ "" + root.getCommentBlock(" *") + " */\n" + //
+ "public final class " + className + " extends ConfigInstance {\n" + //
+ "\n" + //
+ " public final static String CONFIG_DEF_MD5 = \"" + root.getMd5() + "\";\n" + //
+ " public final static String CONFIG_DEF_NAME = \"" + root.getName() + "\";\n" + //
+ " public final static String CONFIG_DEF_NAMESPACE = \"" + root.getNamespace() + "\";\n" + //
+ " public final static String CONFIG_DEF_VERSION = \"" + root.getVersion() + "\";\n" + //
+ " public final static String[] CONFIG_DEF_SCHEMA = {\n" + //
+ "" + indentCode(INDENTATION + INDENTATION, getDefSchema()) + "\n" + //
+ " };\n" + //
+ "\n" + //
+ " public static String getDefMd5() { return CONFIG_DEF_MD5; }\n" + //
+ " public static String getDefName() { return CONFIG_DEF_NAME; }\n" + //
+ " public static String getDefNamespace() { return CONFIG_DEF_NAMESPACE; }\n" + //
+ " public static String getDefVersion() { return CONFIG_DEF_VERSION; }";
+ }
+
+ private String getDefSchema() {
+ return nd.getNormalizedContent().stream().map(l -> "\"" + l.replace("\"", "\\\"") + "\"").collect(Collectors.joining(",\n"));
+ }
+
+ private String getFrameworkCode() {
+ return "public interface Producer extends ConfigInstance.Producer {\n" + //
+ " void getConfig(Builder builder);\n" + //
+ "}";
+ }
+
+ /**
+ * @param rootDir
+ * The root directory for the destination path.
+ * @param javaPackage
+ * The java package
+ * @return the destination path for the generated config file, including the
+ * given rootDir.
+ */
+ private File getDestPath(File rootDir, String javaPackage) {
+ File dir = rootDir;
+ for (String subDir : javaPackage.split("\\.")) {
+ dir = new File(dir, subDir);
+ synchronized (this) {
+ if (!dir.isDirectory() && !dir.mkdir()) {
+ throw new CodegenRuntimeException("Could not create " + dir.getPath());
+ }
+ }
+ }
+ return dir;
+ }
+
+ /**
+ * Returns a name that can be safely used as a local variable in the generated
+ * config class for the given node. The name will be based on the given basis
+ * string, but the basis itself is not a possible return value.
+ *
+ * @param node
+ * The node to find a unused symbol name for.
+ * @param basis
+ * The basis for the generated symbol name.
+ * @return A name that is not used in the given config node.
+ */
+ static String createUniqueSymbol(CNode node, String basis) {
+ Set<String> usedSymbols = Arrays.stream(node.getChildren()).map(CNode::getName).collect(Collectors.toSet());
+ Random rng = new Random();
+
+ for (int i = 1;; i++) {
+ String candidate = (i < basis.length()) ? basis.substring(0, i)
+ : ReservedWords.INTERNAL_PREFIX + basis + rng.nextInt(Integer.MAX_VALUE);
+ if (usedSymbols.contains(candidate) == false) {
+ return candidate;
+ }
+ }
+ }
+
+ public String className() {
+ return className;
+ }
+
+ public String javaPackage() {
+ return javaPackage;
+ }
+}
diff --git a/configgen/src/main/scala/com/yahoo/config/codegen/BuilderGenerator.scala b/configgen/src/main/scala/com/yahoo/config/codegen/BuilderGenerator.scala
deleted file mode 100644
index 4f6f310e32e..00000000000
--- a/configgen/src/main/scala/com/yahoo/config/codegen/BuilderGenerator.scala
+++ /dev/null
@@ -1,350 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.config.codegen
-
-import com.yahoo.config.codegen.ReservedWords.{INTERNAL_PREFIX => InternalPrefix}
-import JavaClassBuilder.{Indentation, createUniqueSymbol}
-import ConfigGenerator.{indentCode, nodeClass, userDataType, boxedDataType}
-import com.yahoo.config.codegen.LeafCNode._
-
-/**
- * @author gjoranv
- */
-
-object BuilderGenerator {
-
- def getBuilder(node: InnerCNode): String = {
- getDeclaration(node) + "\n" +
- indentCode(Indentation,
- getUninitializedScalars(node) + "\n\n" +
- node.getChildren.map(getBuilderFieldDefinition).mkString("\n") + "\n\n" +
- getBuilderConstructors(node, nodeClass(node)) + "\n\n" +
- getOverrideMethod(node) + "\n\n" +
- getBuilderSetters(node) + "\n" +
- getSpecialRootBuilderCode(node)
- ) +
- "}"
- }
-
- private def getDeclaration(node: InnerCNode) = {
- def getInterfaces =
- if (node.getParent == null) "implements ConfigInstance.Builder"
- else "implements ConfigBuilder"
-
- "public static class Builder " + getInterfaces + " {"
- }
-
- private def getSpecialRootBuilderCode(node: InnerCNode) = {
- if (node.getParent == null) "\n" + getDispatchCode(node) + "\n"
- else ""
- }
-
- private def getDispatchCode(node: InnerCNode) = {
- // Use full path to @Override, as users are free to define an inner node called 'override'. (summarymap.def does)
- // The generated inner 'Override' class would otherwise be mistaken for the annotation.
- """
- |@java.lang.Override
- |public final boolean dispatchGetConfig(ConfigInstance.Producer producer) {
- | if (producer instanceof Producer) {
- | ((Producer)producer).getConfig(this);
- | return true;
- | }
- | return false;
- |}
- |
- |@java.lang.Override
- |public final String getDefMd5() { return CONFIG_DEF_MD5; }
- |@java.lang.Override
- |public final String getDefName() { return CONFIG_DEF_NAME; }
- |@java.lang.Override
- |public final String getDefNamespace() { return CONFIG_DEF_NAMESPACE; }
- """.stripMargin.trim
- }
-
- private def getUninitializedScalars(node: InnerCNode): String = {
- val scalarsWithoutDefault = {
- node.getChildren.collect {
- case leaf: LeafCNode if (!leaf.isArray && !leaf.isMap && leaf.getDefaultValue == null) =>
- "\"" + leaf.getName + "\""
- }
- }
-
- val uninitializedList =
- if (scalarsWithoutDefault.size > 0)
- "Arrays.asList(\n" + indentCode(Indentation, scalarsWithoutDefault.mkString("",",\n","\n)"))
- else
- ""
-
- "private Set<String> " + InternalPrefix + "uninitialized = new HashSet<String>(" + uninitializedList + ");"
- }
-
- private def getBuilderFieldDefinition(node: CNode): String = {
-
- (node match {
- case array if node.isArray =>
- "public List<%s> %s = new ArrayList<>()".format(builderType(array), array.getName)
- case map if node.isMap =>
- "public Map<String, %s> %s = new LinkedHashMap<>()".format(builderType(map), map.getName)
- case struct: InnerCNode =>
- "public %s %s = new %s()".format(builderType(struct), struct.getName, builderType(struct))
- case scalar : LeafCNode =>
- "private " + boxedBuilderType(scalar) + " " + scalar.getName + " = null"
- }) + ";"
- }
-
- private def getBuilderSetters(node: CNode): String = {
- val children: Array[CNode] = node.getChildren
-
- def structSetter(node: InnerCNode) = {
- <code>
- |public Builder {node.getName}({builderType(node)} {InternalPrefix}builder) {{
- | {node.getName} = {InternalPrefix}builder;
- | return this;
- |}}
- </code>.text.stripMargin.trim
- }
-
- def innerArraySetters(node: InnerCNode) = {
- <code>
- |/**
- | * Add the given builder to this builder's list of {nodeClass(node)} builders
- | * @param {InternalPrefix}builder a builder
- | * @return this builder
- | */
- |public Builder {node.getName}({builderType(node)} {InternalPrefix}builder) {{
- | {node.getName}.add({InternalPrefix}builder);
- | return this;
- |}}
- |
- |/**
- | * Set the given list as this builder's list of {nodeClass(node)} builders
- | * @param __builders a list of builders
- | * @return this builder
- | */
- |public Builder {node.getName}(List&lt;{builderType(node)}&gt; __builders) {{
- | {node.getName} = __builders;
- | return this;
- |}}
- </code>.text.stripMargin.trim
- }
-
- def leafArraySetters(node: LeafCNode) = {
- val setters =
- <code>
- |public Builder {node.getName}({builderType(node)} {InternalPrefix}value) {{
- | {node.getName}.add({InternalPrefix}value);
- | return this;
- |}}
- |
- |public Builder {node.getName}(Collection&lt;{builderType(node)}&gt; {InternalPrefix}values) {{
- | {node.getName}.addAll({InternalPrefix}values);
- | return this;
- |}}
- </code>.text.stripMargin.trim
-
- val privateSetter =
- if (builderType(node) == "String" || builderType(node) == "FileReference")
- ""
- else
- "\n\n" +
- <code>
- |
- |
- |private Builder {node.getName}(String {InternalPrefix}value) {{
- | return {node.getName}({builderType(node)}.valueOf({InternalPrefix}value));
- |}}
- </code>.text.stripMargin.trim
-
- setters + privateSetter
- }
-
- def innerMapSetters(node: CNode) = {
- <code>
- |public Builder {node.getName}(String {InternalPrefix}key, {builderType(node)} {InternalPrefix}value) {{
- | {node.getName}.put({InternalPrefix}key, {InternalPrefix}value);
- | return this;
- |}}
- |
- |public Builder {node.getName}(Map&lt;String, {builderType(node)}&gt; {InternalPrefix}values) {{
- | {node.getName}.putAll({InternalPrefix}values);
- | return this;
- |}}
- </code>.text.stripMargin.trim
- }
-
- def leafMapSetters(node: LeafCNode) = {
- val privateSetter =
- if (builderType(node) == "String" || builderType(node) == "FileReference")
- ""
- else
- "\n\n" +
- <code>
- |
- |
- |private Builder {node.getName}(String {InternalPrefix}key, String {InternalPrefix}value) {{
- | return {node.getName}({InternalPrefix}key, {builderType(node)}.valueOf({InternalPrefix}value));
- |}}
- </code>.text.stripMargin.trim
-
- innerMapSetters(node) + privateSetter
- }
-
- def scalarSetters(node: LeafCNode): String = {
- val name = node.getName
-
- val signalInitialized =
- if (node.getDefaultValue == null) InternalPrefix + "uninitialized.remove(\"" + name + "\");\n"
- else ""
-
- val stringSetter =
- builderType(node) match {
- case "String" => ""
- case "FileReference" => ""
- case _ =>
- """|
- |private Builder %s(String %svalue) {
- | return %s(%s.valueOf(%svalue));
- |}""".stripMargin.format(name, InternalPrefix,
- name, boxedDataType(node), InternalPrefix)
- }
-
- def getNullGuard = {
- if (builderType(node) != boxedBuilderType(node))
- ""
- else
- "\n" + "if (%svalue == null) throw new IllegalArgumentException(\"Null value is not allowed.\");"
- .format(InternalPrefix)
- }
-
- // TODO: check if 2.9.2 allows string to start with a newline
- """|public Builder %s(%s %svalue) {%s
- | %s = %svalue;
- | %s
- """.stripMargin.format(name, builderType(node), InternalPrefix, getNullGuard,
- name, InternalPrefix,
- signalInitialized).trim +
- "\n return this;" + "\n}\n" +
- stringSetter
- }
-
- (children collect {
- case innerArray: InnerCNode if innerArray.isArray => innerArraySetters(innerArray)
- case innerMap: InnerCNode if innerMap.isMap => innerMapSetters(innerMap)
- case leafArray: LeafCNode if leafArray.isArray => leafArraySetters(leafArray)
- case leafMap: LeafCNode if leafMap.isMap => leafMapSetters(leafMap)
- case struct: InnerCNode => structSetter(struct)
- case scalar: LeafCNode => scalarSetters(scalar)
- } ).mkString("\n\n")
- }
-
- private def getBuilderConstructors(node: CNode, className: String): String = {
- def setBuilderValueFromConfig(child: CNode) = {
- val name = child.getName
- val isArray = child.isArray
- val isMap = child.isMap
-
- child match {
- case fileArray: FileLeaf if isArray => name + "(" + userDataType(fileArray) + ".toValues(config." + name + "()));"
- case fileMap: FileLeaf if isMap => name + "(" + userDataType(fileMap) + ".toValueMap(config." + name + "()));"
- case file: FileLeaf => name + "(config." + name + "().value());"
- case pathArray: PathLeaf if isArray => name + "(" + nodeClass(pathArray) + ".toFileReferences(config." + name + "));"
- case pathMap: PathLeaf if isMap => name + "(" + nodeClass(pathMap) + ".toFileReferenceMap(config." + name + "));"
- case path: PathLeaf => name + "(config." + name + ".getFileReference());"
- case leaf: LeafCNode => name + "(config." + name + "());"
- case innerArray: InnerCNode if isArray => setInnerArrayBuildersFromConfig(innerArray)
- case innerMap: InnerCNode if isMap => setInnerMapBuildersFromConfig(innerMap)
- case struct => name + "(new " + builderType(struct) + "(config." + name + "()));"
- }
- }
-
- def setInnerArrayBuildersFromConfig(innerArr: InnerCNode) = {
- val elemName = createUniqueSymbol(node, innerArr.getName)
- <code>
- |for ({userDataType(innerArr)} {elemName} : config.{innerArr.getName}()) {{
- | {innerArr.getName}(new {builderType(innerArr)}({elemName}));
- |}}
- </code>.text.stripMargin.trim
- }
-
- def setInnerMapBuildersFromConfig(innerMap: InnerCNode) = {
- val entryName = InternalPrefix + "entry"
- <code>
- |for (Map.Entry&lt;String, {userDataType(innerMap)}&gt; {entryName} : config.{innerMap.getName}().entrySet()) {{
- | {innerMap.getName}({entryName}.getKey(), new {userDataType(innerMap)}.Builder({entryName}.getValue()));
- |}}
- </code>.text.stripMargin.trim
- }
-
- <code>
- |public Builder() {{ }}
- |
- |public Builder({className} config) {{
- |{indentCode(Indentation, node.getChildren.map(setBuilderValueFromConfig).mkString("\n"))}
- |}}
- </code>.text.stripMargin.trim
- }
-
- def arrayOverride(name: String, superior: String): String = {
- Indentation + name + ".addAll(" + superior + "." + name + ");"
- }
-
- private def getOverrideMethod(node:CNode): String = {
- val method = "override"
- val superior = InternalPrefix + "superior"
-
- def callSetter(name: String): String = {
- name + "(" + superior + "." + name + ");"
- }
- def overrideBuilderValue(child: CNode) = {
- val name = child.getName
- child match {
- case leafArray: CNode if (child.isArray) =>
- conditionStatement(child) + "\n" + arrayOverride(name, superior)
- case struct: InnerCNode if !(child.isArray || child.isMap) =>
- name + "(" + name + "." + method + "(" + superior + "." + name + "));"
- case map: CNode if child.isMap =>
- callSetter(name)
- case _ =>
- conditionStatement(child) + "\n" +
- Indentation + callSetter(name)
- }
- }
-
- def conditionStatement(child: CNode) = {
- val name = child.getName
- val isArray = child.isArray
- val isMap = child.isMap
- child match {
- case _ if isArray => "if (!" + superior + "." + name + ".isEmpty())"
- case _ if isMap => ""
- case scalar: LeafCNode => "if (" + superior + "." + name + " != null)"
- case struct => ""
- }
- }
-
- <code>
- |private Builder {method}(Builder {superior}) {{
- |{indentCode(Indentation, node.getChildren.map(overrideBuilderValue).mkString("\n"))}
- | return this;
- |}}
- </code>.text.stripMargin.trim
- }
-
- private def builderType(node: CNode): String = {
- node match {
- case inner: InnerCNode => boxedDataType(node) + ".Builder"
- case file: FileLeaf => "String"
- case path: PathLeaf => "FileReference"
- case leafArray: LeafCNode if (node.isArray || node.isMap) => boxedDataType(node)
- case _ => userDataType(node)
- }
- }
-
- private def boxedBuilderType(node: LeafCNode): String = {
- node match {
- case file: FileLeaf => "String"
- case path: PathLeaf => "FileReference"
- case _ => boxedDataType(node)
- }
- }
-
-}
diff --git a/configgen/src/main/scala/com/yahoo/config/codegen/ConfigGenerator.scala b/configgen/src/main/scala/com/yahoo/config/codegen/ConfigGenerator.scala
deleted file mode 100644
index 38306a03575..00000000000
--- a/configgen/src/main/scala/com/yahoo/config/codegen/ConfigGenerator.scala
+++ /dev/null
@@ -1,423 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.config.codegen
-
-
-import com.yahoo.config.codegen.BuilderGenerator.getBuilder
-import com.yahoo.config.codegen.JavaClassBuilder.Indentation
-import com.yahoo.config.codegen.LeafCNode._
-import com.yahoo.config.codegen.ReservedWords.{INTERNAL_PREFIX => InternalPrefix}
-
-/**
- * @author gjoranv
- * @author tonytv
- */
-// TODO: don't take indent as method param - the caller should indent
-object ConfigGenerator {
-
- def generateContent(indent: String, node: InnerCNode, isOuter: Boolean = true): String = {
- val children: Array[CNode] = node.getChildren
-
- def generateCodeForChildren: String = {
- (children collect {
- case enum: EnumLeaf => getEnumCode(enum, "") + "\n"
- case inner: InnerCNode => getInnerDefinition(inner, indent) + "\n"
- } ).mkString("\n")
- }
-
- def getInnerDefinition(inner: InnerCNode, indent: String) = {
- <code>
- |{getClassDoc(inner, indent)}
- |{getClassDeclaration(inner)}
- |{generateContent(indent, inner, false)}
- </code>.text.stripMargin.trim + "\n}"
- }
-
- def getClassDeclaration(node: CNode): String = {
- "public final static class " + nodeClass(node)+ " extends InnerNode { " + "\n"
- }
-
- def getFieldDefinition(node: CNode): String = {
- node.getCommentBlock("//") + "private final " +
- (node match {
- case _: LeafCNode if node.isArray =>
- "LeafNodeVector<%s, %s> %s;".format(boxedDataType(node), nodeClass(node), node.getName)
- case _: InnerCNode if node.isArray =>
- "InnerNodeVector<%s> %s;".format(nodeClass(node), node.getName)
- case _ if node.isMap =>
- "Map<String, %s> %s;".format(nodeClass(node), node.getName)
- case _ =>
- "%s %s;".format(nodeClass(node), node.getName)
- })
- }
-
- def getStaticMethods = {
- if (node.isArray) getStaticMethodsForInnerArray(node) + "\n\n"
- else if (node.isMap) getStaticMethodsForInnerMap(node) + "\n\n"
- else ""
- }
-
- def getContainsFieldsFlaggedWithRestart(node: CNode): String = {
- if (isOuter) {
- """
- |private static boolean containsFieldsFlaggedWithRestart() {
- | return %b;
- |}
- """.stripMargin.trim.format(node.needRestart) + "\n\n"
- } else ""
- }
-
- indentCode(indent,
- getBuilder(node) + "\n\n" +
- children.map(getFieldDefinition).mkString("\n") + "\n\n" +
- getConstructors(node) + "\n\n" +
- getAccessors(children) + "\n\n" +
- getGetChangesRequiringRestart(node) + "\n\n" +
- getContainsFieldsFlaggedWithRestart(node) +
- getStaticMethods +
- generateCodeForChildren
- )
- }
-
- private def getGetChangesRequiringRestart(node: InnerCNode): String = {
- def quotedComment(node: CNode): String = {
- node.getComment.replace("\n", "\\n").replace("\"", "\\\"")
- }
-
- def getComparison(node: CNode): String = node match {
- case inner: InnerCNode if inner.isArray =>
- <code>
- | changes.compareArray(this.{inner.getName}, newConfig.{inner.getName}, "{inner.getName}", "{quotedComment(inner)}",
- | (a,b) -> (({nodeClass(inner)})a).getChangesRequiringRestart(({nodeClass(inner)})b));
- </code>.text.stripMargin.trim
- case inner: InnerCNode if inner.isMap =>
- <code>
- | changes.compareMap(this.{inner.getName}, newConfig.{inner.getName}, "{inner.getName}", "{quotedComment(inner)}",
- | (a,b) -> (({nodeClass(inner)})a).getChangesRequiringRestart(({nodeClass(inner)})b));
- </code>.text.stripMargin.trim
- case inner: InnerCNode =>
- <code>
- | changes.mergeChanges("{inner.getName}", this.{inner.getName}.getChangesRequiringRestart(newConfig.{inner.getName}));
- </code>.text.stripMargin.trim
- case node: CNode if node.isArray =>
- <code>
- | changes.compareArray(this.{node.getName}, newConfig.{node.getName}, "{node.getName}", "{quotedComment(node)}",
- | (a,b) -> new ChangesRequiringRestart("{node.getName}").compare(a,b,"","{quotedComment(node)}"));
- </code>.text.stripMargin.trim
- case node: CNode if node.isMap =>
- <code>
- | changes.compareMap(this.{node.getName}, newConfig.{node.getName}, "{node.getName}", "{quotedComment(node)}",
- | (a,b) -> new ChangesRequiringRestart("{node.getName}").compare(a,b,"","{quotedComment(node)}"));
- </code>.text.stripMargin.trim
- case node: CNode =>
- <code>
- | changes.compare(this.{node.getName}, newConfig.{node.getName}, "{node.getName}", "{quotedComment(node)}");
- </code>.text.stripMargin.trim
- }
-
- val comparisons =
- for {
- c <- node.getChildren if c.needRestart
- } yield "\n " + getComparison(c)
-
- <code>
- |private ChangesRequiringRestart getChangesRequiringRestart({nodeClass(node)} newConfig) {{
- | ChangesRequiringRestart changes = new ChangesRequiringRestart("{node.getName}");{comparisons.mkString("")}
- | return changes;
- |}}
- </code>.text.stripMargin.trim
- }
-
-
- private def scalarDefault(scalar: LeafCNode): String = {
- scalar match {
- case _ if scalar.getDefaultValue == null => ""
- case enumWithNullDefault: EnumLeaf if enumWithNullDefault.getDefaultValue.getValue == null => ""
- case enum: EnumLeaf => nodeClass(enum) + "." + enum.getDefaultValue.getStringRepresentation
- case long: LongLeaf => long.getDefaultValue.getStringRepresentation + "L"
- case double: DoubleLeaf => double.getDefaultValue.getStringRepresentation + "D"
- case _ => scalar.getDefaultValue.getStringRepresentation
- }
- }
-
- private def getConstructors(inner: InnerCNode) = {
-
- def assignFromBuilder(child: CNode) = {
- val name = child.getName
- val className = nodeClass(child)
- val dataType = boxedDataType(child)
- val isArray = child.isArray
- val isMap = child.isMap
-
- def assignIfInitialized(leaf: LeafCNode) = {
- <code>
- |{name} = (builder.{name} == null) ?
- | new {className}({scalarDefault(leaf)}) : new {className}(builder.{name});
- </code>.text.stripMargin.trim
- }
-
- child match {
- case fileArray: FileLeaf if isArray =>
- name + " = LeafNodeVector.createFileNodeVector(builder."+ name +");"
- case pathArray: PathLeaf if isArray =>
- name + " = LeafNodeVector.createPathNodeVector(builder."+ name +");"
- case leafArray: LeafCNode if isArray =>
- name + " = new LeafNodeVector<>(builder."+ name +", new " + className + "());"
- case fileMap: LeafCNode if isMap && child.isInstanceOf[FileLeaf] =>
- name + " = LeafNodeMaps.asFileNodeMap(builder."+ name +");"
- case pathMap: LeafCNode if isMap && child.isInstanceOf[PathLeaf] =>
- name + " = LeafNodeMaps.asPathNodeMap(builder."+ name +");"
- case leafMap: LeafCNode if isMap =>
- name + " = LeafNodeMaps.asNodeMap(builder."+ name +", new " + className + "());"
- case innerArray: InnerCNode if isArray =>
- name + " = " + className + ".createVector(builder." + name + ");"
- case innerMap: InnerCNode if isMap =>
- name + " = " + className + ".createMap(builder." + name + ");"
- case struct: InnerCNode =>
- name + " = new " + className + "(builder." + name + ", throwIfUninitialized);"
- case leaf: LeafCNode =>
- assignIfInitialized(leaf)
- }
- }
-
- // TODO: merge these two constructors into one when the config library uses builders to set values from payload.
- <code>
- |public {nodeClass(inner)}(Builder builder) {{
- | this(builder, true);
- |}}
- |
- |private {nodeClass(inner)}(Builder builder, boolean throwIfUninitialized) {{
- | if (throwIfUninitialized &amp;&amp; ! builder.{InternalPrefix}uninitialized.isEmpty())
- | throw new IllegalArgumentException("The following builder parameters for " +
- | "{inner.getFullName} must be initialized: " + builder.{InternalPrefix}uninitialized);
- |
- |{indentCode(Indentation, inner.getChildren.map(assignFromBuilder).mkString("\n"))}
- |}}
- </code>.text.stripMargin.trim
- }
-
- private def getAccessors(children: Array[CNode]): String = {
-
- def getAccessorCode(indent: String, node: CNode): String = {
- indentCode(indent,
- if (node.isArray)
- accessorsForArray(node)
- else if (node.isMap)
- accessorsForMap(node)
- else
- accessorForStructOrScalar(node))
- }
-
- def valueAccessor(node: CNode) = node match {
- case leaf: LeafCNode => ".value()"
- case inner => ""
- }
-
- def listAccessor(node: CNode) = node match {
- case leaf: LeafCNode => "%s.asList()".format(leaf.getName)
- case inner => inner.getName
- }
-
- def mapAccessor(node: CNode) = node match {
- case leaf: LeafCNode => "LeafNodeMaps.asValueMap(%s)".format(leaf.getName)
- case inner => "Collections.unmodifiableMap(%s)".format(inner.getName)
- }
-
- def accessorsForArray(node: CNode): String = {
- val name = node.getName
- val fullName = node.getFullName
- <code>
- |/**
- | * @return {fullName}
- | */
- |public List&lt;{boxedDataType(node)}&gt; {name}() {{
- | return {listAccessor(node)};
- |}}
- |
- |/**
- | * @param i the index of the value to return
- | * @return {fullName}
- | */
- |public {userDataType(node)} {name}(int i) {{
- | return {name}.get(i){valueAccessor(node)};
- |}}
- </code>.text.stripMargin.trim
- }
-
- def accessorsForMap(node: CNode): String = {
- val name = node.getName
- val fullName = node.getFullName
- <code>
- |/**
- | * @return {fullName}
- | */
- |public Map&lt;String, {boxedDataType(node)}&gt; {name}() {{
- | return {mapAccessor(node)};
- |}}
- |
- |/**
- | * @param key the key of the value to return
- | * @return {fullName}
- | */
- |public {userDataType(node)} {name}(String key) {{
- | return {name}.get(key){valueAccessor(node)};
- |}}
- </code>.text.stripMargin.trim
- }
-
- def accessorForStructOrScalar(node: CNode): String = {
- <code>
- |/**
- | * @return {node.getFullName}
- | */
- |public {userDataType(node)} {node.getName}() {{
- | return {node.getName}{valueAccessor(node)};
- |}}
- </code>.text.stripMargin.trim
- }
-
- val accessors =
- for {
- c <- children
- accessor = getAccessorCode("", c)
- if (accessor.length > 0)
- } yield (accessor + "\n")
- accessors.mkString("\n").trim
- }
-
- private def getStaticMethodsForInnerArray(inner: InnerCNode) = {
- """
- |private static InnerNodeVector<%s> createVector(List<Builder> builders) {
- | List<%s> elems = new ArrayList<>();
- | for (Builder b : builders) {
- | elems.add(new %s(b));
- | }
- | return new InnerNodeVector<%s>(elems);
- |}
- """.stripMargin.format(List.fill(5)(nodeClass(inner)): _*).trim
- }
-
- private def getStaticMethodsForInnerMap(inner: InnerCNode) = {
- """
- |private static Map<String, %s> createMap(Map<String, Builder> builders) {
- | Map<String, %s> ret = new LinkedHashMap<>();
- | for(String key : builders.keySet()) {
- | ret.put(key, new %s(builders.get(key)));
- | }
- | return Collections.unmodifiableMap(ret);
- |}
- """.stripMargin.format(List.fill(3)(nodeClass(inner)): _*).trim
- }
-
- private def getEnumCode(enum: EnumLeaf, indent: String): String = {
-
- def getEnumValues(enum: EnumLeaf): String = {
- val enumValues =
- for (value <- enum.getLegalValues) yield
- """ public final static Enum %s = Enum.%s;""".format(value, value)
- enumValues.mkString("\n")
- }
-
- // TODO: try to rewrite to xml
- val code =
- """
- |%s
- |public final static class %s extends EnumNode<%s> {
-
- | public %s(){
- | this.value = null;
- | }
-
- | public %s(Enum enumValue) {
- | super(enumValue != null);
- | this.value = enumValue;
- | }
-
- | public enum Enum {%s}
- |%s
-
- | @Override
- | protected boolean doSetValue(@NonNull String name) {
- | try {
- | value = Enum.valueOf(name);
- | return true;
- | } catch (IllegalArgumentException e) {
- | }
- | return false;
- | }
- |}
- |"""
- .stripMargin.format(getClassDoc(enum, indent),
- nodeClass(enum),
- nodeClass(enum)+".Enum",
- nodeClass(enum),
- nodeClass(enum),
- enum.getLegalValues.mkString(", "),
- getEnumValues(enum))
-
- indentCode(indent, code).trim
- }
-
- def getClassDoc(node: CNode, indent: String): String = {
- val header = "/**\n" + " * This class represents " + node.getFullName
- val nodeComment = node.getCommentBlock(" *") match {
- case "" => ""
- case s => "\n *\n" + s.stripLineEnd // TODO: strip trailing \n in CNode.getCommentBlock
- }
- header + nodeComment + "\n */"
- }
-
- def indentCode(indent: String, code: String): String = {
- val indentedLines =
- for (s <- code.split("\n", -1)) yield
- if (s.length() > 0) (indent + s) else s
- indentedLines.mkString("\n")
- }
-
- /**
- * @return the name of the class that is generated by this node.
- */
- def nodeClass(node: CNode): String = {
- node match {
- case emptyName: CNode if node.getName.length == 0 =>
- throw new CodegenRuntimeException("Node with empty name, under parent " + emptyName.getParent.getName)
- case root: InnerCNode if root.getParent == null => ConfiggenUtil.createClassName(root.getName)
- case b: BooleanLeaf => "BooleanNode"
- case d: DoubleLeaf => "DoubleNode"
- case f: FileLeaf => "FileNode"
- case p: PathLeaf => "PathNode"
- case i: IntegerLeaf => "IntegerNode"
- case l: LongLeaf => "LongNode"
- case r: ReferenceLeaf => "ReferenceNode"
- case s: StringLeaf => "StringNode"
- case _ => node.getName.capitalize
- }
- }
-
- def userDataType(node: CNode): String = {
- node match {
- case inner: InnerCNode => nodeClass(node)
- case enum: EnumLeaf => nodeClass(enum) + ".Enum"
- case b: BooleanLeaf => "boolean"
- case d: DoubleLeaf => "double"
- case f: FileLeaf => "FileReference"
- case p: PathLeaf => "Path"
- case i: IntegerLeaf => "int"
- case l: LongLeaf => "long"
- case s: StringLeaf => "String"
- }
- }
-
- /**
- * @return the boxed java data type, e.g. Integer for int
- */
- def boxedDataType(node: CNode): String = {
- val rawType = userDataType(node)
-
- rawType match {
- case "int" => "Integer"
- case _ if rawType == rawType.toLowerCase => rawType.capitalize
- case _ => rawType
- }
- }
-
-}
diff --git a/configgen/src/main/scala/com/yahoo/config/codegen/JavaClassBuilder.scala b/configgen/src/main/scala/com/yahoo/config/codegen/JavaClassBuilder.scala
deleted file mode 100644
index e03a6d3d04b..00000000000
--- a/configgen/src/main/scala/com/yahoo/config/codegen/JavaClassBuilder.scala
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.config.codegen
-
-import java.io.{File, FileNotFoundException, FileOutputStream, PrintStream}
-
-import com.yahoo.config.codegen.ConfigGenerator.indentCode
-import com.yahoo.config.codegen.ConfiggenUtil.createClassName
-import com.yahoo.config.codegen.DefParser.DEFAULT_PACKAGE_PREFIX
-
-import scala.collection.JavaConverters._
-import scala.util.Random
-/**
- * Builds one Java class based on the given CNode tree.
- *
- * @author gjoranv
- * @author tonytv
- */
-class JavaClassBuilder(
- root: InnerCNode,
- nd: NormalizedDefinition,
- destDir: File,
- rawPackagePrefix: String)
- extends ClassBuilder
-{
- import JavaClassBuilder._
-
- val packagePrefix = if (rawPackagePrefix != null) rawPackagePrefix else DEFAULT_PACKAGE_PREFIX
- val javaPackage = if (root.getPackage != null) root.getPackage else packagePrefix + root.getNamespace
- val className = createClassName(root.getName)
-
- override def createConfigClasses() {
- try {
- val outFile = new File(getDestPath(destDir, javaPackage), className + ".java")
- var out: PrintStream = null
- try {
- out = new PrintStream(new FileOutputStream(outFile))
- out.print(getConfigClass(className))
- } finally {
- if (out != null) out.close()
- }
- System.err.println(outFile.getPath + " successfully written.")
- }
- catch {
- case e: FileNotFoundException => {
- throw new CodegenRuntimeException(e)
- }
- }
- }
-
- def getConfigClass(className:String): String = {
- val ret = new StringBuilder
-
- ret.append(getHeader).append("\n\n")
- ret.append(getRootClassDeclaration(root, className)).append("\n\n")
- ret.append(indentCode(Indentation, getFrameworkCode(className))).append("\n\n")
- ret.append(ConfigGenerator.generateContent(Indentation, root)).append("\n")
- ret.append("}\n")
-
- ret.toString()
- }
-
- private def getHeader: String = {
- <code>
- |/**
- | * This file is generated from a config definition file.
- | * ------------ D O N O T E D I T ! ------------
- | */
- |
- |package {javaPackage};
- |
- |import java.util.*;
- |import java.nio.file.Path;
- |import edu.umd.cs.findbugs.annotations.NonNull;
- |{getImportFrameworkClasses(root.getNamespace)}
- </code>.text.stripMargin.trim
- }
-
- private def getImportFrameworkClasses(namespace: String): String = {
- if (namespace != CNode.DEFAULT_NAMESPACE)
- "import " + packagePrefix + CNode.DEFAULT_NAMESPACE + ".*;\n"
- else
- ""
- }
-
- // TODO: remove the extra comment line " *" if root.getCommentBlock is empty
- private def getRootClassDeclaration(root:InnerCNode, className: String): String = {
- <code>
- |/**
- | * This class represents the root node of {root.getFullName}
- | *
- |{root.getCommentBlock(" *")} */
- |public final class {className} extends ConfigInstance {{
- |
- | public final static String CONFIG_DEF_MD5 = "{root.getMd5}";
- | public final static String CONFIG_DEF_NAME = "{root.getName}";
- | public final static String CONFIG_DEF_NAMESPACE = "{root.getNamespace}";
- | public final static String CONFIG_DEF_VERSION = "{root.getVersion}";
- | public final static String[] CONFIG_DEF_SCHEMA = {{
- |{indentCode(Indentation * 2, getDefSchema)}
- | }};
- |
- | public static String getDefMd5() {{ return CONFIG_DEF_MD5; }}
- | public static String getDefName() {{ return CONFIG_DEF_NAME; }}
- | public static String getDefNamespace() {{ return CONFIG_DEF_NAMESPACE; }}
- | public static String getDefVersion() {{ return CONFIG_DEF_VERSION; }}
- </code>.text.stripMargin.trim
- }
-
- private def getDefSchema: String = {
- nd.getNormalizedContent.asScala.map { line =>
- "\"" +
- line.replace("\"", "\\\"") +
- "\""
- }.mkString(",\n")
- }
-
- private def getFrameworkCode(className: String): String = {
- getProducerBase
- }
-
- private def getProducerBase = {
- """
- |public interface Producer extends ConfigInstance.Producer {
- | void getConfig(Builder builder);
- |}
- """.stripMargin.trim
- }
-
- /**
- * @param rootDir The root directory for the destination path.
- * @param javaPackage The java package
- * @return the destination path for the generated config file, including the given rootDir.
- */
- private def getDestPath(rootDir: File, javaPackage: String): File = {
- var dir: File = rootDir
- val subDirs: Array[String] = javaPackage.split("""\.""")
- for (subDir <- subDirs) {
- dir = new File(dir, subDir)
- this.synchronized {
- if (!dir.isDirectory && !dir.mkdir) throw new CodegenRuntimeException("Could not create " + dir.getPath)
- }
- }
- dir
- }
-
-}
-
-
-object JavaClassBuilder {
-
- val Indentation = " "
-
- /**
- * Returns a name that can be safely used as a local variable in the generated config class
- * for the given node. The name will be based on the given basis string, but the basis itself is
- * not a possible return value.
- *
- * @param node The node to find a unused symbol name for.
- * @param basis The basis for the generated symbol name.
- * @return A name that is not used in the given config node.
- */
- def createUniqueSymbol(node: CNode, basis: String) = {
-
- def getCandidate(cnt: Int) = {
- if (cnt < basis.length())
- basis.substring(0, cnt)
- else
- ReservedWords.INTERNAL_PREFIX + basis + Random.nextInt().abs
- }
-
- def getUsedSymbols: Set[String] = {
- (node.getChildren map (child => child.getName)).toSet
- }
-
- // TODO: refactoring potential
- val usedSymbols = getUsedSymbols
- var count = 1
- var candidate = getCandidate(count)
- while (usedSymbols contains(candidate)) {
- count += 1
- candidate = getCandidate(count)
- }
- candidate
- }
-
-}
diff --git a/configgen/src/test/java/com/yahoo/config/codegen/JavaClassBuilderTest.java b/configgen/src/test/java/com/yahoo/config/codegen/JavaClassBuilderTest.java
new file mode 100644
index 00000000000..744f8c9b1a2
--- /dev/null
+++ b/configgen/src/test/java/com/yahoo/config/codegen/JavaClassBuilderTest.java
@@ -0,0 +1,116 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.codegen;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+
+import static com.yahoo.config.codegen.ConfiggenUtil.createClassName;
+import static com.yahoo.config.codegen.JavaClassBuilder.createUniqueSymbol;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author gjoranv
+ * @author ollivir
+ */
+public class JavaClassBuilderTest {
+ private static final String TEST_DIR = "target/test-classes/";
+ private static final String DEF_NAME = TEST_DIR + "allfeatures.def";
+ private static final String REFERENCE_NAME = TEST_DIR + "allfeatures.reference";
+
+ @Ignore
+ @Test
+ public void visual_inspection_of_generated_class() {
+ final String testDefinition = "version=1\n" + //
+ "namespace=test\n" + //
+ "p path\n" + //
+ "pathArr[] path\n" + //
+ "f file\n" + //
+ "fileArr[] file\n" + //
+ "i int default=0\n" + //
+ "# A long value\n" + //
+ "l long default=0\n" + //
+ "s string default=\"\"\n" + //
+ "b bool\n" + //
+ "# An enum value\n" + //
+ "e enum {A, B, C}\n" + //
+ "intArr[] int\n" + //
+ "boolArr[] bool\n" + //
+ "enumArr[] enum {FOO, BAR}\n" + //
+ "intMap{} int\n" + //
+ "# A struct\n" + //
+ "# with multi-line\n" + //
+ "# comment and \"quotes\".\n" + //
+ "myStruct.i int\n" + //
+ "myStruct.s string\n" + //
+ "# An inner array\n" + //
+ "myArr[].i int\n" + //
+ "myArr[].newStruct.s string\n" + //
+ "myArr[].newStruct.b bool\n" + //
+ "myArr[].intArr[] int\n" + //
+ "# An inner map\n" + //
+ "myMap{}.i int\n" + //
+ "myMap{}.newStruct.s string\n" + //
+ "myMap{}.newStruct.b bool\n" + //
+ "myMap{}.intArr[] int\n" + //
+ "intMap{} int\n";
+
+ DefParser parser = new DefParser("test", new StringReader(testDefinition));
+ InnerCNode root = parser.getTree();
+ JavaClassBuilder builder = new JavaClassBuilder(root, parser.getNormalizedDefinition(), null, null);
+ String configClass = builder.getConfigClass("TestConfig");
+ System.out.print(configClass);
+ }
+
+ @Test
+ public void testCreateUniqueSymbol() {
+ final String testDefinition = "version=1\n" + //
+ "namespace=test\n" + //
+ "m int\n" + //
+ "n int\n";
+ InnerCNode root = new DefParser("test", new StringReader(testDefinition)).getTree();
+
+ assertThat(createUniqueSymbol(root, "foo"), is("f"));
+ assertThat(createUniqueSymbol(root, "name"), is("na"));
+ assertTrue(createUniqueSymbol(root, "m").startsWith(ReservedWords.INTERNAL_PREFIX + "m"));
+
+ // The basis string is not a legal return value, even if unique, to avoid
+ // multiple symbols with the same name if the same basis string is given twice.
+ assertTrue(createUniqueSymbol(root, "my").startsWith(ReservedWords.INTERNAL_PREFIX + "my"));
+ }
+
+ @Test
+ public void testCreateClassName() {
+ assertThat(createClassName("simple"), is("SimpleConfig"));
+ assertThat(createClassName("a"), is("AConfig"));
+ assertThat(createClassName("a-b-c"), is("ABCConfig"));
+ assertThat(createClassName("a-1-2b"), is("A12bConfig"));
+ assertThat(createClassName("my-app"), is("MyAppConfig"));
+ assertThat(createClassName("MyApp"), is("MyAppConfig"));
+ }
+
+ @Test(expected = CodegenRuntimeException.class)
+ public void testIllegalClassName() {
+ createClassName("+illegal");
+ }
+
+ @Test
+ public void verify_generated_class_against_reference() throws IOException {
+ final String testDefinition = String.join("\n", Files.readAllLines(FileSystems.getDefault().getPath(DEF_NAME)));
+ final String referenceClass = String.join("\n", Files.readAllLines(FileSystems.getDefault().getPath(REFERENCE_NAME))) + "\n";
+
+ DefParser parser = new DefParser("allfeatures", new StringReader(testDefinition));
+ InnerCNode root = parser.getTree();
+ JavaClassBuilder builder = new JavaClassBuilder(root, parser.getNormalizedDefinition(), null, null);
+ String configClass = builder.getConfigClass("AllfeaturesConfig");
+
+ assertEquals(referenceClass, configClass);
+ }
+}
diff --git a/configgen/src/test/resources/allfeatures.reference b/configgen/src/test/resources/allfeatures.reference
new file mode 100644
index 00000000000..ebc21e8255c
--- /dev/null
+++ b/configgen/src/test/resources/allfeatures.reference
@@ -0,0 +1,1983 @@
+/**
+ * This file is generated from a config definition file.
+ * ------------ D O N O T E D I T ! ------------
+ */
+
+package com.yahoo.configgen;
+
+import java.util.*;
+import java.nio.file.Path;
+import edu.umd.cs.findbugs.annotations.NonNull;
+import com.yahoo.config.*;
+
+/**
+ * This class represents the root node of allfeatures
+ *
+ * Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+ *
+ * This def file should test most aspects of def files that makes a difference
+ * for the generated config classes. The goal is to trigger all blocks of
+ * code in the code generators. This includes:
+ *
+ * - Use all legal special characters in the def file name, to ensure that those
+ * that needs to be replaced in type names are actually replaced.
+ * - Use the same enum type twice to verify that we dont declare or define it
+ * twice.
+ * - Use the same struct type twice for the same reason.
+ * - Include arrays of primitives and structs.
+ * - Include enum primitives and array of enums. Arrays of enums must be handled
+ * specially by the C++ code.
+ * - Include enums both with and without default values.
+ * - Include primitive string, numbers & doubles both with and without default
+ * values.
+ * - Have an array within a struct, to verify that we correctly recurse.
+ * - Reuse type name further within to ensure that this works.
+ */
+public final class AllfeaturesConfig extends ConfigInstance {
+
+ public final static String CONFIG_DEF_MD5 = "eb2d24dbbcf054b21be729e2cfaafd93";
+ public final static String CONFIG_DEF_NAME = "allfeatures";
+ public final static String CONFIG_DEF_NAMESPACE = "configgen";
+ public final static String CONFIG_DEF_VERSION = "";
+ public final static String[] CONFIG_DEF_SCHEMA = {
+ "namespace=configgen",
+ "boolVal bool",
+ "bool_with_def bool default=false",
+ "intVal int",
+ "intWithDef int default=-545",
+ "longVal long",
+ "longWithDef long default=1234567890123",
+ "doubleVal double",
+ "double_with_def double default=-6.43",
+ "stringVal string",
+ "stringwithdef string default=\"foobar#notacomment\"",
+ "enumVal enum { FOO, BAR, FOOBAR }",
+ "enumwithdef enum { FOO2, BAR2, FOOBAR2 } default=BAR2",
+ "refVal reference",
+ "refwithdef reference default=\":parent:\"",
+ "fileVal file",
+ "pathVal path",
+ "boolarr[] bool",
+ "intarr[] int",
+ "longarr[] long",
+ "doublearr[] double",
+ "stringarr[] string",
+ "enumarr[] enum { ARRAY, VALUES }",
+ "refarr[] reference",
+ "filearr[] file",
+ "pathArr[] path",
+ "intMap{} int",
+ "pathMap{} file",
+ "basic_struct.foo string default=\"foo\"",
+ "basic_struct.bar int default=0",
+ "struct_of_struct.inner0.name string default=\"inner0\"",
+ "struct_of_struct.inner0.index int default=0",
+ "struct_of_struct.inner1.name string default=\"inner1\"",
+ "struct_of_struct.inner1.index int default=1",
+ "myArray[].intVal int default=14",
+ "myArray[].stringVal[] string",
+ "myArray[].enumVal enum { INNER, ENUM, TYPE } default=TYPE",
+ "myArray[].refVal reference",
+ "myArray[].anotherArray[].foo int default=-4",
+ "myMap{}.intVal int default=15",
+ "myMap{}.stringVal[] string",
+ "myMap{}.enumVal enum { INNER, ENUM, TYPE } default=ENUM",
+ "myMap{}.refVal reference",
+ "myMap{}.anotherArray[].foo int default=-5"
+ };
+
+ public static String getDefMd5() { return CONFIG_DEF_MD5; }
+ public static String getDefName() { return CONFIG_DEF_NAME; }
+ public static String getDefNamespace() { return CONFIG_DEF_NAMESPACE; }
+ public static String getDefVersion() { return CONFIG_DEF_VERSION; }
+
+ public interface Producer extends ConfigInstance.Producer {
+ void getConfig(Builder builder);
+ }
+
+ public static class Builder implements ConfigInstance.Builder {
+ private Set<String> __uninitialized = new HashSet<String>(Arrays.asList(
+ "boolVal",
+ "intVal",
+ "longVal",
+ "doubleVal",
+ "stringVal",
+ "enumVal",
+ "refVal",
+ "fileVal",
+ "pathVal"
+ ));
+
+ private Boolean boolVal = null;
+ private Boolean bool_with_def = null;
+ private Integer intVal = null;
+ private Integer intWithDef = null;
+ private Long longVal = null;
+ private Long longWithDef = null;
+ private Double doubleVal = null;
+ private Double double_with_def = null;
+ private String stringVal = null;
+ private String stringwithdef = null;
+ private EnumVal.Enum enumVal = null;
+ private Enumwithdef.Enum enumwithdef = null;
+ private String refVal = null;
+ private String refwithdef = null;
+ private String fileVal = null;
+ private FileReference pathVal = null;
+ public List<Boolean> boolarr = new ArrayList<>();
+ public List<Integer> intarr = new ArrayList<>();
+ public List<Long> longarr = new ArrayList<>();
+ public List<Double> doublearr = new ArrayList<>();
+ public List<String> stringarr = new ArrayList<>();
+ public List<Enumarr.Enum> enumarr = new ArrayList<>();
+ public List<String> refarr = new ArrayList<>();
+ public List<String> filearr = new ArrayList<>();
+ public List<FileReference> pathArr = new ArrayList<>();
+ public Map<String, Integer> intMap = new LinkedHashMap<>();
+ public Map<String, String> pathMap = new LinkedHashMap<>();
+ public Basic_struct.Builder basic_struct = new Basic_struct.Builder();
+ public Struct_of_struct.Builder struct_of_struct = new Struct_of_struct.Builder();
+ public List<MyArray.Builder> myArray = new ArrayList<>();
+ public Map<String, MyMap.Builder> myMap = new LinkedHashMap<>();
+
+ public Builder() { }
+
+ public Builder(AllfeaturesConfig config) {
+ boolVal(config.boolVal());
+ bool_with_def(config.bool_with_def());
+ intVal(config.intVal());
+ intWithDef(config.intWithDef());
+ longVal(config.longVal());
+ longWithDef(config.longWithDef());
+ doubleVal(config.doubleVal());
+ double_with_def(config.double_with_def());
+ stringVal(config.stringVal());
+ stringwithdef(config.stringwithdef());
+ enumVal(config.enumVal());
+ enumwithdef(config.enumwithdef());
+ refVal(config.refVal());
+ refwithdef(config.refwithdef());
+ fileVal(config.fileVal().value());
+ pathVal(config.pathVal.getFileReference());
+ boolarr(config.boolarr());
+ intarr(config.intarr());
+ longarr(config.longarr());
+ doublearr(config.doublearr());
+ stringarr(config.stringarr());
+ enumarr(config.enumarr());
+ refarr(config.refarr());
+ filearr(FileReference.toValues(config.filearr()));
+ pathArr(PathNode.toFileReferences(config.pathArr));
+ intMap(config.intMap());
+ pathMap(FileReference.toValueMap(config.pathMap()));
+ basic_struct(new Basic_struct.Builder(config.basic_struct()));
+ struct_of_struct(new Struct_of_struct.Builder(config.struct_of_struct()));
+ for (MyArray m : config.myArray()) {
+ myArray(new MyArray.Builder(m));
+ }
+ for (Map.Entry<String, MyMap> __entry : config.myMap().entrySet()) {
+ myMap(__entry.getKey(), new MyMap.Builder(__entry.getValue()));
+ }
+ }
+
+ private Builder override(Builder __superior) {
+ if (__superior.boolVal != null)
+ boolVal(__superior.boolVal);
+ if (__superior.bool_with_def != null)
+ bool_with_def(__superior.bool_with_def);
+ if (__superior.intVal != null)
+ intVal(__superior.intVal);
+ if (__superior.intWithDef != null)
+ intWithDef(__superior.intWithDef);
+ if (__superior.longVal != null)
+ longVal(__superior.longVal);
+ if (__superior.longWithDef != null)
+ longWithDef(__superior.longWithDef);
+ if (__superior.doubleVal != null)
+ doubleVal(__superior.doubleVal);
+ if (__superior.double_with_def != null)
+ double_with_def(__superior.double_with_def);
+ if (__superior.stringVal != null)
+ stringVal(__superior.stringVal);
+ if (__superior.stringwithdef != null)
+ stringwithdef(__superior.stringwithdef);
+ if (__superior.enumVal != null)
+ enumVal(__superior.enumVal);
+ if (__superior.enumwithdef != null)
+ enumwithdef(__superior.enumwithdef);
+ if (__superior.refVal != null)
+ refVal(__superior.refVal);
+ if (__superior.refwithdef != null)
+ refwithdef(__superior.refwithdef);
+ if (__superior.fileVal != null)
+ fileVal(__superior.fileVal);
+ if (__superior.pathVal != null)
+ pathVal(__superior.pathVal);
+ if (!__superior.boolarr.isEmpty())
+ boolarr.addAll(__superior.boolarr);
+ if (!__superior.intarr.isEmpty())
+ intarr.addAll(__superior.intarr);
+ if (!__superior.longarr.isEmpty())
+ longarr.addAll(__superior.longarr);
+ if (!__superior.doublearr.isEmpty())
+ doublearr.addAll(__superior.doublearr);
+ if (!__superior.stringarr.isEmpty())
+ stringarr.addAll(__superior.stringarr);
+ if (!__superior.enumarr.isEmpty())
+ enumarr.addAll(__superior.enumarr);
+ if (!__superior.refarr.isEmpty())
+ refarr.addAll(__superior.refarr);
+ if (!__superior.filearr.isEmpty())
+ filearr.addAll(__superior.filearr);
+ if (!__superior.pathArr.isEmpty())
+ pathArr.addAll(__superior.pathArr);
+ intMap(__superior.intMap);
+ pathMap(__superior.pathMap);
+ basic_struct(basic_struct.override(__superior.basic_struct));
+ struct_of_struct(struct_of_struct.override(__superior.struct_of_struct));
+ if (!__superior.myArray.isEmpty())
+ myArray.addAll(__superior.myArray);
+ myMap(__superior.myMap);
+ return this;
+ }
+
+ public Builder boolVal(boolean __value) {
+ boolVal = __value;
+ __uninitialized.remove("boolVal");
+ return this;
+ }
+
+ private Builder boolVal(String __value) {
+ return boolVal(Boolean.valueOf(__value));
+ }
+
+ public Builder bool_with_def(boolean __value) {
+ bool_with_def = __value;
+ return this;
+ }
+
+ private Builder bool_with_def(String __value) {
+ return bool_with_def(Boolean.valueOf(__value));
+ }
+
+ public Builder intVal(int __value) {
+ intVal = __value;
+ __uninitialized.remove("intVal");
+ return this;
+ }
+
+ private Builder intVal(String __value) {
+ return intVal(Integer.valueOf(__value));
+ }
+
+ public Builder intWithDef(int __value) {
+ intWithDef = __value;
+ return this;
+ }
+
+ private Builder intWithDef(String __value) {
+ return intWithDef(Integer.valueOf(__value));
+ }
+
+ public Builder longVal(long __value) {
+ longVal = __value;
+ __uninitialized.remove("longVal");
+ return this;
+ }
+
+ private Builder longVal(String __value) {
+ return longVal(Long.valueOf(__value));
+ }
+
+ public Builder longWithDef(long __value) {
+ longWithDef = __value;
+ return this;
+ }
+
+ private Builder longWithDef(String __value) {
+ return longWithDef(Long.valueOf(__value));
+ }
+
+ public Builder doubleVal(double __value) {
+ doubleVal = __value;
+ __uninitialized.remove("doubleVal");
+ return this;
+ }
+
+ private Builder doubleVal(String __value) {
+ return doubleVal(Double.valueOf(__value));
+ }
+
+ public Builder double_with_def(double __value) {
+ double_with_def = __value;
+ return this;
+ }
+
+ private Builder double_with_def(String __value) {
+ return double_with_def(Double.valueOf(__value));
+ }
+
+ public Builder stringVal(String __value) {
+ if (__value == null) throw new IllegalArgumentException("Null value is not allowed.");
+ stringVal = __value;
+ __uninitialized.remove("stringVal");
+ return this;
+ }
+
+
+ public Builder stringwithdef(String __value) {
+ if (__value == null) throw new IllegalArgumentException("Null value is not allowed.");
+ stringwithdef = __value;
+ return this;
+ }
+
+
+ public Builder enumVal(EnumVal.Enum __value) {
+ if (__value == null) throw new IllegalArgumentException("Null value is not allowed.");
+ enumVal = __value;
+ __uninitialized.remove("enumVal");
+ return this;
+ }
+
+ private Builder enumVal(String __value) {
+ return enumVal(EnumVal.Enum.valueOf(__value));
+ }
+
+ public Builder enumwithdef(Enumwithdef.Enum __value) {
+ if (__value == null) throw new IllegalArgumentException("Null value is not allowed.");
+ enumwithdef = __value;
+ return this;
+ }
+
+ private Builder enumwithdef(String __value) {
+ return enumwithdef(Enumwithdef.Enum.valueOf(__value));
+ }
+
+ public Builder refVal(String __value) {
+ if (__value == null) throw new IllegalArgumentException("Null value is not allowed.");
+ refVal = __value;
+ __uninitialized.remove("refVal");
+ return this;
+ }
+
+
+ public Builder refwithdef(String __value) {
+ if (__value == null) throw new IllegalArgumentException("Null value is not allowed.");
+ refwithdef = __value;
+ return this;
+ }
+
+
+ public Builder fileVal(String __value) {
+ if (__value == null) throw new IllegalArgumentException("Null value is not allowed.");
+ fileVal = __value;
+ __uninitialized.remove("fileVal");
+ return this;
+ }
+
+
+ public Builder pathVal(FileReference __value) {
+ if (__value == null) throw new IllegalArgumentException("Null value is not allowed.");
+ pathVal = __value;
+ __uninitialized.remove("pathVal");
+ return this;
+ }
+
+
+ public Builder boolarr(Boolean __value) {
+ boolarr.add(__value);
+ return this;
+ }
+
+ public Builder boolarr(Collection<Boolean> __values) {
+ boolarr.addAll(__values);
+ return this;
+ }
+
+ private Builder boolarr(String __value) {
+ return boolarr(Boolean.valueOf(__value));
+ }
+
+ public Builder intarr(Integer __value) {
+ intarr.add(__value);
+ return this;
+ }
+
+ public Builder intarr(Collection<Integer> __values) {
+ intarr.addAll(__values);
+ return this;
+ }
+
+ private Builder intarr(String __value) {
+ return intarr(Integer.valueOf(__value));
+ }
+
+ public Builder longarr(Long __value) {
+ longarr.add(__value);
+ return this;
+ }
+
+ public Builder longarr(Collection<Long> __values) {
+ longarr.addAll(__values);
+ return this;
+ }
+
+ private Builder longarr(String __value) {
+ return longarr(Long.valueOf(__value));
+ }
+
+ public Builder doublearr(Double __value) {
+ doublearr.add(__value);
+ return this;
+ }
+
+ public Builder doublearr(Collection<Double> __values) {
+ doublearr.addAll(__values);
+ return this;
+ }
+
+ private Builder doublearr(String __value) {
+ return doublearr(Double.valueOf(__value));
+ }
+
+ public Builder stringarr(String __value) {
+ stringarr.add(__value);
+ return this;
+ }
+
+ public Builder stringarr(Collection<String> __values) {
+ stringarr.addAll(__values);
+ return this;
+ }
+
+ public Builder enumarr(Enumarr.Enum __value) {
+ enumarr.add(__value);
+ return this;
+ }
+
+ public Builder enumarr(Collection<Enumarr.Enum> __values) {
+ enumarr.addAll(__values);
+ return this;
+ }
+
+ private Builder enumarr(String __value) {
+ return enumarr(Enumarr.Enum.valueOf(__value));
+ }
+
+ public Builder refarr(String __value) {
+ refarr.add(__value);
+ return this;
+ }
+
+ public Builder refarr(Collection<String> __values) {
+ refarr.addAll(__values);
+ return this;
+ }
+
+ public Builder filearr(String __value) {
+ filearr.add(__value);
+ return this;
+ }
+
+ public Builder filearr(Collection<String> __values) {
+ filearr.addAll(__values);
+ return this;
+ }
+
+ public Builder pathArr(FileReference __value) {
+ pathArr.add(__value);
+ return this;
+ }
+
+ public Builder pathArr(Collection<FileReference> __values) {
+ pathArr.addAll(__values);
+ return this;
+ }
+
+ public Builder intMap(String __key, Integer __value) {
+ intMap.put(__key, __value);
+ return this;
+ }
+
+ public Builder intMap(Map<String, Integer> __values) {
+ intMap.putAll(__values);
+ return this;
+ }
+
+ private Builder intMap(String __key, String __value) {
+ return intMap(__key, Integer.valueOf(__value));
+ }
+
+ public Builder pathMap(String __key, String __value) {
+ pathMap.put(__key, __value);
+ return this;
+ }
+
+ public Builder pathMap(Map<String, String> __values) {
+ pathMap.putAll(__values);
+ return this;
+ }
+
+ public Builder basic_struct(Basic_struct.Builder __builder) {
+ basic_struct = __builder;
+ return this;
+ }
+
+ public Builder struct_of_struct(Struct_of_struct.Builder __builder) {
+ struct_of_struct = __builder;
+ return this;
+ }
+
+ /**
+ * Add the given builder to this builder's list of MyArray builders
+ * @param __builder a builder
+ * @return this builder
+ */
+ public Builder myArray(MyArray.Builder __builder) {
+ myArray.add(__builder);
+ return this;
+ }
+
+ /**
+ * Set the given list as this builder's list of MyArray builders
+ * @param __builders a list of builders
+ * @return this builder
+ */
+ public Builder myArray(List<MyArray.Builder> __builders) {
+ myArray = __builders;
+ return this;
+ }
+
+ public Builder myMap(String __key, MyMap.Builder __value) {
+ myMap.put(__key, __value);
+ return this;
+ }
+
+ public Builder myMap(Map<String, MyMap.Builder> __values) {
+ myMap.putAll(__values);
+ return this;
+ }
+
+ @java.lang.Override
+ public final boolean dispatchGetConfig(ConfigInstance.Producer producer) {
+ if (producer instanceof Producer) {
+ ((Producer)producer).getConfig(this);
+ return true;
+ }
+ return false;
+ }
+
+ @java.lang.Override
+ public final String getDefMd5() { return CONFIG_DEF_MD5; }
+ @java.lang.Override
+ public final String getDefName() { return CONFIG_DEF_NAME; }
+ @java.lang.Override
+ public final String getDefNamespace() { return CONFIG_DEF_NAMESPACE; }
+ }
+
+ // Some random bool without a default value. These comments exist to check
+ // that comment parsing works.e
+ private final BooleanNode boolVal;
+ // A bool with a default value set.
+ private final BooleanNode bool_with_def;
+ private final IntegerNode intVal;
+ private final IntegerNode intWithDef;
+ private final LongNode longVal;
+ private final LongNode longWithDef;
+ private final DoubleNode doubleVal;
+ private final DoubleNode double_with_def;
+ // Another comment
+ private final StringNode stringVal;
+ private final StringNode stringwithdef;
+ private final EnumVal enumVal;
+ private final Enumwithdef enumwithdef;
+ private final ReferenceNode refVal;
+ private final ReferenceNode refwithdef;
+ private final FileNode fileVal;
+ private final PathNode pathVal;
+ private final LeafNodeVector<Boolean, BooleanNode> boolarr;
+ private final LeafNodeVector<Integer, IntegerNode> intarr;
+ private final LeafNodeVector<Long, LongNode> longarr;
+ private final LeafNodeVector<Double, DoubleNode> doublearr;
+ private final LeafNodeVector<String, StringNode> stringarr;
+ private final LeafNodeVector<Enumarr.Enum, Enumarr> enumarr;
+ private final LeafNodeVector<String, ReferenceNode> refarr;
+ private final LeafNodeVector<FileReference, FileNode> filearr;
+ private final LeafNodeVector<Path, PathNode> pathArr;
+ private final Map<String, IntegerNode> intMap;
+ private final Map<String, FileNode> pathMap;
+ private final Basic_struct basic_struct;
+ private final Struct_of_struct struct_of_struct;
+ private final InnerNodeVector<MyArray> myArray;
+ private final Map<String, MyMap> myMap;
+
+ public AllfeaturesConfig(Builder builder) {
+ this(builder, true);
+ }
+
+ private AllfeaturesConfig(Builder builder, boolean throwIfUninitialized) {
+ if (throwIfUninitialized && ! builder.__uninitialized.isEmpty())
+ throw new IllegalArgumentException("The following builder parameters for " +
+ "allfeatures must be initialized: " + builder.__uninitialized);
+
+ boolVal = (builder.boolVal == null) ?
+ new BooleanNode() : new BooleanNode(builder.boolVal);
+ bool_with_def = (builder.bool_with_def == null) ?
+ new BooleanNode(false) : new BooleanNode(builder.bool_with_def);
+ intVal = (builder.intVal == null) ?
+ new IntegerNode() : new IntegerNode(builder.intVal);
+ intWithDef = (builder.intWithDef == null) ?
+ new IntegerNode(-545) : new IntegerNode(builder.intWithDef);
+ longVal = (builder.longVal == null) ?
+ new LongNode() : new LongNode(builder.longVal);
+ longWithDef = (builder.longWithDef == null) ?
+ new LongNode(1234567890123L) : new LongNode(builder.longWithDef);
+ doubleVal = (builder.doubleVal == null) ?
+ new DoubleNode() : new DoubleNode(builder.doubleVal);
+ double_with_def = (builder.double_with_def == null) ?
+ new DoubleNode(-6.43D) : new DoubleNode(builder.double_with_def);
+ stringVal = (builder.stringVal == null) ?
+ new StringNode() : new StringNode(builder.stringVal);
+ stringwithdef = (builder.stringwithdef == null) ?
+ new StringNode("foobar#notacomment") : new StringNode(builder.stringwithdef);
+ enumVal = (builder.enumVal == null) ?
+ new EnumVal() : new EnumVal(builder.enumVal);
+ enumwithdef = (builder.enumwithdef == null) ?
+ new Enumwithdef(Enumwithdef.BAR2) : new Enumwithdef(builder.enumwithdef);
+ refVal = (builder.refVal == null) ?
+ new ReferenceNode() : new ReferenceNode(builder.refVal);
+ refwithdef = (builder.refwithdef == null) ?
+ new ReferenceNode(":parent:") : new ReferenceNode(builder.refwithdef);
+ fileVal = (builder.fileVal == null) ?
+ new FileNode() : new FileNode(builder.fileVal);
+ pathVal = (builder.pathVal == null) ?
+ new PathNode() : new PathNode(builder.pathVal);
+ boolarr = new LeafNodeVector<>(builder.boolarr, new BooleanNode());
+ intarr = new LeafNodeVector<>(builder.intarr, new IntegerNode());
+ longarr = new LeafNodeVector<>(builder.longarr, new LongNode());
+ doublearr = new LeafNodeVector<>(builder.doublearr, new DoubleNode());
+ stringarr = new LeafNodeVector<>(builder.stringarr, new StringNode());
+ enumarr = new LeafNodeVector<>(builder.enumarr, new Enumarr());
+ refarr = new LeafNodeVector<>(builder.refarr, new ReferenceNode());
+ filearr = LeafNodeVector.createFileNodeVector(builder.filearr);
+ pathArr = LeafNodeVector.createPathNodeVector(builder.pathArr);
+ intMap = LeafNodeMaps.asNodeMap(builder.intMap, new IntegerNode());
+ pathMap = LeafNodeMaps.asFileNodeMap(builder.pathMap);
+ basic_struct = new Basic_struct(builder.basic_struct, throwIfUninitialized);
+ struct_of_struct = new Struct_of_struct(builder.struct_of_struct, throwIfUninitialized);
+ myArray = MyArray.createVector(builder.myArray);
+ myMap = MyMap.createMap(builder.myMap);
+ }
+
+ /**
+ * @return allfeatures.boolVal
+ */
+ public boolean boolVal() {
+ return boolVal.value();
+ }
+
+ /**
+ * @return allfeatures.bool_with_def
+ */
+ public boolean bool_with_def() {
+ return bool_with_def.value();
+ }
+
+ /**
+ * @return allfeatures.intVal
+ */
+ public int intVal() {
+ return intVal.value();
+ }
+
+ /**
+ * @return allfeatures.intWithDef
+ */
+ public int intWithDef() {
+ return intWithDef.value();
+ }
+
+ /**
+ * @return allfeatures.longVal
+ */
+ public long longVal() {
+ return longVal.value();
+ }
+
+ /**
+ * @return allfeatures.longWithDef
+ */
+ public long longWithDef() {
+ return longWithDef.value();
+ }
+
+ /**
+ * @return allfeatures.doubleVal
+ */
+ public double doubleVal() {
+ return doubleVal.value();
+ }
+
+ /**
+ * @return allfeatures.double_with_def
+ */
+ public double double_with_def() {
+ return double_with_def.value();
+ }
+
+ /**
+ * @return allfeatures.stringVal
+ */
+ public String stringVal() {
+ return stringVal.value();
+ }
+
+ /**
+ * @return allfeatures.stringwithdef
+ */
+ public String stringwithdef() {
+ return stringwithdef.value();
+ }
+
+ /**
+ * @return allfeatures.enumVal
+ */
+ public EnumVal.Enum enumVal() {
+ return enumVal.value();
+ }
+
+ /**
+ * @return allfeatures.enumwithdef
+ */
+ public Enumwithdef.Enum enumwithdef() {
+ return enumwithdef.value();
+ }
+
+ /**
+ * @return allfeatures.refVal
+ */
+ public String refVal() {
+ return refVal.value();
+ }
+
+ /**
+ * @return allfeatures.refwithdef
+ */
+ public String refwithdef() {
+ return refwithdef.value();
+ }
+
+ /**
+ * @return allfeatures.fileVal
+ */
+ public FileReference fileVal() {
+ return fileVal.value();
+ }
+
+ /**
+ * @return allfeatures.pathVal
+ */
+ public Path pathVal() {
+ return pathVal.value();
+ }
+
+ /**
+ * @return allfeatures.boolarr[]
+ */
+ public List<Boolean> boolarr() {
+ return boolarr.asList();
+ }
+
+ /**
+ * @param i the index of the value to return
+ * @return allfeatures.boolarr[]
+ */
+ public boolean boolarr(int i) {
+ return boolarr.get(i).value();
+ }
+
+ /**
+ * @return allfeatures.intarr[]
+ */
+ public List<Integer> intarr() {
+ return intarr.asList();
+ }
+
+ /**
+ * @param i the index of the value to return
+ * @return allfeatures.intarr[]
+ */
+ public int intarr(int i) {
+ return intarr.get(i).value();
+ }
+
+ /**
+ * @return allfeatures.longarr[]
+ */
+ public List<Long> longarr() {
+ return longarr.asList();
+ }
+
+ /**
+ * @param i the index of the value to return
+ * @return allfeatures.longarr[]
+ */
+ public long longarr(int i) {
+ return longarr.get(i).value();
+ }
+
+ /**
+ * @return allfeatures.doublearr[]
+ */
+ public List<Double> doublearr() {
+ return doublearr.asList();
+ }
+
+ /**
+ * @param i the index of the value to return
+ * @return allfeatures.doublearr[]
+ */
+ public double doublearr(int i) {
+ return doublearr.get(i).value();
+ }
+
+ /**
+ * @return allfeatures.stringarr[]
+ */
+ public List<String> stringarr() {
+ return stringarr.asList();
+ }
+
+ /**
+ * @param i the index of the value to return
+ * @return allfeatures.stringarr[]
+ */
+ public String stringarr(int i) {
+ return stringarr.get(i).value();
+ }
+
+ /**
+ * @return allfeatures.enumarr[]
+ */
+ public List<Enumarr.Enum> enumarr() {
+ return enumarr.asList();
+ }
+
+ /**
+ * @param i the index of the value to return
+ * @return allfeatures.enumarr[]
+ */
+ public Enumarr.Enum enumarr(int i) {
+ return enumarr.get(i).value();
+ }
+
+ /**
+ * @return allfeatures.refarr[]
+ */
+ public List<String> refarr() {
+ return refarr.asList();
+ }
+
+ /**
+ * @param i the index of the value to return
+ * @return allfeatures.refarr[]
+ */
+ public String refarr(int i) {
+ return refarr.get(i).value();
+ }
+
+ /**
+ * @return allfeatures.filearr[]
+ */
+ public List<FileReference> filearr() {
+ return filearr.asList();
+ }
+
+ /**
+ * @param i the index of the value to return
+ * @return allfeatures.filearr[]
+ */
+ public FileReference filearr(int i) {
+ return filearr.get(i).value();
+ }
+
+ /**
+ * @return allfeatures.pathArr[]
+ */
+ public List<Path> pathArr() {
+ return pathArr.asList();
+ }
+
+ /**
+ * @param i the index of the value to return
+ * @return allfeatures.pathArr[]
+ */
+ public Path pathArr(int i) {
+ return pathArr.get(i).value();
+ }
+
+ /**
+ * @return allfeatures.intMap{}
+ */
+ public Map<String, Integer> intMap() {
+ return LeafNodeMaps.asValueMap(intMap);
+ }
+
+ /**
+ * @param key the key of the value to return
+ * @return allfeatures.intMap{}
+ */
+ public int intMap(String key) {
+ return intMap.get(key).value();
+ }
+
+ /**
+ * @return allfeatures.pathMap{}
+ */
+ public Map<String, FileReference> pathMap() {
+ return LeafNodeMaps.asValueMap(pathMap);
+ }
+
+ /**
+ * @param key the key of the value to return
+ * @return allfeatures.pathMap{}
+ */
+ public FileReference pathMap(String key) {
+ return pathMap.get(key).value();
+ }
+
+ /**
+ * @return allfeatures.basic_struct
+ */
+ public Basic_struct basic_struct() {
+ return basic_struct;
+ }
+
+ /**
+ * @return allfeatures.struct_of_struct
+ */
+ public Struct_of_struct struct_of_struct() {
+ return struct_of_struct;
+ }
+
+ /**
+ * @return allfeatures.myArray[]
+ */
+ public List<MyArray> myArray() {
+ return myArray;
+ }
+
+ /**
+ * @param i the index of the value to return
+ * @return allfeatures.myArray[]
+ */
+ public MyArray myArray(int i) {
+ return myArray.get(i);
+ }
+
+ /**
+ * @return allfeatures.myMap{}
+ */
+ public Map<String, MyMap> myMap() {
+ return Collections.unmodifiableMap(myMap);
+ }
+
+ /**
+ * @param key the key of the value to return
+ * @return allfeatures.myMap{}
+ */
+ public MyMap myMap(String key) {
+ return myMap.get(key);
+ }
+
+ private ChangesRequiringRestart getChangesRequiringRestart(AllfeaturesConfig newConfig) {
+ ChangesRequiringRestart changes = new ChangesRequiringRestart("allfeatures");
+ return changes;
+ }
+
+ private static boolean containsFieldsFlaggedWithRestart() {
+ return false;
+ }
+
+ /**
+ * This class represents allfeatures.enumVal
+ */
+ public final static class EnumVal extends EnumNode<EnumVal.Enum> {
+
+ public EnumVal(){
+ this.value = null;
+ }
+
+ public EnumVal(Enum enumValue) {
+ super(enumValue != null);
+ this.value = enumValue;
+ }
+
+ public enum Enum {FOO, BAR, FOOBAR}
+ public final static Enum FOO = Enum.FOO;
+ public final static Enum BAR = Enum.BAR;
+ public final static Enum FOOBAR = Enum.FOOBAR;
+
+ @Override
+ protected boolean doSetValue(@NonNull String name) {
+ try {
+ value = Enum.valueOf(name);
+ return true;
+ } catch (IllegalArgumentException e) {
+ }
+ return false;
+ }
+ }
+
+ /**
+ * This class represents allfeatures.enumwithdef
+ */
+ public final static class Enumwithdef extends EnumNode<Enumwithdef.Enum> {
+
+ public Enumwithdef(){
+ this.value = null;
+ }
+
+ public Enumwithdef(Enum enumValue) {
+ super(enumValue != null);
+ this.value = enumValue;
+ }
+
+ public enum Enum {FOO2, BAR2, FOOBAR2}
+ public final static Enum FOO2 = Enum.FOO2;
+ public final static Enum BAR2 = Enum.BAR2;
+ public final static Enum FOOBAR2 = Enum.FOOBAR2;
+
+ @Override
+ protected boolean doSetValue(@NonNull String name) {
+ try {
+ value = Enum.valueOf(name);
+ return true;
+ } catch (IllegalArgumentException e) {
+ }
+ return false;
+ }
+ }
+
+ /**
+ * This class represents allfeatures.enumarr[]
+ */
+ public final static class Enumarr extends EnumNode<Enumarr.Enum> {
+
+ public Enumarr(){
+ this.value = null;
+ }
+
+ public Enumarr(Enum enumValue) {
+ super(enumValue != null);
+ this.value = enumValue;
+ }
+
+ public enum Enum {ARRAY, VALUES}
+ public final static Enum ARRAY = Enum.ARRAY;
+ public final static Enum VALUES = Enum.VALUES;
+
+ @Override
+ protected boolean doSetValue(@NonNull String name) {
+ try {
+ value = Enum.valueOf(name);
+ return true;
+ } catch (IllegalArgumentException e) {
+ }
+ return false;
+ }
+ }
+
+ /**
+ * This class represents allfeatures.basic_struct
+ */
+ public final static class Basic_struct extends InnerNode {
+
+ public static class Builder implements ConfigBuilder {
+ private Set<String> __uninitialized = new HashSet<String>();
+
+ private String foo = null;
+ private Integer bar = null;
+
+ public Builder() { }
+
+ public Builder(Basic_struct config) {
+ foo(config.foo());
+ bar(config.bar());
+ }
+
+ private Builder override(Builder __superior) {
+ if (__superior.foo != null)
+ foo(__superior.foo);
+ if (__superior.bar != null)
+ bar(__superior.bar);
+ return this;
+ }
+
+ public Builder foo(String __value) {
+ if (__value == null) throw new IllegalArgumentException("Null value is not allowed.");
+ foo = __value;
+ return this;
+ }
+
+
+ public Builder bar(int __value) {
+ bar = __value;
+ return this;
+ }
+
+ private Builder bar(String __value) {
+ return bar(Integer.valueOf(__value));
+ }
+ }
+
+ // A basic struct
+ private final StringNode foo;
+ private final IntegerNode bar;
+
+ public Basic_struct(Builder builder) {
+ this(builder, true);
+ }
+
+ private Basic_struct(Builder builder, boolean throwIfUninitialized) {
+ if (throwIfUninitialized && ! builder.__uninitialized.isEmpty())
+ throw new IllegalArgumentException("The following builder parameters for " +
+ "allfeatures.basic_struct must be initialized: " + builder.__uninitialized);
+
+ foo = (builder.foo == null) ?
+ new StringNode("foo") : new StringNode(builder.foo);
+ bar = (builder.bar == null) ?
+ new IntegerNode(0) : new IntegerNode(builder.bar);
+ }
+
+ /**
+ * @return allfeatures.basic_struct.foo
+ */
+ public String foo() {
+ return foo.value();
+ }
+
+ /**
+ * @return allfeatures.basic_struct.bar
+ */
+ public int bar() {
+ return bar.value();
+ }
+
+ private ChangesRequiringRestart getChangesRequiringRestart(Basic_struct newConfig) {
+ ChangesRequiringRestart changes = new ChangesRequiringRestart("basic_struct");
+ return changes;
+ }
+ }
+
+ /**
+ * This class represents allfeatures.struct_of_struct
+ */
+ public final static class Struct_of_struct extends InnerNode {
+
+ public static class Builder implements ConfigBuilder {
+ private Set<String> __uninitialized = new HashSet<String>();
+
+ public Inner0.Builder inner0 = new Inner0.Builder();
+ public Inner1.Builder inner1 = new Inner1.Builder();
+
+ public Builder() { }
+
+ public Builder(Struct_of_struct config) {
+ inner0(new Inner0.Builder(config.inner0()));
+ inner1(new Inner1.Builder(config.inner1()));
+ }
+
+ private Builder override(Builder __superior) {
+ inner0(inner0.override(__superior.inner0));
+ inner1(inner1.override(__superior.inner1));
+ return this;
+ }
+
+ public Builder inner0(Inner0.Builder __builder) {
+ inner0 = __builder;
+ return this;
+ }
+
+ public Builder inner1(Inner1.Builder __builder) {
+ inner1 = __builder;
+ return this;
+ }
+ }
+
+ private final Inner0 inner0;
+ private final Inner1 inner1;
+
+ public Struct_of_struct(Builder builder) {
+ this(builder, true);
+ }
+
+ private Struct_of_struct(Builder builder, boolean throwIfUninitialized) {
+ if (throwIfUninitialized && ! builder.__uninitialized.isEmpty())
+ throw new IllegalArgumentException("The following builder parameters for " +
+ "allfeatures.struct_of_struct must be initialized: " + builder.__uninitialized);
+
+ inner0 = new Inner0(builder.inner0, throwIfUninitialized);
+ inner1 = new Inner1(builder.inner1, throwIfUninitialized);
+ }
+
+ /**
+ * @return allfeatures.struct_of_struct.inner0
+ */
+ public Inner0 inner0() {
+ return inner0;
+ }
+
+ /**
+ * @return allfeatures.struct_of_struct.inner1
+ */
+ public Inner1 inner1() {
+ return inner1;
+ }
+
+ private ChangesRequiringRestart getChangesRequiringRestart(Struct_of_struct newConfig) {
+ ChangesRequiringRestart changes = new ChangesRequiringRestart("struct_of_struct");
+ return changes;
+ }
+
+ /**
+ * This class represents allfeatures.struct_of_struct.inner0
+ */
+ public final static class Inner0 extends InnerNode {
+
+ public static class Builder implements ConfigBuilder {
+ private Set<String> __uninitialized = new HashSet<String>();
+
+ private String name = null;
+ private Integer index = null;
+
+ public Builder() { }
+
+ public Builder(Inner0 config) {
+ name(config.name());
+ index(config.index());
+ }
+
+ private Builder override(Builder __superior) {
+ if (__superior.name != null)
+ name(__superior.name);
+ if (__superior.index != null)
+ index(__superior.index);
+ return this;
+ }
+
+ public Builder name(String __value) {
+ if (__value == null) throw new IllegalArgumentException("Null value is not allowed.");
+ name = __value;
+ return this;
+ }
+
+
+ public Builder index(int __value) {
+ index = __value;
+ return this;
+ }
+
+ private Builder index(String __value) {
+ return index(Integer.valueOf(__value));
+ }
+ }
+
+ // A struct of struct
+ private final StringNode name;
+ private final IntegerNode index;
+
+ public Inner0(Builder builder) {
+ this(builder, true);
+ }
+
+ private Inner0(Builder builder, boolean throwIfUninitialized) {
+ if (throwIfUninitialized && ! builder.__uninitialized.isEmpty())
+ throw new IllegalArgumentException("The following builder parameters for " +
+ "allfeatures.struct_of_struct.inner0 must be initialized: " + builder.__uninitialized);
+
+ name = (builder.name == null) ?
+ new StringNode("inner0") : new StringNode(builder.name);
+ index = (builder.index == null) ?
+ new IntegerNode(0) : new IntegerNode(builder.index);
+ }
+
+ /**
+ * @return allfeatures.struct_of_struct.inner0.name
+ */
+ public String name() {
+ return name.value();
+ }
+
+ /**
+ * @return allfeatures.struct_of_struct.inner0.index
+ */
+ public int index() {
+ return index.value();
+ }
+
+ private ChangesRequiringRestart getChangesRequiringRestart(Inner0 newConfig) {
+ ChangesRequiringRestart changes = new ChangesRequiringRestart("inner0");
+ return changes;
+ }
+ }
+
+ /**
+ * This class represents allfeatures.struct_of_struct.inner1
+ */
+ public final static class Inner1 extends InnerNode {
+
+ public static class Builder implements ConfigBuilder {
+ private Set<String> __uninitialized = new HashSet<String>();
+
+ private String name = null;
+ private Integer index = null;
+
+ public Builder() { }
+
+ public Builder(Inner1 config) {
+ name(config.name());
+ index(config.index());
+ }
+
+ private Builder override(Builder __superior) {
+ if (__superior.name != null)
+ name(__superior.name);
+ if (__superior.index != null)
+ index(__superior.index);
+ return this;
+ }
+
+ public Builder name(String __value) {
+ if (__value == null) throw new IllegalArgumentException("Null value is not allowed.");
+ name = __value;
+ return this;
+ }
+
+
+ public Builder index(int __value) {
+ index = __value;
+ return this;
+ }
+
+ private Builder index(String __value) {
+ return index(Integer.valueOf(__value));
+ }
+ }
+
+ private final StringNode name;
+ private final IntegerNode index;
+
+ public Inner1(Builder builder) {
+ this(builder, true);
+ }
+
+ private Inner1(Builder builder, boolean throwIfUninitialized) {
+ if (throwIfUninitialized && ! builder.__uninitialized.isEmpty())
+ throw new IllegalArgumentException("The following builder parameters for " +
+ "allfeatures.struct_of_struct.inner1 must be initialized: " + builder.__uninitialized);
+
+ name = (builder.name == null) ?
+ new StringNode("inner1") : new StringNode(builder.name);
+ index = (builder.index == null) ?
+ new IntegerNode(1) : new IntegerNode(builder.index);
+ }
+
+ /**
+ * @return allfeatures.struct_of_struct.inner1.name
+ */
+ public String name() {
+ return name.value();
+ }
+
+ /**
+ * @return allfeatures.struct_of_struct.inner1.index
+ */
+ public int index() {
+ return index.value();
+ }
+
+ private ChangesRequiringRestart getChangesRequiringRestart(Inner1 newConfig) {
+ ChangesRequiringRestart changes = new ChangesRequiringRestart("inner1");
+ return changes;
+ }
+ }
+ }
+
+ /**
+ * This class represents allfeatures.myArray[]
+ */
+ public final static class MyArray extends InnerNode {
+
+ public static class Builder implements ConfigBuilder {
+ private Set<String> __uninitialized = new HashSet<String>(Arrays.asList(
+ "refVal"
+ ));
+
+ private Integer intVal = null;
+ public List<String> stringVal = new ArrayList<>();
+ private EnumVal.Enum enumVal = null;
+ private String refVal = null;
+ public List<AnotherArray.Builder> anotherArray = new ArrayList<>();
+
+ public Builder() { }
+
+ public Builder(MyArray config) {
+ intVal(config.intVal());
+ stringVal(config.stringVal());
+ enumVal(config.enumVal());
+ refVal(config.refVal());
+ for (AnotherArray a : config.anotherArray()) {
+ anotherArray(new AnotherArray.Builder(a));
+ }
+ }
+
+ private Builder override(Builder __superior) {
+ if (__superior.intVal != null)
+ intVal(__superior.intVal);
+ if (!__superior.stringVal.isEmpty())
+ stringVal.addAll(__superior.stringVal);
+ if (__superior.enumVal != null)
+ enumVal(__superior.enumVal);
+ if (__superior.refVal != null)
+ refVal(__superior.refVal);
+ if (!__superior.anotherArray.isEmpty())
+ anotherArray.addAll(__superior.anotherArray);
+ return this;
+ }
+
+ public Builder intVal(int __value) {
+ intVal = __value;
+ return this;
+ }
+
+ private Builder intVal(String __value) {
+ return intVal(Integer.valueOf(__value));
+ }
+
+ public Builder stringVal(String __value) {
+ stringVal.add(__value);
+ return this;
+ }
+
+ public Builder stringVal(Collection<String> __values) {
+ stringVal.addAll(__values);
+ return this;
+ }
+
+ public Builder enumVal(EnumVal.Enum __value) {
+ if (__value == null) throw new IllegalArgumentException("Null value is not allowed.");
+ enumVal = __value;
+ return this;
+ }
+
+ private Builder enumVal(String __value) {
+ return enumVal(EnumVal.Enum.valueOf(__value));
+ }
+
+ public Builder refVal(String __value) {
+ if (__value == null) throw new IllegalArgumentException("Null value is not allowed.");
+ refVal = __value;
+ __uninitialized.remove("refVal");
+ return this;
+ }
+
+
+ /**
+ * Add the given builder to this builder's list of AnotherArray builders
+ * @param __builder a builder
+ * @return this builder
+ */
+ public Builder anotherArray(AnotherArray.Builder __builder) {
+ anotherArray.add(__builder);
+ return this;
+ }
+
+ /**
+ * Set the given list as this builder's list of AnotherArray builders
+ * @param __builders a list of builders
+ * @return this builder
+ */
+ public Builder anotherArray(List<AnotherArray.Builder> __builders) {
+ anotherArray = __builders;
+ return this;
+ }
+ }
+
+ private final IntegerNode intVal;
+ private final LeafNodeVector<String, StringNode> stringVal;
+ private final EnumVal enumVal;
+ private final ReferenceNode refVal;
+ private final InnerNodeVector<AnotherArray> anotherArray;
+
+ public MyArray(Builder builder) {
+ this(builder, true);
+ }
+
+ private MyArray(Builder builder, boolean throwIfUninitialized) {
+ if (throwIfUninitialized && ! builder.__uninitialized.isEmpty())
+ throw new IllegalArgumentException("The following builder parameters for " +
+ "allfeatures.myArray[] must be initialized: " + builder.__uninitialized);
+
+ intVal = (builder.intVal == null) ?
+ new IntegerNode(14) : new IntegerNode(builder.intVal);
+ stringVal = new LeafNodeVector<>(builder.stringVal, new StringNode());
+ enumVal = (builder.enumVal == null) ?
+ new EnumVal(EnumVal.TYPE) : new EnumVal(builder.enumVal);
+ refVal = (builder.refVal == null) ?
+ new ReferenceNode() : new ReferenceNode(builder.refVal);
+ anotherArray = AnotherArray.createVector(builder.anotherArray);
+ }
+
+ /**
+ * @return allfeatures.myArray[].intVal
+ */
+ public int intVal() {
+ return intVal.value();
+ }
+
+ /**
+ * @return allfeatures.myArray[].stringVal[]
+ */
+ public List<String> stringVal() {
+ return stringVal.asList();
+ }
+
+ /**
+ * @param i the index of the value to return
+ * @return allfeatures.myArray[].stringVal[]
+ */
+ public String stringVal(int i) {
+ return stringVal.get(i).value();
+ }
+
+ /**
+ * @return allfeatures.myArray[].enumVal
+ */
+ public EnumVal.Enum enumVal() {
+ return enumVal.value();
+ }
+
+ /**
+ * @return allfeatures.myArray[].refVal
+ */
+ public String refVal() {
+ return refVal.value();
+ }
+
+ /**
+ * @return allfeatures.myArray[].anotherArray[]
+ */
+ public List<AnotherArray> anotherArray() {
+ return anotherArray;
+ }
+
+ /**
+ * @param i the index of the value to return
+ * @return allfeatures.myArray[].anotherArray[]
+ */
+ public AnotherArray anotherArray(int i) {
+ return anotherArray.get(i);
+ }
+
+ private ChangesRequiringRestart getChangesRequiringRestart(MyArray newConfig) {
+ ChangesRequiringRestart changes = new ChangesRequiringRestart("myArray");
+ return changes;
+ }
+
+ private static InnerNodeVector<MyArray> createVector(List<Builder> builders) {
+ List<MyArray> elems = new ArrayList<>();
+ for (Builder b : builders) {
+ elems.add(new MyArray(b));
+ }
+ return new InnerNodeVector<MyArray>(elems);
+ }
+
+ /**
+ * This class represents allfeatures.myArray[].enumVal
+ */
+ public final static class EnumVal extends EnumNode<EnumVal.Enum> {
+
+ public EnumVal(){
+ this.value = null;
+ }
+
+ public EnumVal(Enum enumValue) {
+ super(enumValue != null);
+ this.value = enumValue;
+ }
+
+ public enum Enum {INNER, ENUM, TYPE}
+ public final static Enum INNER = Enum.INNER;
+ public final static Enum ENUM = Enum.ENUM;
+ public final static Enum TYPE = Enum.TYPE;
+
+ @Override
+ protected boolean doSetValue(@NonNull String name) {
+ try {
+ value = Enum.valueOf(name);
+ return true;
+ } catch (IllegalArgumentException e) {
+ }
+ return false;
+ }
+ }
+
+ /**
+ * This class represents allfeatures.myArray[].anotherArray[]
+ */
+ public final static class AnotherArray extends InnerNode {
+
+ public static class Builder implements ConfigBuilder {
+ private Set<String> __uninitialized = new HashSet<String>();
+
+ private Integer foo = null;
+
+ public Builder() { }
+
+ public Builder(AnotherArray config) {
+ foo(config.foo());
+ }
+
+ private Builder override(Builder __superior) {
+ if (__superior.foo != null)
+ foo(__superior.foo);
+ return this;
+ }
+
+ public Builder foo(int __value) {
+ foo = __value;
+ return this;
+ }
+
+ private Builder foo(String __value) {
+ return foo(Integer.valueOf(__value));
+ }
+ }
+
+ private final IntegerNode foo;
+
+ public AnotherArray(Builder builder) {
+ this(builder, true);
+ }
+
+ private AnotherArray(Builder builder, boolean throwIfUninitialized) {
+ if (throwIfUninitialized && ! builder.__uninitialized.isEmpty())
+ throw new IllegalArgumentException("The following builder parameters for " +
+ "allfeatures.myArray[].anotherArray[] must be initialized: " + builder.__uninitialized);
+
+ foo = (builder.foo == null) ?
+ new IntegerNode(-4) : new IntegerNode(builder.foo);
+ }
+
+ /**
+ * @return allfeatures.myArray[].anotherArray[].foo
+ */
+ public int foo() {
+ return foo.value();
+ }
+
+ private ChangesRequiringRestart getChangesRequiringRestart(AnotherArray newConfig) {
+ ChangesRequiringRestart changes = new ChangesRequiringRestart("anotherArray");
+ return changes;
+ }
+
+ private static InnerNodeVector<AnotherArray> createVector(List<Builder> builders) {
+ List<AnotherArray> elems = new ArrayList<>();
+ for (Builder b : builders) {
+ elems.add(new AnotherArray(b));
+ }
+ return new InnerNodeVector<AnotherArray>(elems);
+ }
+ }
+ }
+
+ /**
+ * This class represents allfeatures.myMap{}
+ */
+ public final static class MyMap extends InnerNode {
+
+ public static class Builder implements ConfigBuilder {
+ private Set<String> __uninitialized = new HashSet<String>(Arrays.asList(
+ "refVal"
+ ));
+
+ private Integer intVal = null;
+ public List<String> stringVal = new ArrayList<>();
+ private EnumVal.Enum enumVal = null;
+ private String refVal = null;
+ public List<AnotherArray.Builder> anotherArray = new ArrayList<>();
+
+ public Builder() { }
+
+ public Builder(MyMap config) {
+ intVal(config.intVal());
+ stringVal(config.stringVal());
+ enumVal(config.enumVal());
+ refVal(config.refVal());
+ for (AnotherArray a : config.anotherArray()) {
+ anotherArray(new AnotherArray.Builder(a));
+ }
+ }
+
+ private Builder override(Builder __superior) {
+ if (__superior.intVal != null)
+ intVal(__superior.intVal);
+ if (!__superior.stringVal.isEmpty())
+ stringVal.addAll(__superior.stringVal);
+ if (__superior.enumVal != null)
+ enumVal(__superior.enumVal);
+ if (__superior.refVal != null)
+ refVal(__superior.refVal);
+ if (!__superior.anotherArray.isEmpty())
+ anotherArray.addAll(__superior.anotherArray);
+ return this;
+ }
+
+ public Builder intVal(int __value) {
+ intVal = __value;
+ return this;
+ }
+
+ private Builder intVal(String __value) {
+ return intVal(Integer.valueOf(__value));
+ }
+
+ public Builder stringVal(String __value) {
+ stringVal.add(__value);
+ return this;
+ }
+
+ public Builder stringVal(Collection<String> __values) {
+ stringVal.addAll(__values);
+ return this;
+ }
+
+ public Builder enumVal(EnumVal.Enum __value) {
+ if (__value == null) throw new IllegalArgumentException("Null value is not allowed.");
+ enumVal = __value;
+ return this;
+ }
+
+ private Builder enumVal(String __value) {
+ return enumVal(EnumVal.Enum.valueOf(__value));
+ }
+
+ public Builder refVal(String __value) {
+ if (__value == null) throw new IllegalArgumentException("Null value is not allowed.");
+ refVal = __value;
+ __uninitialized.remove("refVal");
+ return this;
+ }
+
+
+ /**
+ * Add the given builder to this builder's list of AnotherArray builders
+ * @param __builder a builder
+ * @return this builder
+ */
+ public Builder anotherArray(AnotherArray.Builder __builder) {
+ anotherArray.add(__builder);
+ return this;
+ }
+
+ /**
+ * Set the given list as this builder's list of AnotherArray builders
+ * @param __builders a list of builders
+ * @return this builder
+ */
+ public Builder anotherArray(List<AnotherArray.Builder> __builders) {
+ anotherArray = __builders;
+ return this;
+ }
+ }
+
+ private final IntegerNode intVal;
+ private final LeafNodeVector<String, StringNode> stringVal;
+ private final EnumVal enumVal;
+ private final ReferenceNode refVal;
+ private final InnerNodeVector<AnotherArray> anotherArray;
+
+ public MyMap(Builder builder) {
+ this(builder, true);
+ }
+
+ private MyMap(Builder builder, boolean throwIfUninitialized) {
+ if (throwIfUninitialized && ! builder.__uninitialized.isEmpty())
+ throw new IllegalArgumentException("The following builder parameters for " +
+ "allfeatures.myMap{} must be initialized: " + builder.__uninitialized);
+
+ intVal = (builder.intVal == null) ?
+ new IntegerNode(15) : new IntegerNode(builder.intVal);
+ stringVal = new LeafNodeVector<>(builder.stringVal, new StringNode());
+ enumVal = (builder.enumVal == null) ?
+ new EnumVal(EnumVal.ENUM) : new EnumVal(builder.enumVal);
+ refVal = (builder.refVal == null) ?
+ new ReferenceNode() : new ReferenceNode(builder.refVal);
+ anotherArray = AnotherArray.createVector(builder.anotherArray);
+ }
+
+ /**
+ * @return allfeatures.myMap{}.intVal
+ */
+ public int intVal() {
+ return intVal.value();
+ }
+
+ /**
+ * @return allfeatures.myMap{}.stringVal[]
+ */
+ public List<String> stringVal() {
+ return stringVal.asList();
+ }
+
+ /**
+ * @param i the index of the value to return
+ * @return allfeatures.myMap{}.stringVal[]
+ */
+ public String stringVal(int i) {
+ return stringVal.get(i).value();
+ }
+
+ /**
+ * @return allfeatures.myMap{}.enumVal
+ */
+ public EnumVal.Enum enumVal() {
+ return enumVal.value();
+ }
+
+ /**
+ * @return allfeatures.myMap{}.refVal
+ */
+ public String refVal() {
+ return refVal.value();
+ }
+
+ /**
+ * @return allfeatures.myMap{}.anotherArray[]
+ */
+ public List<AnotherArray> anotherArray() {
+ return anotherArray;
+ }
+
+ /**
+ * @param i the index of the value to return
+ * @return allfeatures.myMap{}.anotherArray[]
+ */
+ public AnotherArray anotherArray(int i) {
+ return anotherArray.get(i);
+ }
+
+ private ChangesRequiringRestart getChangesRequiringRestart(MyMap newConfig) {
+ ChangesRequiringRestart changes = new ChangesRequiringRestart("myMap");
+ return changes;
+ }
+
+ private static Map<String, MyMap> createMap(Map<String, Builder> builders) {
+ Map<String, MyMap> ret = new LinkedHashMap<>();
+ for(String key : builders.keySet()) {
+ ret.put(key, new MyMap(builders.get(key)));
+ }
+ return Collections.unmodifiableMap(ret);
+ }
+
+ /**
+ * This class represents allfeatures.myMap{}.enumVal
+ */
+ public final static class EnumVal extends EnumNode<EnumVal.Enum> {
+
+ public EnumVal(){
+ this.value = null;
+ }
+
+ public EnumVal(Enum enumValue) {
+ super(enumValue != null);
+ this.value = enumValue;
+ }
+
+ public enum Enum {INNER, ENUM, TYPE}
+ public final static Enum INNER = Enum.INNER;
+ public final static Enum ENUM = Enum.ENUM;
+ public final static Enum TYPE = Enum.TYPE;
+
+ @Override
+ protected boolean doSetValue(@NonNull String name) {
+ try {
+ value = Enum.valueOf(name);
+ return true;
+ } catch (IllegalArgumentException e) {
+ }
+ return false;
+ }
+ }
+
+ /**
+ * This class represents allfeatures.myMap{}.anotherArray[]
+ */
+ public final static class AnotherArray extends InnerNode {
+
+ public static class Builder implements ConfigBuilder {
+ private Set<String> __uninitialized = new HashSet<String>();
+
+ private Integer foo = null;
+
+ public Builder() { }
+
+ public Builder(AnotherArray config) {
+ foo(config.foo());
+ }
+
+ private Builder override(Builder __superior) {
+ if (__superior.foo != null)
+ foo(__superior.foo);
+ return this;
+ }
+
+ public Builder foo(int __value) {
+ foo = __value;
+ return this;
+ }
+
+ private Builder foo(String __value) {
+ return foo(Integer.valueOf(__value));
+ }
+ }
+
+ private final IntegerNode foo;
+
+ public AnotherArray(Builder builder) {
+ this(builder, true);
+ }
+
+ private AnotherArray(Builder builder, boolean throwIfUninitialized) {
+ if (throwIfUninitialized && ! builder.__uninitialized.isEmpty())
+ throw new IllegalArgumentException("The following builder parameters for " +
+ "allfeatures.myMap{}.anotherArray[] must be initialized: " + builder.__uninitialized);
+
+ foo = (builder.foo == null) ?
+ new IntegerNode(-5) : new IntegerNode(builder.foo);
+ }
+
+ /**
+ * @return allfeatures.myMap{}.anotherArray[].foo
+ */
+ public int foo() {
+ return foo.value();
+ }
+
+ private ChangesRequiringRestart getChangesRequiringRestart(AnotherArray newConfig) {
+ ChangesRequiringRestart changes = new ChangesRequiringRestart("anotherArray");
+ return changes;
+ }
+
+ private static InnerNodeVector<AnotherArray> createVector(List<Builder> builders) {
+ List<AnotherArray> elems = new ArrayList<>();
+ for (Builder b : builders) {
+ elems.add(new AnotherArray(b));
+ }
+ return new InnerNodeVector<AnotherArray>(elems);
+ }
+ }
+ }
+
+}
diff --git a/configgen/src/test/scala/com/yahoo/config/codegen/JavaClassBuilderTest.scala b/configgen/src/test/scala/com/yahoo/config/codegen/JavaClassBuilderTest.scala
deleted file mode 100644
index c1a5eb2dd6a..00000000000
--- a/configgen/src/test/scala/com/yahoo/config/codegen/JavaClassBuilderTest.scala
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.config.codegen
-
-import org.junit.Assert.assertThat
-import org.junit.Assert.assertTrue
-import org.hamcrest.CoreMatchers.is
-import java.io.StringReader
-import ConfiggenUtil.createClassName
-import JavaClassBuilder.createUniqueSymbol
-import org.junit.{Ignore, Test}
-
-/**
- * @author gjoranv
- */
-class JavaClassBuilderTest {
-
- @Ignore
- @Test
- def visual_inspection_of_generated_class() {
- val testDefinition =
- """version=1
- |namespace=test
- |p path
- |pathArr[] path
- |f file
- |fileArr[] file
- |i int default=0
- |# A long value
- |l long default=0
- |s string default=""
- |b bool
- |# An enum value
- |e enum {A, B, C}
- |intArr[] int
- |boolArr[] bool
- |enumArr[] enum {FOO, BAR}
- |intMap{} int
- |# A struct
- |# with multi-line
- |# comment and "quotes".
- |myStruct.i int
- |myStruct.s string
- |# An inner array
- |myArr[].i int
- |myArr[].newStruct.s string
- |myArr[].newStruct.b bool
- |myArr[].intArr[] int
- |# An inner map
- |myMap{}.i int
- |myMap{}.newStruct.s string
- |myMap{}.newStruct.b bool
- |myMap{}.intArr[] int
- |intMap{} int
- |""".stripMargin
-
- val parser = new DefParser("test", new StringReader(testDefinition))
- val root = parser.getTree
- val builder = new JavaClassBuilder(root, parser.getNormalizedDefinition, null, null)
- val configClass = builder.getConfigClass("TestConfig")
- print(configClass)
- }
-
- @Test
- def testCreateUniqueSymbol() {
- val testDefinition =
- """version=1
- |namespace=test
- |m int
- |n int
- """.stripMargin
- val root = new DefParser("test", new StringReader(testDefinition)).getTree
-
- assertThat(createUniqueSymbol(root, "foo"), is("f"))
- assertThat(createUniqueSymbol(root, "name"), is("na"))
- assertTrue(createUniqueSymbol(root, "m").startsWith(ReservedWords.INTERNAL_PREFIX + "m"))
-
- // The basis string is not a legal return value, even if unique, to avoid multiple symbols
- // with the same name if the same basis string is given twice.
- assertTrue(createUniqueSymbol(root, "my").startsWith(ReservedWords.INTERNAL_PREFIX + "my"))
- }
-
- @Test
- def testCreateClassName() {
- assertThat(createClassName("simple"), is("SimpleConfig"))
- assertThat(createClassName("a"), is("AConfig"))
- assertThat(createClassName("a-b-c"), is("ABCConfig"))
- assertThat(createClassName("a-1-2b"), is("A12bConfig"))
- assertThat(createClassName("my-app"), is("MyAppConfig"))
- assertThat(createClassName("MyApp"), is("MyAppConfig"))
- }
-
- @Test(expected=classOf[CodegenRuntimeException])
- def testIllegalClassName() {
- createClassName("+illegal")
- }
-
-}