From a0f2e49a85782603cbae8d1310d5d152be56b53b Mon Sep 17 00:00:00 2001 From: Wu Zhenwei Date: Sat, 24 Jan 2015 21:44:37 +0800 Subject: [PATCH 1/3] Add methods to create and set origin. --- .../java/com/typesafe/config/ConfigList.java | 2 + .../com/typesafe/config/ConfigObject.java | 3 + .../com/typesafe/config/ConfigOrigin.java | 32 ++++++++++ .../typesafe/config/ConfigOriginFactory.java | 59 +++++++++++++++++++ .../java/com/typesafe/config/ConfigValue.java | 9 +++ .../config/impl/AbstractConfigObject.java | 6 +- .../config/impl/AbstractConfigValue.java | 1 + .../com/typesafe/config/impl/ConfigImpl.java | 21 +++++++ .../config/impl/SimpleConfigList.java | 5 ++ .../config/impl/SimpleConfigOrigin.java | 14 +++++ 10 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 config/src/main/java/com/typesafe/config/ConfigOriginFactory.java diff --git a/config/src/main/java/com/typesafe/config/ConfigList.java b/config/src/main/java/com/typesafe/config/ConfigList.java index 5c694a50..01eca152 100644 --- a/config/src/main/java/com/typesafe/config/ConfigList.java +++ b/config/src/main/java/com/typesafe/config/ConfigList.java @@ -41,4 +41,6 @@ public interface ConfigList extends List, ConfigValue { @Override List unwrapped(); + @Override + ConfigList withOrigin(ConfigOrigin origin); } diff --git a/config/src/main/java/com/typesafe/config/ConfigObject.java b/config/src/main/java/com/typesafe/config/ConfigObject.java index 76414edc..84583c79 100644 --- a/config/src/main/java/com/typesafe/config/ConfigObject.java +++ b/config/src/main/java/com/typesafe/config/ConfigObject.java @@ -129,4 +129,7 @@ public interface ConfigObject extends ConfigValue, Map { * @return the new instance with the new map entry */ ConfigObject withValue(String key, ConfigValue value); + + @Override + ConfigObject withOrigin(ConfigOrigin origin); } diff --git a/config/src/main/java/com/typesafe/config/ConfigOrigin.java b/config/src/main/java/com/typesafe/config/ConfigOrigin.java index c34767fb..bc23898f 100644 --- a/config/src/main/java/com/typesafe/config/ConfigOrigin.java +++ b/config/src/main/java/com/typesafe/config/ConfigOrigin.java @@ -79,4 +79,36 @@ public interface ConfigOrigin { * none */ public List comments(); + + /** + * Returns a {@code ConfigOrigin} based on this one, but with the given + * comments. Does not modify this instance or any {@code ConfigValue}s with + * this origin (since they are immutable). To set the returned origin to a + * {@code ConfigValue}, use {@link ConfigValue#withOrigin}. + * + *

+ * Note that when the given comments are equal to the comments on this object, + * a new instance may not be created and {@code this} is returned directly. + * + * @param comments the comments used on the returned origin + * @return the ConfigOrigin with the given comments + */ + public ConfigOrigin withComments(List comments); + + /** + * Returns a {@code ConfigOrigin} based on this one, but with the given + * line number. This origin must be a FILE, URL or RESOURCE. Does not modify + * this instance or any {@code ConfigValue}s with this origin (since they are + * immutable). To set the returned origin to a {@code ConfigValue}, use + * {@link ConfigValue#withOrigin}. + * + *

+ * Note that when the given lineNumber are equal to the lineNumber on this + * object, a new instance may not be created and {@code this} is returned + * directly. + * + * @param comments the comments used on the returned origin + * @return the created ConfigOrigin + */ + public ConfigOrigin withLineNumber(int lineNumber); } diff --git a/config/src/main/java/com/typesafe/config/ConfigOriginFactory.java b/config/src/main/java/com/typesafe/config/ConfigOriginFactory.java new file mode 100644 index 00000000..86004f6e --- /dev/null +++ b/config/src/main/java/com/typesafe/config/ConfigOriginFactory.java @@ -0,0 +1,59 @@ +package com.typesafe.config; + +import java.net.URL; + +import com.typesafe.config.impl.ConfigImpl; + +/** + * This class contains some static factory methods for building a {@link + * ConfigOrigin}. {@code ConfigOrigin}s are automatically created when you + * call other API methods to get a {@code ConfigValue} or {@code Config}. + * But you can also set the origin of an existing {@code ConfigValue}, using + * {@link ConfigValue#withOrigin(ConfigOrigin)}. + * + */ +public final class ConfigOriginFactory { + private ConfigOriginFactory() { + } + + /** + * Returns the default origin for values when no other information is + * provided. This is the origin used in {@link ConfigValueFactory + * #fromAnyRef(Object)}. + * + * @return the default origin + */ + public static ConfigOrigin newSimple() { + return newSimple(null); + } + + /** + * Returns a origin with the given description. + * + * @param description brief description of what the origin is + * @return + */ + public static ConfigOrigin newSimple(String description) { + return ConfigImpl.newSimpleOrigin(description); + } + + /** + * Creates a file origin with the given filename. + * + * @param filename the filename of this origin + * @return + */ + public static ConfigOrigin newFile(String filename) { + return ConfigImpl.newFileOrigin(filename); + } + + /** + * Creates a url origin with the given URL object. + * + * @param url the url of this origin + * @return + */ + public static ConfigOrigin newURL(URL url) { + return ConfigImpl.newURLOrigin(url); + } +} diff --git a/config/src/main/java/com/typesafe/config/ConfigValue.java b/config/src/main/java/com/typesafe/config/ConfigValue.java index 35c40b8b..b5dc2411 100644 --- a/config/src/main/java/com/typesafe/config/ConfigValue.java +++ b/config/src/main/java/com/typesafe/config/ConfigValue.java @@ -106,4 +106,13 @@ public interface ConfigValue extends ConfigMergeable { * @return a {@code Config} instance containing this value at the given key. */ Config atKey(String key); + + /** + * Returns a new {@code ConfigValue} based on this one, but with the given + * origin. This is useful when you are parsing a new format of file or setting + * comments for a single ConfigValue. + * @param origin the origin set on the returned value + * @return the new ConfigValue with the given origin + */ + ConfigValue withOrigin(ConfigOrigin origin); } diff --git a/config/src/main/java/com/typesafe/config/impl/AbstractConfigObject.java b/config/src/main/java/com/typesafe/config/impl/AbstractConfigObject.java index a6863672..a98515de 100644 --- a/config/src/main/java/com/typesafe/config/impl/AbstractConfigObject.java +++ b/config/src/main/java/com/typesafe/config/impl/AbstractConfigObject.java @@ -18,7 +18,6 @@ import com.typesafe.config.ConfigValue; import com.typesafe.config.ConfigValueType; abstract class AbstractConfigObject extends AbstractConfigValue implements ConfigObject, Container { - final private SimpleConfig config; protected AbstractConfigObject(ConfigOrigin origin) { @@ -214,4 +213,9 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements Confi public ConfigValue remove(Object arg0) { throw weAreImmutable("remove"); } + + @Override + public AbstractConfigObject withOrigin(ConfigOrigin origin) { + return (AbstractConfigObject) super.withOrigin(origin); + } } diff --git a/config/src/main/java/com/typesafe/config/impl/AbstractConfigValue.java b/config/src/main/java/com/typesafe/config/impl/AbstractConfigValue.java index 0720417e..4c3dd5b2 100644 --- a/config/src/main/java/com/typesafe/config/impl/AbstractConfigValue.java +++ b/config/src/main/java/com/typesafe/config/impl/AbstractConfigValue.java @@ -257,6 +257,7 @@ abstract class AbstractConfigValue implements ConfigValue, MergeableValue { return mergedWithNonObject(Collections.singletonList(this), fallback); } + @Override public AbstractConfigValue withOrigin(ConfigOrigin origin) { if (this.origin == origin) return this; diff --git a/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java b/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java index d06b2c34..332a754d 100644 --- a/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java +++ b/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java @@ -5,6 +5,7 @@ package com.typesafe.config.impl; import java.io.File; import java.lang.ref.WeakReference; +import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -461,4 +462,24 @@ public class ConfigImpl { else return new ConfigException.NotResolved(newMessage, original); } + + /** For use ONLY by library internals, DO NOT TOUCH not guaranteed ABI */ + public static ConfigOrigin newSimpleOrigin(String description) { + if (description == null) { + return defaultValueOrigin; + } else { + return SimpleConfigOrigin.newSimple(description); + } + } + + /** For use ONLY by library internals, DO NOT TOUCH not guaranteed ABI */ + public static ConfigOrigin newFileOrigin(String filename) { + return SimpleConfigOrigin.newFile(filename); + } + + /** For use ONLY by library internals, DO NOT TOUCH not guaranteed ABI */ + public static ConfigOrigin newURLOrigin(URL url) { + return SimpleConfigOrigin.newURL(url); + } + } diff --git a/config/src/main/java/com/typesafe/config/impl/SimpleConfigList.java b/config/src/main/java/com/typesafe/config/impl/SimpleConfigList.java index 49387177..57ea7af0 100644 --- a/config/src/main/java/com/typesafe/config/impl/SimpleConfigList.java +++ b/config/src/main/java/com/typesafe/config/impl/SimpleConfigList.java @@ -451,4 +451,9 @@ final class SimpleConfigList extends AbstractConfigValue implements ConfigList, private Object writeReplace() throws ObjectStreamException { return new SerializedConfigValue(this); } + + @Override + public SimpleConfigList withOrigin(ConfigOrigin origin) { + return (SimpleConfigList) super.withOrigin(origin); + } } diff --git a/config/src/main/java/com/typesafe/config/impl/SimpleConfigOrigin.java b/config/src/main/java/com/typesafe/config/impl/SimpleConfigOrigin.java index 25bbae3e..6e275d34 100644 --- a/config/src/main/java/com/typesafe/config/impl/SimpleConfigOrigin.java +++ b/config/src/main/java/com/typesafe/config/impl/SimpleConfigOrigin.java @@ -550,4 +550,18 @@ final class SimpleConfigOrigin implements ConfigOrigin { Map fields = applyFieldsDelta(baseFields, delta); return fromFields(fields); } + + @Override + public ConfigOrigin withComments(List comments) { + return this.setComments(comments); + } + + @Override + public ConfigOrigin withLineNumber(int lineNumber) { + if (this.originType == OriginType.GENERIC) { + //This type should not have a lineNumber. + throw new UnsupportedOperationException(); + } + return this.setLineNumber(lineNumber); + } } From 4a8e1023a3c7dd540cbece4796b279ec7bb643a9 Mon Sep 17 00:00:00 2001 From: Wu Zhenwei Date: Sun, 25 Jan 2015 12:33:52 +0800 Subject: [PATCH 2/3] Rename set functions to with. --- .../java/com/typesafe/config/ConfigValue.java | 5 ++-- .../java/com/typesafe/config/impl/Parser.java | 6 ++-- .../config/impl/SimpleConfigOrigin.java | 28 ++++++------------- .../com/typesafe/config/impl/Tokenizer.java | 8 +++--- 4 files changed, 18 insertions(+), 29 deletions(-) diff --git a/config/src/main/java/com/typesafe/config/ConfigValue.java b/config/src/main/java/com/typesafe/config/ConfigValue.java index b5dc2411..795454cd 100644 --- a/config/src/main/java/com/typesafe/config/ConfigValue.java +++ b/config/src/main/java/com/typesafe/config/ConfigValue.java @@ -108,9 +108,10 @@ public interface ConfigValue extends ConfigMergeable { Config atKey(String key); /** - * Returns a new {@code ConfigValue} based on this one, but with the given - * origin. This is useful when you are parsing a new format of file or setting + * Returns a {@code ConfigValue} based on this one, but with the given + * origin. This is useful when you are parsing a new format of file or setting * comments for a single ConfigValue. + * * @param origin the origin set on the returned value * @return the new ConfigValue with the given origin */ diff --git a/config/src/main/java/com/typesafe/config/impl/Parser.java b/config/src/main/java/com/typesafe/config/impl/Parser.java index 221ae9e7..8f9b4735 100644 --- a/config/src/main/java/com/typesafe/config/impl/Parser.java +++ b/config/src/main/java/com/typesafe/config/impl/Parser.java @@ -424,7 +424,7 @@ final class Parser { } private SimpleConfigOrigin lineOrigin() { - return ((SimpleConfigOrigin) baseOrigin).setLineNumber(lineNumber); + return ((SimpleConfigOrigin) baseOrigin).withLineNumber(lineNumber); } private ConfigException parseError(String message) { @@ -559,13 +559,13 @@ final class Parser { // "foo.bar" not also to "foo" ListIterator i = keys.listIterator(keys.size()); String deepest = i.previous(); - AbstractConfigObject o = new SimpleConfigObject(value.origin().setComments(null), + AbstractConfigObject o = new SimpleConfigObject(value.origin().withComments(null), Collections. singletonMap( deepest, value)); while (i.hasPrevious()) { Map m = Collections. singletonMap( i.previous(), o); - o = new SimpleConfigObject(value.origin().setComments(null), m); + o = new SimpleConfigObject(value.origin().withComments(null), m); } return o; diff --git a/config/src/main/java/com/typesafe/config/impl/SimpleConfigOrigin.java b/config/src/main/java/com/typesafe/config/impl/SimpleConfigOrigin.java index 6e275d34..5e39077e 100644 --- a/config/src/main/java/com/typesafe/config/impl/SimpleConfigOrigin.java +++ b/config/src/main/java/com/typesafe/config/impl/SimpleConfigOrigin.java @@ -70,7 +70,8 @@ final class SimpleConfigOrigin implements ConfigOrigin { return newResource(resource, null); } - SimpleConfigOrigin setLineNumber(int lineNumber) { + @Override + public SimpleConfigOrigin withLineNumber(int lineNumber) { if (lineNumber == this.lineNumber && lineNumber == this.endLineNumber) { return this; } else { @@ -84,7 +85,8 @@ final class SimpleConfigOrigin implements ConfigOrigin { this.originType, url != null ? url.toExternalForm() : null, this.commentsOrNull); } - SimpleConfigOrigin setComments(List comments) { + @Override + public SimpleConfigOrigin withComments(List comments) { if (ConfigImplUtil.equalsHandlingNull(comments, this.commentsOrNull)) { return this; } else { @@ -97,13 +99,13 @@ final class SimpleConfigOrigin implements ConfigOrigin { if (ConfigImplUtil.equalsHandlingNull(comments, this.commentsOrNull) || comments == null) { return this; } else if (this.commentsOrNull == null) { - return setComments(comments); + return withComments(comments); } else { List merged = new ArrayList(comments.size() + this.commentsOrNull.size()); merged.addAll(comments); merged.addAll(this.commentsOrNull); - return setComments(merged); + return withComments(merged); } } @@ -111,13 +113,13 @@ final class SimpleConfigOrigin implements ConfigOrigin { if (ConfigImplUtil.equalsHandlingNull(comments, this.commentsOrNull) || comments == null) { return this; } else if (this.commentsOrNull == null) { - return setComments(comments); + return withComments(comments); } else { List merged = new ArrayList(comments.size() + this.commentsOrNull.size()); merged.addAll(this.commentsOrNull); merged.addAll(comments); - return setComments(merged); + return withComments(merged); } } @@ -550,18 +552,4 @@ final class SimpleConfigOrigin implements ConfigOrigin { Map fields = applyFieldsDelta(baseFields, delta); return fromFields(fields); } - - @Override - public ConfigOrigin withComments(List comments) { - return this.setComments(comments); - } - - @Override - public ConfigOrigin withLineNumber(int lineNumber) { - if (this.originType == OriginType.GENERIC) { - //This type should not have a lineNumber. - throw new UnsupportedOperationException(); - } - return this.setLineNumber(lineNumber); - } } diff --git a/config/src/main/java/com/typesafe/config/impl/Tokenizer.java b/config/src/main/java/com/typesafe/config/impl/Tokenizer.java index 03460ed7..d8701f93 100644 --- a/config/src/main/java/com/typesafe/config/impl/Tokenizer.java +++ b/config/src/main/java/com/typesafe/config/impl/Tokenizer.java @@ -128,7 +128,7 @@ final class Tokenizer { this.allowComments = allowComments; this.buffer = new LinkedList(); lineNumber = 1; - lineOrigin = this.origin.setLineNumber(lineNumber); + lineOrigin = this.origin.withLineNumber(lineNumber); tokens = new LinkedList(); tokens.add(Tokens.START); whitespaceSaver = new WhitespaceSaver(); @@ -254,7 +254,7 @@ final class Tokenizer { private static ConfigOrigin lineOrigin(ConfigOrigin baseOrigin, int lineNumber) { - return ((SimpleConfigOrigin) baseOrigin).setLineNumber(lineNumber); + return ((SimpleConfigOrigin) baseOrigin).withLineNumber(lineNumber); } // ONE char has always been consumed, either the # or the first /, but @@ -446,7 +446,7 @@ final class Tokenizer { else if (c == '\n') { // keep the line number accurate lineNumber += 1; - lineOrigin = origin.setLineNumber(lineNumber); + lineOrigin = origin.withLineNumber(lineNumber); } } @@ -549,7 +549,7 @@ final class Tokenizer { // newline tokens have the just-ended line number Token line = Tokens.newLine(lineOrigin); lineNumber += 1; - lineOrigin = origin.setLineNumber(lineNumber); + lineOrigin = origin.withLineNumber(lineNumber); return line; } else { Token t; From 7c91260a709ce2e159f9853d9f947be4ef244bc1 Mon Sep 17 00:00:00 2001 From: Wu Zhenwei Date: Sun, 25 Jan 2015 12:46:01 +0800 Subject: [PATCH 3/3] Fix function name in scala and comments. --- .../main/java/com/typesafe/config/impl/Parser.java | 2 +- .../com/typesafe/config/impl/ConfigValueTest.scala | 12 ++++++------ .../com/typesafe/config/impl/PublicApiTest.scala | 2 +- .../scala/com/typesafe/config/impl/TestUtils.scala | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/config/src/main/java/com/typesafe/config/impl/Parser.java b/config/src/main/java/com/typesafe/config/impl/Parser.java index 8f9b4735..7d1d301c 100644 --- a/config/src/main/java/com/typesafe/config/impl/Parser.java +++ b/config/src/main/java/com/typesafe/config/impl/Parser.java @@ -553,7 +553,7 @@ final class Parser { } } - // the setComments(null) is to ensure comments are only + // the withComments(null) is to ensure comments are only // on the exact leaf node they apply to. // a comment before "foo.bar" applies to the full setting // "foo.bar" not also to "foo" diff --git a/config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala b/config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala index df2aecec..e4a40d09 100644 --- a/config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala +++ b/config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala @@ -663,8 +663,8 @@ class ConfigValueTest extends TestUtils { def configOriginFileAndLine() { val hasFilename = SimpleConfigOrigin.newFile("foo") val noFilename = SimpleConfigOrigin.newSimple("bar") - val filenameWithLine = hasFilename.setLineNumber(3) - val noFilenameWithLine = noFilename.setLineNumber(4) + val filenameWithLine = hasFilename.withLineNumber(3) + val noFilenameWithLine = noFilename.withLineNumber(4) assertEquals("foo", hasFilename.filename()) assertEquals("foo", filenameWithLine.filename()) @@ -866,10 +866,10 @@ class ConfigValueTest extends TestUtils { val combos = bases.flatMap({ base => Seq( - (base, base.setComments(Seq("this is a comment", "another one").asJava)), - (base, base.setComments(null)), - (base, base.setLineNumber(41)), - (base, SimpleConfigOrigin.mergeOrigins(base.setLineNumber(10), base.setLineNumber(20)))) + (base, base.withComments(Seq("this is a comment", "another one").asJava)), + (base, base.withComments(null)), + (base, base.withLineNumber(41)), + (base, SimpleConfigOrigin.mergeOrigins(base.withLineNumber(10), base.withLineNumber(20)))) }) ++ bases.sliding(2).map({ seq => (seq.head, seq.tail.head) }) ++ bases.sliding(3).map({ seq => (seq.head, seq.tail.tail.head) }) ++ diff --git a/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala b/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala index 2e4e2624..7c9cd48e 100644 --- a/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala +++ b/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala @@ -888,7 +888,7 @@ class PublicApiTest extends TestUtils { def exceptionSerializable() { // ArrayList is a serialization problem so we want to cover it in tests val comments = new java.util.ArrayList(List("comment 1", "comment 2").asJava) - val e = new ConfigException.WrongType(SimpleConfigOrigin.newSimple("an origin").setComments(comments), + val e = new ConfigException.WrongType(SimpleConfigOrigin.newSimple("an origin").withComments(comments), "this is a message", new RuntimeException("this is a cause")) val eCopy = checkSerializableNoMeaningfulEquals(e) assertTrue("messages equal after deserialize", e.getMessage.equals(eCopy.getMessage)) diff --git a/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala b/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala index ef49c167..a444e72c 100644 --- a/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala +++ b/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala @@ -614,7 +614,7 @@ abstract trait TestUtils { def tokenDouble(d: Double) = Tokens.newDouble(fakeOrigin(), d, null) def tokenInt(i: Int) = Tokens.newInt(fakeOrigin(), i, null) def tokenLong(l: Long) = Tokens.newLong(fakeOrigin(), l, null) - def tokenLine(line: Int) = Tokens.newLine(fakeOrigin.setLineNumber(line)) + def tokenLine(line: Int) = Tokens.newLine(fakeOrigin.withLineNumber(line)) def tokenComment(text: String) = Tokens.newComment(fakeOrigin(), text) private def tokenMaybeOptionalSubstitution(optional: Boolean, expression: Token*) = {