How to do the following properly in Java? I would like to have a generic routine that can create a list of objects. In this routine I expect the constructor of the class of these objects to support a particular parameter.
To clarify: I would like this routine to create a List<T>
from a JSON string. This is part of a larger deserialization code. If I can somehow specify that each supported T
implements a constructor that creates T
given a JSONObject
, then I could write the routine something like this:
interface CreatableFromJSONObject<T> {
T(JSONObject object); // Complains about missing return type.
}
static <T> List<T extends CreatableFromJSONObject> jsonArrayToList(JSONArray array) {
List<T> result = new ArrayList<T>();
for (int i = 0; i < array.length; ++i) {
JSONObject jsonObject = array.getJSONObject(i);
result.add(T(jsonObject)); // If T has one constructor with 1 one argument JSONObject
}
return result;
}
and then with an example class that implements this interface
class SomeClass implements CreatableFromJSONObject {
SomeClass(JSONObject object) throws JSONException {
// implementation here
}
}
I could use the desired method as:
List<SomeClass> list = jsonArrayToList<SomeClass>(someJSONArray);
Now, there are quite some hits on this on StackOverflow, so there I have learned that what I outlined above is not possible because Java does not support specifying a particular constructor in an interface and also not for static methods (which would be an alternative route to the same thing and not possible for the same reason).
So, what is then the best way of achieving this?
My current best attempt is the following:
public static <T> List<T> jsonArrayToList(final JSONArray jsonArray, Constructor<T> fromJSONObjectConstructor) {
List<T> result = new ArrayList<T>();
try {
for (int i = 0; i < jsonArray.length(); i++) {
result.add(fromJSONObjectConstructor.newInstance(jsonArray.getJSONObject(i)));
}
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (JSONException e) {
throw new RuntimeException(e);
}
return result;
}
and then to add to each class that should be supported by this method:
public class SomeClass {
public static final Constructor<SomeClass> jsonObjectConstructor;
static {
try {
jsonObjectConstructor = CafellowEntity.class.getConstructor(JSONObject.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
SomeClass(JSONObject object) throws JSONException {
// Implementation here
}
}
which I use as
List<SomeClass> list = jsonArrayToList(myJSONArray, SomeClass.jsonObjectConstructor);
It is the most pretty solution I could come up with apart from not using a generic implementation at all and just put the (in this case) couple of lines of code that is actually doing the work in the routine wherever I need them for a particular class.
Any suggestions? What about the performance of this versus alternative solutions? By not supporting it just like this Java is probably telling me I should not be wanting to do this, but that does not prevent me from wondering about it anyway.