Updated to latest config lib 38fb8d6
This commit is contained in:
parent
eebe068aa5
commit
db075d094a
14 changed files with 299 additions and 123 deletions
|
|
@ -87,9 +87,6 @@ public interface Config extends ConfigMergeable {
|
|||
@Override
|
||||
Config withFallback(ConfigMergeable other);
|
||||
|
||||
@Override
|
||||
ConfigObject toValue();
|
||||
|
||||
/**
|
||||
* Returns a replacement config with all substitutions (the
|
||||
* <code>${foo.bar}</code> syntax, see <a
|
||||
|
|
@ -163,11 +160,11 @@ public interface Config extends ConfigMergeable {
|
|||
* with your module. It's best to allow the modules owning those paths to
|
||||
* validate them. Also, if every module validates only its own stuff, there
|
||||
* isn't as much redundant work being done.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* If no paths are specified in <code>checkValid()</code>'s parameter list,
|
||||
* validation is for the entire config.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* If you specify paths that are not in the reference config, those paths
|
||||
* are ignored. (There's nothing to validate.)
|
||||
|
|
@ -465,7 +462,7 @@ public interface Config extends ConfigMergeable {
|
|||
|
||||
List<? extends Object> getAnyRefList(String path);
|
||||
|
||||
List<Long> getMemorySizeInBytesList(String path);
|
||||
List<Long> getBytesList(String path);
|
||||
|
||||
List<Long> getMillisecondsList(String path);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ package com.typesafe.config;
|
|||
/**
|
||||
* All exceptions thrown by the library are subclasses of ConfigException.
|
||||
*/
|
||||
public class ConfigException extends RuntimeException {
|
||||
public abstract class ConfigException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
final private ConfigOrigin origin;
|
||||
|
|
@ -152,6 +152,11 @@ public class ConfigException extends RuntimeException {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception indicating that a path expression was invalid. Try putting
|
||||
* double quotes around path elements that contain "special" characters.
|
||||
*
|
||||
*/
|
||||
public static class BadPath extends ConfigException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
|
@ -267,6 +272,11 @@ public class ConfigException extends RuntimeException {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about a problem that occurred in {@link Config#checkValid}. A
|
||||
* {@link ConfigException.ValidationFailed} exception thrown from
|
||||
* <code>checkValid()</code> includes a list of problems encountered.
|
||||
*/
|
||||
public static class ValidationProblem {
|
||||
|
||||
final private String path;
|
||||
|
|
@ -279,19 +289,31 @@ public class ConfigException extends RuntimeException {
|
|||
this.problem = problem;
|
||||
}
|
||||
|
||||
/** Returns the config setting causing the problem. */
|
||||
public String path() {
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns where the problem occurred (origin may include info on the
|
||||
* file, line number, etc.).
|
||||
*/
|
||||
public ConfigOrigin origin() {
|
||||
return origin;
|
||||
}
|
||||
|
||||
/** Returns a description of the problem. */
|
||||
public String problem() {
|
||||
return problem;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception indicating that {@link Config#checkValid} found validity
|
||||
* problems. The problems are available via the {@link #problems()} method.
|
||||
* The <code>getMessage()</code> of this exception is a potentially very
|
||||
* long string listing all the problems found.
|
||||
*/
|
||||
public static class ValidationFailed extends ConfigException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
|
@ -321,4 +343,20 @@ public class ConfigException extends RuntimeException {
|
|||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception that doesn't fall into any other category.
|
||||
*/
|
||||
public static class Generic extends ConfigException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public Generic(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public Generic(String message) {
|
||||
this(message, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@ package com.typesafe.config;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.Reader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import com.typesafe.config.impl.ConfigImpl;
|
||||
import com.typesafe.config.impl.ConfigUtil;
|
||||
import com.typesafe.config.impl.Parseable;
|
||||
|
||||
/**
|
||||
|
|
@ -57,16 +59,6 @@ public final class ConfigFactory {
|
|||
/**
|
||||
* Like {@link #load(String)} but allows you to specify parse and resolve
|
||||
* options.
|
||||
*
|
||||
* <p>
|
||||
* To be aware of: using
|
||||
* {@link ConfigResolveOptions#setUseSystemProperties(boolean)
|
||||
* setUseSystemProperties(false)} with this method has no meaningful effect,
|
||||
* because the system properties are merged into the config as overrides
|
||||
* anyway. <code>setUseSystemProperties</code> affects whether to fall back
|
||||
* to system properties when they are not found in the config, but with
|
||||
* <code>load()</code>, they will be in the config.
|
||||
*
|
||||
* @param resourceBasename
|
||||
* the classpath resource name with optional extension
|
||||
* @param parseOptions
|
||||
|
|
@ -100,15 +92,6 @@ public final class ConfigFactory {
|
|||
* Like {@link #load(Config)} but allows you to specify
|
||||
* {@link ConfigResolveOptions}.
|
||||
*
|
||||
* <p>
|
||||
* To be aware of: using
|
||||
* {@link ConfigResolveOptions#setUseSystemProperties(boolean)
|
||||
* setUseSystemProperties(false)} with this method has no meaningful effect,
|
||||
* because the system properties are merged into the config as overrides
|
||||
* anyway. <code>setUseSystemProperties</code> affects whether to fall back
|
||||
* to system properties when they are not found in the config, but with
|
||||
* <code>load()</code>, they will be in the config.
|
||||
*
|
||||
* @param config
|
||||
* the application's portion of the configuration
|
||||
* @param resolveOptions
|
||||
|
|
@ -121,20 +104,83 @@ public final class ConfigFactory {
|
|||
}
|
||||
|
||||
private static class DefaultConfigHolder {
|
||||
static final Config defaultConfig = load("application");
|
||||
|
||||
private static Config loadDefaultConfig() {
|
||||
int specified = 0;
|
||||
|
||||
// override application.conf with config.file, config.resource,
|
||||
// config.url if requested.
|
||||
String resource = System.getProperty("config.resource");
|
||||
if (resource != null)
|
||||
specified += 1;
|
||||
String file = System.getProperty("config.file");
|
||||
if (file != null)
|
||||
specified += 1;
|
||||
String url = System.getProperty("config.url");
|
||||
if (url != null)
|
||||
specified += 1;
|
||||
|
||||
if (specified == 0) {
|
||||
return load("application");
|
||||
} else if (specified > 1) {
|
||||
throw new ConfigException.Generic("You set more than one of config.file='" + file
|
||||
+ "', config.url='" + url + "', config.resource='" + resource
|
||||
+ "'; don't know which one to use!");
|
||||
} else {
|
||||
if (resource != null) {
|
||||
// this deliberately does not parseResourcesAnySyntax; if
|
||||
// people want that they can use an include statement.
|
||||
return load(parseResources(ConfigFactory.class, resource));
|
||||
} else if (file != null) {
|
||||
return load(parseFile(new File(file)));
|
||||
} else {
|
||||
try {
|
||||
return load(parseURL(new URL(url)));
|
||||
} catch (MalformedURLException e) {
|
||||
throw new ConfigException.Generic(
|
||||
"Bad URL in config.url system property: '" + url + "': "
|
||||
+ e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final Config defaultConfig = loadDefaultConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a default configuration, equivalent to {@link #load(String)
|
||||
* load("application")}. This configuration should be used by libraries and
|
||||
* frameworks unless an application provides a different one.
|
||||
* load("application")} in most cases. This configuration should be used by
|
||||
* libraries and frameworks unless an application provides a different one.
|
||||
* <p>
|
||||
* This method may return a cached singleton.
|
||||
* <p>
|
||||
* If the system properties <code>config.resource</code>,
|
||||
* <code>config.file</code>, or <code>config.url</code> are set, then the
|
||||
* classpath resource, file, or URL specified in those properties will be
|
||||
* used rather than the default
|
||||
* <code>application.{conf,json,properties}</code> classpath resources.
|
||||
* These system properties should not be set in code (after all, you can
|
||||
* just parse whatever you want manually and then use {@link #load(Config)
|
||||
* if you don't want to use <code>application.conf</code>}). The properties
|
||||
* are intended for use by the person or script launching the application.
|
||||
* For example someone might have a <code>production.conf</code> that
|
||||
* include <code>application.conf</code> but then change a couple of values.
|
||||
* When launching the app they could specify
|
||||
* <code>-Dconfig.resource=production.conf</code> to get production mode.
|
||||
* <p>
|
||||
* If no system properties are set to change the location of the default
|
||||
* configuration, <code>ConfigFactory.load()</code> is equivalent to
|
||||
* <code>ConfigFactory.load("application")</code>.
|
||||
*
|
||||
* @return configuration for an application
|
||||
*/
|
||||
public static Config load() {
|
||||
return DefaultConfigHolder.defaultConfig;
|
||||
try {
|
||||
return DefaultConfigHolder.defaultConfig;
|
||||
} catch (ExceptionInInitializerError e) {
|
||||
throw ConfigUtil.extractInitializerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -17,15 +17,6 @@ package com.typesafe.config;
|
|||
* implementations will break.
|
||||
*/
|
||||
public interface ConfigMergeable {
|
||||
/**
|
||||
* Converts this instance to a {@link ConfigValue}. If called on a
|
||||
* {@code ConfigValue} it returns {@code this}, if called on a
|
||||
* {@link Config} it's equivalent to {@link Config#root()}.
|
||||
*
|
||||
* @return this instance as a {@code ConfigValue}
|
||||
*/
|
||||
ConfigValue toValue();
|
||||
|
||||
/**
|
||||
* Returns a new value computed by merging this value with another, with
|
||||
* keys in this value "winning" over the other one. Only
|
||||
|
|
|
|||
|
|
@ -7,31 +7,24 @@ package com.typesafe.config;
|
|||
* A set of options related to resolving substitutions. Substitutions use the
|
||||
* <code>${foo.bar}</code> syntax and are documented in the <a
|
||||
* href="https://github.com/havocp/config/blob/master/HOCON.md">HOCON</a> spec.
|
||||
*
|
||||
* <p>
|
||||
* This object is immutable, so the "setters" return a new object.
|
||||
*
|
||||
* <p>
|
||||
* Here is an example of creating a custom {@code ConfigResolveOptions}:
|
||||
*
|
||||
* <pre>
|
||||
* ConfigResolveOptions options = ConfigResolveOptions.defaults()
|
||||
* .setUseSystemProperties(false)
|
||||
* .setUseSystemEnvironment(false)
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* In addition to {@link ConfigResolveOptions#defaults}, there's a prebuilt
|
||||
* {@link ConfigResolveOptions#noSystem} which avoids looking at any system
|
||||
* properties or environment variables.
|
||||
* environment variables or other external system information. (Right now,
|
||||
* environment variables are the only example.)
|
||||
*/
|
||||
public final class ConfigResolveOptions {
|
||||
private final boolean useSystemProperties;
|
||||
private final boolean useSystemEnvironment;
|
||||
|
||||
private ConfigResolveOptions(boolean useSystemProperties,
|
||||
boolean useSystemEnvironment) {
|
||||
this.useSystemProperties = useSystemProperties;
|
||||
private ConfigResolveOptions(boolean useSystemEnvironment) {
|
||||
this.useSystemEnvironment = useSystemEnvironment;
|
||||
}
|
||||
|
||||
|
|
@ -41,31 +34,17 @@ public final class ConfigResolveOptions {
|
|||
* @return the default resolve options
|
||||
*/
|
||||
public static ConfigResolveOptions defaults() {
|
||||
return new ConfigResolveOptions(true, true);
|
||||
return new ConfigResolveOptions(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns resolve options that disable any reference to "system" data
|
||||
* (system properties or environment variables).
|
||||
* (currently, this means environment variables).
|
||||
*
|
||||
* @return the resolve options with system properties and env variables
|
||||
* disabled
|
||||
* @return the resolve options with env variables disabled
|
||||
*/
|
||||
public static ConfigResolveOptions noSystem() {
|
||||
return defaults().setUseSystemEnvironment(false).setUseSystemProperties(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns options with use of Java system properties set to the given
|
||||
* value.
|
||||
*
|
||||
* @param value
|
||||
* true to resolve substitutions falling back to Java system
|
||||
* properties.
|
||||
* @return options with requested setting for use of system properties
|
||||
*/
|
||||
public ConfigResolveOptions setUseSystemProperties(boolean value) {
|
||||
return new ConfigResolveOptions(value, useSystemEnvironment);
|
||||
return defaults().setUseSystemEnvironment(false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -76,18 +55,9 @@ public final class ConfigResolveOptions {
|
|||
* variables.
|
||||
* @return options with requested setting for use of environment variables
|
||||
*/
|
||||
@SuppressWarnings("static-method")
|
||||
public ConfigResolveOptions setUseSystemEnvironment(boolean value) {
|
||||
return new ConfigResolveOptions(useSystemProperties, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the options enable use of system properties. This method
|
||||
* is mostly used by the config lib internally, not by applications.
|
||||
*
|
||||
* @return true if system properties should be used
|
||||
*/
|
||||
public boolean getUseSystemProperties() {
|
||||
return useSystemProperties;
|
||||
return new ConfigResolveOptions(value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -35,6 +35,11 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
|
|||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractConfigObject toFallbackValue() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This looks up the key with no transformation or type conversion of any
|
||||
* kind, and returns null if the key is not present.
|
||||
|
|
@ -135,6 +140,7 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
|
|||
if (ignoresFallbacks())
|
||||
throw new ConfigException.BugOrBroken("should not be reached");
|
||||
|
||||
boolean changed = false;
|
||||
boolean allResolved = true;
|
||||
Map<String, AbstractConfigValue> merged = new HashMap<String, AbstractConfigValue>();
|
||||
Set<String> allKeys = new HashSet<String>();
|
||||
|
|
@ -150,12 +156,26 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
|
|||
kept = first;
|
||||
else
|
||||
kept = first.withFallback(second);
|
||||
|
||||
merged.put(key, kept);
|
||||
|
||||
if (first != kept)
|
||||
changed = true;
|
||||
|
||||
if (kept.resolveStatus() == ResolveStatus.UNRESOLVED)
|
||||
allResolved = false;
|
||||
}
|
||||
return new SimpleConfigObject(mergeOrigins(this, fallback), merged,
|
||||
ResolveStatus.fromBoolean(allResolved), fallback.ignoresFallbacks());
|
||||
|
||||
ResolveStatus newResolveStatus = ResolveStatus.fromBoolean(allResolved);
|
||||
boolean newIgnoresFallbacks = fallback.ignoresFallbacks();
|
||||
|
||||
if (changed)
|
||||
return new SimpleConfigObject(mergeOrigins(this, fallback), merged, newResolveStatus,
|
||||
newIgnoresFallbacks);
|
||||
else if (newResolveStatus != resolveStatus() || newIgnoresFallbacks != ignoresFallbacks())
|
||||
return newCopy(newResolveStatus, newIgnoresFallbacks);
|
||||
else
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import com.typesafe.config.ConfigValue;
|
|||
* improperly-factored and non-modular code. Please don't add parent().
|
||||
*
|
||||
*/
|
||||
abstract class AbstractConfigValue implements ConfigValue {
|
||||
abstract class AbstractConfigValue implements ConfigValue, MergeableValue {
|
||||
|
||||
final private ConfigOrigin origin;
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ abstract class AbstractConfigValue implements ConfigValue {
|
|||
}
|
||||
|
||||
@Override
|
||||
public AbstractConfigValue toValue() {
|
||||
public AbstractConfigValue toFallbackValue() {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -110,7 +110,7 @@ abstract class AbstractConfigValue implements ConfigValue {
|
|||
if (ignoresFallbacks()) {
|
||||
return this;
|
||||
} else {
|
||||
ConfigValue other = mergeable.toValue();
|
||||
ConfigValue other = ((MergeableValue) mergeable).toFallbackValue();
|
||||
|
||||
if (other instanceof Unmergeable) {
|
||||
return mergedWithTheUnmergeable((Unmergeable) other);
|
||||
|
|
|
|||
|
|
@ -305,7 +305,11 @@ public class ConfigImpl {
|
|||
}
|
||||
|
||||
static ConfigIncluder defaultIncluder() {
|
||||
return DefaultIncluderHolder.defaultIncluder;
|
||||
try {
|
||||
return DefaultIncluderHolder.defaultIncluder;
|
||||
} catch (ExceptionInInitializerError e) {
|
||||
throw ConfigUtil.extractInitializerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static AbstractConfigObject loadSystemProperties() {
|
||||
|
|
@ -319,7 +323,11 @@ public class ConfigImpl {
|
|||
}
|
||||
|
||||
static AbstractConfigObject systemPropertiesAsConfigObject() {
|
||||
return SystemPropertiesHolder.systemProperties;
|
||||
try {
|
||||
return SystemPropertiesHolder.systemProperties;
|
||||
} catch (ExceptionInInitializerError e) {
|
||||
throw ConfigUtil.extractInitializerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** For use ONLY by library internals, DO NOT TOUCH not guaranteed ABI */
|
||||
|
|
@ -351,7 +359,11 @@ public class ConfigImpl {
|
|||
}
|
||||
|
||||
static AbstractConfigObject envVariablesAsConfigObject() {
|
||||
return EnvVariablesHolder.envVariables;
|
||||
try {
|
||||
return EnvVariablesHolder.envVariables;
|
||||
} catch (ExceptionInInitializerError e) {
|
||||
throw ConfigUtil.extractInitializerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** For use ONLY by library internals, DO NOT TOUCH not guaranteed ABI */
|
||||
|
|
@ -369,6 +381,10 @@ public class ConfigImpl {
|
|||
|
||||
/** For use ONLY by library internals, DO NOT TOUCH not guaranteed ABI */
|
||||
public static Config defaultReference() {
|
||||
return ReferenceHolder.referenceConfig;
|
||||
try {
|
||||
return ReferenceHolder.referenceConfig;
|
||||
} catch (ExceptionInInitializerError e) {
|
||||
throw ConfigUtil.extractInitializerError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,22 +131,25 @@ final class ConfigSubstitution extends AbstractConfigValue implements
|
|||
|
||||
private ConfigValue resolve(SubstitutionResolver resolver, SubstitutionExpression subst,
|
||||
int depth, ConfigResolveOptions options) {
|
||||
// First we look up the full path, which means relative to the
|
||||
// included file if we were not a root file
|
||||
ConfigValue result = findInObject(resolver.root(), resolver, subst.path(),
|
||||
depth, options);
|
||||
|
||||
// when looking up system props and env variables,
|
||||
// we don't want the prefix that was added when
|
||||
// we were included in another file.
|
||||
Path unprefixed = subst.path().subPath(prefixLength);
|
||||
if (result == null) {
|
||||
// Then we want to check relative to the root file. We don't
|
||||
// want the prefix we were included at to be used when looking up
|
||||
// env variables either.
|
||||
Path unprefixed = subst.path().subPath(prefixLength);
|
||||
|
||||
if (result == null && options.getUseSystemProperties()) {
|
||||
result = findInObject(ConfigImpl.systemPropertiesAsConfigObject(), null,
|
||||
unprefixed, depth, options);
|
||||
}
|
||||
if (result == null && prefixLength > 0) {
|
||||
result = findInObject(resolver.root(), resolver, unprefixed, depth, options);
|
||||
}
|
||||
|
||||
if (result == null && options.getUseSystemEnvironment()) {
|
||||
result = findInObject(ConfigImpl.envVariablesAsConfigObject(), null,
|
||||
unprefixed, depth, options);
|
||||
if (result == null && options.getUseSystemEnvironment()) {
|
||||
result = findInObject(ConfigImpl.envVariablesAsConfigObject(), null, unprefixed,
|
||||
depth, options);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@
|
|||
*/
|
||||
package com.typesafe.config.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
||||
import com.typesafe.config.ConfigException;
|
||||
|
||||
|
||||
/** This is public just for the "config" package to use, don't touch it */
|
||||
final public class ConfigUtil {
|
||||
|
|
@ -118,4 +124,26 @@ final public class ConfigUtil {
|
|||
}
|
||||
return s.substring(start, end);
|
||||
}
|
||||
|
||||
/** This is public just for the "config" package to use, don't touch it! */
|
||||
public static ConfigException extractInitializerError(ExceptionInInitializerError e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause != null && cause instanceof ConfigException) {
|
||||
return (ConfigException) cause;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
static File urlToFile(URL url) {
|
||||
// this isn't really right, clearly, but not sure what to do.
|
||||
try {
|
||||
// this will properly handle hex escapes, etc.
|
||||
return new File(url.toURI());
|
||||
} catch (URISyntaxException e) {
|
||||
// this handles some stuff like file:///c:/Whatever/
|
||||
// apparently but mangles handling of hex escapes
|
||||
return new File(url.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
package com.typesafe.config.impl;
|
||||
|
||||
import com.typesafe.config.ConfigMergeable;
|
||||
import com.typesafe.config.ConfigValue;
|
||||
|
||||
interface MergeableValue extends ConfigMergeable {
|
||||
// converts a Config to its root object and a ConfigValue to itself
|
||||
ConfigValue toFallbackValue();
|
||||
}
|
||||
|
|
@ -247,6 +247,20 @@ public abstract class Parseable implements ConfigParseable {
|
|||
}
|
||||
}
|
||||
|
||||
static File relativeTo(File file, String filename) {
|
||||
File child = new File(filename);
|
||||
|
||||
if (child.isAbsolute())
|
||||
return null;
|
||||
|
||||
File parent = file.getParentFile();
|
||||
|
||||
if (parent == null)
|
||||
return null;
|
||||
else
|
||||
return new File(parent, filename);
|
||||
}
|
||||
|
||||
private final static class ParseableReader extends Parseable {
|
||||
final private Reader reader;
|
||||
|
||||
|
|
@ -338,7 +352,13 @@ public abstract class Parseable implements ConfigParseable {
|
|||
}
|
||||
|
||||
public static Parseable newURL(URL input, ConfigParseOptions options) {
|
||||
return new ParseableURL(input, options);
|
||||
// we want file: URLs and files to always behave the same, so switch
|
||||
// to a file if it's a file: URL
|
||||
if (input.getProtocol().equals("file")) {
|
||||
return newFile(ConfigUtil.urlToFile(input), options);
|
||||
} else {
|
||||
return new ParseableURL(input, options);
|
||||
}
|
||||
}
|
||||
|
||||
private final static class ParseableFile extends Parseable {
|
||||
|
|
@ -362,13 +382,27 @@ public abstract class Parseable implements ConfigParseable {
|
|||
|
||||
@Override
|
||||
ConfigParseable relativeTo(String filename) {
|
||||
try {
|
||||
URL url = relativeTo(input.toURI().toURL(), filename);
|
||||
if (url == null)
|
||||
return null;
|
||||
return newURL(url, options().setOriginDescription(null));
|
||||
} catch (MalformedURLException e) {
|
||||
File sibling;
|
||||
if ((new File(filename)).isAbsolute()) {
|
||||
sibling = new File(filename);
|
||||
} else {
|
||||
// this may return null
|
||||
sibling = relativeTo(input, filename);
|
||||
}
|
||||
if (sibling == null)
|
||||
return null;
|
||||
if (sibling.exists()) {
|
||||
return newFile(sibling, options().setOriginDescription(null));
|
||||
} else {
|
||||
// fall back to classpath; we treat the "filename" as absolute
|
||||
// (don't add a package name in front),
|
||||
// if it starts with "/" then remove the "/", for consistency
|
||||
// with ParseableResources.relativeTo
|
||||
String resource = filename;
|
||||
if (filename.startsWith("/"))
|
||||
resource = filename.substring(1);
|
||||
return newResources(this.getClass().getClassLoader(), resource, options()
|
||||
.setOriginDescription(null));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -450,6 +484,10 @@ public abstract class Parseable implements ConfigParseable {
|
|||
}
|
||||
|
||||
static String parent(String resource) {
|
||||
// the "resource" is not supposed to begin with a "/"
|
||||
// because it's supposed to be the raw resource
|
||||
// (ClassLoader#getResource), not the
|
||||
// resource "syntax" (Class#getResource)
|
||||
int i = resource.lastIndexOf('/');
|
||||
if (i < 0) {
|
||||
return null;
|
||||
|
|
@ -460,18 +498,24 @@ public abstract class Parseable implements ConfigParseable {
|
|||
|
||||
@Override
|
||||
ConfigParseable relativeTo(String sibling) {
|
||||
// here we want to build a new resource name and let
|
||||
// the class loader have it, rather than getting the
|
||||
// url with getResource() and relativizing to that url.
|
||||
// This is needed in case the class loader is going to
|
||||
// search a classpath.
|
||||
String parent = parent(resource);
|
||||
if (parent == null)
|
||||
return newResources(loader, sibling, options()
|
||||
.setOriginDescription(null));
|
||||
else
|
||||
return newResources(loader, parent + "/" + sibling,
|
||||
if (sibling.startsWith("/")) {
|
||||
// if it starts with "/" then don't make it relative to
|
||||
// the including resource
|
||||
return newResources(loader, sibling.substring(1),
|
||||
options().setOriginDescription(null));
|
||||
} else {
|
||||
// here we want to build a new resource name and let
|
||||
// the class loader have it, rather than getting the
|
||||
// url with getResource() and relativizing to that url.
|
||||
// This is needed in case the class loader is going to
|
||||
// search a classpath.
|
||||
String parent = parent(resource);
|
||||
if (parent == null)
|
||||
return newResources(loader, sibling, options().setOriginDescription(null));
|
||||
else
|
||||
return newResources(loader, parent + "/" + sibling, options()
|
||||
.setOriginDescription(null));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -139,11 +139,25 @@ final class Path {
|
|||
}
|
||||
|
||||
// this doesn't have a very precise meaning, just to reduce
|
||||
// noise from quotes in the rendered path
|
||||
// noise from quotes in the rendered path for average cases
|
||||
static boolean hasFunkyChars(String s) {
|
||||
for (int i = 0; i < s.length(); ++i) {
|
||||
int length = s.length();
|
||||
|
||||
if (length == 0)
|
||||
return false;
|
||||
|
||||
// if the path starts with something that could be a number,
|
||||
// we need to quote it because the number could be invalid,
|
||||
// for example it could be a hyphen with no digit afterward
|
||||
// or the exponent "e" notation could be mangled.
|
||||
char first = s.charAt(0);
|
||||
if (!(Character.isLetter(first)))
|
||||
return true;
|
||||
|
||||
for (int i = 1; i < length; ++i) {
|
||||
char c = s.charAt(i);
|
||||
if (Character.isLetterOrDigit(c) || c == ' ')
|
||||
|
||||
if (Character.isLetterOrDigit(c) || c == '-' || c == '_')
|
||||
continue;
|
||||
else
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ import com.typesafe.config.ConfigValueType;
|
|||
* key-value pairs would be all the tree's leaf values, in a big flat list with
|
||||
* their full paths.
|
||||
*/
|
||||
class SimpleConfig implements Config {
|
||||
final class SimpleConfig implements Config, MergeableValue {
|
||||
|
||||
AbstractConfigObject object;
|
||||
final private AbstractConfigObject object;
|
||||
|
||||
SimpleConfig(AbstractConfigObject object) {
|
||||
this.object = object;
|
||||
|
|
@ -327,7 +327,7 @@ class SimpleConfig implements Config {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<Long> getMemorySizeInBytesList(String path) {
|
||||
public List<Long> getBytesList(String path) {
|
||||
List<Long> l = new ArrayList<Long>();
|
||||
List<? extends ConfigValue> list = getList(path);
|
||||
for (ConfigValue v : list) {
|
||||
|
|
@ -378,7 +378,7 @@ class SimpleConfig implements Config {
|
|||
}
|
||||
|
||||
@Override
|
||||
public AbstractConfigObject toValue() {
|
||||
public AbstractConfigObject toFallbackValue() {
|
||||
return object;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue