I've added a human-readable configuration file to my app using java.util.Properties
and am trying to add a wrapper around it to make type conversions easier. Specifically, I want the returned value to "inherit" it's type from the provided default value. Here's what I've got so far:
protected <T> T getProperty(String key, T fallback) {
String value = properties.getProperty(key);
if (value == null) {
return fallback;
} else {
return new T(value);
}
}
The return value from getProperty("foo", true)
would then be a boolean regardless of whether it was read from the properties file and similarly for strings, integers, doubles, &c. Of course, the above snippet doesn't actually compile:
PropertiesExample.java:35: unexpected type
found : type parameter T
required: class
return new T(value);
^
1 error
Am I doing this wrong, or am I simply trying to do something which can't be done?
Edit: Usage example:
// I'm trying to simplify this...
protected void func1() {
foobar = new Integer(properties.getProperty("foobar", "210"));
foobaz = new Boolean(properties.getProperty("foobaz", "true"));
}
// ...into this...
protected void func2() {
foobar = getProperty("foobar", 210);
foobaz = getProperty("foobaz", true);
}
Best Answer
Due to type erasure, you can't instantiate generic objects. Normally you could keep a reference to the
Class
object representing that type and use it to callnewInstance()
. However, this only works for the default constructor. Since you want to use a constructor with parameters, you'll need to look up theConstructor
object and use it for the instantiation:However, seeing how much trouble it is to achieve this, including the performance cost of using reflection, it's worth looking into other approaches first.
If you absolutely need to take this route, and if
T
is limited to a distinct set of types known at compile time, a compromise would be to keep a staticMap
ofConstructor
s, which is loaded at startup - that way you don't have to dynamically look them up at every call to this method. For example aMap<String, Constructor<?>>
orMap<Class<?>, Constructor<?>>
, which is populated using a static block.