5

The idea is to define a base class that can invoke methods defined in derrived classes, but at creation time I want to ensure, that such methods are defined exactly according to the requirements, which is that the methods take only one argument, a HashMap<String String>.

So far I was able with the following code to check that the method contains only one parameter and that it is of Class HashMap, but how can I check that the generic definition is <String, String> ?

public boolean isMethodParameterValid(final Method method) {
  final Class<?>[] parameters = method.getParameterTypes();
  return ((parameters.length == 1) && parameters[0].isAssignableFrom(HashMap.class));
}

4 Answers4

12

Indeed, there is type erasure but it is not applied to variables/fields - only to definitions of classes where the type params are erased and replaced with their upper bounds.

This means that what you are asking can be achieved. Here's how you can inspect the generic params of the first parameter of a method:

class Z
{
  public void f(List<String> lst) { }
}

...

Method m = Z.class.getMethod("f", List.class);
Type t = m.getGenericParameterTypes()[0];
if(t instanceof ParameterizedType) {
  ParameterizedType pt = (ParameterizedType) t;
  System.out.println("Generic params of first argument: " + Arrays.toString(pt.getActualTypeArguments()));
}    
Itay Maman
  • 30,277
  • 10
  • 88
  • 118
  • Yep. If you have an instance of a class, at runtime you cannot ask it for what its generic type parameters might have been. If you have a reflective handle on a method, class, or field that may have been defined with generic type parameters, you can use reflection methods to decide what those generic parameters are -- whether they are types, wildcards, type variables, etc. – pholser Feb 20 '12 at 04:10
7

You can't. Java generic types are "erased" by the compiler, i.e. HashMap<String, String> becomes just HashMap at run-time. See this question.

Community
  • 1
  • 1
Dave Ray
  • 39,616
  • 7
  • 83
  • 82
  • 1
    Not all types are erased. Another example would be `new ArrayList{}`. Neal Gafter's Super Type tokens post is worth a read too: http://gafter.blogspot.com/2006/12/super-type-tokens.html – johnstok Mar 23 '11 at 14:47
  • No, Neals Gafter's super type token ARE erased at compile time. His trick help accessing the Type used to instantiate the generic, at runtime (since Type.getClass() is authorized). – Jérôme Verstrynge Jul 30 '12 at 17:48
1

I dont really understand the goal of what you are trying to do. I have a feeling that it should be possible to check that at compile time by carefully designing your class hierarchy. But without more details on the problem you are trying to solve, I cant help you.

Guillaume
  • 18,494
  • 8
  • 53
  • 74
1

As noted, at runtime you cannot look at the generic portion of a type.

Is there a reason you can just define an abstract method as in the Template Pattern?

Then the checking will be done statically.

protected abstract void process(HashMap<String, String>);

(also is there a reason to require HashMap over just Map?)

Michael Myers
  • 188,989
  • 46
  • 291
  • 292
Kathy Van Stone
  • 25,531
  • 3
  • 32
  • 40