mirror of
https://github.com/lightbend/config.git
synced 2025-01-15 23:01:05 +08:00
Properly track resource file origins
This improves error messages to fix #254.
This commit is contained in:
parent
55bd472c24
commit
a528bf104a
@ -45,6 +45,11 @@ public abstract class Parseable implements ConfigParseable {
|
|||||||
private ConfigParseOptions initialOptions;
|
private ConfigParseOptions initialOptions;
|
||||||
private ConfigOrigin initialOrigin;
|
private ConfigOrigin initialOrigin;
|
||||||
|
|
||||||
|
|
||||||
|
protected interface Relativizer {
|
||||||
|
ConfigParseable relativeTo(String filename);
|
||||||
|
}
|
||||||
|
|
||||||
private static final ThreadLocal<LinkedList<Parseable>> parseStack = new ThreadLocal<LinkedList<Parseable>>() {
|
private static final ThreadLocal<LinkedList<Parseable>> parseStack = new ThreadLocal<LinkedList<Parseable>>() {
|
||||||
@Override
|
@Override
|
||||||
protected LinkedList<Parseable> initialValue() {
|
protected LinkedList<Parseable> initialValue() {
|
||||||
@ -213,7 +218,7 @@ public abstract class Parseable implements ConfigParseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AbstractConfigValue rawParseValue(Reader reader, ConfigOrigin origin,
|
private AbstractConfigValue rawParseValue(Reader reader, ConfigOrigin origin,
|
||||||
ConfigParseOptions finalOptions) throws IOException {
|
ConfigParseOptions finalOptions) throws IOException {
|
||||||
if (finalOptions.getSyntax() == ConfigSyntax.PROPERTIES) {
|
if (finalOptions.getSyntax() == ConfigSyntax.PROPERTIES) {
|
||||||
return PropertiesParser.parse(reader, origin);
|
return PropertiesParser.parse(reader, origin);
|
||||||
@ -412,12 +417,17 @@ public abstract class Parseable implements ConfigParseable {
|
|||||||
return new ParseableString(input, options);
|
return new ParseableString(input, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static class ParseableURL extends Parseable {
|
private static class ParseableURL extends Parseable {
|
||||||
final private URL input;
|
final protected URL input;
|
||||||
private String contentType = null;
|
private String contentType = null;
|
||||||
|
|
||||||
ParseableURL(URL input, ConfigParseOptions options) {
|
protected ParseableURL(URL input) {
|
||||||
this.input = input;
|
this.input = input;
|
||||||
|
// does not postConstruct (subclass does it)
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseableURL(URL input, ConfigParseOptions options) {
|
||||||
|
this(input);
|
||||||
postConstruct(options);
|
postConstruct(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -551,7 +561,35 @@ public abstract class Parseable implements ConfigParseable {
|
|||||||
return new ParseableFile(input, options);
|
return new ParseableFile(input, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static class ParseableResources extends Parseable {
|
|
||||||
|
private final static class ParseableResourceURL extends ParseableURL {
|
||||||
|
|
||||||
|
private final Relativizer relativizer;
|
||||||
|
private final String resource;
|
||||||
|
|
||||||
|
ParseableResourceURL(URL input, ConfigParseOptions options, String resource, Relativizer relativizer) {
|
||||||
|
super(input);
|
||||||
|
this.relativizer = relativizer;
|
||||||
|
this.resource = resource;
|
||||||
|
postConstruct(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ConfigOrigin createOrigin() {
|
||||||
|
return SimpleConfigOrigin.newResource(resource, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
ConfigParseable relativeTo(String filename) {
|
||||||
|
return relativizer.relativeTo(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Parseable newResourceURL(URL input, ConfigParseOptions options, String resource, Relativizer relativizer) {
|
||||||
|
return new ParseableResourceURL(input, options, resource, relativizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static class ParseableResources extends Parseable implements Relativizer {
|
||||||
final private String resource;
|
final private String resource;
|
||||||
|
|
||||||
ParseableResources(String resource, ConfigParseOptions options) {
|
ParseableResources(String resource, ConfigParseOptions options) {
|
||||||
@ -583,31 +621,12 @@ public abstract class Parseable implements ConfigParseable {
|
|||||||
URL url = e.nextElement();
|
URL url = e.nextElement();
|
||||||
|
|
||||||
if (ConfigImpl.traceLoadsEnabled())
|
if (ConfigImpl.traceLoadsEnabled())
|
||||||
trace("Loading config from URL " + url.toExternalForm() + " from class loader "
|
trace("Loading config from resource '" + resource + "' URL " + url.toExternalForm() + " from class loader "
|
||||||
+ loader);
|
+ loader);
|
||||||
|
|
||||||
ConfigOrigin elementOrigin = ((SimpleConfigOrigin) origin).addURL(url);
|
Parseable element = newResourceURL(url, finalOptions, resource, this);
|
||||||
|
|
||||||
AbstractConfigValue v;
|
AbstractConfigValue v = element.parseValue();
|
||||||
|
|
||||||
// it's tempting to use ParseableURL here but it would be wrong
|
|
||||||
// because the wrong relativeTo() would be used for includes.
|
|
||||||
InputStream stream = url.openStream();
|
|
||||||
try {
|
|
||||||
Reader reader = readerFromStream(stream);
|
|
||||||
stream = null; // reader now owns it
|
|
||||||
try {
|
|
||||||
// parse in "raw" mode which will throw any IOException
|
|
||||||
// from here.
|
|
||||||
v = rawParseValue(reader, elementOrigin, finalOptions);
|
|
||||||
} finally {
|
|
||||||
reader.close();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
// stream is null if the reader owns it
|
|
||||||
if (stream != null)
|
|
||||||
stream.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
merged = merged.withFallback(v);
|
merged = merged.withFallback(v);
|
||||||
}
|
}
|
||||||
@ -634,7 +653,7 @@ public abstract class Parseable implements ConfigParseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
ConfigParseable relativeTo(String sibling) {
|
public ConfigParseable relativeTo(String sibling) {
|
||||||
if (sibling.startsWith("/")) {
|
if (sibling.startsWith("/")) {
|
||||||
// if it starts with "/" then don't make it relative to
|
// if it starts with "/" then don't make it relative to
|
||||||
// the including resource
|
// the including resource
|
||||||
|
@ -65,7 +65,9 @@ class SerializedConfigValue extends AbstractConfigValue implements Externalizabl
|
|||||||
ORIGIN_URL,
|
ORIGIN_URL,
|
||||||
ORIGIN_COMMENTS,
|
ORIGIN_COMMENTS,
|
||||||
ORIGIN_NULL_URL,
|
ORIGIN_NULL_URL,
|
||||||
ORIGIN_NULL_COMMENTS;
|
ORIGIN_NULL_COMMENTS,
|
||||||
|
ORIGIN_RESOURCE,
|
||||||
|
ORIGIN_NULL_RESOURCE;
|
||||||
|
|
||||||
static SerializedField forInt(int b) {
|
static SerializedField forInt(int b) {
|
||||||
if (b < values().length)
|
if (b < values().length)
|
||||||
@ -179,6 +181,9 @@ class SerializedConfigValue extends AbstractConfigValue implements Externalizabl
|
|||||||
case ORIGIN_URL:
|
case ORIGIN_URL:
|
||||||
out.writeUTF((String) v);
|
out.writeUTF((String) v);
|
||||||
break;
|
break;
|
||||||
|
case ORIGIN_RESOURCE:
|
||||||
|
out.writeUTF((String) v);
|
||||||
|
break;
|
||||||
case ORIGIN_COMMENTS:
|
case ORIGIN_COMMENTS:
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
List<String> list = (List<String>) v;
|
List<String> list = (List<String>) v;
|
||||||
@ -189,6 +194,7 @@ class SerializedConfigValue extends AbstractConfigValue implements Externalizabl
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ORIGIN_NULL_URL: // FALL THRU
|
case ORIGIN_NULL_URL: // FALL THRU
|
||||||
|
case ORIGIN_NULL_RESOURCE: // FALL THRU
|
||||||
case ORIGIN_NULL_COMMENTS:
|
case ORIGIN_NULL_COMMENTS:
|
||||||
// nothing to write out besides code and length
|
// nothing to write out besides code and length
|
||||||
break;
|
break;
|
||||||
@ -245,6 +251,10 @@ class SerializedConfigValue extends AbstractConfigValue implements Externalizabl
|
|||||||
in.readInt(); // discard length
|
in.readInt(); // discard length
|
||||||
v = in.readUTF();
|
v = in.readUTF();
|
||||||
break;
|
break;
|
||||||
|
case ORIGIN_RESOURCE:
|
||||||
|
in.readInt(); // discard length
|
||||||
|
v = in.readUTF();
|
||||||
|
break;
|
||||||
case ORIGIN_COMMENTS:
|
case ORIGIN_COMMENTS:
|
||||||
in.readInt(); // discard length
|
in.readInt(); // discard length
|
||||||
int size = in.readInt();
|
int size = in.readInt();
|
||||||
@ -255,6 +265,7 @@ class SerializedConfigValue extends AbstractConfigValue implements Externalizabl
|
|||||||
v = list;
|
v = list;
|
||||||
break;
|
break;
|
||||||
case ORIGIN_NULL_URL: // FALL THRU
|
case ORIGIN_NULL_URL: // FALL THRU
|
||||||
|
case ORIGIN_NULL_RESOURCE: // FALL THRU
|
||||||
case ORIGIN_NULL_COMMENTS:
|
case ORIGIN_NULL_COMMENTS:
|
||||||
// nothing to read besides code and length
|
// nothing to read besides code and length
|
||||||
in.readInt(); // discard length
|
in.readInt(); // discard length
|
||||||
|
@ -28,10 +28,11 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
final private int endLineNumber;
|
final private int endLineNumber;
|
||||||
final private OriginType originType;
|
final private OriginType originType;
|
||||||
final private String urlOrNull;
|
final private String urlOrNull;
|
||||||
|
final private String resourceOrNull;
|
||||||
final private List<String> commentsOrNull;
|
final private List<String> commentsOrNull;
|
||||||
|
|
||||||
protected SimpleConfigOrigin(String description, int lineNumber, int endLineNumber,
|
protected SimpleConfigOrigin(String description, int lineNumber, int endLineNumber, OriginType originType,
|
||||||
OriginType originType, String urlOrNull, List<String> commentsOrNull) {
|
String urlOrNull, String resourceOrNull, List<String> commentsOrNull) {
|
||||||
if (description == null)
|
if (description == null)
|
||||||
throw new ConfigException.BugOrBroken("description may not be null");
|
throw new ConfigException.BugOrBroken("description may not be null");
|
||||||
this.description = description;
|
this.description = description;
|
||||||
@ -39,11 +40,12 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
this.endLineNumber = endLineNumber;
|
this.endLineNumber = endLineNumber;
|
||||||
this.originType = originType;
|
this.originType = originType;
|
||||||
this.urlOrNull = urlOrNull;
|
this.urlOrNull = urlOrNull;
|
||||||
|
this.resourceOrNull = resourceOrNull;
|
||||||
this.commentsOrNull = commentsOrNull;
|
this.commentsOrNull = commentsOrNull;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SimpleConfigOrigin newSimple(String description) {
|
static SimpleConfigOrigin newSimple(String description) {
|
||||||
return new SimpleConfigOrigin(description, -1, -1, OriginType.GENERIC, null, null);
|
return new SimpleConfigOrigin(description, -1, -1, OriginType.GENERIC, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SimpleConfigOrigin newFile(String filename) {
|
static SimpleConfigOrigin newFile(String filename) {
|
||||||
@ -53,17 +55,22 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
url = null;
|
url = null;
|
||||||
}
|
}
|
||||||
return new SimpleConfigOrigin(filename, -1, -1, OriginType.FILE, url, null);
|
return new SimpleConfigOrigin(filename, -1, -1, OriginType.FILE, url, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SimpleConfigOrigin newURL(URL url) {
|
static SimpleConfigOrigin newURL(URL url) {
|
||||||
String u = url.toExternalForm();
|
String u = url.toExternalForm();
|
||||||
return new SimpleConfigOrigin(u, -1, -1, OriginType.URL, u, null);
|
return new SimpleConfigOrigin(u, -1, -1, OriginType.URL, u, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SimpleConfigOrigin newResource(String resource, URL url) {
|
static SimpleConfigOrigin newResource(String resource, URL url) {
|
||||||
return new SimpleConfigOrigin(resource, -1, -1, OriginType.RESOURCE,
|
String desc;
|
||||||
url != null ? url.toExternalForm() : null, null);
|
if (url != null)
|
||||||
|
desc = resource + " @ " + url.toExternalForm();
|
||||||
|
else
|
||||||
|
desc = resource;
|
||||||
|
return new SimpleConfigOrigin(desc, -1, -1, OriginType.RESOURCE, url != null ? url.toExternalForm() : null,
|
||||||
|
resource, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SimpleConfigOrigin newResource(String resource) {
|
static SimpleConfigOrigin newResource(String resource) {
|
||||||
@ -75,14 +82,14 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
if (lineNumber == this.lineNumber && lineNumber == this.endLineNumber) {
|
if (lineNumber == this.lineNumber && lineNumber == this.endLineNumber) {
|
||||||
return this;
|
return this;
|
||||||
} else {
|
} else {
|
||||||
return new SimpleConfigOrigin(this.description, lineNumber, lineNumber,
|
return new SimpleConfigOrigin(this.description, lineNumber, lineNumber, this.originType, this.urlOrNull,
|
||||||
this.originType, this.urlOrNull, this.commentsOrNull);
|
this.resourceOrNull, this.commentsOrNull);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleConfigOrigin addURL(URL url) {
|
SimpleConfigOrigin addURL(URL url) {
|
||||||
return new SimpleConfigOrigin(this.description, this.lineNumber, this.endLineNumber,
|
return new SimpleConfigOrigin(this.description, this.lineNumber, this.endLineNumber, this.originType,
|
||||||
this.originType, url != null ? url.toExternalForm() : null, this.commentsOrNull);
|
url != null ? url.toExternalForm() : null, this.resourceOrNull, this.commentsOrNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -90,8 +97,8 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
if (ConfigImplUtil.equalsHandlingNull(comments, this.commentsOrNull)) {
|
if (ConfigImplUtil.equalsHandlingNull(comments, this.commentsOrNull)) {
|
||||||
return this;
|
return this;
|
||||||
} else {
|
} else {
|
||||||
return new SimpleConfigOrigin(this.description, this.lineNumber, this.endLineNumber,
|
return new SimpleConfigOrigin(this.description, this.lineNumber, this.endLineNumber, this.originType,
|
||||||
this.originType, this.urlOrNull, comments);
|
this.urlOrNull, this.resourceOrNull, comments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,8 +108,7 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
} else if (this.commentsOrNull == null) {
|
} else if (this.commentsOrNull == null) {
|
||||||
return withComments(comments);
|
return withComments(comments);
|
||||||
} else {
|
} else {
|
||||||
List<String> merged = new ArrayList<String>(comments.size()
|
List<String> merged = new ArrayList<String>(comments.size() + this.commentsOrNull.size());
|
||||||
+ this.commentsOrNull.size());
|
|
||||||
merged.addAll(comments);
|
merged.addAll(comments);
|
||||||
merged.addAll(this.commentsOrNull);
|
merged.addAll(this.commentsOrNull);
|
||||||
return withComments(merged);
|
return withComments(merged);
|
||||||
@ -115,8 +121,7 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
} else if (this.commentsOrNull == null) {
|
} else if (this.commentsOrNull == null) {
|
||||||
return withComments(comments);
|
return withComments(comments);
|
||||||
} else {
|
} else {
|
||||||
List<String> merged = new ArrayList<String>(comments.size()
|
List<String> merged = new ArrayList<String>(comments.size() + this.commentsOrNull.size());
|
||||||
+ this.commentsOrNull.size());
|
|
||||||
merged.addAll(this.commentsOrNull);
|
merged.addAll(this.commentsOrNull);
|
||||||
merged.addAll(comments);
|
merged.addAll(comments);
|
||||||
return withComments(merged);
|
return withComments(merged);
|
||||||
@ -125,8 +130,6 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String description() {
|
public String description() {
|
||||||
// not putting the URL in here for files and resources, because people
|
|
||||||
// parsing "file: line" syntax would hit the ":" in the URL.
|
|
||||||
if (lineNumber < 0) {
|
if (lineNumber < 0) {
|
||||||
return description;
|
return description;
|
||||||
} else if (endLineNumber == lineNumber) {
|
} else if (endLineNumber == lineNumber) {
|
||||||
@ -141,11 +144,10 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
if (other instanceof SimpleConfigOrigin) {
|
if (other instanceof SimpleConfigOrigin) {
|
||||||
SimpleConfigOrigin otherOrigin = (SimpleConfigOrigin) other;
|
SimpleConfigOrigin otherOrigin = (SimpleConfigOrigin) other;
|
||||||
|
|
||||||
return this.description.equals(otherOrigin.description)
|
return this.description.equals(otherOrigin.description) && this.lineNumber == otherOrigin.lineNumber
|
||||||
&& this.lineNumber == otherOrigin.lineNumber
|
&& this.endLineNumber == otherOrigin.endLineNumber && this.originType == otherOrigin.originType
|
||||||
&& this.endLineNumber == otherOrigin.endLineNumber
|
&& ConfigImplUtil.equalsHandlingNull(this.urlOrNull, otherOrigin.urlOrNull)
|
||||||
&& this.originType == otherOrigin.originType
|
&& ConfigImplUtil.equalsHandlingNull(this.resourceOrNull, otherOrigin.resourceOrNull);
|
||||||
&& ConfigImplUtil.equalsHandlingNull(this.urlOrNull, otherOrigin.urlOrNull);
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -159,17 +161,14 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
h = 41 * (h + originType.hashCode());
|
h = 41 * (h + originType.hashCode());
|
||||||
if (urlOrNull != null)
|
if (urlOrNull != null)
|
||||||
h = 41 * (h + urlOrNull.hashCode());
|
h = 41 * (h + urlOrNull.hashCode());
|
||||||
|
if (resourceOrNull != null)
|
||||||
|
h = 41 * (h + resourceOrNull.hashCode());
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
// the url is only really useful on top of description for resources
|
return "ConfigOrigin(" + description + ")";
|
||||||
if (originType == OriginType.RESOURCE && urlOrNull != null) {
|
|
||||||
return "ConfigOrigin(" + description + "," + urlOrNull + ")";
|
|
||||||
} else {
|
|
||||||
return "ConfigOrigin(" + description + ")";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -208,11 +207,7 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String resource() {
|
public String resource() {
|
||||||
if (originType == OriginType.RESOURCE) {
|
return resourceOrNull;
|
||||||
return description;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -291,6 +286,13 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
mergedURL = null;
|
mergedURL = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String mergedResource;
|
||||||
|
if (ConfigImplUtil.equalsHandlingNull(a.resourceOrNull, b.resourceOrNull)) {
|
||||||
|
mergedResource = a.resourceOrNull;
|
||||||
|
} else {
|
||||||
|
mergedResource = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (ConfigImplUtil.equalsHandlingNull(a.commentsOrNull, b.commentsOrNull)) {
|
if (ConfigImplUtil.equalsHandlingNull(a.commentsOrNull, b.commentsOrNull)) {
|
||||||
mergedComments = a.commentsOrNull;
|
mergedComments = a.commentsOrNull;
|
||||||
} else {
|
} else {
|
||||||
@ -301,8 +303,8 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
mergedComments.addAll(b.commentsOrNull);
|
mergedComments.addAll(b.commentsOrNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SimpleConfigOrigin(mergedDesc, mergedStartLine, mergedEndLine, mergedType,
|
return new SimpleConfigOrigin(mergedDesc, mergedStartLine, mergedEndLine, mergedType, mergedURL,
|
||||||
mergedURL, mergedComments);
|
mergedResource, mergedComments);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int similarity(SimpleConfigOrigin a, SimpleConfigOrigin b) {
|
private static int similarity(SimpleConfigOrigin a, SimpleConfigOrigin b) {
|
||||||
@ -322,6 +324,8 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
count += 1;
|
count += 1;
|
||||||
if (ConfigImplUtil.equalsHandlingNull(a.urlOrNull, b.urlOrNull))
|
if (ConfigImplUtil.equalsHandlingNull(a.urlOrNull, b.urlOrNull))
|
||||||
count += 1;
|
count += 1;
|
||||||
|
if (ConfigImplUtil.equalsHandlingNull(a.resourceOrNull, b.resourceOrNull))
|
||||||
|
count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
@ -331,8 +335,7 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
// common. we want to merge two lines in the same file rather than something
|
// common. we want to merge two lines in the same file rather than something
|
||||||
// else with one of the lines; because two lines in the same file can be
|
// else with one of the lines; because two lines in the same file can be
|
||||||
// better consolidated.
|
// better consolidated.
|
||||||
private static SimpleConfigOrigin mergeThree(SimpleConfigOrigin a, SimpleConfigOrigin b,
|
private static SimpleConfigOrigin mergeThree(SimpleConfigOrigin a, SimpleConfigOrigin b, SimpleConfigOrigin c) {
|
||||||
SimpleConfigOrigin c) {
|
|
||||||
if (similarity(a, b) >= similarity(b, c)) {
|
if (similarity(a, b) >= similarity(b, c)) {
|
||||||
return mergeTwo(mergeTwo(a, b), c);
|
return mergeTwo(mergeTwo(a, b), c);
|
||||||
} else {
|
} else {
|
||||||
@ -397,6 +400,8 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
|
|
||||||
if (urlOrNull != null)
|
if (urlOrNull != null)
|
||||||
m.put(SerializedField.ORIGIN_URL, urlOrNull);
|
m.put(SerializedField.ORIGIN_URL, urlOrNull);
|
||||||
|
if (resourceOrNull != null)
|
||||||
|
m.put(SerializedField.ORIGIN_RESOURCE, resourceOrNull);
|
||||||
if (commentsOrNull != null)
|
if (commentsOrNull != null)
|
||||||
m.put(SerializedField.ORIGIN_COMMENTS, commentsOrNull);
|
m.put(SerializedField.ORIGIN_COMMENTS, commentsOrNull);
|
||||||
|
|
||||||
@ -422,16 +427,14 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
|
|
||||||
for (Map.Entry<SerializedField, Object> baseEntry : base.entrySet()) {
|
for (Map.Entry<SerializedField, Object> baseEntry : base.entrySet()) {
|
||||||
SerializedField f = baseEntry.getKey();
|
SerializedField f = baseEntry.getKey();
|
||||||
if (m.containsKey(f)
|
if (m.containsKey(f) && ConfigImplUtil.equalsHandlingNull(baseEntry.getValue(), m.get(f))) {
|
||||||
&& ConfigImplUtil.equalsHandlingNull(baseEntry.getValue(), m.get(f))) {
|
|
||||||
// if field is unchanged, just remove it so we inherit
|
// if field is unchanged, just remove it so we inherit
|
||||||
m.remove(f);
|
m.remove(f);
|
||||||
} else if (!m.containsKey(f)) {
|
} else if (!m.containsKey(f)) {
|
||||||
// if field has been removed, we have to add a deletion entry
|
// if field has been removed, we have to add a deletion entry
|
||||||
switch (f) {
|
switch (f) {
|
||||||
case ORIGIN_DESCRIPTION:
|
case ORIGIN_DESCRIPTION:
|
||||||
throw new ConfigException.BugOrBroken("origin missing description field? "
|
throw new ConfigException.BugOrBroken("origin missing description field? " + child);
|
||||||
+ child);
|
|
||||||
case ORIGIN_LINE_NUMBER:
|
case ORIGIN_LINE_NUMBER:
|
||||||
m.put(SerializedField.ORIGIN_LINE_NUMBER, -1);
|
m.put(SerializedField.ORIGIN_LINE_NUMBER, -1);
|
||||||
break;
|
break;
|
||||||
@ -443,14 +446,17 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
case ORIGIN_URL:
|
case ORIGIN_URL:
|
||||||
m.put(SerializedField.ORIGIN_NULL_URL, "");
|
m.put(SerializedField.ORIGIN_NULL_URL, "");
|
||||||
break;
|
break;
|
||||||
|
case ORIGIN_RESOURCE:
|
||||||
|
m.put(SerializedField.ORIGIN_NULL_RESOURCE, "");
|
||||||
|
break;
|
||||||
case ORIGIN_COMMENTS:
|
case ORIGIN_COMMENTS:
|
||||||
m.put(SerializedField.ORIGIN_NULL_COMMENTS, "");
|
m.put(SerializedField.ORIGIN_NULL_COMMENTS, "");
|
||||||
break;
|
break;
|
||||||
case ORIGIN_NULL_URL: // FALL THRU
|
case ORIGIN_NULL_URL: // FALL THRU
|
||||||
|
case ORIGIN_NULL_RESOURCE: // FALL THRU
|
||||||
case ORIGIN_NULL_COMMENTS:
|
case ORIGIN_NULL_COMMENTS:
|
||||||
throw new ConfigException.BugOrBroken(
|
throw new ConfigException.BugOrBroken("computing delta, base object should not contain " + f + " "
|
||||||
"computing delta, base object should not contain " + f
|
+ base);
|
||||||
+ " " + base);
|
|
||||||
case END_MARKER:
|
case END_MARKER:
|
||||||
case ROOT_VALUE:
|
case ROOT_VALUE:
|
||||||
case ROOT_WAS_CONFIG:
|
case ROOT_WAS_CONFIG:
|
||||||
@ -480,10 +486,16 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
throw new IOException("Missing ORIGIN_TYPE field");
|
throw new IOException("Missing ORIGIN_TYPE field");
|
||||||
OriginType originType = OriginType.values()[originTypeOrdinal.byteValue()];
|
OriginType originType = OriginType.values()[originTypeOrdinal.byteValue()];
|
||||||
String urlOrNull = (String) m.get(SerializedField.ORIGIN_URL);
|
String urlOrNull = (String) m.get(SerializedField.ORIGIN_URL);
|
||||||
|
String resourceOrNull = (String) m.get(SerializedField.ORIGIN_RESOURCE);
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
List<String> commentsOrNull = (List<String>) m.get(SerializedField.ORIGIN_COMMENTS);
|
List<String> commentsOrNull = (List<String>) m.get(SerializedField.ORIGIN_COMMENTS);
|
||||||
|
// Older versions did not have a resource field, they stuffed it into
|
||||||
|
// the description.
|
||||||
|
if (originType == OriginType.RESOURCE && resourceOrNull == null) {
|
||||||
|
resourceOrNull = description;
|
||||||
|
}
|
||||||
return new SimpleConfigOrigin(description, lineNumber != null ? lineNumber : -1,
|
return new SimpleConfigOrigin(description, lineNumber != null ? lineNumber : -1,
|
||||||
endLineNumber != null ? endLineNumber : -1, originType, urlOrNull, commentsOrNull);
|
endLineNumber != null ? endLineNumber : -1, originType, urlOrNull, resourceOrNull, commentsOrNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Map<SerializedField, Object> applyFieldsDelta(Map<SerializedField, Object> base,
|
static Map<SerializedField, Object> applyFieldsDelta(Map<SerializedField, Object> base,
|
||||||
@ -510,6 +522,13 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
m.put(f, base.get(f));
|
m.put(f, base.get(f));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ORIGIN_RESOURCE:
|
||||||
|
if (delta.containsKey(SerializedField.ORIGIN_NULL_RESOURCE)) {
|
||||||
|
m.remove(SerializedField.ORIGIN_NULL_RESOURCE);
|
||||||
|
} else {
|
||||||
|
m.put(f, base.get(f));
|
||||||
|
}
|
||||||
|
break;
|
||||||
case ORIGIN_COMMENTS:
|
case ORIGIN_COMMENTS:
|
||||||
if (delta.containsKey(SerializedField.ORIGIN_NULL_COMMENTS)) {
|
if (delta.containsKey(SerializedField.ORIGIN_NULL_COMMENTS)) {
|
||||||
m.remove(SerializedField.ORIGIN_NULL_COMMENTS);
|
m.remove(SerializedField.ORIGIN_NULL_COMMENTS);
|
||||||
@ -518,11 +537,12 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ORIGIN_NULL_URL: // FALL THRU
|
case ORIGIN_NULL_URL: // FALL THRU
|
||||||
|
case ORIGIN_NULL_RESOURCE: // FALL THRU
|
||||||
case ORIGIN_NULL_COMMENTS: // FALL THRU
|
case ORIGIN_NULL_COMMENTS: // FALL THRU
|
||||||
// base objects shouldn't contain these, should just
|
// base objects shouldn't contain these, should just
|
||||||
// lack the field. these are only in deltas.
|
// lack the field. these are only in deltas.
|
||||||
throw new ConfigException.BugOrBroken(
|
throw new ConfigException.BugOrBroken("applying fields, base object should not contain " + f + " "
|
||||||
"applying fields, base object should not contain " + f + " " + base);
|
+ base);
|
||||||
case ORIGIN_END_LINE_NUMBER: // FALL THRU
|
case ORIGIN_END_LINE_NUMBER: // FALL THRU
|
||||||
case ORIGIN_LINE_NUMBER: // FALL THRU
|
case ORIGIN_LINE_NUMBER: // FALL THRU
|
||||||
case ORIGIN_TYPE:
|
case ORIGIN_TYPE:
|
||||||
@ -542,8 +562,8 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SimpleConfigOrigin fromBase(SimpleConfigOrigin baseOrigin,
|
static SimpleConfigOrigin fromBase(SimpleConfigOrigin baseOrigin, Map<SerializedField, Object> delta)
|
||||||
Map<SerializedField, Object> delta) throws IOException {
|
throws IOException {
|
||||||
Map<SerializedField, Object> baseFields;
|
Map<SerializedField, Object> baseFields;
|
||||||
if (baseOrigin != null)
|
if (baseOrigin != null)
|
||||||
baseFields = baseOrigin.toFields();
|
baseFields = baseOrigin.toFields();
|
||||||
|
@ -860,18 +860,27 @@ class ConfigTest extends TestUtils {
|
|||||||
val conf = ConfigFactory.load("test01")
|
val conf = ConfigFactory.load("test01")
|
||||||
|
|
||||||
val o1 = conf.getValue("ints.fortyTwo").origin()
|
val o1 = conf.getValue("ints.fortyTwo").origin()
|
||||||
assertEquals("test01.conf: 3", o1.description)
|
// the checkout directory would be in between this startsWith and endsWith
|
||||||
|
assertTrue("description starts with resource '" + o1.description + "'", o1.description.startsWith("test01.conf @"))
|
||||||
|
assertTrue("description ends with url and line '" + o1.description + "'", o1.description.endsWith("/config/target/test-classes/test01.conf: 3"))
|
||||||
assertEquals("test01.conf", o1.resource)
|
assertEquals("test01.conf", o1.resource)
|
||||||
|
assertTrue("url ends with resource file", o1.url.getPath.endsWith("/config/target/test-classes/test01.conf"))
|
||||||
assertEquals(3, o1.lineNumber)
|
assertEquals(3, o1.lineNumber)
|
||||||
|
|
||||||
val o2 = conf.getValue("fromJson1").origin()
|
val o2 = conf.getValue("fromJson1").origin()
|
||||||
assertEquals("test01.json: 2", o2.description)
|
// the checkout directory would be in between this startsWith and endsWith
|
||||||
|
assertTrue("description starts with json resource '" + o2.description + "'", o2.description.startsWith("test01.json @"))
|
||||||
|
assertTrue("description of json resource ends with url and line '" + o2.description + "'", o2.description.endsWith("/config/target/test-classes/test01.json: 2"))
|
||||||
assertEquals("test01.json", o2.resource)
|
assertEquals("test01.json", o2.resource)
|
||||||
|
assertTrue("url ends with json resource file", o2.url.getPath.endsWith("/config/target/test-classes/test01.json"))
|
||||||
assertEquals(2, o2.lineNumber)
|
assertEquals(2, o2.lineNumber)
|
||||||
|
|
||||||
val o3 = conf.getValue("fromProps.bool").origin()
|
val o3 = conf.getValue("fromProps.bool").origin()
|
||||||
assertEquals("test01.properties", o3.description)
|
// the checkout directory would be in between this startsWith and endsWith
|
||||||
|
assertTrue("description starts with props resource '" + o3.description + "'", o3.description.startsWith("test01.properties @"))
|
||||||
|
assertTrue("description of props resource ends with url '" + o3.description + "'", o3.description.endsWith("/config/target/test-classes/test01.properties"))
|
||||||
assertEquals("test01.properties", o3.resource)
|
assertEquals("test01.properties", o3.resource)
|
||||||
|
assertTrue("url ends with props resource file", o3.url.getPath.endsWith("/config/target/test-classes/test01.properties"))
|
||||||
// we don't have line numbers for properties files
|
// we don't have line numbers for properties files
|
||||||
assertEquals(-1, o3.lineNumber)
|
assertEquals(-1, o3.lineNumber)
|
||||||
}
|
}
|
||||||
|
@ -896,7 +896,8 @@ class ConfigValueTest extends TestUtils {
|
|||||||
SimpleConfigOrigin.newSimple("foo"),
|
SimpleConfigOrigin.newSimple("foo"),
|
||||||
SimpleConfigOrigin.newFile("/tmp/blahblah"),
|
SimpleConfigOrigin.newFile("/tmp/blahblah"),
|
||||||
SimpleConfigOrigin.newURL(new URL("http://example.com")),
|
SimpleConfigOrigin.newURL(new URL("http://example.com")),
|
||||||
SimpleConfigOrigin.newResource("myresource"))
|
SimpleConfigOrigin.newResource("myresource"),
|
||||||
|
SimpleConfigOrigin.newResource("myresource", new URL("file://foo/bar")))
|
||||||
val combos = bases.flatMap({
|
val combos = bases.flatMap({
|
||||||
base =>
|
base =>
|
||||||
Seq(
|
Seq(
|
||||||
|
@ -561,8 +561,8 @@ class PublicApiTest extends TestUtils {
|
|||||||
// check that each value has its own ConfigOrigin
|
// check that each value has its own ConfigOrigin
|
||||||
val v1 = conf.getValue("ints.fortyTwo")
|
val v1 = conf.getValue("ints.fortyTwo")
|
||||||
val v2 = conf.getValue("test-lib.fromTestLib")
|
val v2 = conf.getValue("test-lib.fromTestLib")
|
||||||
assertEquals("test01.conf", v1.origin.resource)
|
assertEquals("v1 has right origin resource", "test01.conf", v1.origin.resource)
|
||||||
assertEquals("test01.conf", v2.origin.resource)
|
assertEquals("v2 has right origin resource", "test01.conf", v2.origin.resource)
|
||||||
assertEquals(v1.origin.resource, v2.origin.resource)
|
assertEquals(v1.origin.resource, v2.origin.resource)
|
||||||
assertFalse("same urls in " + v1.origin + " " + v2.origin, v1.origin.url == v2.origin.url)
|
assertFalse("same urls in " + v1.origin + " " + v2.origin, v1.origin.url == v2.origin.url)
|
||||||
assertFalse(v1.origin.filename == v2.origin.filename)
|
assertFalse(v1.origin.filename == v2.origin.filename)
|
||||||
|
Loading…
Reference in New Issue
Block a user