Skip to content

TTNO1/ConfigValidation4j

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

53 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Logo

Github Release License Maven Central Issues Build
Stars Forks

Overview

A Java library for easily validating configurations before the configuration data is needed.

Instead of getting a value from a configuration when you need it and supplying a default value if it is invalid or missing, this library allows you to validate the entire configuration at initialization and stop if it is invalid. This library functions as a validation layer on top of whatever means you use to get your configuration data. It enables basic type checking for all Java primitives, lists, and configuration subsections (maps) as well as validating more advanced "filters" that can be written by you or selected from a provided set of common filters. Filters also allow you to convert the configuration data into a new type, such as from a String to a URI, to make life easier when you need to access the data later. That also means that you can refer to configuration data in a "statically typed" way and no longer have to rely on passing string paths into getter methods hoping the return value will be what you need.

Strengths

  • Immediate validation of entire config
  • Works on top of any configuration source
  • Customizable filters
  • Data type conversion
  • "Statically typed" configuration data
  • Easy to use

Weaknesses

  • Underlying limitations of configuration source are carried through
  • Nested Lists (see below for details)

Maven Snippet

<dependency>
	<groupId>io.github.ttno1</groupId>
	<artifactId>configvalidation</artifactId>
	<version>1.0.5</version>
</dependency>

How to use

Main Classes

  • ConfigSpec - Represents a specification that a config must meet in order to be valid.
  • ConfigNode - Represents an item in a config that must be present and (optionally) must meet certain requirements.
  • ConfigList - Similar to ConfigNode but for lists.
  • ConfigFilter - A functional interface that takes in a config data value and returns whether it is valid or not. Can optionally transform the value into a new type.
  • ConfigWrapper - An interface that wraps a source of configuration data. This library has default implementations for Apache Commons Config and SnakeYAML.
  • Cfg - A class with static factory methods for constructing ConfigSpecs, ConfigNodes, and ConfigLists.
  • ConfigFilters - A utility class with common ConfigFilters.

Examples

Basic Config Nodes

ConfigWrapper wrapper = new SnakeYamlConfigWrapper(new Yaml().load(/*config input stream*/));
		
Cfg.newSpec()
.addNode("path.to.boolean.node", Cfg.Node.ofBoolean())
.addNode("path.to.integer.node", Cfg.Node.ofInteger())
.addNode("path.to.string.node", Cfg.Node.ofString())
.addNode("path.to.list.of.strings", Cfg.List.ofString())
.addNode("path.to.config.subsection", Cfg.newSpec().addNode(/*etc.*/))
.validate(wrapper)
.handle(result -> {
	if(!result.passed()) {
		//do something when config is invalid
		System.out.println(result.getFailMessage());
	}
});

Config Nodes with Filters

ConfigWrapper wrapper = new SnakeYamlConfigWrapper(new Yaml().load(/*config input stream*/));
		
Cfg.newSpec()
.addNode("path.to.url.node", Cfg.Node.ofString(ConfigFilters.validURL()))
.addNode("path.to.file.node", Cfg.Node.ofString(ConfigFilters.validPath(FileState.PATH)))
.addNode("path.to.string.node", Cfg.Node.ofString((string) -> {
	if(string.contains("mySubString")) {
		return ConfigFilterResult.pass(string.toUpperCase());// ConfigFilterResult#pass() takes in the transformed value, it does not have to be the same type
	} else {
		return ConfigFilterResult.fail("My Fail Message");
	}
}))
.validate(wrapper)
.handle(result -> {
	if(!result.passed()) {
		//do something when config is invalid
		System.out.println(result.getFailMessage());
	}
});

Getting Values from Nodes

The easiest way to save the value of a ConfigNode is with the ConfigFilter#thenRun or ConfigNode#thenRun method.

ConfigWrapper wrapper = new SnakeYamlConfigWrapper(new Yaml().load(/*config input stream*/));

String myConfigStringValue = null;// value to be obtained from config (pretend this is a field in a class)
Path myConfigFileValue = null;// value to be obtained from config (pretend this is a field in a class)

Cfg.newSpec()
.addNode("path.to.file.node", Cfg.Node.ofString(ConfigFilters.validPath(FileState.PATH).thenRun((path) -> {myConfigFileValue = path;})))
.addNode("path.to.string.node", Cfg.Node.ofString().thenRun((string) -> {myConfigStringValue = string;}))
.validate(wrapper)
.handle(result -> {
	if(!result.passed()) {
		//do something when config is invalid
		System.out.println(result.getFailMessage());
	}
});

Dependencies

In order to use this library with SnakeYAML, Apache Commons Configuration, or Apache Commons Validator (for URL validation), you must include those dependencies separately. For your convenience, here are the maven snippets for those dependencies.

<!--SnakeYAML-->
<dependency>
	<groupId>org.yaml</groupId>
	<artifactId>snakeyaml</artifactId>
	<version>2.2</version>
</dependency>
<!--Commons Configuration-->
<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-configuration2</artifactId>
	<version>2.9.0</version>
</dependency>
<!--Commons Validator-->
<dependency>
	<groupId>commons-validator</groupId>
	<artifactId>commons-validator</artifactId>
	<version>1.7</version>
</dependency>

Limitations

Underlying Limitations

This library serves only as a validation layer on top of whatever means you use to get your configuration data. If you choose to use a library like Apache Commons Config or SnakeYAML, then the limitations of that library will still apply.

For example, by default SnakeYAML treats all decimals as doubles, so if you attempt to validate a ConfigNode of type float, it will not work.

Nested Lists

When validating a list of lists (assuming the underlying config library supports nested lists), the inner list cannot have a specific type and will always be a list of objects. This means that for ConfigFilter purposes, the filter will accept a type of List<List<Object>>.

Contributing

Feel free to contribute in any way you please. It is much appreciated.

Questions

Feel free to ask in an issue or by contacting me.

About

A Java library for easy validation of configuration files.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages