diff --git a/src/main/java/com/typesafe/config/impl/AbstractConfigObject.java b/src/main/java/com/typesafe/config/impl/AbstractConfigObject.java index c78f0286..807a64a8 100644 --- a/src/main/java/com/typesafe/config/impl/AbstractConfigObject.java +++ b/src/main/java/com/typesafe/config/impl/AbstractConfigObject.java @@ -261,22 +261,34 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements } @Override - protected void render(StringBuilder sb, int indent) { + protected void render(StringBuilder sb, int indent, boolean formatted) { if (isEmpty()) { sb.append("{}"); } else { - sb.append("{\n"); + sb.append("{"); + if (formatted) + sb.append('\n'); for (String k : keySet()) { AbstractConfigValue v = peek(k); - indent(sb, indent + 1); - sb.append("# "); - sb.append(v.origin().description()); - sb.append("\n"); - indent(sb, indent + 1); - v.render(sb, indent + 1, k); - sb.append(",\n"); + if (formatted) { + indent(sb, indent + 1); + sb.append("# "); + sb.append(v.origin().description()); + sb.append("\n"); + indent(sb, indent + 1); + } + v.render(sb, indent + 1, k, formatted); + sb.append(","); + if (formatted) + sb.append('\n'); + } + // chop comma or newline + sb.setLength(sb.length() - 1); + if (formatted) { + sb.setLength(sb.length() - 1); // also chop comma + sb.append("\n"); // put a newline back + indent(sb, indent); } - indent(sb, indent); sb.append("}"); } } diff --git a/src/main/java/com/typesafe/config/impl/AbstractConfigValue.java b/src/main/java/com/typesafe/config/impl/AbstractConfigValue.java index 5030e9cb..f94cf221 100644 --- a/src/main/java/com/typesafe/config/impl/AbstractConfigValue.java +++ b/src/main/java/com/typesafe/config/impl/AbstractConfigValue.java @@ -163,7 +163,9 @@ abstract class AbstractConfigValue implements ConfigValue { @Override public final String toString() { - return getClass().getSimpleName() + "(" + render() + ")"; + StringBuilder sb = new StringBuilder(); + render(sb, 0, null /* atKey */, false /* formatted */); + return getClass().getSimpleName() + "(" + sb.toString() + ")"; } protected static void indent(StringBuilder sb, int indent) { @@ -174,15 +176,15 @@ abstract class AbstractConfigValue implements ConfigValue { } } - protected void render(StringBuilder sb, int indent, String atKey) { + protected void render(StringBuilder sb, int indent, String atKey, boolean formatted) { if (atKey != null) { sb.append(ConfigUtil.renderJsonString(atKey)); sb.append(" : "); } - render(sb, indent); + render(sb, indent, formatted); } - protected void render(StringBuilder sb, int indent) { + protected void render(StringBuilder sb, int indent, boolean formatted) { Object u = unwrapped(); sb.append(u.toString()); } @@ -191,7 +193,7 @@ abstract class AbstractConfigValue implements ConfigValue { @Override public final String render() { StringBuilder sb = new StringBuilder(); - render(sb, 0, null); + render(sb, 0, null, true /* formatted */); return sb.toString(); } diff --git a/src/main/java/com/typesafe/config/impl/ConfigDelayedMerge.java b/src/main/java/com/typesafe/config/impl/ConfigDelayedMerge.java index 5622772b..4c7d66da 100644 --- a/src/main/java/com/typesafe/config/impl/ConfigDelayedMerge.java +++ b/src/main/java/com/typesafe/config/impl/ConfigDelayedMerge.java @@ -161,17 +161,20 @@ final class ConfigDelayedMerge extends AbstractConfigValue implements } @Override - protected void render(StringBuilder sb, int indent, String atKey) { - render(stack, sb, indent, atKey); + protected void render(StringBuilder sb, int indent, String atKey, boolean formatted) { + render(stack, sb, indent, atKey, formatted); } // static method also used by ConfigDelayedMergeObject. - static void render(List<AbstractConfigValue> stack, StringBuilder sb, int indent, String atKey) { - sb.append("# unresolved merge of " + stack.size() + " values follows (\n"); - if (atKey == null) { - indent(sb, indent); - sb.append("# this unresolved merge will not be parseable because it's at the root of the object\n"); - sb.append("# the HOCON format has no way to list multiple root objects in a single file\n"); + static void render(List<AbstractConfigValue> stack, StringBuilder sb, int indent, String atKey, + boolean formatted) { + if (formatted) { + sb.append("# unresolved merge of " + stack.size() + " values follows (\n"); + if (atKey == null) { + indent(sb, indent); + sb.append("# this unresolved merge will not be parseable because it's at the root of the object\n"); + sb.append("# the HOCON format has no way to list multiple root objects in a single file\n"); + } } List<AbstractConfigValue> reversed = new ArrayList<AbstractConfigValue>(); @@ -180,27 +183,36 @@ final class ConfigDelayedMerge extends AbstractConfigValue implements int i = 0; for (AbstractConfigValue v : reversed) { - indent(sb, indent); - if (atKey != null) { - sb.append("# unmerged value " + i + " for key " - + ConfigUtil.renderJsonString(atKey) + " from "); - } else { - sb.append("# unmerged value " + i + " from "); + if (formatted) { + indent(sb, indent); + if (atKey != null) { + sb.append("# unmerged value " + i + " for key " + + ConfigUtil.renderJsonString(atKey) + " from "); + } else { + sb.append("# unmerged value " + i + " from "); + } + i += 1; + sb.append(v.origin().description()); + sb.append("\n"); + indent(sb, indent); } - i += 1; - sb.append(v.origin().description()); - sb.append("\n"); - indent(sb, indent); + if (atKey != null) { sb.append(ConfigUtil.renderJsonString(atKey)); sb.append(" : "); } - v.render(sb, indent); - sb.append(",\n"); + v.render(sb, indent, formatted); + sb.append(","); + if (formatted) + sb.append('\n'); + } + // chop comma or newline + sb.setLength(sb.length() - 1); + if (formatted) { + sb.setLength(sb.length() - 1); // also chop comma + sb.append("\n"); // put a newline back + indent(sb, indent); + sb.append("# ) end of unresolved merge\n"); } - sb.setLength(sb.length() - 2); // chop comma and newline - sb.append("\n"); - indent(sb, indent); - sb.append("# ) end of unresolved merge\n"); } } diff --git a/src/main/java/com/typesafe/config/impl/ConfigDelayedMergeObject.java b/src/main/java/com/typesafe/config/impl/ConfigDelayedMergeObject.java index 741cce17..5669f62f 100644 --- a/src/main/java/com/typesafe/config/impl/ConfigDelayedMergeObject.java +++ b/src/main/java/com/typesafe/config/impl/ConfigDelayedMergeObject.java @@ -139,8 +139,8 @@ class ConfigDelayedMergeObject extends AbstractConfigObject implements } @Override - protected void render(StringBuilder sb, int indent, String atKey) { - ConfigDelayedMerge.render(stack, sb, indent, atKey); + protected void render(StringBuilder sb, int indent, String atKey, boolean formatted) { + ConfigDelayedMerge.render(stack, sb, indent, atKey, formatted); } private static ConfigException notResolved() { diff --git a/src/main/java/com/typesafe/config/impl/ConfigNull.java b/src/main/java/com/typesafe/config/impl/ConfigNull.java index 0c23cb5d..a45d2dbc 100644 --- a/src/main/java/com/typesafe/config/impl/ConfigNull.java +++ b/src/main/java/com/typesafe/config/impl/ConfigNull.java @@ -36,7 +36,7 @@ final class ConfigNull extends AbstractConfigValue { } @Override - protected void render(StringBuilder sb, int indent) { + protected void render(StringBuilder sb, int indent, boolean formatted) { sb.append("null"); } } diff --git a/src/main/java/com/typesafe/config/impl/ConfigString.java b/src/main/java/com/typesafe/config/impl/ConfigString.java index 4a8e2d02..dd8a5fa3 100644 --- a/src/main/java/com/typesafe/config/impl/ConfigString.java +++ b/src/main/java/com/typesafe/config/impl/ConfigString.java @@ -31,7 +31,7 @@ final class ConfigString extends AbstractConfigValue { } @Override - protected void render(StringBuilder sb, int indent) { + protected void render(StringBuilder sb, int indent, boolean formatted) { sb.append(ConfigUtil.renderJsonString(value)); } } diff --git a/src/main/java/com/typesafe/config/impl/ConfigSubstitution.java b/src/main/java/com/typesafe/config/impl/ConfigSubstitution.java index f21f0a10..89118076 100644 --- a/src/main/java/com/typesafe/config/impl/ConfigSubstitution.java +++ b/src/main/java/com/typesafe/config/impl/ConfigSubstitution.java @@ -244,7 +244,7 @@ final class ConfigSubstitution extends AbstractConfigValue implements } @Override - protected void render(StringBuilder sb, int indent) { + protected void render(StringBuilder sb, int indent, boolean formatted) { for (Object p : pieces) { if (p instanceof Path) { sb.append("${"); diff --git a/src/main/java/com/typesafe/config/impl/SimpleConfigList.java b/src/main/java/com/typesafe/config/impl/SimpleConfigList.java index 94a649a4..76d99637 100644 --- a/src/main/java/com/typesafe/config/impl/SimpleConfigList.java +++ b/src/main/java/com/typesafe/config/impl/SimpleConfigList.java @@ -135,24 +135,32 @@ final class SimpleConfigList extends AbstractConfigValue implements ConfigList { } @Override - protected void render(StringBuilder sb, int indent) { + protected void render(StringBuilder sb, int indent, boolean formatted) { if (value.isEmpty()) { sb.append("[]"); } else { - sb.append("[\n"); + sb.append("["); + if (formatted) + sb.append('\n'); for (AbstractConfigValue v : value) { - indent(sb, indent + 1); - sb.append("# "); - sb.append(v.origin().description()); - sb.append("\n"); - indent(sb, indent + 1); - v.render(sb, indent + 1); - sb.append(",\n"); + if (formatted) { + indent(sb, indent + 1); + sb.append("# "); + sb.append(v.origin().description()); + sb.append("\n"); + indent(sb, indent + 1); + } + v.render(sb, indent + 1, formatted); + sb.append(","); + if (formatted) + sb.append('\n'); + } + sb.setLength(sb.length() - 1); // chop or newline + if (formatted) { + sb.setLength(sb.length() - 1); // also chop comma + sb.append('\n'); + indent(sb, indent); } - sb.setLength(sb.length() - 2); // chop comma and newline - sb.append("\n"); - - indent(sb, indent); sb.append("]"); } } diff --git a/src/test/scala/Rendering.scala b/src/test/scala/Rendering.scala index d121e5ea..310c3bab 100644 --- a/src/test/scala/Rendering.scala +++ b/src/test/scala/Rendering.scala @@ -11,6 +11,10 @@ object RenderExample extends App { println("=== BEGIN RESOLVED " + what) println(conf.resolve().root.render()) println("=== END RESOLVED " + what) + + println("=== BEGIN UNRESOLVED toString() " + what) + println(conf.root.toString()) + println("=== END UNRESOLVED toString() " + what) } render("test01")