diff --git a/src/main/java/li/cil/oc/Settings.scala b/src/main/java/li/cil/oc/Settings.scala
index 4ba13789b..f42630e7b 100644
--- a/src/main/java/li/cil/oc/Settings.scala
+++ b/src/main/java/li/cil/oc/Settings.scala
@@ -196,8 +196,6 @@ object Settings {
val renderSettings = ConfigRenderOptions.defaults.setJson(false).setOriginComments(false)
val out = new PrintWriter(file)
out.write(config.root.render(renderSettings).lines.
- // Strip extra spaces in front.
- map(_.stripPrefix(" ")).
// Indent two spaces instead of four.
map(line => """^(\s*)""".r.replaceAllIn(line, m => m.group(1).replace(" ", " "))).
// Finalize the string.
diff --git a/src/main/required/com/typesafe/config/Config.java b/src/main/required/com/typesafe/config/Config.java
index 42e4df0cb..f04361443 100644
--- a/src/main/required/com/typesafe/config/Config.java
+++ b/src/main/required/com/typesafe/config/Config.java
@@ -9,46 +9,76 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
- * An immutable map from config paths to config values.
- *
+ * An immutable map from config paths to config values. Paths are dot-separated
+ * expressions such as foo.bar.baz
. Values are as in JSON
+ * (booleans, strings, numbers, lists, or objects), represented by
+ * {@link ConfigValue} instances. Values accessed through the
+ * Config
interface are never null.
+ *
*
- * Contrast with {@link ConfigObject} which is a map from config keys, - * rather than paths, to config values. A {@code Config} contains a tree of - * {@code ConfigObject}, and {@link Config#root()} returns the tree's root - * object. - * + * {@code Config} is an immutable object and thus safe to use from multiple + * threads. There's never a need for "defensive copies." + * *
- * Throughout the API, there is a distinction between "keys" and "paths". A key
- * is a key in a JSON object; it's just a string that's the key in a map. A
- * "path" is a parseable expression with a syntax and it refers to a series of
- * keys. Path expressions are described in the resolving substitutions with {@link Config#resolve()}, and
+ * merging configs using {@link Config#withFallback(ConfigMergeable)}.
+ *
+ *
+ * All operations return a new immutable {@code Config} rather than modifying
+ * the original instance.
+ *
+ *
+ * Examples
+ *
+ *
+ * You can find an example app and library on
+ * GitHub. Also be sure to read the package overview which
+ * describes the big picture as shown in those examples.
+ *
+ *
+ * Paths, keys, and Config vs. ConfigObject
+ *
+ *
+ *
+ * The API tries to consistently use the terms "key" and "path." A key is a key
+ * in a JSON object; it's just a string that's the key in a map. A "path" is a
+ * parseable expression with a syntax and it refers to a series of keys. Path
+ * expressions are described in the spec for
* Human-Optimized Config Object Notation. In brief, a path is
* period-separated so "a.b.c" looks for key c in object b in object a in the
* root object. Sometimes double quotes are needed around special characters in
* path expressions.
- *
+ *
*
* The API for a {@code Config} is in terms of path expressions, while the API
* for a {@code ConfigObject} is in terms of keys. Conceptually, {@code Config}
* is a one-level map from paths to values, while a
* {@code ConfigObject} is a tree of nested maps from keys to values.
- *
+ *
*
* Use {@link ConfigUtil#joinPath} and {@link ConfigUtil#splitPath} to convert
* between path expressions and individual path elements (keys).
- *
+ *
*
* Another difference between {@code Config} and {@code ConfigObject} is that
* conceptually, {@code ConfigValue}s with a {@link ConfigValue#valueType()
* valueType()} of {@link ConfigValueType#NULL NULL} exist in a
* {@code ConfigObject}, while a {@code Config} treats null values as if they
* were missing.
- *
+ *
*
- * {@code Config} is an immutable object and thus safe to use from multiple
- * threads. There's never a need for "defensive copies."
- *
+ * Getting configuration values
+ *
*
* The "getters" on a {@code Config} all work in the same way. They never return
* null, nor do they return a {@code ConfigValue} with
@@ -59,25 +89,71 @@ import java.util.concurrent.TimeUnit;
* thrown. {@link ConfigException.WrongType} will be thrown anytime you ask for
* a type and the value has an incompatible type. Reasonable type conversions
* are performed for you though.
- *
+ *
+ *
+ * Iteration
+ *
*
* If you want to iterate over the contents of a {@code Config}, you can get its
* {@code ConfigObject} with {@link #root()}, and then iterate over the
* {@code ConfigObject} (which implements Before using a {@code Config} it's necessary to call {@link Config#resolve()}
- * to handle substitutions (though {@link ConfigFactory#load()} and similar methods
- * will do the resolve for you already).
- *
- * You can find an example app and library on
- * GitHub. Also be sure to read the package
- * overview which describes the big picture as shown in those
- * examples.
- *
+ *
+ *
+ * Resolving substitutions
+ *
+ *
+ * Substitutions are the
+ * Before using a {@code Config} it's necessary to call {@link Config#resolve()}
+ * to handle substitutions (though {@link ConfigFactory#load()} and similar
+ * methods will do the resolve for you already).
+ *
+ *
+ * Merging
+ *
+ *
+ * The full
+ * Serialization
+ *
+ *
+ * Convert a
+ * As an alternative to {@link ConfigObject#render()}, the
+ *
+ * Java serialization is supported as well for
+ * This is an interface but don't implement it yourself
+ *
*
* Do not implement {@code Config}; it should only be implemented by
* the config library. Arbitrary implementations will not work because the
@@ -114,19 +190,20 @@ public interface Config extends ConfigMergeable {
*
* This method uses {@link ConfigResolveOptions#defaults()}, there is
* another variant {@link Config#resolve(ConfigResolveOptions)} which lets
* you specify non-default options.
- *
+ *
*
* A given {@link Config} must be resolved before using it to retrieve
* config values, but ideally should be resolved one time for your entire
* stack of fallbacks (see {@link Config#withFallback}). Otherwise, some
* substitutions that could have resolved with all fallbacks available may
- * not resolve, which will be a user-visible oddity.
- *
+ * not resolve, which will be potentially confusing for your application's
+ * users.
+ *
*
*
- * Many methods on {@link ConfigFactory} such as {@link
- * ConfigFactory#load()} automatically resolve the loaded
+ * Many methods on {@link ConfigFactory} such as
+ * {@link ConfigFactory#load()} automatically resolve the loaded
* Resolving an already-resolved config is a harmless
- * no-op, but again, it is best to resolve an entire stack of
- * fallbacks (such as all your config files combined) rather
- * than resolving each one individually.
- *
+ *
+ *
+ * Resolving an already-resolved config is a harmless no-op, but again, it
+ * is best to resolve an entire stack of fallbacks (such as all your config
+ * files combined) rather than resolving each one individually.
+ *
* @return an immutable object with substitutions resolved
* @throws ConfigException.UnresolvedSubstitution
* if any substitutions refer to nonexistent paths
@@ -168,10 +245,67 @@ public interface Config extends ConfigMergeable {
*
* @param options
* resolve options
- * @return the resolved
+ * Note that this method does NOT look in this instance for substitution
+ * values. If you want to do that, you could either merge this instance into
+ * your value source using {@link Config#withFallback}, or you could resolve
+ * multiple times with multiple sources (using
+ * {@link ConfigResolveOptions#setAllowUnresolved(boolean)} so the partial
+ * resolves don't fail).
+ *
+ * @param source
+ * configuration to pull values from
+ * @return an immutable object with substitutions resolved
+ * @throws ConfigException.UnresolvedSubstitution
+ * if any substitutions refer to paths which are not in the
+ * source
+ * @throws ConfigException
+ * some other config exception if there are other problems
+ * @since 1.2.0
+ */
+ Config resolveWith(Config source);
+
+ /**
+ * Like {@link Config#resolveWith(Config)} but allows you to specify
+ * non-default options.
+ *
+ * @param source
+ * source configuration to pull values from
+ * @param options
+ * resolve options
+ * @return the resolved Config
is a view onto a tree of {@link ConfigObject}; the
+ * corresponding object tree can be found through {@link Config#root()}.
+ * ConfigObject
is a map from config keys, rather than
+ * paths, to config values. Think of ConfigObject
as a JSON object
+ * and Config
as a configuration API.
+ *
+ * java.util.Map
). Or, you
* can use {@link #entrySet()} which recurses the object tree for you and builds
* up a Set
of all path-value pairs where the value is not null.
- *
- * ${foo.bar}
syntax in config
+ * files, described in the specification. Resolving substitutions replaces these references with real
+ * values.
+ *
+ * Config
for your application can be constructed using
+ * the associative operation {@link Config#withFallback(ConfigMergeable)}. If
+ * you use {@link ConfigFactory#load()} (recommended), it merges system
+ * properties over the top of application.conf
over the top of
+ * reference.conf
, using withFallback
. You can add in
+ * additional sources of configuration in the same way (usually, custom layers
+ * should go either just above or just below application.conf
,
+ * keeping reference.conf
at the bottom and system properties at
+ * the top).
+ *
+ * Config
to a JSON or HOCON string by calling
+ * {@link ConfigObject#render()} on the root object,
+ * myConfig.root().render()
. There's also a variant
+ * {@link ConfigObject#render(ConfigRenderOptions)} which allows you to control
+ * the format of the rendered string. (See {@link ConfigRenderOptions}.) Note
+ * that Config
does not remember the formatting of the original
+ * file, so if you load, modify, and re-save a config file, it will be
+ * substantially reformatted.
+ *
+ * toString()
method produces a debug-output-oriented
+ * representation (which is not valid JSON).
+ *
+ * Config
and all
+ * subtypes of ConfigValue
.
+ *
+ * Config
as the root object, that is, a substitution
* ${foo.bar}
will be replaced with the result of
* getValue("foo.bar")
.
- *
+ *
* resolve()
should be invoked on root config objects, rather
* than on a subtree (a subtree is the result of something like
@@ -136,24 +213,24 @@ public interface Config extends ConfigMergeable {
* from the root. For example, if you did
* config.getConfig("foo").resolve()
on the below config file,
* it would not work:
- *
+ *
*
* common-value = 10
* foo {
* whatever = ${common-value}
* }
*
- *
+ *
* Config
on the loaded stack of config files.
- *
- * Config
+ * @return the resolved Config
(may be only partially resolved if options are set to allow unresolved)
*/
Config resolve(ConfigResolveOptions options);
+ /**
+ * Checks whether the config is completely resolved. After a successful call
+ * to {@link Config#resolve()} it will be completely resolved, but after
+ * calling {@link Config#resolve(ConfigResolveOptions)} with
+ * allowUnresolved
set in the options, it may or may not be
+ * completely resolved. A newly-loaded config may or may not be completely
+ * resolved depending on whether there were substitutions present in the
+ * file.
+ *
+ * @return true if there are no unresolved substitutions remaining in this
+ * configuration.
+ * @since 1.2.0
+ */
+ boolean isResolved();
+
+ /**
+ * Like {@link Config#resolve()} except that substitution values are looked
+ * up in the given source, rather than in this instance. This is a
+ * special-purpose method which doesn't make sense to use in most cases;
+ * it's only needed if you're constructing some sort of app-specific custom
+ * approach to configuration. The more usual approach if you have a source
+ * of substitution values would be to merge that source into your config
+ * stack using {@link Config#withFallback} and then resolve.
+ * Config
(may be only partially resolved
+ * if options are set to allow unresolved)
+ * @since 1.2.0
+ */
+ Config resolveWith(Config source, ConfigResolveOptions options);
+
/**
* Validates this config against a reference config, throwing an exception
* if it is invalid. The purpose of this method is to "fail early" with a
@@ -484,7 +618,7 @@ public interface Config extends ConfigMergeable {
* href="https://github.com/typesafehub/config/blob/master/HOCON.md">the
* spec
The semantics of merging are described in the
+ * This associative operation may be used to combine configurations from
+ * multiple sources (such as multiple configuration files).
+ *
+ *
+ * The semantics of merging are described in the spec
- * for HOCON. Merging typically occurs when either the
- * same object is created twice in the same file, or two
- * config files are both loaded. For example:
+ * for HOCON
* foo = { a: 42 } * foo = { b: 43 } *+ * * Here, the two objects are merged as if you had written: + * *
* foo = { a: 42, b: 43 } *- * + * *
- * Note that objects do not merge "across" non-objects; if you write
+ * Only {@link ConfigObject} and {@link Config} instances do anything in
+ * this method (they need to merge the fallback keys into themselves). All
+ * other values just return the original value, since they automatically
+ * override any fallback. This means that objects do not merge "across"
+ * non-objects; if you write
* object.withFallback(nonObject).withFallback(otherObject)
,
* then otherObject
will simply be ignored. This is an
* intentional part of how merging works, because non-objects such as
- * strings and integers replace (rather than merging with) any
- * prior value:
+ * strings and integers replace (rather than merging with) any prior value:
+ *
*
* foo = { a: 42 } * foo = 10 *+ * * Here, the number 10 "wins" and the value of
foo
would be
* simply 10. Again, for details see the spec.
- *
+ *
* @param other
- * an object whose keys should be used if the keys are not
- * present in this one
+ * an object whose keys should be used as fallbacks, if the keys
+ * are not present in this one
* @return a new object (or the original one, if the fallback doesn't get
* used)
*/
diff --git a/src/main/required/com/typesafe/config/ConfigObject.java b/src/main/required/com/typesafe/config/ConfigObject.java
index 54f6bd813..76414edc9 100644
--- a/src/main/required/com/typesafe/config/ConfigObject.java
+++ b/src/main/required/com/typesafe/config/ConfigObject.java
@@ -6,53 +6,58 @@ package com.typesafe.config;
import java.util.Map;
/**
- * Subtype of {@link ConfigValue} representing an object (dictionary, map)
- * value, as in JSON's { "a" : 42 }
syntax.
- *
+ * Subtype of {@link ConfigValue} representing an object (AKA dictionary or map)
+ * value, as in JSON's curly brace { "a" : 42 }
syntax.
+ *
+ * + * An object may also be viewed as a {@link Config} by calling + * {@link ConfigObject#toConfig()}. + * *
* {@code ConfigObject} implements {@code java.util.Map
* Like all {@link ConfigValue} subtypes, {@code ConfigObject} is immutable.
* This makes it threadsafe and you never have to create "defensive copies." The
* mutator methods from {@link java.util.Map} all throw
* {@link java.lang.UnsupportedOperationException}.
- *
+ *
*
* The {@link ConfigValue#valueType} method on an object returns
* {@link ConfigValueType#OBJECT}.
- *
+ *
*
* In most cases you want to use the {@link Config} interface rather than this
* one. Call {@link #toConfig()} to convert a {@code ConfigObject} to a
* {@code Config}.
- *
+ *
*
* The API for a {@code ConfigObject} is in terms of keys, while the API for a
* {@link Config} is in terms of path expressions. Conceptually,
* {@code ConfigObject} is a tree of maps from keys to values, while a
* {@code Config} is a one-level map from paths to values.
- *
+ *
*
* Use {@link ConfigUtil#joinPath} and {@link ConfigUtil#splitPath} to convert
* between path expressions and individual path elements (keys).
- *
+ *
*
* A {@code ConfigObject} may contain null values, which will have
* {@link ConfigValue#valueType()} equal to {@link ConfigValueType#NULL}. If
- * {@code get()} returns Java's null then the key was not present in the parsed
- * file (or wherever this value tree came from). If {@code get()} returns a
- * {@link ConfigValue} with type {@code ConfigValueType#NULL} then the key was
- * set to null explicitly in the config file.
- *
+ * {@link ConfigObject#get(Object)} returns Java's null then the key was not
+ * present in the parsed file (or wherever this value tree came from). If
+ * {@code get("key")} returns a {@link ConfigValue} with type
+ * {@code ConfigValueType#NULL} then the key was set to null explicitly in the
+ * config file.
+ *
*
- * Do not implement {@code ConfigObject}; it should only be implemented
- * by the config library. Arbitrary implementations will not work because the
- * library internals assume a specific concrete implementation. Also, this
- * interface is likely to grow new methods over time, so third-party
+ * Do not implement interface {@code ConfigObject}; it should only be
+ * implemented by the config library. Arbitrary implementations will not work
+ * because the library internals assume a specific concrete implementation.
+ * Also, this interface is likely to grow new methods over time, so third-party
* implementations will break.
*/
public interface ConfigObject extends ConfigValue, Map
+ * Typically this class would be used with the method
+ * {@link Config#resolve(ConfigResolveOptions)}.
+ *
* This object is immutable, so the "setters" return a new object.
*
* Here is an example of creating a custom {@code ConfigResolveOptions}:
@@ -25,18 +28,21 @@ package com.typesafe.config;
*/
public final class ConfigResolveOptions {
private final boolean useSystemEnvironment;
+ private final boolean allowUnresolved;
- private ConfigResolveOptions(boolean useSystemEnvironment) {
+ private ConfigResolveOptions(boolean useSystemEnvironment, boolean allowUnresolved) {
this.useSystemEnvironment = useSystemEnvironment;
+ this.allowUnresolved = allowUnresolved;
}
/**
- * Returns the default resolve options.
- *
+ * Returns the default resolve options. By default the system environment
+ * will be used and unresolved substitutions are not allowed.
+ *
* @return the default resolve options
*/
public static ConfigResolveOptions defaults() {
- return new ConfigResolveOptions(true);
+ return new ConfigResolveOptions(true, false);
}
/**
@@ -57,9 +63,8 @@ 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(value);
+ return new ConfigResolveOptions(value, allowUnresolved);
}
/**
@@ -72,4 +77,31 @@ public final class ConfigResolveOptions {
public boolean getUseSystemEnvironment() {
return useSystemEnvironment;
}
+
+ /**
+ * Returns options with "allow unresolved" set to the given value. By
+ * default, unresolved substitutions are an error. If unresolved
+ * substitutions are allowed, then a future attempt to use the unresolved
+ * value may fail, but {@link Config#resolve(ConfigResolveOptions)} itself
+ * will now throw.
+ *
+ * @param value
+ * true to silently ignore unresolved substitutions.
+ * @return options with requested setting for whether to allow substitutions
+ * @since 1.2.0
+ */
+ public ConfigResolveOptions setAllowUnresolved(boolean value) {
+ return new ConfigResolveOptions(useSystemEnvironment, value);
+ }
+
+ /**
+ * Returns whether the options allow unresolved substitutions. This method
+ * is mostly used by the config lib internally, not by applications.
+ *
+ * @return true if unresolved substitutions are allowed
+ * @since 1.2.0
+ */
+ public boolean getAllowUnresolved() {
+ return allowUnresolved;
+ }
}
diff --git a/src/main/required/com/typesafe/config/ConfigSyntax.java b/src/main/required/com/typesafe/config/ConfigSyntax.java
index 54529fad0..ed560296c 100644
--- a/src/main/required/com/typesafe/config/ConfigSyntax.java
+++ b/src/main/required/com/typesafe/config/ConfigSyntax.java
@@ -4,29 +4,33 @@
package com.typesafe.config;
/**
- * The syntax of a character stream, JSON, JSON, HOCON
* aka ".conf", or Java properties.
- *
+ * >Java properties).
+ *
*/
public enum ConfigSyntax {
/**
* Pedantically strict JSON format; no
* comments, no unexpected commas, no duplicate keys in the same object.
+ * Associated with the
* Because this object is immutable, it is safe to use from multiple threads and
* there's no need for "defensive copies."
- *
+ *
*
- * Do not implement {@code ConfigValue}; it should only be implemented
- * by the config library. Arbitrary implementations will not work because the
- * library internals assume a specific concrete implementation. Also, this
- * interface is likely to grow new methods over time, so third-party
+ * Do not implement interface {@code ConfigValue}; it should only be
+ * implemented by the config library. Arbitrary implementations will not work
+ * because the library internals assume a specific concrete implementation.
+ * Also, this interface is likely to grow new methods over time, so third-party
* implementations will break.
*/
public interface ConfigValue extends ConfigMergeable {
@@ -47,36 +47,36 @@ public interface ConfigValue extends ConfigMergeable {
* Renders the config value as a HOCON string. This method is primarily
* intended for debugging, so it tries to add helpful comments and
* whitespace.
- *
+ *
*
* If the config value has not been resolved (see {@link Config#resolve}),
* it's possible that it can't be rendered as valid HOCON. In that case the
* rendering should still be useful for debugging but you might not be able
- * to parse it.
- *
+ * to parse it. If the value has been resolved, it will always be parseable.
+ *
*
* This method is equivalent to
* {@code render(ConfigRenderOptions.defaults())}.
- *
+ *
* @return the rendered value
*/
String render();
/**
* Renders the config value to a string, using the provided options.
- *
+ *
*
* If the config value has not been resolved (see {@link Config#resolve}),
* it's possible that it can't be rendered as valid HOCON. In that case the
* rendering should still be useful for debugging but you might not be able
- * to parse it.
- *
+ * to parse it. If the value has been resolved, it will always be parseable.
+ *
*
* If the config value has been resolved and the options disable all
* HOCON-specific features (such as comments), the rendering will be valid
* JSON. If you enable HOCON-only features such as comments, the rendering
* will not be valid JSON.
- *
+ *
* @param options
* the rendering options
* @return the rendered value
@@ -87,9 +87,9 @@ public interface ConfigValue extends ConfigMergeable {
ConfigValue withFallback(ConfigMergeable other);
/**
- * Places the value inside a {@code Config} at the given path. See also
- * atKey().
- *
+ * Places the value inside a {@link Config} at the given path. See also
+ * {@link ConfigValue#atKey(String)}.
+ *
* @param path
* path to store this value at.
* @return a {@code Config} instance containing this value at the given
@@ -98,9 +98,9 @@ public interface ConfigValue extends ConfigMergeable {
Config atPath(String path);
/**
- * Places the value inside a {@code Config} at the given key. See also
- * atPath().
- *
+ * Places the value inside a {@link Config} at the given key. See also
+ * {@link ConfigValue#atPath(String)}.
+ *
* @param key
* key to store this value at.
* @return a {@code Config} instance containing this value at the given key.
diff --git a/src/main/required/com/typesafe/config/ConfigValueFactory.java b/src/main/required/com/typesafe/config/ConfigValueFactory.java
index 02cb095e9..e92bb7722 100644
--- a/src/main/required/com/typesafe/config/ConfigValueFactory.java
+++ b/src/main/required/com/typesafe/config/ConfigValueFactory.java
@@ -17,40 +17,45 @@ public final class ConfigValueFactory {
}
/**
- * Creates a ConfigValue from a plain Java boxed value, which may be a
- * Boolean, Number, String, Map, Iterable, or null. A Map must be a Map from
- * String to more values that can be supplied to fromAnyRef(). An Iterable
- * must iterate over more values that can be supplied to fromAnyRef(). A Map
- * will become a ConfigObject and an Iterable will become a ConfigList. If
- * the Iterable is not an ordered collection, results could be strange,
- * since ConfigList is ordered.
- *
+ * Creates a {@link ConfigValue} from a plain Java boxed value, which may be
+ * a
- * In a Map passed to fromAnyRef(), the map's keys are plain keys, not path
- * expressions. So if your Map has a key "foo.bar" then you will get one
- * object with a key called "foo.bar", rather than an object with a key
- * "foo" containing another object with a key "bar".
- *
+ * In a
* The originDescription will be used to set the origin() field on the
* ConfigValue. It should normally be the name of the file the values came
* from, or something short describing the value such as "default settings".
* The originDescription is prefixed to error messages so users can tell
* where problematic values are coming from.
- *
+ *
*
* Supplying the result of ConfigValue.unwrapped() to this function is
* guaranteed to work and should give you back a ConfigValue that matches
* the one you unwrapped. The re-wrapped ConfigValue will lose some
* information that was present in the original such as its origin, but it
* will have matching values.
- *
+ *
*
* This function throws if you supply a value that cannot be converted to a
* ConfigValue, but supplying such a value is a bug in your program, so you
* should never handle the exception. Just fix your program (or report a bug
* against this library).
- *
+ *
* @param object
* object to convert to ConfigValue
* @param originDescription
@@ -62,23 +67,24 @@ public final class ConfigValueFactory {
}
/**
- * See the fromAnyRef() documentation for details. This is a typesafe
- * wrapper that only works on {@link java.util.Map} and returns
- * {@link ConfigObject} rather than {@link ConfigValue}.
- *
+ * See the {@link #fromAnyRef(Object,String)} documentation for details.
+ * This is a typesafe wrapper that only works on {@link java.util.Map} and
+ * returns {@link ConfigObject} rather than {@link ConfigValue}.
+ *
*
- * If your Map has a key "foo.bar" then you will get one object with a key
- * called "foo.bar", rather than an object with a key "foo" containing
- * another object with a key "bar". The keys in the map are keys; not path
- * expressions. That is, the Map corresponds exactly to a single
- * {@code ConfigObject}. The keys will not be parsed or modified, and the
- * values are wrapped in ConfigValue. To get nested {@code ConfigObject},
- * some of the values in the map would have to be more maps.
- *
+ * If your
* See also {@link ConfigFactory#parseMap(Map,String)} which interprets the
* keys in the map as path expressions.
- *
+ *
* @param values
* @param originDescription
* @return a new {@link ConfigObject} value
@@ -89,10 +95,10 @@ public final class ConfigValueFactory {
}
/**
- * See the fromAnyRef() documentation for details. This is a typesafe
- * wrapper that only works on {@link java.lang.Iterable} and returns
- * {@link ConfigList} rather than {@link ConfigValue}.
- *
+ * See the {@link #fromAnyRef(Object,String)} documentation for details.
+ * This is a typesafe wrapper that only works on {@link java.lang.Iterable}
+ * and returns {@link ConfigList} rather than {@link ConfigValue}.
+ *
* @param values
* @param originDescription
* @return a new {@link ConfigList} value
diff --git a/src/main/required/com/typesafe/config/impl/AbstractConfigObject.java b/src/main/required/com/typesafe/config/impl/AbstractConfigObject.java
index d4dfc6ad8..394931dee 100644
--- a/src/main/required/com/typesafe/config/impl/AbstractConfigObject.java
+++ b/src/main/required/com/typesafe/config/impl/AbstractConfigObject.java
@@ -218,7 +218,7 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements Confi
public abstract AbstractConfigValue get(Object key);
@Override
- protected abstract void render(StringBuilder sb, int indent, ConfigRenderOptions options);
+ protected abstract void render(StringBuilder sb, int indent, boolean atRoot, ConfigRenderOptions options);
private static UnsupportedOperationException weAreImmutable(String method) {
return new UnsupportedOperationException("ConfigObject is immutable, you can't call Map."
diff --git a/src/main/required/com/typesafe/config/impl/AbstractConfigValue.java b/src/main/required/com/typesafe/config/impl/AbstractConfigValue.java
index 0b2cb7665..9b6b1fd91 100644
--- a/src/main/required/com/typesafe/config/impl/AbstractConfigValue.java
+++ b/src/main/required/com/typesafe/config/impl/AbstractConfigValue.java
@@ -279,7 +279,7 @@ abstract class AbstractConfigValue implements ConfigValue, MergeableValue {
@Override
public final String toString() {
StringBuilder sb = new StringBuilder();
- render(sb, 0, null /* atKey */, ConfigRenderOptions.concise());
+ render(sb, 0, true /* atRoot */, null /* atKey */, ConfigRenderOptions.concise());
return getClass().getSimpleName() + "(" + sb.toString() + ")";
}
@@ -293,7 +293,7 @@ abstract class AbstractConfigValue implements ConfigValue, MergeableValue {
}
}
- protected void render(StringBuilder sb, int indent, String atKey, ConfigRenderOptions options) {
+ protected void render(StringBuilder sb, int indent, boolean atRoot, String atKey, ConfigRenderOptions options) {
if (atKey != null) {
String renderedKey;
if (options.getJson())
@@ -318,10 +318,10 @@ abstract class AbstractConfigValue implements ConfigValue, MergeableValue {
}
}
}
- render(sb, indent, options);
+ render(sb, indent, atRoot, options);
}
- protected void render(StringBuilder sb, int indent, ConfigRenderOptions options) {
+ protected void render(StringBuilder sb, int indent, boolean atRoot, ConfigRenderOptions options) {
Object u = unwrapped();
sb.append(u.toString());
}
@@ -334,7 +334,7 @@ abstract class AbstractConfigValue implements ConfigValue, MergeableValue {
@Override
public final String render(ConfigRenderOptions options) {
StringBuilder sb = new StringBuilder();
- render(sb, 0, null, options);
+ render(sb, 0, true, null, options);
return sb.toString();
}
diff --git a/src/main/required/com/typesafe/config/impl/ConfigConcatenation.java b/src/main/required/com/typesafe/config/impl/ConfigConcatenation.java
index a38b0003b..958d82e5e 100644
--- a/src/main/required/com/typesafe/config/impl/ConfigConcatenation.java
+++ b/src/main/required/com/typesafe/config/impl/ConfigConcatenation.java
@@ -232,9 +232,9 @@ final class ConfigConcatenation extends AbstractConfigValue implements Unmergeab
}
@Override
- protected void render(StringBuilder sb, int indent, ConfigRenderOptions options) {
+ protected void render(StringBuilder sb, int indent, boolean atRoot, ConfigRenderOptions options) {
for (AbstractConfigValue p : pieces) {
- p.render(sb, indent, options);
+ p.render(sb, indent, atRoot, options);
}
}
diff --git a/src/main/required/com/typesafe/config/impl/ConfigDelayedMerge.java b/src/main/required/com/typesafe/config/impl/ConfigDelayedMerge.java
index 21f5371b5..28153331f 100644
--- a/src/main/required/com/typesafe/config/impl/ConfigDelayedMerge.java
+++ b/src/main/required/com/typesafe/config/impl/ConfigDelayedMerge.java
@@ -216,12 +216,12 @@ final class ConfigDelayedMerge extends AbstractConfigValue implements Unmergeabl
}
@Override
- protected void render(StringBuilder sb, int indent, String atKey, ConfigRenderOptions options) {
- render(stack, sb, indent, atKey, options);
+ protected void render(StringBuilder sb, int indent, boolean atRoot, String atKey, ConfigRenderOptions options) {
+ render(stack, sb, indent, atRoot, atKey, options);
}
// static method also used by ConfigDelayedMergeObject.
- static void render(List
Typically you would load configuration with a static method from {@link com.typesafe.config.ConfigFactory} and then use
-it with methods in the {@link com.typesafe.config.Config} interface.
+it with methods in the {@link com.typesafe.config.Config} interface. Configuration may be in the form of JSON files,
+Java properties, or HOCON files; you may also
+build your own configuration in code or from your own file formats.
@@ -24,6 +26,8 @@ its configuration in "application.conf" on the classpath.
If you use the default configuration from {@link com.typesafe.config.ConfigFactory#load()}
there's no need to pass a configuration to your libraries
and frameworks, as long as they all default to this same default, which they should.
+
@@ -32,10 +36,22 @@ A library or framework should ship a file "reference.conf" in its jar, and allow
call {@link com.typesafe.config.ConfigFactory#load()}
to get the default one. Typically a library might offer two constructors, one with a
-You can find an example app and library on GitHub.
+Check out the full examples directory on GitHub.
+
+What else to read:
+.json
file extension and
+ * application/json
Content-Type.
*/
JSON,
/**
* The JSON-superset HOCON format.
+ * >HOCON format. Associated with the .conf
file extension
+ * and application/hocon
Content-Type.
*/
CONF,
/**
* Standard Java properties format.
+ * >Java properties format. Associated with the .properties
+ * file extension and text/x-java-properties
Content-Type.
*/
PROPERTIES;
}
diff --git a/src/main/required/com/typesafe/config/ConfigValue.java b/src/main/required/com/typesafe/config/ConfigValue.java
index 514336c74..35c40b8ba 100644
--- a/src/main/required/com/typesafe/config/ConfigValue.java
+++ b/src/main/required/com/typesafe/config/ConfigValue.java
@@ -6,16 +6,16 @@ package com.typesafe.config;
/**
* An immutable value, following the JSON type
* schema.
- *
+ *
* Boolean
, Number
, String
,
+ * Map
, Iterable
, or null
. A
+ * Map
must be a Map
from String to more values
+ * that can be supplied to fromAnyRef()
. An
+ * Iterable
must iterate over more values that can be supplied
+ * to fromAnyRef()
. A Map
will become a
+ * {@link ConfigObject} and an Iterable
will become a
+ * {@link ConfigList}. If the Iterable
is not an ordered
+ * collection, results could be strange, since ConfigList
is
+ * ordered.
+ *
* Map
passed to fromAnyRef()
, the map's keys
+ * are plain keys, not path expressions. So if your Map
has a
+ * key "foo.bar" then you will get one object with a key called "foo.bar",
+ * rather than an object with a key "foo" containing another object with a
+ * key "bar".
+ *
* Map
has a key "foo.bar" then you will get one object
+ * with a key called "foo.bar", rather than an object with a key "foo"
+ * containing another object with a key "bar". The keys in the map are keys;
+ * not path expressions. That is, the Map
corresponds exactly
+ * to a single {@code ConfigObject}. The keys will not be parsed or
+ * modified, and the values are wrapped in ConfigValue. To get nested
+ * {@code ConfigObject}, some of the values in the map would have to be more
+ * maps.
+ *
*
Example application code: Java and Scala.
+
Showing a couple of more special-purpose features, a more complex example: Java and Scala.
Config
parameter
and one which uses {@link com.typesafe.config.ConfigFactory#load()}.
+
Example library code: Java and Scala.
+
.conf
files in addition to .json
and .properties
,
+ see the README for some short examples
+ and the full HOCON spec for the long version.