Reputation: 26882
I have a piece of code that I have been using to manage properties for a while now. My boss didn't like this solution on the ground that property management should be done by well-known libraries, like Spring/Guice. That's understandable, and I'm looking for alternatives, but I can't find one that gives me the features that I want (or maybe I don't know how to use them properly).
The features I'm looking for are:
Are there any library that gives me these features?
If I'm missing something and these can all be satisfied by Spring/Guice, are there any good resource online?
Example usage of my solution
Sample of generated property file TEMPLATE (you copy and edit this)
Upvotes: 2
Views: 1231
Reputation: 70574
No need to touch constructor, add dedicated field or setters
That is not the dependency injection pattern. You might substitute the resource locator pattern, but doing that well (in particular, in a way the retains testability) is not trivial: With a setter, I can easily reconfigure the class under test. If that class depends on a config file, will I write a separate config file whenever I need to change settings for the unit test? Will I mock the config class? Possible, but not exactly straighforward ...
Ability to auto-generate property file TEMPLATE
As already pointed out in the comments, this doesn't seem very useful, as it can not migrate an old config file.
Ability to update config at runtime, in a thread-safe manner
That, in general, requires support from the component being configured (for instance, changing a setting for thread pool size involves starting / stopping worker threads ...). In general, the only simple way to handle that is restarting the application ...
If you drop these requirements, Spring's PropertyOverrideConfigurer fits nicely.
Alternatively, if you run inside a servlet container, you could pepper your Spring config with JNDI lookups.
If you really want to generate templates, I don't know a ready-made solution. I might do something like:
class Configuration {
int threadCount = 10;
String secretKey;
@Description("Number of workers. Default value is number of available cores.")
int workerThreadCount = Runtime.getRuntime().availableProcessors();
/** Use default settings */
Configuration() {
}
/** read the settings from the file */
Configuration(Properties props) {
for (String prop : props) {
Field f = getClass().getField(prop);
f.set(this, props.getValue(prop));
// TODO: type conversion,
// e.g. with PropertyEditors,
// or Spring's ConversionService,
// or invoking the constructor that takes a single string argument,
// or ...
}
}
void save() {
for (Field f : getClass().getFields()) {
// TODO save the setting
}
}
}
Writing the default configuration would be a simple as new Configuration().save(file)
, or upgrading an existing configuration as simple as `new Configuration(file).save(file)'.
Unlike your approach, this approach is statically type safe, and doesn't clutter the code accessing the configuration settings with redundant type specifiers. That is, instead of
if(config.value(Prop.PROXY_ENABLED,Boolean.class)){
you could simply write
if (config.proxyEnabled) {
and because the field can be of type boolean (not Boolean), you don't even risk a NullPointerException here.
Upvotes: 3