Reading configuration in Java - java

I have recently started working in Java. I am trying to find a good way to specify my application's configuration values in an easy to read way. I'd like the ability to create a base configuration file and then include in a derived configuration file that also allows overwriting the values in the base file.
Not sure if the java properties file provides the second feature. After searching on google I found apache commons configuration and ini4j but I'm not sure if they are actively maintained or how many people are actually using those.

An easy option is java.util.Properties, which not only supports loading configuration data from key=value and XML files, but also directly supports the hierarchical defaults you describe.
For example:
Properties base = new Properties();
base.load(new FileReader("base.cfg"));
Properties custom = new Properties(base);
custom.load(new FileReader("custom.cfg"));
// 'custom' defers to 'base' for properties that were not in "custom.cfg".
// custom.remove(key) can be used to restore a default from 'base'.
Note that Properties does not have built-in support for grouped / hierarchical properties (e.g. an XML tree or an INI file with sections), but will generally get the job done in many cases.
It is possible to load the base configuration after the custom configuration as well if, for example, the custom configuration contains a property that specifies the base file name (this may be useful given some of your comments below):
Properties base = new Properties();
Properties custom = new Properties(base);
custom.load(new FileReader("custom.cfg"));
base.load(new FileReader(custom.getProperty("basefile")));
By the way, both libraries you mentioned (Apache Commons Configuration and ini4j) are in good working condition. The Apache library has support for a wider range of formats and is more actively maintained, but ini4j is mature (been around for about 10 years and INI files haven't changed) and also works well. I've personally used both a number of times and they have always delivered as promised.
All null / exception handling left out of examples for clarity.

Related

The Opposite of Swagger-Core?

I am an experienced technical writer but new to the management of Swagger or OpenAPI.
We currently use Swagger-Core, where all the settings are in #Operation or #Parameter within Java or Python files.
However, I have seen set ups where those configuration statements are in yaml files. The biggest advantage is that the text inside a description tag can get as extensive as needed.
Somehow they are connected to the Java or Python files. The configurations get set in the yaml files and they get applied to the Java methods.
What is that system called? How does that get done?

Java - how to make a library I made use config values

Long story short, I'm making a java library that requires several 'config values'. Currently, I'm just using a config.properties file in the root directory and reading from it, but I don't see how that can work with a distributable jar file.
I've thought about making these config values parameters to a constructor of a class in the library, but there are too many values- it just doesn't seem like the correct way of doing things.
Essentially, I just need some way that a user of my library can just use the jar file, but also have the ability to change several configuration values that affect the function of the library.
If it makes any difference, I'm using maven to build my project.
Thanks in advance.
(Assuming you are just working in JavaSE, as Java EE has other configuration mechanisms.)
A pattern is to create a singleton class in your jar that provides configuration to the other classes. Which is reads default values from the property file in the jar. Allow the caller of the jar to override properties by setting them as system properties.
In the java doc for Property class there is a constructor to provide defaults and overrides and get the 'net' properties.
Giving the caller the option specify a property file by giving a file path as a system property.
Log4j and java.util.logging work of like this. Reading through there config documentation will help explain.
I will split your question into two parts and then answer each part separately.
I've thought about making these config values parameters to a constructor of a class in the library, but there are too many values- it just doesn't seem like the correct way of doing things.
For the part of your question I have quoted above, see the accepted answer (written by me) to the following StackOverflow question: How to handle large number of configuration parameters across a program conceptually?
Essentially, I just need some way that a user of my library can just use the jar file, but also have the ability to change several configuration values that affect the function of the library.
It sounds like your configuration file will contain N variables, and a user might want to customize the values of, say, just 2 or 3 of those variables. If N is relatively small, then it will probably be okay to use an either-or approach to configuration:
either the user provides a configuration file containing values for all N variables (the location of this file might be specified via, say, a system property, an environment variable, or a parameter to the constructor of your library);
or your library uses a "built-in" set of default configuration values, which I suggest you place in a properties file that you bundle into your library's jar file and then access by calling ClassLoader.getSystemResourceAsStream().
However, if N is large, then you might want your library to provide and semantics for configuration variables:
your library uses a "built-in" set of default configuration values, which I suggest you place in a properties file that you bundle into your library's jar file and then access by calling ClassLoader.getSystemResourceAsStream(). This provides default values for all N variables.
and your library loads an (optional) user-specified configuration file that might contain anywhere between 0 and N variables. The values of the user-specified configuration variables are used to override the built-in default values.
Obviously, you will need to implement the and logic within your library, but that is really just a SMOP (Simple Matter of Programming). Perhaps the simplest way is to iterate over the entries in the user-provided Properties object and copy them into the Properties object that contains the default values. In this way, the user-specified value will override default values.

Best practice to create a config file for an existing software programmatically

I am working on a tool that can help me generate a configuration file for use with an existing software (Vagrant), of course, in the format which Vagrant understands.
However, I am having a tough time planning my program design that can help me with dynamic generation of the configuration file with a programmatic approach. Moreover, the config file structure will consist of many optional snippets as well which may/not be required in the final configuration file as per the requirements of the user. I can't think of some efficient approach to go about it.
Three approaches which I have thought of are :
1) Working on a readymade template and just replacing the placeholders with appropriate text.
2) Creating the config file on the fly with String append etc. (Doesn't look like a robust and future proof solution to me).
3) Bifurcation of the basic config structure into sub parts and then including each required component one by one as and when required, then replacing the placeholder values.
I am not very confident if any of these is the best professional approach to dynamically generate such a file.
Are there any constraints on the format of the config file? If not, use YAML (or similar) with two config files: default.yml and deploy.yml. Put the defaults for non-required config params in default.yml and then have Vagrant/Chef/Ansible/bash/whatever write the deploy.yml file. On launch, your app reads both config files, giving precedence to deploy.yml.

