The Support Layer
Moving on to the support interface and object (Listing Three, available for download here),
the first thing to notice is that ConfigurationSupportstaticSupport
More Insights
White Papers
More >>Reports
- Informed CIO: SDN and Server Virtualization on a Collision Course
- InformationWeek 2013 IT Spending Priorities Survey
Webcasts
More >>
The particular interface contains one dependent interface (VerifierSupportRegExVerifierRangeVerifier
Now let's return to the Configuration.Supportenum values,
and a File
The
paramsWithDefaultsNotRequiredInConfigFileallowUnusedKeyskey=value pairs in the properties file.
On one hand, it's nice to have an empty configuration file where everything defaults.
On the other, it's annoying to forget to define a variable and have it silently default to the wrong value.
Since neither approach is "correct" in every situation, you can control the system's behavior by setting
paramsWithDefaultsNotRequiredInConfigFiletrueenumConfigurationError
By the same token, you may or may not want to
permit extra key=value pairs in the properties file. You might, for example, be using a single
properties file to initialize several enums. However, when defaults are on the scene, an
"extra" key might actually be a misspelling of a real key, and your replacement value would be ignored.
The safest approach is to make an extra key an error, but that would preclude the multiple-enums-for-one-file approach.
Setting allowUnusedKeysallowUnusedKeysConfigurationError
Most of the work happens in this constructor, inside the loop on line 144, which processes every
enumenumtype()defaultvaluesMap
If the default can't be used directly, the constructor must create the value from a StringStringStringtoString()createFromString(...)
The actual work is only two lines of code:
Constructor<?> constructor = type.getConstructor(String.class);
return constructor.newInstance(initialValue);
The Java reflection APIs create objects by calling the constructor, in this case, the one with a
StringString.classgetConstuctor(...)newInstance(...)
The other 50 lines of this method handle the impossible number of exceptions that can be thrown by those two method calls.
Because I didn't want the user of my class to deal with six different exception types, I catch all the possible exceptions,
create an error message that a normal human being can understand, and then throw a ConfigurationError
The only other interesting methods in the SupportcreateConfigFile(Writer)createConfigFileUsingDefaults(...)
The first method is not staticSupportstatic
The remainder of the file are the two out-of-the-box Verifier
Conculsion
I've found this approach to configuration to be really useful in practice. You can just use
configuration parameters without having to worry if they're valid or not, all of the annoying error-related
code and default values are handled for you in the background, and implementing a new enumSupport
Next month, I'm planning on changing the topic slightly by looking at how I tested the classes I've been discussing for the past few columns. Testing object-oriented systems has it's own peculiarities, and I plan to discuss the testing approaches that I use most often: mock-based tests built on top of Mockito and PowerMock (which are, themselves, built on JUnit).
Related Articles
Solving the Configuration Problem for Java Apps
Custom Configuring Java Apps: Extending log4j


