owner: Java properties files read through typed interfaces
Get rid of the boilerplate code in properties based configuration.
At a glance
- What is it?
- owner turns a .properties file into a Java interface, so configuration access becomes a method call with a converted return type instead of a string lookup. The catch is that the published artifact is still 1.0.12 from 2020 while the 2.0.0 rewrite sits on master, so adopters have to choose between the stable old line and the documented new one.
- Who is it for?
- owner suits Java services that keep configuration in properties files and want typed access, defaults and validation without a dependency injection container, and it suits readers looking for one well documented small library. It does not suit a team that needs a released artifact matching the current documentation, because Maven Central still serves 1.0.12 from 2020-06-07 while the described 2.0.0 is only in preparation on master.
- Can I use it commercially?
- Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The configuration model is a Java interface
Most Java projects read configuration the same way: a Properties object is loaded, and then somebody writes a getter for every key, casts a String to an Integer, and hopes the file had the right key. The boilerplate is dull but it is also where bugs live, because a typo in a key name is only discovered at runtime, in production, under a specific profile.
owner takes a different route. The approach it uses is to define a Java interface associated with a properties file. Given a ServerConfig.properties file like this:
port=80
hostname=foobar.com
maxThreads=100you declare an interface that extends Config:
public interface ServerConfig extends Config {
int port();
String hostname();
int maxThreads();
}The documentation calls this the Properties Mapping Interface, or just Mapping Interface, and describes its goal as mapping Properties into an easy to use piece of code. The important detail is what the interface does not contain. There is no annotation processor to run, no code generation step, and no container to sit inside. The README makes a point of this across the whole feature table, saying that everything works on an interface like the one above, with no context to build, no container to be inside, and no dependency to add unless the row says so.
That is the reason to care about this library. owner is usable in a plain main method, in a servlet, in a test, or inside whatever framework you already run, because it binds to a type rather than to a runtime environment.
ConfigFactory.create is the only call most code needs
Once the interface exists, the access pattern is a single static factory call and then ordinary method calls on the result:
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());
}
}The return type of each method is what the interface declares, so port() returns an int and hostname() returns a String. The conversion from the string in the file to the declared type happens inside the library, which removes the cast from every call site. The alternative documented on the site, the Basic usage page, is where the rest of the feature set lives, so this snippet is deliberately the tip rather than the whole surface.
The type support is broader than primitives. The documentation lists primitives, enums, URL, Duration, arrays and collections, anything with a valueOf method or a single String constructor, Optional of those, or a converter you supply. The last two entries matter most in practice. A valueOf or one argument constructor is a convention, not an interface, so third party types that follow it can be used without writing an adapter. Optional support matters because it turns a missing key into a present absence rather than a null, which removes a class of null checks from the calling code.
A custom converter is the escape hatch for everything else, and it is the point at which a configuration binding starts to behave like a validation layer.
One key, four spellings
Key naming is where property based configuration usually gets in the way, because the file, the environment and the code rarely agree on spelling. owner documents four accepted forms for the same key. The example given is that firstName() finds firstName, first-name, first_name or the environment's FIRST_NAME.
That single rule collapses several kinds of drift. A file written in the camelCase style of Java code, a file written in the hyphenated style that some deployment tools rewrite, and an environment variable injected by a container orchestrator all resolve to the same accessor without the application code caring which one was used. The dashed and underscored variants are the common case for a project that migrated from a .properties file to a YAML or environment based deployment and kept the old interface.
The same section of the documentation covers defaults, variables and parameters. There is a DefaultValue annotation for a fallback, an expansion syntax that lets one property refer to another, and a value that can be used as a format string for the arguments of the method. The expansion is useful for values that must stay consistent, such as a host name that appears in several places in the same file, and the fact that expansion supports a default of its own means a missing reference does not have to fail the whole load.
Together these turn the interface into the single description of the configuration contract, with the file, the environment and the code all bound to it.
Where the properties come from, and the file that needs no configuration
A properties file on the classpath is the obvious source, and owner covers a good deal more than that. The loading strategies documented on the site include a file, the classpath, the environment, system properties, a URL, JNDI and ZooKeeper, and the sources can either be tried in turn or merged.
The mode that deserves attention is the last one in that list: the file named after the interface. If you declare ServerConfig, owner will look for ServerConfig.properties on its own, with no configuration to point at it. For a project with a single configuration surface, that removes a line of setup from every test and every entry point, and it makes the mapping obvious to a new reader of the code, since the file name and the interface name match.
The other sources matter in specific deployments. JNDI and ZooKeeper cover environments where configuration is published to a registry rather than shipped in the artifact, which is a common pattern in application servers. The environment source matters for container deployments. System properties matter when a JVM is started with overrides, and the URL source covers the case where the file is fetched from somewhere else at boot.
Because the sources can be merged rather than tried in turn, precedence becomes a design decision for the application rather than an accident of library code, and that is where the loading strategy page is worth reading before you pick one.
Nested sections, lists and maps read from the same interface
Flat properties files get awkward once a configuration grows sections, so owner extends the mapping interface to cover structure. The documentation describes three cases. A method that returns another mapping interface reads a section of the file. A List of mapping interfaces reads keys of the form servers[0].host. A Map reads keys of the form servers.alpha.host.
The bracket and dotted forms are the key detail, because they are the notation a properties file can already express without becoming a different format. A section is just a prefix, an indexed element is a prefix with a bracketed number, and a map entry is a prefix with a dotted key. Nothing is restructured, so the file stays a properties file and the interface stays the description of it.
The same file also handles formats other than .properties. The core covers .properties, XML, .env and INI. JSON, YAML and TOML live in a separate artifact called owner-formats, and the documentation makes a design point of that: they are parsed by hand, so adding them adds nothing else to your build. HOCON arrives through owner-extras, which pulls in Typesafe Config. The separation into owner, owner-formats and owner-extras means a plain properties user has no YAML parser on the classpath at all, and the repository layout shows those as sibling modules alongside owner itself, owner-examples, owner-site and owner-assembly.
The cost of the hand written parsers is that each format has a smaller feature set than a dedicated library would, which is a reasonable trade for a project that does not want a parser dependency.
Reload, mutation, secrets and the debugging switch
The feature table in the README is dense, and three rows deserve a closer look because they change what a configuration binding can be used for.
The first is reload. Configuration can be reloaded on demand, or by watching the file, synchronously or on a schedule. Reload is the feature that pushes a properties binding past a convenience and into service territory, and it is also the feature that needs the most care, since a value read by one component and reloaded under another can produce a half applied configuration.
The second is writing. The library can look at the properties through Accessible, change them through Mutable, and ask through Traceable which source a value came from. There is a save(File) method that writes the file back, and the documentation stresses that it keeps the comments and the order of the original file. For a configuration file that a human edits, preserving comments is the difference between a tool people use and a tool people are afraid of.
The third is secrets, where an encrypted value can live in the file together with the cipher it needs, using either one passphrase or a key pair so that whoever can add a secret cannot read the others. There is also Bean Validation support, with the constraint annotations checked on the accessors, and the documentation states the guiding rule plainly: a constraint nobody is checking is reported rather than ignored.
And when something goes wrong, one switch makes the library report what it looked for, what it found, which loader answered and which key each method resolves to, with a Sensitive annotation keeping secrets out of that output. For a library whose failure mode is a confusing null, that is the most valuable feature on the page.
The published artifact is from 2020 and the documented one is not
The version story of this project needs reading carefully, because the documentation describes an API that Maven Central does not yet serve.
The download section gives the dependency for version 1.0.12 and states that this is the latest published release. The same paragraph says that 2.0.0 is in preparation, that it requires Java 8, that the documentation describes that version, and that a news page lists what it adds and the little it removes. The release history backs that up: owner-1.0.12 was published on 2020-06-07, owner-1.0.11 on the same day with a note telling people to skip it, and owner-1.0.10 back in March 2018.
The repository itself is not dormant. It is not archived, the last push was on 2026-10-19, and the master branch carries the build for the next major version. The layout shows a Maven multi module project with a wrapper, a site module, an examples module, a presentation directory and a renovate configuration, plus working notes at the root such as COMPARISON.md, CRYPTO.md, FORMATS.md, INCLUDES.md, RELEASING.md and WRITING.md.
So the practical advice is narrow. If you want the published artifact, pin org.aeonbits.owner:owner:1.0.12 and accept that it is a 2020 release whose API is not the one the website describes. If you want the documented behaviour, build from master. The installation page also points at the owner-formats and owner-extras artifacts, which are released separately, so a project using YAML or HOCON has three coordinates to keep aligned rather than one.
The licence field says BSD-3-Clause, a permissive licence with a retention clause, so embedding it in a proprietary product carries no source disclosure obligation. That is a licensing observation rather than legal advice.
Against a hand written Properties loader
The honest alternative is not another configuration library, it is the code you already have. A team that keeps a Properties object and writes its own accessors gets the same result with no dependency at all: Properties.getProperty, a cast, and a null check per key. That approach wins on dependency count and on debuggability, because a stack trace points straight at the line that read the key.
It loses on everything that has to be built by hand afterwards. Type conversion becomes a cast in every call site rather than a declared return type. Defaults become a helper method. Variable expansion becomes a resolver. Reload becomes a file watcher plus a cache invalidation strategy. Validation becomes a separate library or a block of asserts in a factory method. Secrets become an encryption utility with its own key management. owner is, in effect, the sum of those helpers, already written and already tested, for the price of one artifact.
The middle option is the format question. The library itself treats HOCON as a supported format through owner-extras and Typesafe Config, and JSON, YAML and TOML as supported through owner-formats. If your configuration is already YAML, the comparison to make is not owner against your own loader, it is owner against the ecosystem you have already chosen, and there the hand written parsers and the Typesafe Config dependency both become the deciding factor.
The point of the library is not that properties files are good. It is that the boilerplate around them is optional.
Editorial conclusion
owner suits Java services that keep configuration in properties files and want typed access, defaults and validation without a dependency injection container, and it suits readers looking for one well documented small library. It does not suit a team that needs a released artifact matching the current documentation, because Maven Central still serves 1.0.12 from 2020-06-07 while the described 2.0.0 is only in preparation on master. Verify the version first: add org.aeonbits.owner:owner:1.0.12 if you need the published API, or build the master branch for the documented behaviour, and check Maven Central for the newest version before you pin either.
Frequently asked questions
How do I add owner to a Maven project?
The README gives the dependency as org.aeonbits.owner with artifact owner and version 1.0.12, published on Maven Central. The installation page also covers the owner-formats and owner-extras artifacts for JSON, YAML, TOML and HOCON support.
How does owner read a configuration file?
You declare an interface that extends Config, with one method per property, and call ConfigFactory.create with that interface. The library maps the properties file onto the interface and converts each value to the declared return type.
Which key spellings does owner accept?
The documentation states that firstName() finds firstName, first-name, first_name or the environment's FIRST_NAME, so a method name resolves against the camelCase form, the hyphenated form, the form with underscores and the environment variable form.
Is owner 2.0.0 released yet?
No. The download section states that 1.0.12 is the latest published release and that 2.0.0 is in preparation, and it is the version the current documentation describes. The release history shows owner-1.0.12 published on 2020-06-07 and owner-1.0.10 on 2018-03-01.
Does owner support reloading configuration at runtime?
Yes. The reload documentation covers reloading on demand or by watching the file, synchronously or on a schedule. The library can also expose the values as accessible and mutable, ask which source a value came from, and save a file back keeping its comments and order.
What licence is owner released under?
The licence field on the repository says BSD-3-Clause, and the README carries a BSD license badge pointing at the LICENSE file.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/matteobaccan-owner)Was this useful?