OWNER, an API to ease Java property files usage.
The goal of OWNER API is to minimize the code required to handle application configuration through Java properties files.
Full documentation available on project website.
The approach used by OWNER APIs, is to define a Java interface associated to a properties file.
Suppose your properties file is defined
as ServerConfig.properties
:
port=80
hostname=foobar.com
maxThreads=100
To access this property you need to define a convenient Java
interface in ServerConfig.java
:
public interface ServerConfig extends Config {
int port();
String hostname();
int maxThreads();
}
We'll call this interface the Properties Mapping Interface or just Mapping Interface since its goal is to map Properties into a an easy to use piece of code.
Then, you can use it from inside your code:
public class MyApp {
public static void main(String[] args) {
ServerConfig cfg = ConfigFactory.create(ServerConfig.class);
System.out.println("Server " + cfg.hostname() + ":" + cfg.port() +
" will run " + cfg.maxThreads());
}
}
But this is just the tip of the iceberg.
Continue reading here: Basic usage.
Public Releases can be downloaded from GitHub Releases page or Maven Central Repository.
Make sure to have a look at the documentation on project website to learn how flexible and powerful OWNER is, and why you may need it!
Chinese documentation is provided by Yunfeng Cheng via a GitHub independent project at this address.
OWNER is released under the BSD license. See LICENSE file included for the details.
owner's People
Forkers
svoflee vmseba evren ffbit bbossola mikechampagne nxbdi h2000 tylerorme gilbertoca devisnotnull cybernetics frimastudio stevecstian svetanesterenko hemus2121 dw-wcheng matriksdata banj eladidan sant3 evanchooly drapostolos robinmeiss kevin-canadian cemo admizh andyphillips404 krevelen abrueck marcottedan kba adamether whurt mooreds ant1g jghoman rrialq ketan utexasdelirium fmarinelli caiodangelo alfredzhang channingbj yaloo tomzhang michielzh liujianyu4303 geekmug gurdeepss rishumehrotra jason-az jabby gtimbo stfs icirellik dearabao bcrook coverxiaoeye mosoft521 belkacem hleecs cbe317 ssullivan ilyad91 padabou junlapong carlhuth aillamsun honne zjpjohn the-bytecode hopeliao chrisgtaylor 292388900 okgint sandy-yan paranoidq brentcrammond llhua2329 okwangxing yongfahuang kiefinger xiaolezheng aliveon johnsblatter mlouis5 flakytestdetection shhz broncho layou1989 luswei zmyer leusonmario uberto xiashuijun bulldog478 redbiscuit yigui2 ylsn19821104owner's Issues
@Prefix annotation on interfaces for keys
I'd rather write:
@Prefix("foo.bar")
interface Shorter extends Config {
int a();
String b();
}
Than:
interface Longer extends Config {
@Key("foo.bar.a")
int a();
@Key("foo.bar.b")
String b();
}
Especially as @key doesn't seem to like @key("${prefix}.baz"). (But please consider @Prefix first! Or @KeyPrefix!)
Support for EncryptableProperties
Owner is very cool framework in my opinion. However, how about the security of storing password in properties? Can owner support for encryptable properties like in Jasypt http://www.jasypt.org/encrypting-configuration.html ?
Thanks
implement list()
The methods list(PrintWriter) and list(PrintStream) method can be proxied from Config interface to java.util.Properties.
It is especially useful when many properties files get merged (via overrides, see issue #1 ) with others: it may become not easy to understand the resulting value. So I will need to provide a method like list().
Implement XML properties support.
Since JDK 1.5 Java properties support XML format via loadFromXML()
and storeToXML()
There is no reason why I shouldn't implement those two methods.
RFE: Smart properties save() method
I use properties files as config files in Gitblit so your project is very interesting to me. Issue 15 (hot reload) is definitely a requirement for me to adopt your library, but another thing I would be missing is an enhanced write feature that replaces a property value in the file without destroying the file. I currently document config settings within the properties file (example https://github.com/gitblit/gitblit/blob/master/distrib/gitblit.properties). Unfortunately, the stock Properties class destroys the source file when you save. It is not very smart. :(
To work around this I implemented a smarter save. You can see my implementation of this here: https://github.com/gitblit/gitblit/blob/master/src/com/gitblit/FileSettings.java#L86
That capability is actually pretty small and I think would make a nice addition to your library.
Properties values runtime modifications
From a private email:
I would say that the main feature I am looking forward to is changing the value of a property at runtime without editing the file.
The reason is that I'm coding a server that is deployed on many environments, each having its own unique values for many properties.
I have :
- a default value or not, depending if it makes sense for every environment,
- a specific starting value (per environment) written in the file,
- a "hot" value, that I sometimes want to apply at runtime (the change may be temporary, so I might want to change it back few minutes/hours later).
This issue is also related to #19 since changing properties values at runtime, it can be nice to have a jmx bean for that too.
Imported properties have lower priority than the resources associated to the Config object or by @Sources
The behavior of OWNER is that imported properties have lowest priority over the one associated to the Config
object or the ones specified by the @Sources
annotation.
I thought that this was the best behavior, but actually I felt that there was no reasonable reason to why I decided it (I also wrote a junit test to fix this behavior as "correct").
Now reading an email I just received, I feel like the use case specified by Ivan makes sense, and it is also not an uncommon thing to do. See email below.
So I wrote a test to reproduce the bug and to redefine the correct behavior and keep it safe from regressions, see 3178f1a:
/*
src/test/resources/org/aeonbits/owner/ImportConfigTest$ImportedPropertiesHaveHigherPriority.properties
minAge=18
*/
interface ImportedPropertiesHaveHigherPriority extends Config {
Integer minAge();
}
@Test
public void testImportedPropertiesShouldOverrideSources() {
ImportedPropertiesHaveHigherPriority cfg = ConfigFactory.create(ImportedPropertiesHaveHigherPriority.class);
assertEquals(Integer.valueOf(18), cfg.minAge());
ImportedPropertiesHaveHigherPriority cfg2 = ConfigFactory.create(ImportedPropertiesHaveHigherPriority.class,
new Properties() {{
setProperty("minAge", "21");
}},
new Properties() {{
setProperty("minAge", "22");
}}
);
assertEquals(Integer.valueOf(21), cfg2.minAge());
}
I already rolled out version 1.0.3.1 as a bugfix release, and I am waiting for a feedback from Ivan before to promote the version to the maven central repository.
Received a mail from Ivan G.
Hi Luigi,
Basically, I have an executable JAR containing a PROPERTIES file inside some resources folder. This is handled by Maven, so after the build is complete, BenchmarkConfig.properties will be in the same folder as BenchmarkConfig.java. The structure is somewhat as follows:
src/
main/
java/
SomeDriver.java
BenchmarkConfig.java
resources/
BenchmarkConfig.properties
I intend to run the JAR file as follows:
Usage:
java -jar some.jar <properties-path>
Example:
java -jar some.jar --
Uses the default properties file bundled inside the JAR.
java -jar some.jar SomeOtherConfig.properties
Uses the specified properties file to completely override
the default one.
However, when I try to run my JAR with the second method, there seems to be no option to completely override the default properties file when I do the following call:
1 try {
2 Properties props = new Properties();
3 props.load(new FileInputStream("path/to/SomeOtherConfig.properties");
4
5 /* Can't do this, because it will find the key-value pair from the default
6 * properties file (BenchmarkConfig.properties) first, and not even bother
7 * searching from SomeOtherConfig.properties
8 */
9 BenchmarkConfig cfg = ConfigFactory.create(BenchmarkConfig.class, props);
10
11 } catch (IOException e) {}
When I do the above, even when I specified a different properties file (someOtherPropertiesPath) and passed it in through props on line 6, it will still find the key-value pair from the default properties file.
I don't want this behavior. Instead, what I want is, when I pass in the props argument on the create() call, I want to completely override the entire default properties file with the file I've specified.
Is there a way to do this in your framework? I've only seen the @LoadPolicy(FIRST)
and @LoadPolicy(MERGE)
, but I don't think those two seem fit for my purpose.
Automatic reload for configuration files.
It is not uncommon for some application to have a consistent and efficient "hot reload" for configuration files. At the moment, the configuration is loaded when the create method is invoked, and no cache is implemented; so it would not be hard for a user to implement some reload mechanism from outside the API. But, things would be better if the reload is triggered by file change, transparently. This should of course be kept thread safe to avoid inconsistent states.
link to #5
Google App Engine Compatibility Issue
It looks like there is some issue with the Google App Engine:
java.lang.NoClassDefFoundError: java.net.URLStreamHandler is a restricted class. Please see the Google App Engine developer's guide for more details.
at com.google.appengine.tools.development.agent.runtime.Runtime.reject(Runtime.java:51)
at org.aeonbits.owner.ConfigURLStreamHandler.<init>(ConfigURLStreamHandler.java:40)
at org.aeonbits.owner.PropertiesManager.<init>(PropertiesManager.java:66)
at org.aeonbits.owner.ConfigFactory.create(ConfigFactory.java:43)
(the above stacktrace and line numbers may relate to version 1.0.2 or 1.0.3)
sounds like a security policy: http://stackoverflow.com/questions/15673942/urlstreamhandler-is-a-restricted-class
The bug is reported to the GAE:
https://code.google.com/p/googleappengine/issues/detail?id=1384
From my point of view, this bug should be fixed in the GAE, but it would be nice to implement a workaround in the OWNER library.
Provide a toString() method
Please provide a toString() method in your proxy so that I can see the content of the config and I can also use it in a log message easily. Something like:
{"max.threads":25, "max.folders":99, "default.name": "untitled"}
Extend Converters to cover more Object types
At the moment the converters are able to instantiate objects having a single parameter constructor accepting a String or Object. But since the Converter itself is able to convert String to primitive (and non-primitive) types, it should not be difficult to extend it to cover Object with a single parameter constructor accepting any type already covered by the Converters.
Who uses OWNER?
I would like to know who uses this API, and how many downloads have been made?
Allow to register user specified loaders to support additional file formats
Something like:
ConfigFactory.registerLoader(new YamlLoader());
Substitution and format not working as expected when used together
This test is failing in version 1.0.3
public static interface SubstituteAndFormat extends Config {
@DefaultValue("Hello ${mister}")
String salutation(String name);
@DefaultValue("Mr. %s")
String mister(String name);
}
@Test
public void testSubstitutionAndFormat() {
SubstituteAndFormat cfg = ConfigFactory.create(SubstituteAndFormat.class);
assertEquals("Hello Mr. Luigi", cfg.salutation("Luigi")); // this fails returning "Hello Mr. %s"
assertEquals("Mr. Luigi", cfg.mister("Luigi"));
}
@Required
It would be nice if OWNER supports the possibility to declare an option as required, maybe with an annotation called @required. If no value was assigned to such an option, OWNER should throw an exception and gives the possibility to write a nice overview of options that are required to a given OutputStream.
What do you think?
Add a method to get all the keys (aka keySet()) to the Accessible interface
The Accessible interface is cool but it lacks a method to programmatic-ally get a list of all the keys, just in case you need to show the configuration in any different way from the basic list mechanism already present
Different sources for configuration (file formats)
At the moment, the only supported format for configuration files handled by owner api is java Properties. It would be nice to have a plugin based architecture that adds support for different file formats.
Apache commons configuration provides support for several file formats.
While Java properties can be provided out of the box, without dependencies, it would be good to implements "plugins" depending on commons configuration to add the supported file formats transparently, keeping all other features unvaried.
In my opinion it is important to not add transitive dependencies in the current apache module; so I would implement the additional file formats inside different maven module(s).
Objects are not serializable
Version: 1.0.4.1
I am using OWNER framework with Twitter/Storm. Such frameworks requires all instance variables should be serializable. Could you please make all objects you define be serializable?
Custom Types conversion
CUSTOM & SPECIAL RETURN TYPES
Since version 1.0.2 it is possible to have configuration interfaces to declare complex return types or even custom ones.
Example:
public interface SpecialTypes extends Config {
@DefaultValue("foobar.txt")
File sampleFile();
@DefaultValue("http://owner.aeonbits.org")
URL sampleURL();
@DefaultValue("example")
CustomType customType();
@DefaultValue("Hello %s!")
CustomType salutation(String name);
}
The user can define his own class types as CustomType
in the previous example. The return type needs to be a public
class declaring a public constructor with a single argument of type `java.lang.String'.
Example:
public class CustomType {
private final String text;
public CustomType(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
If any error happens during the constructor call you'll receive a java.lang.UnsupportedOperationException
.
Example:
java.lang.UnsupportedOperationException: Cannot convert 'example' to org.aeonbits.owner.CustomType
at org.aeonbits.owner.PropertiesInvocationHandler.convert(PropertiesInvocationHandler.java:108)
at org.aeonbits.owner.PropertiesInvocationHandler.resolveProperty(PropertiesInvocationHandler.java:72)
at org.aeonbits.owner.PropertiesInvocationHandler.invoke(PropertiesInvocationHandler.java:63)
at $Proxy4.customType(Unknown Source)
... 31 more
Caused by: java.lang.NoSuchMethodException: org.aeonbits.owner.CustomType.<init>(java.lang.String)
at java.lang.Class.getConstructor0(Class.java:2721)
at java.lang.Class.getConstructor(Class.java:1674)
at org.aeonbits.owner.PropertiesInvocationHandler.convert(PropertiesInvocationHandler.java:105)
... 38 more
The exception description states that OWNER failed to convert the text 'example' to org.aeonbits.owner.CustomType
and
the cause, in this case is because OWNER was unable to find the public constructor with a single String
parameter.
You can also register your custom PropertyEditor
to convert text properties into your objects
using the static method PropertyEditorManager.registerEditor()
.
See also PropertyEditorSupport
, it may be useful if you want to implement a PropertyEditor
.
Add a method to detect which properties were changed in a reload
The HotReload is super cool :) however I think that generally it would be nice to know which properties has changed so that you can re-configure only the affected services, It can be embedded into the ReloadEvent, or it could be possible have a helper method (like I have in my code now) that is able to do a "diff" in the properties for me.
Allow a non-static ConfigFactory
At the moment ConfigFactory is static, so if somebody configures it using ConfigFactory.setProperty(), this affect the singleton object (across the VM). It would be nice to have a non static ConfigFactory. i.e. ConfigFactory.newInstance() that allows configuration for just that instance.
Nested Properties
It could be interesting to think about some structure (i.e. nesting)
interface Foo extends Config {
String fooProp();
interface Bar extends Config {
barProp();
}
@Key("bar");
Bar bar();
}
So, to access barProp, the default key in the properties file would be foo.bar.barProp
.
Method invocation will then be Foo.bar().barProp()
.
Not sure it is a good thing to have. Implementation may not be trivial. We can discuss it.
@ConverterClass annotation
As per discussion in issue #37
Given a properties file like:
servers=www.google.com:80, www.github.com:8080
and a Java source like
public interface ServerConfig extends Config {
Server[] servers;
// or
List<Server> servers;
}
public class Server {
private final String name;
private final Integer port;
public Server(String name, Integer port) {
this.name = name;
this.port = port;
}
public String getName() { return name; }
public Integer getPort() { return port; }
}
public interface ServerConfig extends Config {
@ConverterClass(ServerConverter.class)
Server[] servers;
// or
List<Server> servers;
}
public class ServerConverter extends Converter<Server> {
public Server convert(Method targetMethod, String text) {
String[] split = text.split(":", -1);
String name = split[0];
Integer port = 80;
if (split.lenght >= 2)
port = Integer.valueOf(split[1]);
return new Server(name, port);
}
}
The @ConverterClass annotation should allow the user to specify a class specific to a method to convert the associated property to the resulting object.
It should work also for collections and lists as in the above example.
Nested collections/arrays
Related to #2: support for collections (or arrays) of complex types. E.g.
public interface ServerConfig extends Config {
String host();
int port();
}
public interface AppConfig extends Config {
ServerConfig[] servers(); // could also be List<ServerConfig> or Map<String, ServerConfig>
}
and in the properties file
servers.1.host=www.google.com
servers.1.port=80
servers.2.host=www.github.com
servers.2.port=80
should produce an array of 2 servers (or map with keys "1"
and "2"
).
Provide YAML support in config files
With YAML we will be able to describe entire objects, rather than properties: it fits very well the mechanics for complex configuration.
http://en.wikipedia.org/wiki/YAML
http://yaml.org/
I suggest to use SnakeYAML as java library:
http://code.google.com/p/snakeyaml/
Hot reload does not work when file name needs to be expanded
The hot reload feature is not working when the file name needs to be expanded, i.e.:
"file:${application.configurationFile}"
or
"file:~/config.properties"
When an absolute file name is present the hotreload will work as expected.
Enable passing sources explicitly
Sometimes it may be desirable to determine source location at runtime, and pass them to ConfigFactory explicitly (e.g. if we want to find config files relative to the jar file's directory http://stackoverflow.com/questions/2837263/how-do-i-get-the-directory-that-the-currently-executing-jar-file-is-in).
Validation (was @Mandatory annotation : fail if property is not set)
Like you wrote in your faq ( http://lviggiano.github.io/owner/#faq ), we might want some properties without a default value, thus forcing the user to set it in the properties file. It would be nice to have the feature juste like you describe it.
Github pages broken
http://lviggiano.github.io/owner/ is currently broken.
Merge multiple properties configuration files from different sources.
It would be interesting to have a @SourceLoadPolicy annotation that defines a different policy to load the sources.
At the moment the @sources is scanned sequentially and the first resource available is used to load the properties.
But it would be nice to have the possibility to have an overriding mechanism:
Example:
- I have a property in the jar
- I have a global configuration under
/etc/myapp.config
- I have a user-level configuration under
~/.myapp/config
The @SourceLoadPolicy("override")
whould resolve a call config.someProperty()
looking for someProperty
inside user-level configuration first, then on the global configuration and finally in the jar resource (or the interface itself, that defines the @DefaultValue
).
Add Coveralls to the build process
implement list()
Support for indexed keys
I would like to request an option to include duplicate keys or keys with index. The config should return list/array for all the values for this key.
e.g.
server=Sometext
server=Othertext
OR
server.0=Sometext
server.1=Othertext
@key("server")
String[] server;
Thanks,
Improvements on javadocs and online documentation
Things that need documentation (javadoc and readme.md) improvements:
- new interface Listable
- new interface Reloadable
- owner website needs to be rewritten. The single page layout is not scaling with the addition of new features.
as in subject. I'll keep things here that need documentation improvements, until release.
Implement XML properties support.
Since JDK 1.5 Java properties support XML format via loadFromXML()
and storeToXML()
There is no reason why OWNER API shouldn't implement those two methods.
~ expansion is not correct
~ expansion should not happen always. only path beginning with "~/" should be replaced to ~/ not all , since the file named 'foo' is a perfectly valid file name. also notice that ~ expansion follows different rules with bash than just home expansion: http://www.thegeekstuff.com/2010/06/bash-tilde-expansion/
implement list()
Add support for YAML and JSON loaders
Given that a properties file is not nearly as convenient to edit as a YAML or JSON file, support to load configuration in these formats would definitely be a good thing.
In my case, it would make the choice of owner to manage application settings a no-brainer.
Add support for arrays (and collections?) in type conversion
Support for arrays and collections may be nice:
class MyConfig extends Config {
@Separator({",", "|"})
String[] strings();
@Separator(File.pathSeparator);
File[] path();
List<Integer> ints();
}
Add test to ensure PropertyManager.reload() works fine under heavy concurrency
properties member instance can be accessed and modified concurrently here:
need to create some threads that ensure things are done properly.
L.
Config methods with multiple `@Key`s and `@DefaultValue`s
At the moment, the @Key
annotation only accept one value (as well the @DefaultValue
annotation), it would be nice if for a single property we can specify multiple @Key
s and multiple @DefaultValue
s.
Example
interface MyConfig extends Config {
@Key({"db.driver", "db.url", "db.user", "db.password"})
@DefaultValue({"org.h2.Driver", "jdbc:h2:~/.myapp/data", "scott", "tiger"})
ConnectionPool connectionPool()
}
public class ConnectionPool {
ConnectionPool(String driverClassName, String url, String user, String pwd) { ... }
// or... better (see issue #44)
ConnectionPool(Class driver, String url, String user, String pwd) { ... }
Connection getConnection() { ... }
}
Tool to generate properties file from Config sub-interfaces
Since one can have Config interfaces with @DefaultValue
s without using properties files, it would be useful to have a command line tool (or a maven mojo) that checks all the classes in a project and generate properties files with the default values, so that it would be easier to change those files and/or use them as template for changing the configutation.
Deploy the artifact jars to Maven Central
Don't know yet how to do it, but it would be much better to have the jars on mvn central, than using the repository on github website.
add Travis CI to the repository
Properties values variables expansion
Implement variable substitution (multi-level) for properties values
Example:
public interface ConfigWithSubstitutionAnnotations extends Config {
@DefaultValue("The ${animal} jumped over the ${target}")
String story();
@DefaultValue("quick ${color} fox")
String animal();
@DefaultValue("${target.attribute} dog")
String target();
@Key("target.attribute")
@DefaultValue("lazy")
String targetAttribute();
@DefaultValue("brown")
String color();
}
@Test
public void testConfigWithSubstitutionAnnotation() {
ConfigWithSubstitutionAnnotations conf = ConfigFactory.create(ConfigWithSubstitutionAnnotations.class);
assertEquals("The quick brown fox jumped over the lazy dog", conf.story());
}
It must work also with Config based on properties files:
story=The ${animal} jumped over the ${target}
animal=quick ${color} fox
target=${target.attribute} dog
target.attribute=lazy
color=brown
alias ConfigFactory.create ConfigFactory.get
That's it, maybe ConfigFactory.get
is a better name for ConfigFactory.create
.
All in all, very interesting library and a well done one. Thank you, I would definitely use it for my next projects.
Oh, I just thought of a feature like generating an application specific secret, than use it to encrypt things like password and integrate into owner so there would be no implicit decryption logic.
add method/class addRollbackListener()
When a rollback happens, a RollbackListener
class should receive the notification of the RollbackEvent
, which also include the event generating the rollback (like a PropertyChangeEvent
or a ReloadEvent
)
The user can intercept rollback event and do something useful for the application (i.e. print some log information)
Add a JMX mBean for each Property
It would be awesome to automatically manage a JMX mBean for every property created / setted using your library.
We would have full control over configuration in the JDK jVisualVM for hot-modification.
Support for Map objects
sample property:
something.foo=1
something.bar=2
something.baz=3
sample class:
interface MyConfig extends Config {
Map<String, Integer> something();
}
something()
should return a map containing: foo=1, bar=2, baz=3
Add the possibility to disable variable expansion and parametrized formatting
An annotation could be used to specify the context (on class level or on method level), and it should be good enough to express the will of the programmer to disable one or both of those features.
Example:
@DisableFeature({VARIABLE_EXPANSION, PARAMETER_FORMATTING})
public static String someMethod(String p1, String p2);
// or
@DisableVariableExpansion
public class FooBar {...}
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. ๐๐๐
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google โค๏ธ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.