The issue with reflection and java is type erasure. You just need to give the compiler a hint.
Since the object you are expecting is of type T, and the method itself is generic, you kinda have to
let java know what type you really are working with.
All it needs is a bit of a hint, something during runtime that can be passed through a compiled method that holds that type information.
So at compile time you have a method that takes in:
Class<String>
the compiler only knows the compiled type, so has no clue that the type itself is a class definition, making it impossible to assign if you don't tell java what the type of the assignment is.
So this works:
Class<String> myVar = String.class;
Or this works:
Class<String> myVar = isA(String.class);
Or this works
public <T> T myMethod(Class<T> object)
Class<String> class = myMethod(String.class)
but this doesn't work
public <T> void myMethod(Class<T> object);
since we have no assignment of T for the generic.
so how do you let the compiler know that T really is a class?
public <T> void myClassWrapper(Class<? super T> object);
myMethod(myClassWrapper(String.class));
so by passing it through a method that accepts you let the compiler know that at minimum that this thing is a class and that it represents T at some part of T's own hierarchy, thus letting the method compile.
or of course you could always just do
myMethod((Class<String>)string.class));
but I think thats kinda hackish personally. I am not a fan of casts that are not explcit and wrapped in a method.
Since you cannot control the signature of the test framework, you can however let java know your intentions.
I am not sure how easy mock works, but heres a test to kinda help explain whats going on.
@Test
public void testCreation(){
Object integer = 5;
String myString = "A String";
int five = typeTheObject(Integer.class, integer);
Class<String> stringClass = typeTheObject(myString);
Class<Integer> myInt = typeTheObject(five);
Class<?> myClass = typeTheObject(String.class);
TypeValidator typeValidator = new TypeValidator(stringClass);
typeValidator.isA(typeTheObject(String.class));
}
public static class TypeValidator{
private final Object objectToValidate;
public TypeValidator(Object object){
objectToValidate = object;
}
public <T> T isA(T type){
if(objectToValidate.getClass().isAssignableFrom(type.getClass())){
return type;
}else{
Assert.fail();
return null; //cuase
}
}
}
public static <T> Class<T> typeTheObject(Class<? super T> type){
return (Class<T>)type;
}
public static <T> T typeTheObject(Class<T> type, Object object){
if(object.getClass().isAssignableFrom(type)){
return (T)object;
}
return (T)object;
}
public static <T> Class<T> typeTheObject(Object object){
return (Class<T>)((T)object).getClass();
}
Though one big drawback is paramaterized types. But those can be solved using a guice type literal.
(new TypeLiteral<List<String>(){}).getRawType();
since its annon the type holds during runtime.