make ConfigException.Null extend Missing instead of WrongType

WrongType makes sense in the context of ConfigObject, but
Missing makes sense in the context of Config.
This commit is contained in:
Havoc Pennington 2011-11-17 21:45:07 -05:00
parent 7cdbe721a9
commit f6395d629d
2 changed files with 115 additions and 13 deletions

View File

@ -5,7 +5,7 @@ import java.util.List;
/**
* This class represents an immutable map from config paths to config values. It
* also contains some static methods for creating configs.
*
*
* 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
@ -14,30 +14,30 @@ import java.util.List;
* 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 Config is in terms of path expressions, while the API for a
* ConfigObject is in terms of keys. Conceptually, Config is a one-level map
* from paths to values, while a ConfigObject is a tree of maps from keys to
* values.
*
*
* Another difference between Config and ConfigObject is that conceptually,
* ConfigValue with valueType() of ConfigValueType.NULL exist in a ConfigObject,
* while a Config treats null values as if they were missing.
*
*
* Config is an immutable object and thus safe to use from multiple threads.
*
*
* The "getters" on a Config all work in the same way. They never return null,
* or a ConfigValue with valueType() of ConfigValueType.NULL. If the value is
* completely absent then ConfigException.Missing will be thrown, and if the
* value is present but null, ConfigException.Null will be thrown.
* ConfigException.Null is a subclass of ConfigException.WrongType, where
* nor do they return a ConfigValue with valueType() of ConfigValueType.NULL.
* Instead, they throw ConfigException.Missing if the value is completely absent
* or set to null. If the value is set to null, a subtype of
* ConfigException.Missing called ConfigException.Null will be thrown.
* 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
* ConfigObject with toObject, and then iterate over the ConfigObject.
*
*
*/
public interface Config extends ConfigMergeable {
/**
@ -80,25 +80,93 @@ public interface Config extends ConfigMergeable {
boolean isEmpty();
/**
*
* @param path
* @return
* @throws ConfigException.Missing
* if value is absent or null
* @throws ConfigException.WrongType
* if value is not convertible to boolean
*/
boolean getBoolean(String path);
/**
* @param path
* @return
* @throws ConfigException.Missing
* if value is absent or null
* @throws ConfigException.WrongType
* if value is not convertible to a number
*/
Number getNumber(String path);
/**
* @param path
* @return
* @throws ConfigException.Missing
* if value is absent or null
* @throws ConfigException.WrongType
* if value is not convertible to an int
*/
int getInt(String path);
/**
* @param path
* @return
* @throws ConfigException.Missing
* if value is absent or null
* @throws ConfigException.WrongType
* if value is not convertible to a long
*/
long getLong(String path);
/**
* @param path
* @return
* @throws ConfigException.Missing
* if value is absent or null
* @throws ConfigException.WrongType
* if value is not convertible to a double
*/
double getDouble(String path);
/**
* @param path
* @return
* @throws ConfigException.Missing
* if value is absent or null
* @throws ConfigException.WrongType
* if value is not convertible to a string
*/
String getString(String path);
/**
* @param path
* @return
* @throws ConfigException.Missing
* if value is absent or null
* @throws ConfigException.WrongType
* if value is not convertible to an object
*/
ConfigObject getObject(String path);
/**
* @param path
* @return
* @throws ConfigException.Missing
* if value is absent or null
* @throws ConfigException.WrongType
* if value is not convertible to a Config
*/
Config getConfig(String path);
/**
* Gets the value at the path as an unwrapped Java boxed value (Boolean,
* Integer, Long, etc.)
*
* @throws ConfigException.Missing
* if value is absent or null
*/
Object getAnyRef(String path);
@ -109,6 +177,8 @@ public interface Config extends ConfigMergeable {
*
* @param path
* @return
* @throws ConfigException.Missing
* if value is absent or null
*/
ConfigValue getValue(String path);
@ -116,6 +186,13 @@ public interface Config extends ConfigMergeable {
* Get 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
* are in powers of two.
*
* @throws ConfigException.Missing
* if value is absent or null
* @throws ConfigException.WrongType
* if value is not convertible to Long or String
* @throws ConfigException.BadValue
* if value cannot be parsed as a memory size
*/
Long getMemorySizeInBytes(String path);
@ -123,6 +200,13 @@ public interface Config extends ConfigMergeable {
* 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
* units suffixes like "10m" or "5ns"
*
* @throws ConfigException.Missing
* if value is absent or null
* @throws ConfigException.WrongType
* if value is not convertible to Long or String
* @throws ConfigException.BadValue
* if value cannot be parsed as a number of milliseconds
*/
Long getMilliseconds(String path);
@ -130,6 +214,13 @@ public interface Config extends ConfigMergeable {
* 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
* string, it's parsed understanding unit suffixes.
*
* @throws ConfigException.Missing
* if value is absent or null
* @throws ConfigException.WrongType
* if value is not convertible to Long or String
* @throws ConfigException.BadValue
* if value cannot be parsed as a number of nanoseconds
*/
Long getNanoseconds(String path);
@ -141,6 +232,10 @@ public interface Config extends ConfigMergeable {
* @param path
* the path to the list value.
* @return the ConfigList at the path
* @throws ConfigException.Missing
* if value is absent or null
* @throws ConfigException.WrongType
* if value is not convertible to a ConfigList
*/
ConfigList getList(String path);

View File

@ -69,13 +69,20 @@ public class ConfigException extends RuntimeException {
this(path, null);
}
protected Missing(ConfigOrigin origin, String message, Throwable cause) {
super(origin, message, cause);
}
protected Missing(ConfigOrigin origin, String message) {
this(origin, message, null);
}
}
/**
* Exception indicates that the type was wrong and specifically the value
* was null instead of a real value.
* Exception indicates that the setting was treated as missing because it
* was set to null.
*/
public static class Null extends WrongType {
public static class Null extends Missing {
private static final long serialVersionUID = 1L;
private static String makeMessage(String path, String expected) {