Configuration library based on annotation processing

Overview

net.cactusthorn.config

The Java library with the goal of minimizing the code required to handle application configuration.

build Coverage Status Language grade: Java Codacy Badge Maven Central with version prefix filter GitHub Build by Maven

Motivation

The inspiring idea for the project comes from OWNER. OWNER is a nice Java library for the same purpose, but it's not factually maintained anymore, and it's not really support "new" language features from Java 8+.

So, this project is providing library with similar with OWNER API, but

  • Based not on Reflection, but on compile-time Code Generation (Java Annotation Processing).
  • Required at least Java 8, as result it support "more fresh" language features.

Features

  • Core is plain Java 8 without any external dependencies

  • Uses no reflection or runtime bytecode generation; generates plain Java source code.

  • Small (< 100KB) & lightweight core runtime part

  • Ready to use with OSGi

  • Supports multiple configuration sources: files, classpath, URLs, environment variables, system properties, META-INF/MANIFEST.MF, Apache ZooKeeper

  • Supports files in Multiple formats:

  • Supports multiple loading strategies (configuration sources fallback/merging)

  • Expandable with custom source loaders

  • Powerful type conversions: collections, maps, enums, etc.

  • Parameterized type converters

  • Expandable with custom type converters

  • Special support for java.util.Optional, java.time.*, byte-size settings (e.g. 10Mb), Jasypt password-based encryption

  • Caching

  • Seamless integration with DI containers

  • Thread-safe

  • Reloading, Periodical auto reloading, Reload event listeners

Basics

Installing

Download: Maven Central Repository.
Download: GitHub Packages.

In order to use the library in a project, it's need to add the dependency to the pom.xml:

<dependency>
    <groupId>net.cactusthorn.config</groupId>
    <artifactId>config-core</artifactId>
    <version>0.70</version>
</dependency>

It's also need to include the compiler used to convert annotated "source"-interfaces into the code:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
         <annotationProcessorPaths>
              <path>
                  <groupId>net.cactusthorn.config</groupId>
                  <artifactId>config-compiler</artifactId>
                  <version>0.70</version>
              </path>
         </annotationProcessorPaths>
    </configuration>
</plugin>

FYI: With this configuration, Maven will output the generated code into target/generated-sources/annotations.

Same with Gradle:

api 'net.cactusthorn.config:config-core:0.70'
annotationProcessor 'net.cactusthorn.config:config-compiler:0.70'

Basic usage

To access properties it's need to define a convenient Java interface, e.g. :

@Config
@Prefix("app") 
public interface MyConfig {

    @Default("unknown")
    String val();

    @Key("number")
    int intVal();

    URI uri();

    @Disable(PREFIX) 
    Optional<List<UUID>> ids();

    @Split("[,:;]")
    @Default("DAYS:HOURS")
    Set<TimeUnit> units();

    @LocalDateParser({ "dd.MM.yyyy", "yyyy-MM-dd" })
    LocalDate date();
}
  • An interface must be annotated with @Config.
  • An interface must contain at least one method declaration (but methods declaration can be also in super interface(s)).
  • All methods must be without parameters

Based on the interface, the annotation processor will generate an implementation, that can be obtained using ConfigFactory:

MyConfig myConfig =
    ConfigFactory.builder()
        .setLoadStrategy(LoadStrategy.MERGE)
        .addSource("file:~/myconfig.xml")
        .addSource("classpath:config/myconfig-owner.xml")
        .addSource("jar:file:path/to/some.jar!/path/to/myconfig.properties")
        .addSource("https://somewhere.com/myconfig.toml")
        .addSource("file:./myconfig.json")
        .addSource("file:./myconfig.yaml")
        .build()
        .create(MyConfig.class);

e.g. "myconfig.properties":

app.val=ABC
app.number=10
app.uri=http://java.sun.com/j2se/1.3/
ids=f8c3de3d-1fea-4d7c-a8b0-29f63c4c3454,123e4567-e89b-12d3-a456-556642440000
app.units=DAYS:HOURS;MICROSECONDS
app.date=12.11.2005

e.g. "myconfig.xml" (properties style xml):

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
    <entry key="app.val">ABC</entry>
    <entry key="app.number">10</entry>
    <entry key="app.uri">http://java.sun.com/j2se/1.3/</entry>
    <entry key="ids">f8c3de3d-1fea-4d7c-a8b0-29f63c4c3454,123e4567-e89b-12d3-a456-556642440000</entry>
    <entry key="app.units">DAYS:HOURS;MICROSECONDS</entry>
    <entry key="app.date">12.11.2005</entry>
</properties>

e.g. "myconfig-owner.xml" (OWNER xml format):

<?xml version="1.0" encoding="UTF-8"?>
<app>
    <val>ABC</val>
    <number>10</number>
    <uri>http://java.sun.com/j2se/1.3/</uri>
    <units>DAYS:HOURS;MICROSECONDS</units>
    <date>12.11.2005</date>
</app>

e.g. "myconfig.toml" (TOML format):

ids = ["f8c3de3d-1fea-4d7c-a8b0-29f63c4c3454","123e4567-e89b-12d3-a456-556642440000"]

[app]
val = "ABC"
number = 10
uri = "http://java.sun.com/j2se/1.3/"
units = ["DAYS", "HOURS", "MICROSECONDS"]
date = 2005-11-12

e.g. "myconfig.json" (JSON format):

{
    "ids" : ["f8c3de3d-1fea-4d7c-a8b0-29f63c4c3454", "123e4567-e89b-12d3-a456-556642440000"],
    "app" : {
        "val" : "ABC",
        "number" : 10,
        "uri" : "http://java.sun.com/j2se/1.3/",
        "units" : ["DAYS", "HOURS", "MICROSECONDS"],
        "date" : "2005-11-12"
    }
}

e.g. "myconfig.yaml" (YAML format):

ids:
  - f8c3de3d-1fea-4d7c-a8b0-29f63c4c3454
  - 123e4567-e89b-12d3-a456-556642440000
app:
  val: ABC
  number: 10
  uri: http://java.sun.com/j2se/1.3/
  units:
    - DAYS
    - HOURS
    - MICROSECONDS
  date: '2005-11-12'

