Skip to content

A248/DazzleConf

Repository files navigation

DazzleConf Maven Central Javadoc discord

A sleek, usable, and fully-featured configuration library. Supports HOCON, TOML, and YAML.

Documentation is in the /docs/ folder.

Version 2 is still in the preview stage while we stabilize the API; for version 1.0, see the "master" branch.

Objectives

  • Extensible and user-friendly. All types use the same framework, and library users can easily add new types.
  • Type safety. Configuration is an immutable interface.
  • Automatically update old configurations with the latest keys. No need to version config files.
  • No NULLs. No public mutable fields. No stringly-typed spaghetti such as getString("key"), and no type-unsafe calls like getInt("maybe-not-really-an-integer").
  • Informative, helpful error reports. Messages that human beings (even non-programmers!) can understand. Reports key path and line number, and library error messages can even be translated depending on the locale.

Introduction

DazzleConf is a clean, well-tested library to meet your configuration needs. It's quick to get running, and all you need to do is provide an interface:

Configuration<AppConfig> configuration = Configuration.defaultBuilder(AppConfig.class).build();
Backend backend = new YamlBackend(new PathRoot(Path.of("config.yml")));
AppConfig config = configuration.configureOrFallback(backend, new StandardErrorPrint(output -> output.printTo(System.out)));
// DONE! You now have a user-friendly, type-safe configuration system

if (config.woah()) {
    System.out.println(config.awesome());
}

interface AppConfig { 
    default boolean woah() { return true; }

    @Comments("An awesome comment")
    default String awesome() { return "hello world"; }

    @IntegerRange(min = 1, max = 100)
    default long boundedNumeric() { return 10; }

    @SubSection MoreStuff moreStuff();

    interface MoreStuff {

        @Comments(value = "Inline comment", location = CommentLocation.INLINE)
        default String userMessage() { return "Hello user"; }

        @Comments("Every annotation shown above works here too")
        default String flexibility() {
            return "Also, methods are inherited if this interface extends another, enabling inheritable config interfaces";
        }
    }
}

When using the YAML backend, the following result is generated by writing the default configuration.

Notice how keys are mapped to lower-snake-case. This happens automatically depending on the backend you choose.

woah: true
# An awesome comment
awesome: hello world
more-stuff:
  user-message: 'Hello user' # Inline comment
  # Every annotation shown above works here too
  flexibility: 'Also, methods are inherited if this interface extends another, enabling inheritable config interfaces'

The same document can be reparsed to an instance of the configuration interface. Type and constraint validation is performed when the configuration is loaded, not when the methods are called - having an instance of the config interface is enough to ensure the configuration is valid.

Configuration formats

We offer multiple configuration formats depending on your preference. Simply depend on the artifact matching the format you want.

Format Reference Artifact Comment Support
HOCON HOCON.md dazzleconf-hocon Writing only
TOML TOML 1.0 spec dazzleconf-toml Writing only
YAML YAML 1.2 spec dazzleconf-yaml Full

Check out this page to get started using the library: Getting started. The documentation has many examples such as with setting up a reloadable configuration, automatically updating the configuration with the latest keys, and more.

Full Feature List

  • Serializers can depend on each other.
  • Full generics support. Support for infinitely nested generics, collections, configuration subsections, etc.
    • List<List<List<List<MyType>>>> is fully usable, requiring no extra code.
    • Library users can write their own type like MyGeneric<T>, extract the generic parameter T, and get a serializer for T.
    • Anything you can imagine is possible. Even generic parameters on the configuration itself are supported. For example, MyConfig<V> with a method V myOption().
    • Annotations are usable as well.
  • Immutable and thread safe by design.
    • Values loaded once and never modified thereafter.
    • Loading is fail-fast: if a configured value from the text file is not interpretable as the desired return type, it is rejected.
  • Reading and writing:
    • Read from file. ✔️
    • Write to file. ✔️
    • Combined read/write operation, to update existing data. ✔️
    • Can write any object implementing the configuration interface (not just implementations by the library).
  • Reloading:
    • Easy-to-reload "shell" instance can be created, to swap the values in a live configuration.
  • Migrations:
    • Detect old versions, and migrate safely to latest version.
    • Lets you change keys, move keys around, and merge or separate sections.
    • Lets you migrate from other configuration libraries when their files exist on disk.
  • Notifications. Caller can listen for:
    • When data is updated with a better representation. E.g. "3" -> 3 or fAlSE -> false.
    • When missing keys are added.
    • If using migrations, when migrations are triggered.
  • Excellent and translatable error messages:
    • Select user locale, or auto-detect default locale.
    • Community can provide translations of all messages.
    • If you made a mistake as a developer, error message includes information needed to fix the problem.
  • Backends:
    • HOCON, TOML, and YAML implemented so far.
    • No external dependencies: they are shaded in.
    • Relevant library features (key format, comment support) automatically adapt to the backend in use.
  • Low-level DataTree API:
    • Can read and write data, independent of the backend.
    • Can read and write comments if the backend supports it, including document-level header and footer.
    • Comments can be placed above, below, or inline.

Not yet implemented:

  • Streaming API for more efficient read/write.
    • Would make I/O more efficient.
    • Could skip intermediate structures like unnecessary maps and lists, and have them created in an on-demand basis.
  • Greater communication between backend format and configuration definition, where the configuration interface gives the backend hints about which basic types (e.g., string or integer) and type structures (scalar/map/array) are preferred
    • Planned to be combined with the streaming API.

Extra

Requirements

  • Java 8

Java 11 is recommended, but not required.

module-info files are also included, and these are backwards compatible with Java 8.

Documentation

See the docs folder of this repository for documentation on using this library.

Additionally, the javadocs are published with the artifact. They can also be browsed here.

License

LGPL. See the license file for more information.