-
Notifications
You must be signed in to change notification settings - Fork 28
Configurations
A configuration is a data structure that maps keys to values. Each key is unique and associated to zero or one value. In essence, a configuration is very similar to a Map<String, Object>
.
Configurations can be nested to create any structure you want.
Keys are strings that represent the path of a value. It can be a simple name, or a compound path in the case of nested configurations. Compound paths are expressed with dots, like a.b.c
.
For instance, take the following json document:
{
"a": "something",
"b": {
"c": 123
},
"key.with.dots": true
}
-
something
is accessible with the keya
-
{"c": 123}
is accessible with the keyb
-
123
is accessible with the compound keyb.c
. Here we say thatb
is a sub-configuration. -
true
is accessible with the simple keykey.with.dots
, which is not a compound path despite having dots. We'll see later how to tell NightConfig that such a key isn't compound.
Values can be anything... until you write them in a particular format, for instance JSON. At this moment, you have to be sure that all the values are supported by the configuration format, typically:
- Standard numbers (int, long, float, etc.)
- Strings
- Booleans
- Sub-configurations
- Lists of such values (Java
Collection
)
Map<String, Object>
should be avoided and replaced by proper configuration objects.
NightConfig provides several config types. The most important ones are UnmodifiableConfig
and Config
.
Config
is your basic, read-write configuration interface and, as the name suggests, UnmodifiableConfig
is a read-only configuration. Beware that every modifiable Config
inherits from UnmodifiableConfig
. Therefore, one can obtain a ready-only view that reflects the changes made to the modifiable config. UnmodifiableConfigs aren't guaranteed to be immutable.
The Config
class provides static methods to create new configurations. One of them is inMemory()
, which creates an in-memory configuration which is independent of any configuration format (see Config formats).
By default, configurations aren't thread-safe. You have to ask for thread-safety when you create the configuration object.
Config config = Config.inMemory(); // in-memory, not thread-safe
UnmodifiableConfig configView = config; // read-only view of config
Config safeConfig = Config.inMemoryConcurrent(); // in-memory, thread-safe
UnmodifiableConfig safeView = safeConfig; // read-only view of safeConfig
With FileConfig.of(File)
you can get a configuration from a file, providing that its name allows NightConfig to know its configuration format and that you've added the module corresponding to that format.
Here is an example with JSON:
File configFile = new File("path/to/my/config.json");
FileConfig config = FileConfig.of(configFile); // Associates the file to the config
// For now, the configuration is empty. We need to read its content:
config.load(); // Reads the file and populates the config
In this paragraph, the examples assume that you've read the following JSON data with FileConfig:
{
"a": "something",
"b": {
"c": 123
},
"key.with.dots": true
}
UnmodifiableConfig defines the get
and getOptional
methods that allow you to read values from the config. You give the path as a String parameter. If it contains dots, the path is parsed as a compound path. Otherwise, it is a simple path.
String str = config.get("a");
Optional<String> strOptional = config.getOptional("a"); // Optional of "something"
Optional<String> notFound = config.getOptional("I'm not in the config"); // Empty optional
Config sub = config.get("b"); // sub configuration
int subN = sub.get("c");
int n = config.get("b.c"); // compound path
assert subN == n; // OK: subN and n are the same
Note that you don't have to specify the type of the value, because NightConfig automatically uses the type of the variable you assign the value to.
OK, so we can use compound paths by separating the different parts with dots. But how to use a simple key that contains dots? The answer is simple: bypass path parsing with a list.
boolean value = config.get(Arrays.of("key.with.dots"));
Each element of the list is a key. In our example, we create a list with only one element to access our simple value.
We could have used a list instead of b.c
:
int n = config.get(Arrays.of("b", "c"));
Use Config.set
to replace existing values and to add new ones.
config.set("a", "new value");
config.set("new key", "new value");
config.set(Arrays.of("key.with.dots"), 12345);
Use Config.add
to add new values without overwriting existing ones, and Config.remove
to remove existing values.
config.add("a new key", "a new value"); // ok
config.add("a", "new value for existing key a"); // won't modify the value of a
config.remove("a");
As always, you can use List
paths instead of String
paths.