Annotations

  1. @Config

    • @Target(TYPE)
    • The "source" interface must be annotated with this annotation.
  2. @Factory

    • @Target(TYPE)
    • The "factory" interface must be annotated with this annotation.
  3. @Prefix

    • @Target(TYPE)
    • Set global prefix for all property names
  4. @Key

    • @Target(METHOD)
    • Set property name for the method. If this annotation is not present method-name will be used as property name
  5. @Default

    • @Target(METHOD)
    • Set default value (if property will not found in sources, the default value will be used).
    • Can't be used for methods with Optional return type.
  6. @Disable

    • @Target({TYPE, METHOD})
    • Disable "global"-level features for this method.
  7. @Split

    • @Target({TYPE, METHOD})
    • Set splitter regular expression for splitting value for collections, or key+value "entries" for maps.
    • If this annotation is not present, default "splitter" is comma : ,
  8. @ConverterClass

    • @Target({METHOD, ANNOTATION_TYPE})
    • apply custom converter implementation
  9. @LocalDateParser, @LocalDateTimeParser, @LocalTimeParser, @ZonedDateTimeParser, @OffsetDateTimeParser, @OffsetTimeParser, @YearParser, @YearMonthParser

    • @Target(METHOD)
    • apply a parameterized by formats converter to the relevant java.time.* type
  10. @PBEDecryptor

    • @Target(METHOD)
    • decrypt properties that were encrypted with Jasypt Password-Based Encryption. FYI: jasypt

Property not found : @Default or Optional

There are three ways for dealing with properties that are not found in sources:

  1. If method return type is not Optional and the method do not annotated with @Default, the ConfigFactory.create method will throw runtime exception "property ... not found"

  2. If method return type is Optional -> method will return Optional.empty()

  3. If method return type is not Optional, but the method do annotated with @Default -> method will return converted to return type default value. FYI: The @Default annotation can't be used with a method that returns Optional.

@Config annotation parameters

There are two optional parameters sources and loadStrategy which can be used to override these settings from ConfigFactory. e.g.

@Config(sources = {"classpath:config/testconfig2.properties","nocache:system:properties"},
        loadStrategy = LoadStrategy.FIRST)
public interface ConfigOverride {

    String string();
}
  1. If sources parameter is present, all sources added in the ConfigFactory (using ConfigFactory.Builder.addSource methods) will be ignored.
  2. If loadStrategy parameter is present, it will be used instead of loadStrategy from ConfigFactory.
  3. Manually added properties (which added using ConfigFactory.Builder.setSource(Map<String, String> properties) method) are highest priority anyway. These properties will be merged in any case.

System properties and/or environment variables in @Key and/or @Prefix

This feature makes it possible to store, for example, settings for different environments in a single configuration file. e.g. (TOML):

host = "https://www.google.com/"
port = 80

[dev]
host = "https://github.com/"
port = 90

[prod]
host = "https://www.wikipedia.org/"
port = 100

Syntax: {name}

e.g.

@Config
public interface MyServer {
    @Key("{env}.host") URL host();
    @Key("{env}.port") int port();
}

or (with same result)

@Config
@Prefix("{env}")
public interface MyServer {
    URL host();
    int port();
}

usage e.g.:

java -Denv=dev -jar myapp.jar

FYI:

  1. If a system property or environment variable does not exist, an empty string will be used as the value.
  2. After expanding, start & end points . will be dropped.
  3. After expanding, multiple points (e.g ...) inside the key name will be substituted to single ..
system property value key config resulting key
dev {env}.host dev.host
{env}.host host
dev server.{env}.host server.dev.host
server.{env}.host server.host
dev host.{env} host.dev
host.{env} host

The ConfigFactory

The ConfigFactory is thread-safe, but not stateless.
It stores loaded properties in the internal cache (see Caching), and also control auto reloading.
Therefore, it certainly makes sense to create and use one single instance of ConfigFactory for the whole application.

Direct access to properties

It's possible to get loaded properties without define config-interface.

ConfigHolder holder =
    ConfigFactory.builder()
        .setLoadStrategy(LoadStrategy.FIRST)
        .addSource("file:./myconfig.properties")
        .addSource("classpath:config/myconfig.properties", "system:properties")
        .build()
        .configHolder();

String val = holder.getString("app.val", "unknown");
int intVal = holder.getInt("app.number");
Optional<List<UUID>> ids = holder.getOptionalList(UUID::fromString, "ids", ",");
Set<TimeUnit> units = holder.getSet(TimeUnit::valueOf, "app.units", "[:;]", "DAYS:HOURS");

The @Factory annotation

There is one place where Java-reflection is used: ConfigFactory.create method. @Factory annotation provides the ability to generate "Factory"-class(es) which helps to avoid reflection completely.

@Config
public interface MyConfig {
    String val();
}
@Factory
public interface MyFactory {
    MyConfig createMyConfig();
}
MyConfig myConfig = Factory_MyFactory.builder().addSource("file:./myconfig.properties").build().createMyConfig();

As you can see, based on the MyFactory-interface annotated by @Factory, the class Factory_MyFactory will be generated, which has same API with ConfigFactory but instead of create-method it provides "create"-methods for the interface annotated by @Factory. Restrictions:

  • an interface annotated by @Factory must contains at least one method
  • an interface annotated by @Factory must contains only methods without parameters
  • all methods of an interface annotated by @Factory must return only types annotated by @Config

Manually added properties

The ConfigFactory.Builder contains a method for adding properties manually: setSource(Map<String, String> properties). Manually added properties are highest priority always: loaded by URIs properties merged with manually added properties, independent of loading strategy. In other words: the manually added properties will always override (sure, when the property keys are same) properties loaded by URI(s).

There is two major use-cases for the feature: unit-tests & console applications.
For console applications, it is convenient to provide command line arguments to the ConfigFactory using this feature.

Caching

By default, ConfigFactory caches loaded properties using source-URI (after resolving system properties and/or environment variable in it) as a cache key.

To not cache properties related to the URI(s), use URI-prefix nocache: this will switch off caching for the URI.
e.g.

  • nocache:system:properties
  • nocache:file:~/my.properties

Global Prefix

The ConfigFactory.Builder provide the method to set global prefix setGlobalPrefix(String prefix), which will be used for all "config"-interfaces that will be created using the factory:

app.val=ABC
@Config
public interface MyConfig {
    String val();
}
MyConfig myConfig = ConfigFactory.builder().setGlobalPrefix("app").build().create(MyConfig.class);

This makes it possible to avoid @Prefix or/and @Key annotations, in case several "config"-interfaces are created based on the same source(s). FYI:

  • Global-prefix is added before the prefix from the @Prefix annotation. They can be used together.
  • Global-prefix also support system properties and/or environment variables (like @Prefix and @Key)
  • Global-prefix can be switched off for the method or "config"-interface using @Disable(Disable.Feature.GLOBAL_PREFIX)

Type conversion

Supported method return types

