mirror of
https://github.com/lightbend/config.git
synced 2025-01-15 23:01:05 +08:00
Merge pull request #243 from acaly/set_origin
Add methods to create and set origin.
This commit is contained in:
commit
ce394080a1
@ -41,4 +41,6 @@ public interface ConfigList extends List<ConfigValue>, ConfigValue {
|
||||
@Override
|
||||
List<Object> unwrapped();
|
||||
|
||||
@Override
|
||||
ConfigList withOrigin(ConfigOrigin origin);
|
||||
}
|
||||
|
@ -129,4 +129,7 @@ public interface ConfigObject extends ConfigValue, Map<String, ConfigValue> {
|
||||
* @return the new instance with the new map entry
|
||||
*/
|
||||
ConfigObject withValue(String key, ConfigValue value);
|
||||
|
||||
@Override
|
||||
ConfigObject withOrigin(ConfigOrigin origin);
|
||||
}
|
||||
|
@ -79,4 +79,36 @@ public interface ConfigOrigin {
|
||||
* none
|
||||
*/
|
||||
public List<String> 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}.
|
||||
*
|
||||
* <p>
|
||||
* 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<String> 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}.
|
||||
*
|
||||
* <p>
|
||||
* 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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -106,4 +106,14 @@ public interface ConfigValue extends ConfigMergeable {
|
||||
* @return a {@code Config} instance containing this value at the given key.
|
||||
*/
|
||||
Config atKey(String key);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
ConfigValue withOrigin(ConfigOrigin origin);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
@ -553,19 +553,19 @@ 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"
|
||||
ListIterator<String> 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.<String, AbstractConfigValue> singletonMap(
|
||||
deepest, value));
|
||||
while (i.hasPrevious()) {
|
||||
Map<String, AbstractConfigValue> m = Collections.<String, AbstractConfigValue> singletonMap(
|
||||
i.previous(), o);
|
||||
o = new SimpleConfigObject(value.origin().setComments(null), m);
|
||||
o = new SimpleConfigObject(value.origin().withComments(null), m);
|
||||
}
|
||||
|
||||
return o;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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<String> comments) {
|
||||
@Override
|
||||
public SimpleConfigOrigin withComments(List<String> 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<String> merged = new ArrayList<String>(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<String> merged = new ArrayList<String>(comments.size()
|
||||
+ this.commentsOrNull.size());
|
||||
merged.addAll(this.commentsOrNull);
|
||||
merged.addAll(comments);
|
||||
return setComments(merged);
|
||||
return withComments(merged);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ final class Tokenizer {
|
||||
this.allowComments = allowComments;
|
||||
this.buffer = new LinkedList<Integer>();
|
||||
lineNumber = 1;
|
||||
lineOrigin = this.origin.setLineNumber(lineNumber);
|
||||
lineOrigin = this.origin.withLineNumber(lineNumber);
|
||||
tokens = new LinkedList<Token>();
|
||||
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;
|
||||
|
@ -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) }) ++
|
||||
|
@ -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))
|
||||
|
@ -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*) = {
|
||||
|
Loading…
Reference in New Issue
Block a user