EDIT: Sorry the example I provide below doesn't reproduce the problem... I'm trying to find the right way to reproduce it. Before that, you may just ignore my question...
Usually we grab the parameter type of a method like this:
Class<?> clazz = method.getParameterTypes()[0]
I have never thought twice about it before, but recently I bumped into an issue that I always got class java.lang.Object
when doing that. After an inspection, I found out the case can be described like this:
/** A parameterized interface */
public interface IService<T> {
Result create(T obj);
}
/** An implementation */
public class CarService implements IService<Car> {
public Result create(Car car) { ... }
}
And then when I use the way above to get the class of the parameter car
, it turns out to be a class java.lang.Object
:
Method methods = CarService.class.getMethods();
for (Method method : methods) {
Class<?>[] types = method.getParameterTypes();
// when the loop meets "create" here ...
}
I guess I have totally forgot something very fundamental about type erase? But now I really need get the actual parameter type in this case, if it's possible...
Yes, this is type erasure being annoying. It's worth looking at what you get in bytecode here:
class Car {}
interface IService<T> {
void create(T obj);
}
class CarService implements IService<Car> {
public void create(Car car) {}
}
Then:
$ javac Test.java # Contains all the above...
$ javap -c CarService
Compiled from "Test.java"
class CarService implements IService<Car> {
CarService();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void create(Car);
Code:
0: return
public void create(java.lang.Object);
Code:
0: aload_0
1: aload_1
2: checkcast #2 // class Car
5: invokevirtual #3 // Method create:(LCar;)V
8: return
}
And those are also shown when you use reflection:
public class Test {
public static void main(String[] args) {
Method[] methods = CarService.class.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName());
for (Class<?> type : method.getParameterTypes()) {
System.out.printf("- %s%n", type.getName());
}
}
}
}
Output:
create
- Car
create
- java.lang.Object
How you use this will depend on exactly what you're trying to achieve, but hopefully the awareness that there are multiple methods in the bytecode will help...
See more on this question at Stackoverflow