The return type of the interface methods must either:

  1. Be a primitive type

  2. Have a public constructor that accepts a single String argument

  3. Have a public static method named valueOf or fromString that accepts a single String argument

  4. Be

    • java.net.URL
    • java.net.URI
    • java.nio.file.Path
    • java.util.Currency
    • java.time.Instant
    • java.time.Duration
    • java.time.Period
    • java.time.LocalDate
    • java.time.LocalDateTime
    • java.time.LocalTime
    • java.time.ZonedDateTime
    • java.time.OffsetDateTime
    • java.time.OffsetTime
    • java.time.Year
    • java.time.YearMonth
    • net.cactusthorn.config.core.converter.bytesize.ByteSize
  5. Be List<T>, Set<T> or SortedSet<T>, where T satisfies 2, 3 or 4 above. The resulting collection is read-only.

  6. Be Map<K,V> or SortedMap<K,V>, where

    • K satisfies 2, 3 or 4 above.
    • V satisfies 2, 3 or 4 above.
    • The resulting map is read-only.
  7. Be Optional<T>, where T satisfies 2, 3, 4, 5 or 6 above

Maps

Maps support is limited to two restrictions:

  1. custom converters are not supported for the key
  2. as key-value separator can be used only | (pipe character)

e.g. "myconfig.properties":

map=A|10,BBB|20
map2=10000|10;20000|20
@Config(sources="classpath:/myconfig.properties") 
public interface ConfigMap {

    Map<String, Integer> map();

    @Split(";") Optional<Map<Integer, Byte>> map2();

    @Default("123e4567-e89b-12d3-a456-556642440000|https://github.com") Map<UUID, URL> map3();
}

FYI:

  1. In case of Maps, @Split annotation set splitter for key+value "entries" (default "splitter" is comma : ,).
  2. In case of Maps, the annotations associated with converters( e.g. @ConverterClass, @ZonedDateTimeParser etc.) only affect the Map values.

java.time.Instant format

The string must represent a valid instant in UTC and is parsed using DateTimeFormatter.ISO_INSTANT
e.g. 2011-12-03T10:15:30Z

java.time.Duration formats

  1. Standard ISO 8601 format, as described in the JavaDoc for java.time.Duration. e.g. P2DT3H4M

  2. "unit strings" format:

    1. Bare numbers are taken to be in milliseconds: 10

    2. Strings are parsed as a number plus an optional unit string: 10ms, 10 days

    3. The supported unit strings for duration are case sensitive and must be lowercase. Exactly these strings are supported:

      • ns, nano, nanos, nanosecond, nanoseconds
      • us, ยตs, micro, micros, microsecond, microseconds
      • ms, milli, millis, millisecond, milliseconds
      • s, second, seconds
      • m, minute, minutes
      • h, hour, hours
      • d, day, days

java.time.Period formats

  1. Standard ISO 8601 format, as described in the JavaDoc for java.time.Period. e.g. P1Y2M3W4D

  2. "unit strings" format:

    1. Bare numbers are taken to be in days: 10

    2. Strings are parsed as a number plus an optional unit string: 10y, 10 days

    3. The supported unit strings for duration are case sensitive and must be lowercase. Exactly these strings are supported:

      • d, day, days
      • w, week, weeks
      • m, mo, month, months
      • y, year, years

net.cactusthorn.config.core.converter.bytesize.ByteSize format

It based on OWNER classes to represent data sizes.

usage:

@Config
public interface MyByteSize {

    @Default("10 megabytes") 
    ByteSize size();
}

The supported unit strings for ByteSize are case sensitive and must be lowercase. Exactly these strings are supported:

  • byte, bytes, b
  • kilobyte, kilobytes, k, ki, kib
  • kibibyte, kibibytes, kb
  • megabyte, megabytes, m, mi, mib
  • mebibyte, mebibytes, mb
  • gigabyte, gigabytes, g, gi, gib
  • gibibyte, gibibytes, gb
  • terabyte, terabytes, t, ti, tib
  • tebibyte, tebibytes, tb
  • petabyte, petabytes, p, pi, pib
  • pebibyte, pebibytes, pb
  • exabyte, exabytes, e, ei, eib
  • exbibyte, exbibytes, eb
  • zettabyte, zettabytes, z, zi, zib
  • zebibyte, zebibytes, zb
  • yottabyte, yottabytes, y, yi, yib
  • yobibyte, yobibytes, yb

Custom converters

If it's need to deal with class which is not supported "by default" (see Supported method return types), a custom converter can be implemented and used.

public class MyClassConverter implements Converter<MyClass> {

    @Override public MyClass convert(String value, String[] parameters) {
        ...
    }
}

The @ConverterClass annotation allows to specify the Converter-implementation for the config-interface method:

@Config public interface MyConfigWithConverter {

    @ConverterClass(MyClassConverter.class) @Default("some super default value") MyClass theValue();

    @ConverterClass(MyClassConverter.class) Optional<MyClass> mayBeValue();

    @ConverterClass(MyClassConverter.class) Optional<List<MyClass>> values();
}

FYI: Converter-implementation must be stateless and must have a default(no-argument) public constructor.

Parameterized custom converters

Sometimes it's convenient to set several constant parameters for the custom converter. For example, to provide format(s) with a converter for date-time types. This can be achieved with converter-annotation for the custom-converter:

@Retention(SOURCE)
@Target(METHOD) 
@ConverterClass(MyClassConverter.class) //converter implementation
public @interface MySuperParser {

    String[] value() default "";
}

FYI:

  • the annotation must contains String[] value() default "" parameter, otherwise parameters will be ignored by compiler
  • the annotation can be made for any converter (even for converter which is, actually, not need parameters)

usage:

@Config 
public interface MyConfig {

    @MySuperParser({"param1", "param1"})
    MyClass myValue();
}

Several of these annotations shipped with the library:

  • @LocalDateParser
  • @LocalDateTimeParser
  • @LocalTimeParser
  • @ZonedDateTimeParser
  • @OffsetDateTimeParser
  • @OffsetTimeParser
  • @YearParser
  • @YearMonthParser

Loaders