A "Resource bundle" for persisting other then localization data

I need system similar to ResourceBundles except that I will not use it for localization. Basically, I need to store several versions of settings. One version of that settings is String-to-String map, that can be represented by Properties file. These settings versions must be easily persisted to file system inside application .jar (alike PropertyResourceBundle).
The idea is to have different versions of application settings (settings profiles), represented by key-value pairs of type string, that can be chosen from at application start up based of user decision. Again these are not language versions so ResourceBundle (according to its javadoc) is not the right way to implement it.
Any easy way how to do that without implementing the whole think myself? Please do not suggest third-party it should only use Java SE classes.
Edit: I forgot to mention one important detail. It would be hard for me to get stream like this: Thread.currentThread().getContextClassLoader().getResourceAsStream("/your/resource/here");. That is because the project that would contain properties file is compiled by Ant and used as a dynamically loaded library in different GUI projects that actually run. I might have all properties files in fixed project folder but since Thread.currentThread().getContextClassLoader() returns context of GUI project and I do not know where in that project was the .jar with property file placed by Ant I do not know what to use as "/your/resource/here".
I might have misunderstood the question however seems to me you can easily do something like this:
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("/your/resource/here");
Properties prop = new Properties();
prop.load(inputStream);
This will be safe in a Java EE environment as well and you can call you anytime you need if you want settings to change.
Update: as long as the resource is on the classpath you should be able to find it without knowing the full path of the resource as well.

Internationalization - listing and adding languages

I'm making an application in Java. This application can be internationalized using ResourceBundles. I want to allow user to choose the language that he want to the application have. And there's a question: how to list available languages for the program? I don't want to use Locale.getAvailableLocales(), because I don't know if the app's got a .properties file for the chosen language. There's also the second question: can I add an ability to add additional language files outside the .jar file? And the last question: is there any better internationalization solution?
Regards
You could just store a fixed list of supported locales in some constant of your application. If you need to make this dynamic, I see two solutions:
use a properties file listing the supported locales, and load them from this properties file at startup.
iterate through the available locales (or languages), try to load a corresponding bundle properties file (using Class.getResourceAsStream()), and consider that the locale is supported if you get an InputStream, and not supported if you get null.
You could let the user add a bundle by putting some directory in the classpath, in addition to your jar. Drop the properties file in this directory (respecting the package hierarchy), et voilĂ .

Categories