Clean up the javadocs.

This commit is contained in:
Havoc Pennington 2011-11-21 11:36:58 -05:00
parent 554461eabb
commit d9cac206e1
17 changed files with 515 additions and 188 deletions

View File

@ -6,51 +6,82 @@ package com.typesafe.config;
import java.util.List; import java.util.List;
/** /**
* This class represents an immutable map from config paths to config values. It * An immutable map from config paths to config values.
* also contains some static methods for creating configs.
* *
* <p>
* Contrast with {@link ConfigObject} which is a map from config <em>keys</em>,
* rather than paths, to config values. A {@code Config} contains a tree of
* {@code ConfigObject}, and {@link Config#toObject()} returns the tree's root
* object.
*
* <p>
* Throughout the API, there is a distinction between "keys" and "paths". A key * 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 * 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 * "path" is a parseable expression with a syntax and it refers to a series of
* keys. Path expressions are described in the spec for "HOCON", which can be * keys. Path expressions are described in the <a
* found at https://github.com/havocp/config/blob/master/HOCON.md; in brief, a * href="https://github.com/havocp/config/blob/master/HOCON.md">spec for
* path is period-separated so "a.b.c" looks for key c in object b in object a * Human-Optimized Config Object Notation</a>. In brief, a path is
* in the root object. Sometimes double quotes are needed around special * period-separated so "a.b.c" looks for key c in object b in object a in the
* characters in path expressions. * root object. Sometimes double quotes are needed around special characters in
* path expressions.
* *
* The API for a Config is in terms of path expressions, while the API for a * <p>
* ConfigObject is in terms of keys. Conceptually, Config is a one-level map * The API for a {@code Config} is in terms of path expressions, while the API
* from paths to values, while a ConfigObject is a tree of maps from keys to * for a {@code ConfigObject} is in terms of keys. Conceptually, {@code Config}
* values. * is a one-level map from <em>paths</em> to values, while a
* {@code ConfigObject} is a tree of nested maps from <em>keys</em> to values.
* *
* Another difference between Config and ConfigObject is that conceptually, * <p>
* ConfigValue with valueType() of ConfigValueType.NULL exist in a ConfigObject, * Another difference between {@code Config} and {@code ConfigObject} is that
* while a Config treats null values as if they were missing. * 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.
* *
* Config is an immutable object and thus safe to use from multiple threads. * <p>
* {@code Config} is an immutable object and thus safe to use from multiple
* threads. There's never a need for "defensive copies."
* *
* The "getters" on a Config all work in the same way. They never return null, * <p>
* nor do they return a ConfigValue with valueType() of ConfigValueType.NULL. * The "getters" on a {@code Config} all work in the same way. They never return
* Instead, they throw ConfigException.Missing if the value is completely absent * null, nor do they return a {@code ConfigValue} with
* or set to null. If the value is set to null, a subtype of * {@link ConfigValue#valueType() valueType()} of {@link ConfigValueType#NULL
* ConfigException.Missing called ConfigException.Null will be thrown. * NULL}. Instead, they throw {@link ConfigException.Missing} if the value is
* ConfigException.WrongType will be thrown anytime you ask for a type and the * completely absent or set to null. If the value is set to null, a subtype of
* value has an incompatible type. Reasonable type conversions are performed for * {@code ConfigException.Missing} called {@link ConfigException.Null} will be
* you though. * 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.
* *
* If you want to iterate over the contents of a Config, you have to get its * <p>
* ConfigObject with toObject, and then iterate over the ConfigObject. * If you want to iterate over the contents of a {@code Config}, you have to get
* its {@code ConfigObject} with {@link #toObject()}, and then iterate over the
* {@code ConfigObject}.
* *
*
* <p>
* <em>Do not implement {@code Config}</em>; 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 Config extends ConfigMergeable { public interface Config extends ConfigMergeable {
/** /**
* Gets the config as a tree of ConfigObject. This is a constant-time * Gets the {@code Config} as a tree of {@link ConfigObject}. This is a
* operation (it is not proportional to the number of values in the Config). * constant-time operation (it is not proportional to the number of values
* in the {@code Config}).
* *
* @return * @return the root object in the configuration
*/ */
ConfigObject toObject(); ConfigObject toObject();
/**
* Gets the origin of the {@code Config}, which may be a file, or a file
* with a line number, or just a descriptive phrase.
*
* @return the origin of the {@code Config} for use in error messages
*/
ConfigOrigin origin(); ConfigOrigin origin();
@Override @Override
@ -61,14 +92,16 @@ public interface Config extends ConfigMergeable {
/** /**
* Checks whether a value is present and non-null at the given path. This * Checks whether a value is present and non-null at the given path. This
* differs in two ways from ConfigObject.containsKey(): it looks for a path * differs in two ways from {@code Map.containsKey()} as implemented by
* expression, not a key; and it returns false for null values, while * {@link ConfigObject}: it looks for a path expression, not a key; and it
* containsKey() returns true indicating that the object contains a null * returns false for null values, while {@code containsKey()} returns true
* value for the key. * indicating that the object contains a null value for the key.
* *
* If a path exists according to hasPath(), then getValue() will never throw * <p>
* an exception. However, the typed getters, such as getInt(), will still * If a path exists according to {@link #hasPath(String)}, then
* throw if the value is not convertible to the requested type. * {@link #getValue(String)} will never throw an exception. However, the
* typed getters, such as {@link #getInt(String)}, will still throw if the
* value is not convertible to the requested type.
* *
* @param path * @param path
* the path expression * the path expression
@ -78,12 +111,19 @@ public interface Config extends ConfigMergeable {
*/ */
boolean hasPath(String path); boolean hasPath(String path);
/**
* Returns true if the {@code Config}'s root object contains no key-value
* pairs.
*
* @return true if the configuration is empty
*/
boolean isEmpty(); boolean isEmpty();
/** /**
* *
* @param path * @param path
* @return * path expression
* @return the boolean value at the requested path
* @throws ConfigException.Missing * @throws ConfigException.Missing
* if value is absent or null * if value is absent or null
* @throws ConfigException.WrongType * @throws ConfigException.WrongType
@ -93,7 +133,8 @@ public interface Config extends ConfigMergeable {
/** /**
* @param path * @param path
* @return * path expression
* @return the numeric value at the requested path
* @throws ConfigException.Missing * @throws ConfigException.Missing
* if value is absent or null * if value is absent or null
* @throws ConfigException.WrongType * @throws ConfigException.WrongType
@ -103,17 +144,20 @@ public interface Config extends ConfigMergeable {
/** /**
* @param path * @param path
* @return * path expression
* @return the 32-bit integer value at the requested path
* @throws ConfigException.Missing * @throws ConfigException.Missing
* if value is absent or null * if value is absent or null
* @throws ConfigException.WrongType * @throws ConfigException.WrongType
* if value is not convertible to an int * if value is not convertible to an int (for example it is out
* of range, or it's a boolean value)
*/ */
int getInt(String path); int getInt(String path);
/** /**
* @param path * @param path
* @return * path expression
* @return the 64-bit long value at the requested path
* @throws ConfigException.Missing * @throws ConfigException.Missing
* if value is absent or null * if value is absent or null
* @throws ConfigException.WrongType * @throws ConfigException.WrongType
@ -123,7 +167,8 @@ public interface Config extends ConfigMergeable {
/** /**
* @param path * @param path
* @return * path expression
* @return the floating-point value at the requested path
* @throws ConfigException.Missing * @throws ConfigException.Missing
* if value is absent or null * if value is absent or null
* @throws ConfigException.WrongType * @throws ConfigException.WrongType
@ -133,7 +178,8 @@ public interface Config extends ConfigMergeable {
/** /**
* @param path * @param path
* @return * path expression
* @return the string value at the requested path
* @throws ConfigException.Missing * @throws ConfigException.Missing
* if value is absent or null * if value is absent or null
* @throws ConfigException.WrongType * @throws ConfigException.WrongType
@ -143,7 +189,8 @@ public interface Config extends ConfigMergeable {
/** /**
* @param path * @param path
* @return * path expression
* @return the {@link ConfigObject} value at the requested path
* @throws ConfigException.Missing * @throws ConfigException.Missing
* if value is absent or null * if value is absent or null
* @throws ConfigException.WrongType * @throws ConfigException.WrongType
@ -153,7 +200,8 @@ public interface Config extends ConfigMergeable {
/** /**
* @param path * @param path
* @return * path expression
* @return the nested {@code Config} value at the requested path
* @throws ConfigException.Missing * @throws ConfigException.Missing
* if value is absent or null * if value is absent or null
* @throws ConfigException.WrongType * @throws ConfigException.WrongType
@ -162,9 +210,13 @@ public interface Config extends ConfigMergeable {
Config getConfig(String path); Config getConfig(String path);
/** /**
* Gets the value at the path as an unwrapped Java boxed value (Boolean, * Gets the value at the path as an unwrapped Java boxed value (
* Integer, Long, etc.) * {@link java.lang.Boolean Boolean}, {@link java.lang.Integer Integer}, and
* so on - see {@link ConfigValue#unwrapped()}).
* *
* @param path
* path expression
* @return the unwrapped value at the requested path
* @throws ConfigException.Missing * @throws ConfigException.Missing
* if value is absent or null * if value is absent or null
*/ */
@ -172,21 +224,30 @@ public interface Config extends ConfigMergeable {
/** /**
* Gets the value at the given path, unless the value is a null value or * Gets the value at the given path, unless the value is a null value or
* missing, in which case it throws just like the other getters. Use get() * missing, in which case it throws just like the other getters. Use
* from the Map interface if you want an unprocessed value. * {@code get()} from the {@link java.util.Map Map} interface if you want an
* unprocessed value.
* *
* @param path * @param path
* @return * path expression
* @return the value at the requested path
* @throws ConfigException.Missing * @throws ConfigException.Missing
* if value is absent or null * if value is absent or null
*/ */
ConfigValue getValue(String path); ConfigValue getValue(String path);
/** /**
* Get value as a size in bytes (parses special strings like "128M"). The * Gets a value as a size in bytes (parses special strings like "128M"). The
* size units are interpreted as for memory, not as for disk space, so they * size units are interpreted as for memory, not as for disk space, so they
* are in powers of two. * are in powers of two. If the value is already a number, then it's left
* alone; if it's a string, it's parsed understanding unit suffixes such as
* "128K", as documented in the <a
* href="https://github.com/havocp/config/blob/master/HOCON.md">the
* spec</a>.
* *
* @param path
* path expression
* @return the memory size value at the requested path, in bytes
* @throws ConfigException.Missing * @throws ConfigException.Missing
* if value is absent or null * if value is absent or null
* @throws ConfigException.WrongType * @throws ConfigException.WrongType
@ -199,8 +260,13 @@ public interface Config extends ConfigMergeable {
/** /**
* Get value as a duration in milliseconds. If the value is already a * Get value as a duration in milliseconds. If the value is already a
* number, then it's left alone; if it's a string, it's parsed understanding * number, then it's left alone; if it's a string, it's parsed understanding
* units suffixes like "10m" or "5ns" * units suffixes like "10m" or "5ns" as documented in the <a
* href="https://github.com/havocp/config/blob/master/HOCON.md">the
* spec</a>.
* *
* @param path
* path expression
* @return the duration value at the requested path, in milliseconds
* @throws ConfigException.Missing * @throws ConfigException.Missing
* if value is absent or null * if value is absent or null
* @throws ConfigException.WrongType * @throws ConfigException.WrongType
@ -213,8 +279,12 @@ public interface Config extends ConfigMergeable {
/** /**
* Get value as a duration in nanoseconds. If the value is already a number * Get value as a duration in nanoseconds. If the value is already a number
* it's taken as milliseconds and converted to nanoseconds. If it's a * it's taken as milliseconds and converted to nanoseconds. If it's a
* string, it's parsed understanding unit suffixes. * string, it's parsed understanding unit suffixes, as for
* {@link #getMilliseconds(String)}.
* *
* @param path
* path expression
* @return the duration value at the requested path, in nanoseconds
* @throws ConfigException.Missing * @throws ConfigException.Missing
* if value is absent or null * if value is absent or null
* @throws ConfigException.WrongType * @throws ConfigException.WrongType
@ -225,13 +295,13 @@ public interface Config extends ConfigMergeable {
Long getNanoseconds(String path); Long getNanoseconds(String path);
/** /**
* Gets a list value (with any element type) as a ConfigList, which * Gets a list value (with any element type) as a {@link ConfigList}, which
* implements java.util.List<ConfigValue>. Throws if the path is unset or * implements {@code java.util.List<ConfigValue>}. Throws if the path is
* null. * unset or null.
* *
* @param path * @param path
* the path to the list value. * the path to the list value.
* @return the ConfigList at the path * @return the {@link ConfigList} at the path
* @throws ConfigException.Missing * @throws ConfigException.Missing
* if value is absent or null * if value is absent or null
* @throws ConfigException.WrongType * @throws ConfigException.WrongType

View File

@ -13,12 +13,18 @@ import com.typesafe.config.impl.ConfigImpl;
import com.typesafe.config.impl.Parseable; import com.typesafe.config.impl.Parseable;
/** /**
* This class contains static methods for creating Config objects. * Contains static methods for creating {@link Config} instances.
* *
* <p>
* See also {@link ConfigValueFactory} which contains static methods for
* converting Java values into a {@link ConfigObject}. You can then convert a
* {@code ConfigObject} into a {@code Config} with {@link ConfigObject#toConfig}.
*
* <p>
* The static methods with "load" in the name do some sort of higher-level * The static methods with "load" in the name do some sort of higher-level
* operation potentially parsing multiple resources and resolving substitutions, * operation potentially parsing multiple resources and resolving substitutions,
* while the ones with "parse" in the name just create a ConfigValue from a * while the ones with "parse" in the name just create a {@link ConfigValue}
* resource and nothing else. * from a resource and nothing else.
*/ */
public final class ConfigFactory { public final class ConfigFactory {
/** /**
@ -45,7 +51,7 @@ public final class ConfigFactory {
* *
* @param rootPath * @param rootPath
* the configuration "domain" * the configuration "domain"
* @return configuration object for the requested root path * @return configuration for the requested root path
*/ */
public static ConfigRoot load(String rootPath) { public static ConfigRoot load(String rootPath) {
return loadWithoutResolving(rootPath).resolve(); return loadWithoutResolving(rootPath).resolve();
@ -60,10 +66,10 @@ public final class ConfigFactory {
/** /**
* Like load() but does not resolve the object, so you can go ahead and add * Like load() but does not resolve the object, so you can go ahead and add
* more fallbacks and stuff and have them seen by substitutions when you do * more fallbacks and stuff and have them seen by substitutions when you do
* call {@link ConfigRoot.resolve()}. * call {@link ConfigRoot#resolve}.
* *
* @param rootPath * @param rootPath
* @return * @return configuration for the requested root path
*/ */
public static ConfigRoot loadWithoutResolving(String rootPath) { public static ConfigRoot loadWithoutResolving(String rootPath) {
return loadWithoutResolving(rootPath, ConfigParseOptions.defaults()); return loadWithoutResolving(rootPath, ConfigParseOptions.defaults());
@ -125,7 +131,7 @@ public final class ConfigFactory {
* @param properties * @param properties
* a Java Properties object * a Java Properties object
* @param options * @param options
* @return * @return the parsed configuration
*/ */
public static Config parseProperties(Properties properties, public static Config parseProperties(Properties properties,
ConfigParseOptions options) { ConfigParseOptions options) {
@ -155,7 +161,7 @@ public final class ConfigFactory {
* *
* @param fileBasename * @param fileBasename
* @param options * @param options
* @return * @return the parsed configuration
*/ */
public static Config parseFileAnySyntax(File fileBasename, public static Config parseFileAnySyntax(File fileBasename,
ConfigParseOptions options) { ConfigParseOptions options) {
@ -175,7 +181,7 @@ public final class ConfigFactory {
* @param klass * @param klass
* @param resourceBasename * @param resourceBasename
* @param options * @param options
* @return * @return the parsed configuration
*/ */
public static Config parseResourceAnySyntax(Class<?> klass, String resourceBasename, public static Config parseResourceAnySyntax(Class<?> klass, String resourceBasename,
ConfigParseOptions options) { ConfigParseOptions options) {
@ -193,9 +199,9 @@ public final class ConfigFactory {
* "/foo-bar.conf", "/foo-bar.json", and "/foo-bar.properties". If more than * "/foo-bar.conf", "/foo-bar.json", and "/foo-bar.properties". If more than
* one of those exists, they are merged. * one of those exists, they are merged.
* *
* @param path * @param rootPath
* @param options * @param options
* @return * @return the parsed configuration
*/ */
public static Config parseResourcesForPath(String rootPath, public static Config parseResourcesForPath(String rootPath,
ConfigParseOptions options) { ConfigParseOptions options) {
@ -204,12 +210,15 @@ public final class ConfigFactory {
} }
/** /**
* Similar to ConfigValueFactory.fromMap(), but the keys in the map are path * Creates a {@code Config} based on a {@link java.util.Map} from paths to
* expressions, rather than keys; and correspondingly it returns a Config * plain Java values. Similar to
* instead of a ConfigObject. This is more convenient if you are writing * {@link ConfigValueFactory#fromMap(Map,String)}, except the keys in the
* literal maps in code, and less convenient if you are getting your maps * map are path expressions, rather than keys; and correspondingly it
* from some data source such as a parser. * returns a {@code Config} instead of a {@code ConfigObject}. This is more
* convenient if you are writing literal maps in code, and less convenient
* if you are getting your maps from some data source such as a parser.
* *
* <p>
* An exception will be thrown (and it is a bug in the caller of the method) * An exception will be thrown (and it is a bug in the caller of the method)
* if a path is both an object and a value, for example if you had both * if a path is both an object and a value, for example if you had both
* "a=foo" and "a.b=bar", then "a" is both the string "foo" and the parent * "a=foo" and "a.b=bar", then "a" is both the string "foo" and the parent
@ -221,7 +230,7 @@ public final class ConfigFactory {
* description of what this map represents, like a filename, or * description of what this map represents, like a filename, or
* "default settings" (origin description is used in error * "default settings" (origin description is used in error
* messages) * messages)
* @return * @return the map converted to a {@code Config}
*/ */
public static Config parseMap(Map<String, ? extends Object> values, public static Config parseMap(Map<String, ? extends Object> values,
String originDescription) { String originDescription) {
@ -229,11 +238,11 @@ public final class ConfigFactory {
} }
/** /**
* See the other overload of parseMap() for details, this one just uses a * See the other overload of {@link #parseMap(Map, String)} for details,
* default origin description. * this one just uses a default origin description.
* *
* @param values * @param values
* @return * @return the map converted to a {@code Config}
*/ */
public static Config parseMap(Map<String, ? extends Object> values) { public static Config parseMap(Map<String, ? extends Object> values) {
return parseMap(values, null); return parseMap(values, null);

View File

@ -5,8 +5,9 @@ package com.typesafe.config;
/** /**
* A ConfigIncludeContext is passed to a ConfigIncluder. This interface is not * Context provided to a {@link ConfigIncluder}; this interface is only useful
* intended for apps to implement. * inside a {@code ConfigIncluder} implementation, and is not intended for apps
* to implement.
*/ */
public interface ConfigIncludeContext { public interface ConfigIncludeContext {
/** /**

View File

@ -4,8 +4,9 @@
package com.typesafe.config; package com.typesafe.config;
/** /**
* Interface you have to implement to customize "include" statements in config * Implement this interface and provide an instance to
* files. * {@link ConfigParseOptions#setIncluder ConfigParseOptions.setIncluder()} to
* customize handling of {@code include} statements in config files.
*/ */
public interface ConfigIncluder { public interface ConfigIncluder {
/** /**

View File

@ -6,9 +6,30 @@ package com.typesafe.config;
import java.util.List; import java.util.List;
/** /**
* A list (aka array) value corresponding to ConfigValueType.LIST or JSON's * Subtype of {@link ConfigValue} representing a list value, as in JSON's
* "[1,2,3]" value. Implements java.util.List<ConfigValue> so you can use it * {@code [1,2,3]} syntax.
* like a regular Java list. *
* <p>
* {@code ConfigList} implements {@code java.util.List<ConfigValue>} so you can
* use it like a regular Java list. Or call {@link #unwrapped()} to unwrap the
* list elements into plain Java values.
*
* <p>
* Like all {@link ConfigValue} subtypes, {@code ConfigList} is immutable. This
* makes it threadsafe and you never have to create "defensive copies." The
* mutator methods from {@link java.util.List} all throw
* {@link java.lang.UnsupportedOperationException}.
*
* <p>
* The {@link ConfigValue#valueType} method on a list returns
* {@link ConfigValueType#LIST}.
*
* <p>
* <em>Do not implement {@code ConfigList}</em>; 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 ConfigList extends List<ConfigValue>, ConfigValue { public interface ConfigList extends List<ConfigValue>, ConfigValue {

View File

@ -4,28 +4,43 @@
package com.typesafe.config; package com.typesafe.config;
/** /**
* This is a marker for types that can be merged as a fallback into a Config or * Marker for types whose instances can be merged, that is {@link Config} and
* a ConfigValue. Both Config and ConfigValue are mergeable. * {@link ConfigValue}. Instances of {@code Config} and {@code ConfigValue} can
* be combined into a single new instance using the
* {@link ConfigMergeable#withFallback withFallback()} method.
*
* <p>
* <em>Do not implement this interface</em>; 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 ConfigMergeable { public interface ConfigMergeable {
/** /**
* Converts the mergeable to a ConfigValue to be merged. * 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#toObject}.
* *
* @return * @return this instance as a {@code ConfigValue}
*/ */
ConfigValue toValue(); ConfigValue toValue();
/** /**
* Returns a new value computed by merging this value with another, with * Returns a new value computed by merging this value with another, with
* keys in this value "winning" over the other one. Only ConfigObject and * keys in this value "winning" over the other one. Only
* Config instances do anything in this method (they need to merge the * {@link ConfigObject} and {@link Config} instances do anything in this
* fallback keys into themselves). All other values just return the original * method (they need to merge the fallback keys into themselves). All other
* value, since they automatically override any fallback. * values just return the original value, since they automatically override
* any fallback.
* *
* The semantics of merging are described in * <p>
* https://github.com/havocp/config/blob/master/HOCON.md * The semantics of merging are described in the <a
* href="https://github.com/havocp/config/blob/master/HOCON.md">spec for
* HOCON</a>.
* *
* Note that objects do not merge "across" non-objects; if you do * <p>
* Note that objects do not merge "across" non-objects; if you write
* <code>object.withFallback(nonObject).withFallback(otherObject)</code>, * <code>object.withFallback(nonObject).withFallback(otherObject)</code>,
* then <code>otherObject</code> will simply be ignored. This is an * then <code>otherObject</code> will simply be ignored. This is an
* intentional part of how merging works. Both non-objects, and any object * intentional part of how merging works. Both non-objects, and any object

View File

@ -6,54 +6,67 @@ package com.typesafe.config;
import java.util.Map; import java.util.Map;
/** /**
* A ConfigObject is a read-only configuration object, which may have nested * Subtype of {@link ConfigValue} representing an object (dictionary, map)
* child objects. Implementations of ConfigObject should be immutable (at least * value, as in JSON's <code>{ "a" : 42 }</code> syntax.
* from the perspective of anyone using this interface) and thus thread-safe.
* *
* In most cases you want to use the Config interface rather than this one. Call * <p>
* toConfig() to convert a ConfigObject to a config. * {@code ConfigObject} implements {@code java.util.Map<String, ConfigValue>} so
* you can use it like a regular Java map. Or call {@link #unwrapped()} to
* unwrap the map to a map with plain Java values rather than
* {@code ConfigValue}.
* *
* The API for a ConfigObject is in terms of keys, while the API for a Config is * <p>
* in terms of path expressions. Conceptually, ConfigObject is a tree of maps * Like all {@link ConfigValue} subtypes, {@code ConfigObject} is immutable.
* from keys to values, while a ConfigObject is a one-level map from paths to * This makes it threadsafe and you never have to create "defensive copies." The
* values. * mutator methods from {@link java.util.Map} all throw
* {@link java.lang.UnsupportedOperationException}.
* *
* Throughout the API, there is a distinction between "keys" and "paths". A key * <p>
* is a key in a JSON object; it's just a string that's the key in a map. A * The {@link ConfigValue#valueType} method on an object returns
* "path" is a parseable expression with a syntax and it refers to a series of * {@link ConfigValueType#OBJECT}.
* keys. A path is used to traverse nested ConfigObject by looking up each key
* in the path. Path expressions are described in the spec for "HOCON", which
* can be found at https://github.com/havocp/config/blob/master/HOCON.md; 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.
* *
* ConfigObject implements java.util.Map<String,ConfigValue> and all methods * <p>
* work with keys, not path expressions. * 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}.
* *
* While ConfigObject implements the standard Java Map interface, the mutator * <p>
* methods all throw UnsupportedOperationException. This Map is immutable. * 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 ConfigObject} is a one-level map from paths to values.
* *
* The Map may contain null values, which will have ConfigValue.valueType() == * <p>
* ConfigValueType.NULL. If get() returns Java's null then the key was not * A {@code ConfigObject} may contain null values, which will have
* present in the parsed file (or wherever this value tree came from). If get() * {@link ConfigValue#valueType()} equal to {@link ConfigValueType#NULL}. If
* returns a ConfigValue with type ConfigValueType.NULL then the key was set to * {@code get()} returns Java's null then the key was not present in the parsed
* null explicitly. * 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.
*
* <p>
* <em>Do not implement {@code ConfigObject}</em>; 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<String, ConfigValue> { public interface ConfigObject extends ConfigValue, Map<String, ConfigValue> {
/** /**
* Converts this object to a Config instance, enabling you to use path * Converts this object to a {@link Config} instance, enabling you to use
* expressions to find values in the object. This is a constant-time * path expressions to find values in the object. This is a constant-time
* operation (it is not proportional to the size of the object). * operation (it is not proportional to the size of the object).
* *
* @return * @return a {@link Config} with this object as its root
*/ */
Config toConfig(); Config toConfig();
/** /**
* Recursively unwraps the object, returning a map from String to whatever * Recursively unwraps the object, returning a map from String to whatever
* plain Java values are unwrapped from the object's values. * plain Java values are unwrapped from the object's values.
*
* @return a {@link java.util.Map} containing plain Java objects
*/ */
@Override @Override
Map<String, Object> unwrapped(); Map<String, Object> unwrapped();
@ -62,10 +75,15 @@ public interface ConfigObject extends ConfigValue, Map<String, ConfigValue> {
ConfigObject withFallback(ConfigMergeable other); ConfigObject withFallback(ConfigMergeable other);
/** /**
* Gets a ConfigValue at the given key, or returns null if there is no * Gets a {@link ConfigValue} at the given key, or returns null if there is
* value. The returned ConfigValue may have ConfigValueType.NULL or any * no value. The returned {@link ConfigValue} may have
* other type, and the passed-in key must be a key in this object, rather * {@link ConfigValueType#NULL} or any other type, and the passed-in key
* than a path expression. * must be a key in this object, rather than a path expression.
*
* @param key
* key to look up
*
* @return the value at the key or null if none
*/ */
@Override @Override
ConfigValue get(Object key); ConfigValue get(Object key);

View File

@ -4,8 +4,16 @@
package com.typesafe.config; package com.typesafe.config;
/** /**
* ConfigOrigin is used to track the origin (such as filename and line number) * Represents the origin (such as filename and line number) of a
* of a ConfigValue or other object. The origin is used in error messages. * {@link ConfigValue} for use in error messages. Obtain the origin of a value
* with {@link ConfigValue#origin}.
*
* <p>
* <em>Do not implement this interface</em>; 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 ConfigOrigin { public interface ConfigOrigin {
public String description(); public String description();

View File

@ -4,6 +4,22 @@
package com.typesafe.config; package com.typesafe.config;
/**
* A set of options related to parsing.
*
* <p>
* This object is immutable, so the "setters" return a new object.
*
* <p>
* Here is an example of creating a custom {@code ConfigParseOptions}:
*
* <pre>
* ConfigParseOptions options = ConfigParseOptions.defaults()
* .setSyntax(ConfigSyntax.JSON)
* .setAllowMissing(false)
* </pre>
*
*/
public final class ConfigParseOptions { public final class ConfigParseOptions {
final ConfigSyntax syntax; final ConfigSyntax syntax;
final String originDescription; final String originDescription;
@ -24,10 +40,11 @@ public final class ConfigParseOptions {
/** /**
* Set the file format. If set to null, try to guess from any available * Set the file format. If set to null, try to guess from any available
* filename extension; if guessing fails, assume ConfigSyntax.CONF. * filename extension; if guessing fails, assume {@link ConfigSyntax#CONF}.
* *
* @param syntax * @param syntax
* @return * a syntax or {@code null} for best guess
* @return options with the syntax set
*/ */
public ConfigParseOptions setSyntax(ConfigSyntax syntax) { public ConfigParseOptions setSyntax(ConfigSyntax syntax) {
if (this.syntax == syntax) if (this.syntax == syntax)
@ -45,10 +62,11 @@ public final class ConfigParseOptions {
* Set a description for the thing being parsed. In most cases this will be * Set a description for the thing being parsed. In most cases this will be
* set up for you to something like the filename, but if you provide just an * set up for you to something like the filename, but if you provide just an
* input stream you might want to improve on it. Set to null to allow the * input stream you might want to improve on it. Set to null to allow the
* library to come up with something automatically. * library to come up with something automatically. This description is the
* basis for the {@link ConfigOrigin} of the parsed values.
* *
* @param originDescription * @param originDescription
* @return * @return options with the origin description set
*/ */
public ConfigParseOptions setOriginDescription(String originDescription) { public ConfigParseOptions setOriginDescription(String originDescription) {
if (this.originDescription == originDescription) if (this.originDescription == originDescription)
@ -79,7 +97,7 @@ public final class ConfigParseOptions {
* case. * case.
* *
* @param allowMissing * @param allowMissing
* @return * @return options with the "allow missing" flag set
*/ */
public ConfigParseOptions setAllowMissing(boolean allowMissing) { public ConfigParseOptions setAllowMissing(boolean allowMissing) {
if (this.allowMissing == allowMissing) if (this.allowMissing == allowMissing)

View File

@ -5,19 +5,39 @@ package com.typesafe.config;
import java.net.URL; import java.net.URL;
/** An opaque handle to something that can be parsed. */ /**
* An opaque handle to something that can be parsed, obtained from
* {@link ConfigIncludeContext}.
*
* <p>
* <em>Do not implement this interface</em>; 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 ConfigParseable { public interface ConfigParseable {
/** /**
* Parse whatever it is. * Parse whatever it is. The options should come from
* {@link ConfigParseable#options options()} but you could tweak them if you
* like.
* *
* @param options * @param options
* parse options, should be based on the ones from options() * parse options, should be based on the ones from
* {@link ConfigParseable#options options()}
*/ */
ConfigObject parse(ConfigParseOptions options); ConfigObject parse(ConfigParseOptions options);
/** Possibly return a URL representing the resource; this may return null. */ /**
* Possibly return a URL representing the resource; this may return null if
* the resource has no meaningful URL representation.
*/
URL url(); URL url();
/** Get the initial options, which can be modified then passed to parse(). */ /**
* Get the initial options, which can be modified then passed to parse().
* These options will have the right description, includer, and other
* parameters already set up.
*/
ConfigParseOptions options(); ConfigParseOptions options();
} }

View File

@ -3,6 +3,28 @@
*/ */
package com.typesafe.config; 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.
*/
public final class ConfigResolveOptions { public final class ConfigResolveOptions {
private final boolean useSystemProperties; private final boolean useSystemProperties;
private final boolean useSystemEnvironment; private final boolean useSystemEnvironment;
@ -13,26 +35,68 @@ public final class ConfigResolveOptions {
this.useSystemEnvironment = useSystemEnvironment; this.useSystemEnvironment = useSystemEnvironment;
} }
/**
* Returns the default resolve options.
*
* @return the default resolve options
*/
public static ConfigResolveOptions defaults() { public static ConfigResolveOptions defaults() {
return new ConfigResolveOptions(true, true); return new ConfigResolveOptions(true, true);
} }
/**
* Returns resolve options that disable any reference to "system" data
* (system properties or environment variables).
*
* @return the resolve options with system properties and env variables
* disabled
*/
public static ConfigResolveOptions noSystem() { public static ConfigResolveOptions noSystem() {
return new ConfigResolveOptions(false, false); return new ConfigResolveOptions(false, 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) { public ConfigResolveOptions setUseSystemProperties(boolean value) {
return new ConfigResolveOptions(value, useSystemEnvironment); return new ConfigResolveOptions(value, useSystemEnvironment);
} }
/**
* Returns options with use of environment variables set to the given value.
*
* @param value
* true to resolve substitutions falling back to environment
* variables.
* @return options with requested setting for use of environment variables
*/
public ConfigResolveOptions setUseSystemEnvironment(boolean value) { public ConfigResolveOptions setUseSystemEnvironment(boolean value) {
return new ConfigResolveOptions(useSystemProperties, 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() { public boolean getUseSystemProperties() {
return useSystemProperties; return useSystemProperties;
} }
/**
* Returns whether the options enable use of system environment variables.
* This method is mostly used by the config lib internally, not by
* applications.
*
* @return true if environment variables should be used
*/
public boolean getUseSystemEnvironment() { public boolean getUseSystemEnvironment() {
return useSystemEnvironment; return useSystemEnvironment;
} }

View File

@ -4,21 +4,36 @@
package com.typesafe.config; package com.typesafe.config;
/** /**
* A root object. The only special thing about a root object is that you can * Subtype of {@link Config} which is a root rather than nested object and
* resolve substitutions against it. So it can have a resolve() method that * supports {@link ConfigRoot#resolve resolving substitutions}.
* doesn't require you to pass in an object to resolve against. *
* <p>
* <em>Do not implement this interface</em>; 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 ConfigRoot extends Config { public interface ConfigRoot extends Config {
/** /**
* Returns a replacement root object with all substitutions (the * Returns a replacement root object with all substitutions (the
* "${foo.bar}" syntax) resolved. Substitutions are looked up in this root * <code>${foo.bar}</code> syntax, see <a
* object. A configuration value tree must be resolved before you can use * href="https://github.com/havocp/config/blob/master/HOCON.md">the
* it. This method uses ConfigResolveOptions.defaults(). * spec</a>) resolved. Substitutions are looked up in this root object. A
* {@link Config} must be resolved before you can use it. This method uses
* {@link ConfigResolveOptions#defaults()}.
* *
* @return an immutable object with substitutions resolved * @return an immutable object with substitutions resolved
*/ */
ConfigRoot resolve(); ConfigRoot resolve();
/**
* Like {@link ConfigRoot#resolve()} but allows you to specify options.
*
* @param options
* resolve options
* @return the resolved root config
*/
ConfigRoot resolve(ConfigResolveOptions options); ConfigRoot resolve(ConfigResolveOptions options);
@Override @Override

View File

@ -3,6 +3,30 @@
*/ */
package com.typesafe.config; package com.typesafe.config;
/**
* The syntax of a character stream, <a href="http://json.org">JSON</a>, <a
* href="https://github.com/havocp/config/blob/master/HOCON.md">HOCON</a> aka
* ".conf", or <a href=
* "http://download.oracle.com/javase/7/docs/api/java/util/Properties.html#load%28java.io.Reader%29"
* >Java properties</a>.
*
*/
public enum ConfigSyntax { public enum ConfigSyntax {
JSON, CONF, PROPERTIES; /**
* Pedantically strict <a href="http://json.org">JSON</a> format; no
* comments, no unexpected commas, no duplicate keys in the same object.
*/
JSON,
/**
* The JSON-superset <a
* href="https://github.com/havocp/config/blob/master/HOCON.md">HOCON</a>
* format.
*/
CONF,
/**
* Standard <a href=
* "http://download.oracle.com/javase/7/docs/api/java/util/Properties.html#load%28java.io.Reader%29"
* >Java properties</a> format.
*/
PROPERTIES;
} }

View File

@ -4,29 +4,42 @@
package com.typesafe.config; package com.typesafe.config;
/** /**
* Interface implemented by any configuration value. From the perspective of * An immutable value, following the <a href="http://json.org">JSON</a> type
* users of this interface, the object is immutable. It is therefore safe to use * schema.
* from multiple threads. *
* <p>
* Because this object is immutable, it is safe to use from multiple threads and
* there's no need for "defensive copies."
*
* <p>
* <em>Do not implement {@code ConfigValue}</em>; 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 { public interface ConfigValue extends ConfigMergeable {
/** /**
* The origin of the value, for debugging and error messages. * The origin of the value (file, line number, etc.), for debugging and
* error messages.
* *
* @return where the value came from * @return where the value came from
*/ */
ConfigOrigin origin(); ConfigOrigin origin();
/** /**
* The type of the value; matches the JSON type schema. * The {@link ConfigValueType} of the value; matches the JSON type schema.
* *
* @return value's type * @return value's type
*/ */
ConfigValueType valueType(); ConfigValueType valueType();
/** /**
* Returns the config value as a plain Java boxed value, should be a String, * Returns the value as a plain Java boxed value, that is, a {@code String},
* Number, etc. matching the valueType() of the ConfigValue. If the value is * {@code Number}, {@code Boolean}, {@code Map<String,Object>},
* a ConfigObject or ConfigList, it is recursively unwrapped. * {@code List<Object>}, or {@code null}, matching the {@link #valueType()}
* of this {@code ConfigValue}. If the value is a {@link ConfigObject} or
* {@link ConfigList}, it is recursively unwrapped.
*/ */
Object unwrapped(); Object unwrapped();

View File

@ -3,7 +3,6 @@
*/ */
package com.typesafe.config; package com.typesafe.config;
import java.util.Collection;
import java.util.Map; import java.util.Map;
import com.typesafe.config.impl.ConfigImpl; import com.typesafe.config.impl.ConfigImpl;
@ -23,23 +22,27 @@ public final class ConfigValueFactory {
* the Iterable is not an ordered collection, results could be strange, * the Iterable is not an ordered collection, results could be strange,
* since ConfigList is ordered. * since ConfigList is ordered.
* *
* <p>
* In a Map passed to fromAnyRef(), the map's keys are plain keys, not path * 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 * 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 * object with a key called "foo.bar", rather than an object with a key
* "foo" containing another object with a key "bar". * "foo" containing another object with a key "bar".
* *
* <p>
* The originDescription will be used to set the origin() field on the * 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 * ConfigValue. It should normally be the name of the file the values came
* from, or something short describing the value such as "default settings". * from, or something short describing the value such as "default settings".
* The originDescription is prefixed to error messages so users can tell * The originDescription is prefixed to error messages so users can tell
* where problematic values are coming from. * where problematic values are coming from.
* *
* <p>
* Supplying the result of ConfigValue.unwrapped() to this function is * Supplying the result of ConfigValue.unwrapped() to this function is
* guaranteed to work and should give you back a ConfigValue that matches * guaranteed to work and should give you back a ConfigValue that matches
* the one you unwrapped. The re-wrapped ConfigValue will lose some * the one you unwrapped. The re-wrapped ConfigValue will lose some
* information that was present in the original such as its origin, but it * information that was present in the original such as its origin, but it
* will have matching values. * will have matching values.
* *
* <p>
* This function throws if you supply a value that cannot be converted to a * 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 * 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 * should never handle the exception. Just fix your program (or report a bug
@ -57,23 +60,25 @@ public final class ConfigValueFactory {
/** /**
* See the fromAnyRef() documentation for details. This is a typesafe * See the fromAnyRef() documentation for details. This is a typesafe
* wrapper that only works on Map and returns ConfigObject rather than * wrapper that only works on {@link java.util.Map} and returns
* ConfigValue. * {@link ConfigObject} rather than {@link ConfigValue}.
* *
* <p>
* If your Map has a key "foo.bar" then you will get one object with a key * 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 * 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 * 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 * expressions. That is, the Map corresponds exactly to a single
* ConfigObject. The keys will not be parsed or modified, and the values are * {@code ConfigObject}. The keys will not be parsed or modified, and the
* wrapped in ConfigValue. To get nested ConfigObject, some of the values in * values are wrapped in ConfigValue. To get nested {@code ConfigObject},
* the map would have to be more maps. * some of the values in the map would have to be more maps.
* *
* There is a separate fromPathMap() that interprets the keys in the map as * <p>
* path expressions. * See also {@link ConfigFactory#parseMap(Map,String)} which interprets the
* keys in the map as path expressions.
* *
* @param values * @param values
* @param originDescription * @param originDescription
* @return * @return a new {@link ConfigObject} value
*/ */
public static ConfigObject fromMap(Map<String, ? extends Object> values, public static ConfigObject fromMap(Map<String, ? extends Object> values,
String originDescription) { String originDescription) {
@ -82,12 +87,12 @@ public final class ConfigValueFactory {
/** /**
* See the fromAnyRef() documentation for details. This is a typesafe * See the fromAnyRef() documentation for details. This is a typesafe
* wrapper that only works on Iterable and returns ConfigList rather than * wrapper that only works on {@link java.util.Iterable} and returns
* ConfigValue. * {@link ConfigList} rather than {@link ConfigValue}.
* *
* @param values * @param values
* @param originDescription * @param originDescription
* @return * @return a new {@link ConfigList} value
*/ */
public static ConfigList fromIterable(Iterable<? extends Object> values, public static ConfigList fromIterable(Iterable<? extends Object> values,
String originDescription) { String originDescription) {
@ -95,35 +100,39 @@ public final class ConfigValueFactory {
} }
/** /**
* See the other overload of fromAnyRef() for details, this one just uses a * See the other overload {@link #fromAnyRef(Object,String)} for details,
* default origin description. * this one just uses a default origin description.
* *
* @param object * @param object
* @return * @return a new {@link ConfigValue}
*/ */
public static ConfigValue fromAnyRef(Object object) { public static ConfigValue fromAnyRef(Object object) {
return fromAnyRef(object, null); return fromAnyRef(object, null);
} }
/** /**
* See the other overload of fromMap() for details, this one just uses a * See the other overload {@link #fromMap(Map,String)} for details, this one
* default origin description. * just uses a default origin description.
*
* <p>
* See also {@link ConfigFactory#parseMap(Map)} which interprets the keys in
* the map as path expressions.
* *
* @param values * @param values
* @return * @return a new {@link ConfigObject}
*/ */
public static ConfigObject fromMap(Map<String, ? extends Object> values) { public static ConfigObject fromMap(Map<String, ? extends Object> values) {
return fromMap(values, null); return fromMap(values, null);
} }
/** /**
* See the other overload of fromIterable() for details, this one just uses * See the other overload of {@link #fromIterable(Iterable, String)} for
* a default origin description. * details, this one just uses a default origin description.
* *
* @param values * @param values
* @return * @return a new {@link ConfigList}
*/ */
public static ConfigList fromIterable(Collection<? extends Object> values) { public static ConfigList fromIterable(Iterable<? extends Object> values) {
return fromIterable(values, null); return fromIterable(values, null);
} }
} }

View File

@ -4,7 +4,8 @@
package com.typesafe.config; package com.typesafe.config;
/** /**
* The type of a configuration value. Value types follow the JSON type schema. * The type of a configuration value (following the <a
* href="http://json.org">JSON</a> type schema).
*/ */
public enum ConfigValueType { public enum ConfigValueType {
OBJECT, LIST, NUMBER, BOOLEAN, NULL, STRING OBJECT, LIST, NUMBER, BOOLEAN, NULL, STRING

View File

@ -0,0 +1,20 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<!--
Copyright (C) 2011 Typesafe Inc. <http://typesafe.com>
-->
</head>
<body bgcolor="white">
An API for loading and using configuration files, see <a href="https://github.com/havocp/config/">the project site</a>
for more information.
<p>
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.
</p>
</body>
</html>