Standard loaders

  1. System properties: system:properties

  2. Environment variables: system:env

  3. properties file from class-path : classpath:relative-path-to-name.properties[#charset]

    • Default charset (if URI fragment not present) is UTF-8
    • e.g. classpath:config/my.properties#ISO-5589-1
  4. properties file from any URI convertable to URL: whatever-what-supported.properties[#charset]

    • Default charset (if URI fragment not present) is UTF-8
    • e.g. the file from the working directory: file:./my.properties
    • e.g. Windows file: file:///C:/my.properties
    • e.g. web: https://raw.githubusercontent.com/Gmugra/net.cactusthorn.config/main/core/src/test/resources/test.properties
    • e.g. jar in file-system: jar:file:path/to/some.jar!/path/to/your.properties
  5. XML file from class-path : classpath:relative-path-to-name.xml[#charset]

    • XML format: properties.dtd or OWNER
    • Default charset (if URI fragment not present) is UTF-8
    • e.g. classpath:config/my.xml#ISO-5589-1
  6. XML file from any URI convertable to URL: whatever-what-supported.xml[#charset]

    • XML format: properties.dtd or OWNER
    • Default charset (if URI fragment not present) is UTF-8
    • e.g. file:./my.xml
  7. META-INF/MANIFEST.MF: classpath:jar:manifest?attribute[=value]

    • The loader scans all JARs in classpath for META-INF/MANIFEST.MF files. First META-INF/MANIFEST.MF, which contain attribute (with optional value) from the URI will be used as source.
    • e.g. MANIFEST.MF must contain attribute Bundle-Name with value JUnit Jupiter API: classpath:jar:manifest?Bundle-Name=JUnit%20Jupiter%20API
    • e.g. MANIFEST.MF must contain attribute exotic-unique-attribute with any value: classpath:jar:manifest?exotic-unique-attribute

Custom loaders

It's possible to implement custom loaders using Loader interface. This makes it possible to load properties from specific sources (e.g. Database) or to support alternative configuration-file formats. e.g.

public final class SinglePropertyLoader implements Loader {

    @Override public boolean accept(URI uri) {
    
        return uri.toString().equals("single:property");
    }

    @Override public Map<String, String> load(URI uri, ClassLoader classLoader) {
    
        Map<String, String> result = new HashMap<>();
        result.put("key", "value");
        return result;
    }
}
ConfigFactory factory =
    ConfigFactory.builder()
    .addLoader(SinglePropertyLoader.class)
    .addSource("single:property")
    .build();

FYI:

  • Custom loaders always have the highest priority if added using ConfigFactory.Builder.addLoader method: last added -> first used.
  • Custom loader implementation must be stateless and must have a default(no-argument) public constructor.

SPI

Service-provider loading facility (introduced in JDK 1.6) can be used to automatically add custom loader implementation to the ConfigFactory. Simple add file META-INF\services\net.cactusthorn.config.core.loader.Loader with full-class-name of custom-loader implementation(s) in the class path.
e.g.

System properties and/or environment variables in sources URIs

Syntax: {name} e.g.

  • file:/{config-path}/my.properties
  • classpath:{config-path}/my.properties#{charset}

FYI: If a system property or environment variable does not exist, an empty string will be used as the value.

Special use-case user home directory: The URIs with file:~/ (e.g. file:~/my.xml or jar:file:~/some.jar!/your.properties) always correctly resolved to user home directory independent from OS.

  • e.g. in Windows, URI file:~/my.xml will be replaced to file:///C:/Users/UserName/my.xml.

Loading strategies

ConfigFactory saves the sequence in which the sources URIs were added.

MyConfig myConfig =
    ConfigFactory.builder()
        .setLoadStrategy(LoadStrategy.FIRST)
        .addSource("file:/myconfig.properties", "classpath:config/myconfig.properties")
        .build()
        .create(MyConfig.class);

Loading strategies:

  • FIRST - only the first (in the sequence of adding) existing and not empty source will be used.
  • MERGE - merging all properties from first added to last added.
  • FIRST_KEYCASEINSENSITIVE - same with FIRST, but property keys are case insensitive
  • MERGE_KEYCASEINSENSITIVE - same with MERGE, but property keys are case insensitive
  • FIRST_KEYRELAXED - same with FIRST, but property keys are "relaxed".
  • MERGE_KEYRELAXED - same with MERGE, but property keys are "relaxed".
  • Default strategy is MERGE

"Relaxed":

  • keys are case insensitive
  • .(dot), -(minus) and _(underscore) characters are ignored
  • For example: person.first-name, person.firstName and PERSON_FIRSTNAME can all be used interchangeably.

Warning: Manually added properties (which added using ConfigFactory.Builder.setSource(Map<String, String> properties) method) are highest priority always. So, loaded by URIs properties merged with manually added properties, independent of loading strategy.

Periodical auto reloading

ConfigFactory can automatically reload configurations which extends net.cactusthorn.config.core.Reloadable interface. To activate auto-reloading need to set "periodInSeconds" using autoReload method:

ConfigFactory factory =
    ConfigFactory.builder()
        .addSource("file:/myconfig.properties")
        .autoReload(5) //reload every 5 seconds
        .build();

Warning: If you do not call autoReload method, auto reloading will not work.

But, the source will be reloaded only if it changed.
Loader-implementation should implement contentHashCode method which return hash-code. (The method return value should be changed, when URI related content is changed).
If Loader-implementation do not support auto-reloading (which is default behavior) the method is returns always same value (e.g. 0).
As result, for the moment, auto reloading only supported for:

  • system:properties
  • URIs with file: scheme (only files related URIs). FYI: file last-modified-time is used as hash-code.

Warning: Be careful, non-cached(nocache:) sources will always be reloaded, whether they are modified or not.

It is possible to disable auto reloading for the "config"-interface, even if it is activated:

@Config
@Disable(Disable.Feature.AUTO_RELOAD)
public interface MyConfig extends Reloadable {
    String value();
}

Filesystems quirks
The date resolution vary from filesystem to filesystem.
For instance, for Ext3, ReiserFS and HSF+ the date resolution is of 1 second.
For FAT32 the date resolution for the last modified time is 2 seconds.
For Ext4 the date resolution is in nanoseconds.

Reload event listeners

It would be nice to know which properties has changed as result of reloading, so that you can e.g. re-configure only the affected services. It's possible to achieve using "Reload event listeners" feature. Example how to do it: https://github.com/Gmugra/net.cactusthorn.config/tree/main/tests/src/test/java/net/cactusthorn/config/tests/listener/ListenerTest.java

Interfaces

Interfaces inheritance

Interfaces inheritance is supported. e.g.

interface MyRoot {

    @Key(rootVal) String value();
}
@Config
interface MyConfig extends MyRoot {

    int intValue();
}
  • There is no limit to the number and "depth" of super-interfaces.
  • Interface level annotations (e.g. @Prefix) on super-interfaces will be ignored.

java.io.Serializable

"config"-interface can extends (directly or over super-interface) java.io.Serializable. In this case generated class will also get private static final long serialVersionUID attribute.

@Config
public interface MyConfig extends java.io.Serializable {

    long serialVersionUID = 100L;

    String val();
}

The interface (as in the example before) can, optionally, contains long serialVersionUID constant. If the constant is present, the value will be used for the private static final long serialVersionUID attribute in the generated class. Otherwise generated class will be generated with private static final long serialVersionUID = 0L.

net.cactusthorn.config.core.Accessible

"config"-interface can extends (directly or over super-interface) net.cactusthorn.config.core.Accessible. In this case generated class will also get methods for this interface:

    Set<String> keys();

    Object get(String key);

    Map<String, Object> asMap();

net.cactusthorn.config.core.Reloadable

"config"-interface can extends (directly or over super-interface) net.cactusthorn.config.core.Reloadable. In this case generated class will also get methods for this interface:

    void reload();

    boolean autoReloadable();

    void addReloadListener(ReloadListener listener);

FYI: The method always reload not cached sources, even if they not changed (see Caching)

Miscellaneous

Extras

"Extras" are optional extensions (converters and loaders) that need external dependencies and therefore can't be integrated into the core library.

  • jasypt : provide @PBEDecryptor annotation which decrypt properties that were encrypted with Jasypt Password-Based Encryption.
  • toml : provide loaders for files in TOML format
  • json : provide loaders for files in JSON format
  • yaml : provide loaders for files in YAML format
  • hjson : provide loaders for files in Hjson format
  • zookeeper : provide loader for properties from Apache ZooKeeper

Logging

The runtime part of the library is using Java Logging API. That's because one of the requirements is that external libraries must not be used, and JUL is only option in this case. However, JUL is rarely chosen for productive use, so, in the application which is using this library, it need to care about to redirect JUL calls to the logging API which is using in the application.

e.g., in case of SLF4J, which is, looks like, the most popular at the moment, you need next dependency:

<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>jul-to-slf4j</artifactId>
	<version>1.7.32</version>
</dependency>

and e.g. this code somewhere at start of the application:

// java.util.logging -> SLF4j
org.slf4j.bridge.SLF4JBridgeHandler.removeHandlersForRootLogger();
org.slf4j.bridge.SLF4JBridgeHandler.install();
java.util.logging.Logger.getLogger("").setLevel(java.util.logging.Level.FINEST);

Profiles

There is no specific support for profiles, but it is easy to achieve similar behavior using System properties and/or environment variables in sources URIs, e.g.:

ConfigFactory.builder()
    .addSource("file:~/myconfig-{myapp.profile}.properties")
    .addSource("file:./myconfig-{myapp.profile}.properties")
    .addSource("classpath:myconfig.properties")
    .build();

and get profile from, for example, system property:

java -Dmyapp.profile=DEV -jar myapp.jar

Integration with DI containers

Example with Dagger 2:

FYI : Eclipse

It does not have annotation-processing enabled by default. To get it, you must install m2e-apt from the eclipse marketplace: https://immutables.github.io/apt.html

LICENSE

net.cactusthorn.config is released under the BSD 3-Clause license. See LICENSE file included for the details.

Comments
  • Update dependency org.slf4j:slf4j-api to v2

    Update dependency org.slf4j:slf4j-api to v2

    Mend Renovate

    This PR contains the following updates:

    | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | org.slf4j:slf4j-api (source) | 1.7.36 -> 2.0.0 | age | adoption | passing | confidence |


    Configuration

    ๐Ÿ“… Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

    ๐Ÿšฆ Automerge: Disabled by config. Please merge this manually once you are satisfied.

    โ™ป Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

    ๐Ÿ”• Ignore: Close this PR and you won't be reminded about this update again.


    • [ ] If you want to rebase/retry this PR, click this checkbox.

    This PR has been generated by Mend Renovate. View repository job log here.

    dependencies 
    opened by renovate[bot] 1
  • [misc] Use Slf4j instead of java.util.logging

    [misc] Use Slf4j instead of java.util.logging

    The runtime part of the library is using Java Logging API. That's because one of the initial requirement is that external libraries must not be used, and JUL is only option in this case.

    But, in real life, JUL is problem: it slow, feature pure, complex to integrate it with other loggers, complex to configurate. Therefore, JUL is rarely used for logging in real-world applications; and the fact that the library is using JUL is disadvantage.

    So: let's use slf4j-api insted of JUL. everything will be much more easy.

    opened by Gmugra 1
  • Update dependency org.glassfish.jaxb:jaxb-runtime to v4

    Update dependency org.glassfish.jaxb:jaxb-runtime to v4

    Mend Renovate

    This PR contains the following updates:

    | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | org.glassfish.jaxb:jaxb-runtime (source) | 2.3.6 -> 4.0.0 | age | adoption | passing | confidence |


    Configuration

    ๐Ÿ“… Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

    ๐Ÿšฆ Automerge: Disabled by config. Please merge this manually once you are satisfied.

    โ™ป Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

    ๐Ÿ”• Ignore: Close this PR and you won't be reminded about this update again.


    • [ ] If you want to rebase/retry this PR, click this checkbox.

    This PR has been generated by Mend Renovate. View repository job log here.

    dependencies 
    opened by renovate[bot] 1
  • [compiler] Simplify generated toString() & equals() methods

    [compiler] Simplify generated toString() & equals() methods

    Generated toString() should based on StringJoiner Generated equals() should based on Objects.equals(...)

    This way, the generated code will be shorter, more readable, and somewhat more reliable. Also the compiler code will be a bit simpler

    enhancement code refactoring 
    opened by Gmugra 1
  • Update dependency com.puppycrawl.tools:checkstyle to v10

    Update dependency com.puppycrawl.tools:checkstyle to v10

    WhiteSource Renovate

    This PR contains the following updates:

    | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | com.puppycrawl.tools:checkstyle (source) | 9.3 -> 10.0 | age | adoption | passing | confidence |


    Configuration

    ๐Ÿ“… Schedule: At any time (no schedule defined).

    ๐Ÿšฆ Automerge: Disabled by config. Please merge this manually once you are satisfied.

    โ™ป Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

    ๐Ÿ”• Ignore: Close this PR and you won't be reminded about this update again.


    • [ ] If you want to rebase/retry this PR, click this checkbox.

    This PR has been generated by WhiteSource Renovate. View repository job log here.

    dependencies 
    opened by renovate[bot] 1
  • [misc] Generate JARs with test sources

    [misc] Generate JARs with test sources

    Need new Maven-profile which will generate JARs with test-sources. FYI: https://stackoverflow.com/questions/53948780/maven-how-do-i-create-source-jar-for-test-package

    enhancement 
    opened by Gmugra 1
  • [misc] add info about compiler source/target JDK in JARs MANIFEST.MF

    [misc] add info about compiler source/target JDK in JARs MANIFEST.MF

    Maven by default adds an Build-Jdk-Spec that contains the version of the JDK used to build the project. So, e.g. when run Maven with JDK 17 - it will be Build-Jdk-Spec: 17, and it have nothing to do with compiler "source" & "target" settings in the pom.xml.

    So, nice to have new properties with compiler settings info:

    X-Compile-Source-JDK: 1.8
    X-Compile-Target-JDK: 1.8
    

    It should be in all generated JARs

    enhancement 
    opened by Gmugra 1
  • [compiler] Compiler could not use standard and custom converters for interfaces and abstract classes

    [compiler] Compiler could not use standard and custom converters for interfaces and abstract classes

    SUBJ

    And such convertors should also work in combintation with collections and maps

    FYI:

    • standard converter which got this problem: convertor for java.nio.file.Path
    • there is not standard converter for abstract class at the moment
    • it was try to fix that according to #286, but it wasn't right fix.

    Also

    • actualize auto-generated classes for DisabledAutoReload & TestConfig (core tests)
    • ConfigConverterTest (tests module) should test more converters: custom, defualt & cutom for the same type, converters for interfaces and abstract classes
    • add in the documentation info about: custom converters for interfaces and abstract classes; custom converter can override standard converter
    bug 
    opened by Gmugra 1
  • [compiler] Compiler should annotates with `@Generated` the generated classes.

    [compiler] Compiler should annotates with `@Generated` the generated classes.

    Java 8 javax.annotation.Generated: https://docs.oracle.com/javase/8/docs/api/javax/annotation/Generated.html

    Java 9 and later javax.annotation.processing.Generated: https://docs.oracle.com/javase/9/docs/api/javax/annotation/processing/Generated.html

    So, yes, depending on the version of Java with which the project is built, different classes must be used for this annotation.

    Compiler should annotates with this annotation the generated classes. "To mark source code that has been generated" (c) JavaDoc

    enhancement 
    opened by Gmugra 1
  • [compiler] Some validators do not provide correct Element when a ProcessorException is thrown

    [compiler] Some validators do not provide correct Element when a ProcessorException is thrown

    e.g.

    @Config
    public interface WrongType {
        FileDescriptor fd();
    }
    

    Maven compiler error :

    Only classes with static valueOf(String), static fromString(String) or constructor from String are supported
    

    But must be:

    /C:/Git/net.cactusthorn.config/tests/src/main/java/net/cactusthorn/config/tests/WrongType.java:[29,20]
    Only classes with static valueOf(String), static fromString(String) or constructor from String are supported
    
    bug 
    opened by Gmugra 1
  • [compiler] toString(), hashCode() & Reloadable

    [compiler] toString(), hashCode() & Reloadable

    If Config-interface is not Reloadable - object is immutable. And, in this case, it have no sense to calculate hashCode and build toString every time: they can be pre-calculated/pre-generated in the local varibales.

    If Config-interface is Reloadable - object is mutable, but it is again have no sense to calculate hashCode and build toString every time. They can be be pre-calculated/pre-generated only in the reload() method.

    enhancement code refactoring 
    opened by Gmugra 1
  • Update dependency.pmd to v6.53.0

    Update dependency.pmd to v6.53.0

    Mend Renovate

    This PR contains the following updates:

    | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | net.sourceforge.pmd:pmd-jsp (source) | 6.52.0 -> 6.53.0 | age | adoption | passing | confidence | | net.sourceforge.pmd:pmd-javascript (source) | 6.52.0 -> 6.53.0 | age | adoption | passing | confidence | | net.sourceforge.pmd:pmd-java (source) | 6.52.0 -> 6.53.0 | age | adoption | passing | confidence | | net.sourceforge.pmd:pmd-core (source) | 6.52.0 -> 6.53.0 | age | adoption | passing | confidence |


    โš  Dependency Lookup Warnings โš 

    Warnings were logged while processing this repo. Please check the Dependency Dashboard for more information.


    Configuration

    ๐Ÿ“… Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

    ๐Ÿšฆ Automerge: Disabled by config. Please merge this manually once you are satisfied.

    โ™ป Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

    ๐Ÿ”• Ignore: Close this PR and you won't be reminded about these updates again.


    • [ ] If you want to rebase/retry this PR, check this box

    This PR has been generated by Mend Renovate. View repository job log here.

    dependencies 
    opened by renovate[bot] 0
  • Update dependency ch.qos.logback:logback-classic to v1.4.5

    Update dependency ch.qos.logback:logback-classic to v1.4.5

    Mend Renovate

    This PR contains the following updates:

    | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | ch.qos.logback:logback-classic (source) | 1.2.11 -> 1.4.5 | age | adoption | passing | confidence |


    โš  Dependency Lookup Warnings โš 

    Warnings were logged while processing this repo. Please check the Dependency Dashboard for more information.


    Configuration

    ๐Ÿ“… Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

    ๐Ÿšฆ Automerge: Disabled by config. Please merge this manually once you are satisfied.

    โ™ป Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

    ๐Ÿ”• Ignore: Close this PR and you won't be reminded about this update again.


    • [ ] If you want to rebase/retry this PR, check this box

    This PR has been generated by Mend Renovate. View repository job log here.

    dependencies 
    opened by renovate[bot] 0
  • [extras] TOML advanced map support

    [extras] TOML advanced map support

    @Config(sources="classpath:/myconfig.toml")
    public interface ConfigMap {
    
        Map<Integer, String> myMap();
    }
    

    At the moment, only way to provide map is "properties" style. e.g. myconfig.toml must be so:

    myMap = "8000|One,8001|Two"
    

    Idea is to provide special support for key-postfix e.g. ".map":

    [myMap.map]
    8000 = "One"
    8001 = "Two"
    

    This should porvide same result as before: property with name myMap (without postfix) with Map inside.

    Sure is should work with complex use case like array as value with complex object like key. e.g. :

    @Config(sources="classpath:/myconfig.toml")
    public interface ConfigMap {
    
        Map<UUID, List<Integer>> complex();
    }
    
    [complex.map]
    46400000-8cc0-11bd-b43e-10d46e4ef14d = [ 8000, 8001, 8002 ]
    46400000-8cc0-11bd-wert-10d46e4ef14d = [ 6000, 6001, 6002 ]
    
    enhancement 
    opened by Gmugra 0
  • [api] Writers

    [api] Writers

    Initial concept:

    • (?) net.cactusthorn.config.core.Accessible should get method to provide "meta" information about property e.g. info about separators for collections.
    • New Writer Interface with method: void write(net.cactusthorn.config.core.Accessible accessible)
    • Sure need Writer implementatin for each file format based on URI pattern (same like with Loaders)
    • New WriterFactory class with static(?) method Writer create(String uri)
    • WriterFactory use SPI to load Writer implmenetations (same way like with Loaders)

    Usage something like that:

    @Config public interface MyConfig extends Accessible {
    ...
    }
    
    MyConfig myConfig = ConfigFactory.builder().addSource("file:/myconfig.properties").build().create(MyConfig.class);
    Writer writer = WriterFactory.create("file:~/myconfig.toml");
    writer.write(myConfig); //save data in TOML format  in user home directory.
    
    enhancement low priority 
    opened by Gmugra 0
  • [api/compiler] `@Factory` annotation parameters

    [api/compiler] `@Factory` annotation parameters

    Idea is to extend @Factory annotation with optional parameters which works like methods from ConfigFactoryBuilder:

    @Factory(
        sources = { "classpath:my.properties", "system.properties" }, 
        loadStrategy = LoadStrategy.FIRST,
        autoReload = true,
        globalPrefix= "gp"
    )
    public interface MyFactory {
        MyConfig createMyConfig();
    }
    
    enhancement low priority 
    opened by Gmugra 0
  • [extras] Consul

    [extras] Consul

    Make loader for HashiCorp Consul Client library:

    <dependency>
      <groupId>com.orbitz.consul</groupId>
      <artifactId>consul-client</artifactId>
      <version>1.5.3</version>
    </dependency>
    

    Example: https://github.com/cfg4j/cfg4j/tree/master/cfg4j-consul

    enhancement 
    opened by Gmugra 0
Releases(v0.80)
  • v0.80(Feb 2, 2022)

    ๐Ÿš€ Features

    • toString(), hashCode() & Reloadable (#284)
    • Add default support for java.util.Locale (#286)
    • Default value for system/environment variables in keys/URIs (#183)
    • Extras: loaders for Hjson (#269) : https://github.com/Gmugra/net.cactusthorn.config/tree/main/hjson

    ๐Ÿ› Bug Fixes

    • Change code to avoid Spotbug "false positive" (#266)
    • Compiler ignore several standard converters (e.g. java.util.Currency) (#286)
    • Compiler could not use standard and custom converters for interfaces and abstract classes (#296)
    • Some validators do not provide correct Element when a ProcessorException is thrown (#292)

    ๐Ÿงฐ Maintenance

    • Add build with Java 17 (#243)
    • Integrate Maven License Plugin (#240)
    • Actualize configurations for PMD (#236)
    • New check-style rule to disallow console output: System\.(out|err)
    • Add info about compiler source/target JDK in JARs MANIFEST.MF (#302)

    ๐Ÿ—Ž Documentation

    Source code(tar.gz)
    Source code(zip)
  • v0.70(Aug 30, 2021)

    Release 0.70

    1. Reload listeners (#205)
    2. Global Prefix (#86)
      1. Also new @Disable feature GLOBAL_PREFIX
    3. Extras: loader for Apache ZooKeeper (#204) : https://github.com/Gmugra/net.cactusthorn.config/tree/main/zookeeper
    4. OSGi support:
      1. config-json.jar OSGi ready (#207)
      2. config-yaml.jar OSGi ready (#209)
      3. config-jasypt.jar OSGi ready (#213): config-jasypt-0.70-bundle.jar
      4. config-toml.jar OSGi ready (#215): config-toml-0.70-bundle.jar
      5. config-zookeeper.jar OSGi ready (#221)
    5. BuildTime in all generated JARs (#211)
    Source code(tar.gz)
    Source code(zip)
  • v0.60(Jul 19, 2021)

    Release 0.60

    1. New supported return type java.util.Currency (#187):
    2. New @Factory annotation (#80)
    3. Extras: loaders for files in YAML format (#165) : https://github.com/Gmugra/net.cactusthorn.config/tree/main/yaml
    4. New package for ConfigFactory: net.cactusthorn.config.core -> net.cactusthorn.config.core.factory (#195)
    Source code(tar.gz)
    Source code(zip)
  • v0.50(Jul 5, 2021)

    Release 0.50

    1. ConfigFactory.Builder.addSourceNoCache methods deleted (#169)
    2. Periodical auto reloading (#168)
    3. New @Disable feature AUTO_RELOAD (#173)
    4. New supported return types of interface methods (#182):
      1. java.time.LocalTime
      2. java.time.OffsetTime
      3. java.time.Year
      4. java.time.YearMonth
    5. New parameterized custom converters related annotations (#182):
      1. @LocalTimeParser
      2. @OffsetTimeParser
      3. @YearParser
      4. @YearMonthParser
    6. New loading strategies (#170):
      1. FIRST_KEYRELAXED
      2. MERGE_KEYRELAXED
    Source code(tar.gz)
    Source code(zip)
  • v0.40(Jun 5, 2021)

    Release 0.40

    1. Support for system properties and/or environment variable in the @Key and @Prefix(#154)
    2. Special support for net.cactusthorn.config.core.Reloadable interface (#166)
    3. Extras: loaders for files in JSON format (#151) : https://github.com/Gmugra/net.cactusthorn.config/tree/main/json
    4. Optimizations in the generated classes (#142, #150, #160)
    Source code(tar.gz)
    Source code(zip)
  • v0.31(May 23, 2021)

    Release 0.31

    The release renames generated artifacts, to make it more unique.

    Old Name | New Name ------------ | ------------- core | config-core compiler | config-compiler jasypt | config-jasypt toml | config-toml

    Source code(tar.gz)
    Source code(zip)
  • v0.30(May 22, 2021)

    Release 0.30

    1. New supported return types of interface methods (#54, #56, #134):
      1. java.time.LocalDate
      2. java.time.LocalDateTime
      3. java.time.ZonedDateTime
      4. java.time.OffsetDateTime
      5. net.cactusthorn.config.core.converter.bytesize.ByteSize (for size settings, e.g. "10Mb")
    2. Added support for parameterized custom converters (#96) and related annotation:
      1. @LocalDateParser
      2. @LocalDateTimeParser
      3. @ZonedDateTimeParser
      4. @OffsetDateTimeParser
    3. Added support for java.util.Map and java.util.SortedMap (#99, #123)
    4. Support Service-provider loading facility for Loaders (#87)
    5. Extras (#124, #131):
      1. parameterized converter to decrypt properties that were encrypted with Jasypt Password-Based Encryption : https://github.com/Gmugra/net.cactusthorn.config/tree/main/jasypt
      2. loaders for files in TOML format : https://github.com/Gmugra/net.cactusthorn.config/tree/main/toml
    Source code(tar.gz)
    Source code(zip)
  • v0.20(May 11, 2021)

    Release 0.20

    1. New supported return types of interface methods (#55, #61, #81, #85):
      1. java.net.URI
      2. java.time.Instant
      3. java.time.Duration
      4. java.time.Period
      5. java.nio.file.Path
    2. New loading strategies (#43):
      1. FIRST_KEYCASEINSENSITIVE
      2. MERGE_KEYCASEINSENSITIVE
    3. New standard loaders (#46, #90)
      1. for XML files (format: properties.dtd or OWNER)
      2. for META-INF/MANIFEST.MF from classpath
    4. Special support for java.io.Serializable interface (#47)
    5. Special support for net.cactusthorn.config.core.Accessible interface (#65)
    6. nocache: URI-prefix (#62)
    7. file:~/ expansion in URI for home-dir (#64)
    8. @Config annotation optional parameters sources and loadStrategy (#75)
    9. ConfigHolder get more conversion methods (#78)
    Source code(tar.gz)
    Source code(zip)
  • v0.10(Apr 30, 2021)

    Release 0.10

    The first release with basic set of features

    1. annotation processor for class & builder generation
    2. Annotations: @Config, @Prefix, @Key, @Default, @Disable, @Split, @ConverterClass
    3. Standard types conversions + Converter interface for custom converters
    4. ClassFactory with support for multiple source and loading strategies
    5. Standard loaders: system:properties, system:env, properties files by URL and from classpath
    6. Loader interface for custom loaders + System properties and/or environment variable in sources URIs
    7. Direct (without interface) access to properties
    8. Caching
    Source code(tar.gz)
    Source code(zip)
Owner
Alexei Khatskevich
Alexei Khatskevich
A Java annotation processor used for automatically generating better builder codes.

BetterBuilder BetterBuilder is a Java annotation processor used for automatically generating better builder codes(builder design pattern), which can m

LEO D PEN 9 Apr 6, 2021
A simple java json configuration system built with gson.

Simple Configuration A simple json configuration system built with gson. Setup ?? Using Maven REPOSITORY <repositories> <repository> <id>j

Kacper Horbacz 2 Sep 24, 2022
kotlin decompiler based on quiltflower

Quiltflower Quiltflower is a fork of Fernflower and ForgeFlower adding additional features for use with the Quilt toolchain. Changes include: Javadoc

Joseph Burton 39 Jan 8, 2023
An Engine to run batch request with JSON based REST APIs

JsonBatch An Engine to run batch request with JSON based REST APIs Some usecase for this library: Provide a batch API to your REST API set. Quickly ro

Rey Pham 11 Jan 3, 2022
High performance JVM JSON library

DSL-JSON library Fastest JVM (Java/Android/Scala/Kotlin) JSON library with advanced compile-time databinding support. Compatible with DSL Platform. Ja

New Generation Software Ltd 835 Jan 2, 2023
A Java serialization/deserialization library to convert Java Objects into JSON and back

Gson Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to a

Google 21.7k Jan 8, 2023
Screaming fast JSON parsing and serialization library for Android.

#LoganSquare The fastest JSON parsing and serializing library available for Android. Based on Jackson's streaming API, LoganSquare is able to consiste

BlueLine Labs 3.2k Dec 18, 2022
A modern JSON library for Kotlin and Java.

Moshi Moshi is a modern JSON library for Android and Java. It makes it easy to parse JSON into Java objects: String json = ...; Moshi moshi = new Mos

Square 8.7k Dec 31, 2022
JSON to JSON transformation library written in Java.

Jolt JSON to JSON transformation library written in Java where the "specification" for the transform is itself a JSON document. Useful For Transformin

Bazaarvoice 1.3k Dec 30, 2022
Sawmill is a JSON transformation Java library

Update: June 25, 2020 The 2.0 release of Sawmill introduces a breaking change to the GeoIpProcessor to comply with the updated license of the MaxMind

Logz.io 100 Jan 1, 2023
MapNeat is a JVM library written in Kotlin that provides an easy to use DSL (Domain Specific Language) for transforming JSON to JSON, XML to JSON, POJO to JSON in a declarative way.

MapNeat is a JVM library written in Kotlin that provides an easy to use DSL (Domain Specific Language) for transforming JSON to JSON, XML to JSON, POJ

Andrei Ciobanu 59 Sep 17, 2022
Genson a fast & modular Java <> Json library

Genson Genson is a complete json <-> java conversion library, providing full databinding, streaming and much more. Gensons main strengths? Easy to use

null 212 Jan 3, 2023
Lean JSON Library for Java, with a compact, elegant API.

mJson is an extremely lightweight Java JSON library with a very concise API. The source code is a single Java file. The license is Apache 2.0. Because

Borislav Iordanov 77 Dec 25, 2022
Open NFCSense Library

OpenNFCSense API Open-source API of NFCSense for the Processing programming environment (http://processing.org/). Please refer to the following workfl

Rong-Hao Liang 13 Jul 25, 2022
A modern and lightweight library for working with email addresses in Java

JMail A modern, fast, zero-dependency library for working with email addresses and performing email address validation in Java. Built for Java 8 and u

Rohan Nagar 67 Dec 22, 2022
A wayfast raycast java library.

NOTE: Rayfast is still in development and is not completely stable api-wise. GridCasting likely will not change, however Area3d's may have some improv

EmortalMC 19 Dec 20, 2022
A JSON Transmission Protocol and an ORM Library for automatically providing APIs and Docs.

?? ้›ถไปฃ็ ใ€็ƒญๆ›ดๆ–ฐใ€ๅ…จ่‡ชๅŠจ ORM ๅบ“๏ผŒๅŽ็ซฏๆŽฅๅฃๅ’Œๆ–‡ๆกฃ้›ถไปฃ็ ๏ผŒๅ‰็ซฏ(ๅฎขๆˆท็ซฏ) ๅฎšๅˆถ่ฟ”ๅ›ž JSON ็š„ๆ•ฐๆฎๅ’Œ็ป“ๆž„ใ€‚ ?? A JSON Transmission Protocol and an ORM Library for automatically providing APIs and Docs.

Tencent 14.4k Dec 31, 2022
A universal types-preserving Java serialization library that can convert arbitrary Java Objects into JSON and back

A universal types-preserving Java serialization library that can convert arbitrary Java Objects into JSON and back, with a transparent support of any kind of self-references and with a full Java 9 compatibility.

Andrey Mogilev 9 Dec 30, 2021
Simple, efficient Excel to POJO library for Java

ZeroCell ZeroCell provides a simple API for loading data from Excel sheets into Plain Old Java Objects (POJOs) using annotations to map columns from a

Credit Data CRB 68 Dec 8, 2022