User supports userType and userFunction by config:
{"userType": "com.user.Person", "userFunction": "com.user.userFunction"}
we expect to get data for user and feed data to userFunction:
public class DataConsumer<T> {
//get data from some place, such as kafka
T data;
}
process() {
String userType = userInput();
DataConsumer<userType> dataConsumer = new DataConsumer<userType>(); // error because generic class's type name don't support String or Class
userFunction(dataConsumer.data); // We get this function by reflection
}
// This is ok in the user side
userFunction(userType data) {
data;
}
How can I implement this function without error? If it is not possible, Is there another way?
At last, I use Object to stand all type names. But user must transform Object type to userType manually. Is there a better way?
{
String userType = userInput();
DataConsumer<Object> dataConsumer = new DataConsumer<Object>(); // ok
userFunction(dataConsumer.data);
}
userFunction(Object data) {
(userType)data;
}
Ah, you should know that generics in java are only syntax sugar in compiler for most of the time, so if you don’t know runtime type just use wildcard or raw type:
MyClass<?> myClass = new MyClass<>();
, MyClass myClass = new MyClass();
But if user input is always of known type like that String then you can just do:
MyClass<String> myClass = new MyClass<>();
You can also create generic constructor in your class like this:
public class MyClass<T> {
T data;
public <T> MyClass(T data) {this.data = data;}
}
So generic type will be of type of data you passed to it - but this only exist at compile time, in runtime java IGNORES all generics here, like this is valid java code:
List<String> strings = new ArrayList<>();
strings.add(“a”);
List<Integer> integersKindOf = (List)strings;
integersKindOf.remove(“a”);
Java only saves generic type of fields, super classes (class MyMap extends HashMap<String, Integer>
- you can get that super type with generic parameters) and methods. But they are not used in runtime and but reflections can be used to read that type.
For local variables this is not possible and would be useless due to that type erasure.
There is also common pattern for unsafe generic cast, but you should be very careful when to use it:
public <T> T doSomething(String type) {
return (T) Class.forName(type).newInstance();
}
and then this can be used like this:
ArrayList<Whatever> list = doSomething("java.util.ArrayList");
but it can be also used like this:
Integer list = doSomething("java.util.ArrayList");
And this will throw exception at runtime, and this is why it is very unsafe.