title: Why can't I .invokeExact() here, even though the MethodType is OK?
body: <p>For one of my project I have to make dynamic invocations of constructor. But since this is Java 7, instead of the "classic" reflection API, I use java.lang.invoke.</p>
  
  <p>Code:</p>
  
  <pre><code>@ParametersAreNonnullByDefault
  public class PathMatcherProvider
  {
      private static final MethodHandles.Lookup LOOKUP
          = MethodHandles.publicLookup();
      private static final MethodType CONSTRUCTOR_TYPE
          = MethodType.methodType(void.class, String.class);
  
      private final Map&lt;String, Class&lt;? extends PathMatcher&gt;&gt; classMap
          = new HashMap&lt;&gt;();
      private final Map&lt;Class&lt;? extends PathMatcher&gt;, MethodHandle&gt; handleMap
          = new HashMap&lt;&gt;();
  
      public PathMatcherProvider()
      {
          registerPathMatcher("glob", GlobPathMatcher.class);
          registerPathMatcher("regex", RegexPathMatcher.class);
      }
  
      public final PathMatcher getPathMatcher(final String name, final String arg)
      {
          Objects.requireNonNull(name);
          Objects.requireNonNull(arg);
  
          final Class&lt;? extends PathMatcher&gt; c = classMap.get(name);
          if (c == null)
              throw new UnsupportedOperationException();
  
          try {
              return c.cast(handleMap.get(c).invoke(arg));
          } catch (Throwable throwable) {
              throw new RuntimeException("Unhandled exception", throwable);
          }
      }
  
      protected final void registerPathMatcher(@Nonnull final String name,
          @Nonnull final Class&lt;? extends PathMatcher&gt; matcherClass)
      {
          Objects.requireNonNull(name);
          Objects.requireNonNull(matcherClass);
          try {
              classMap.put(name, matcherClass);
              handleMap.put(matcherClass, findConstructor(matcherClass));
          } catch (NoSuchMethodException | IllegalAccessException e) {
              throw new RuntimeException("cannot find constructor", e);
          }
      }
  
      private static &lt;T extends PathMatcher&gt; MethodHandle findConstructor(
          final Class&lt;T&gt; matcherClass)
          throws NoSuchMethodException, IllegalAccessException
      {
          Objects.requireNonNull(matcherClass);
          return LOOKUP.findConstructor(matcherClass, CONSTRUCTOR_TYPE);
      }
  
      public static void main(final String... args)
      {
          new PathMatcherProvider().getPathMatcher("regex", "^a");
      }
  }
  </code></pre>
  
  <p>OK, this works.</p>
  
  <p>The problem I have is with this line:</p>
  
  <pre><code>return c.cast(handleMap.get(c).invoke(arg));
  </code></pre>
  
  <p>If I replace <code>invoke</code> with <code>invokeExact</code>, I get this stack trace:</p>
  
  <pre><code>Exception in thread "main" java.lang.RuntimeException: Unhandled exception
      at com.github.fge.filesystem.path.matchers.PathMatcherProvider.getPathMatcher(PathMatcherProvider.java:62)
      at com.github.fge.filesystem.path.matchers.PathMatcherProvider.main(PathMatcherProvider.java:89)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:606)
      at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
  Caused by: java.lang.invoke.WrongMethodTypeException: expected (String)RegexPathMatcher but found (String)Object
      at java.lang.invoke.Invokers.newWrongMethodTypeException(Invokers.java:350)
      at java.lang.invoke.Invokers.checkExactType(Invokers.java:361)
      at com.github.fge.filesystem.path.matchers.PathMatcherProvider.getPathMatcher(PathMatcherProvider.java:60)
  </code></pre>
  
  <p>I don't quite get it. Both of <code>GlobPathMatcher</code> and <code>RegexPathMatcher</code> use a single constructor with a <code>String</code> as an argument, and the <code>MethodType</code> for both is therefore what is defined in <code>CONSTRUCTOR_TYPE</code>. If it weren't I couldn't have "grabbed" the <code>MethodHandle</code>s anyway.</p>
  
  <p>Yet I get a <code>WrongMethodTypeException</code>. Why?</p>
  
  <hr>
  
  <p>EDIT: here is the code after I have read the answer; now I don't need the intermediate map: I just have to have one map, mapping a <code>String</code> to a <code>MethodHandle</code>:</p>
  
  <pre><code>@ParametersAreNonnullByDefault
  public class PathMatcherProvider
  {
      private static final MethodHandles.Lookup LOOKUP
          = MethodHandles.publicLookup();
      private static final MethodType CONSTRUCTOR_TYPE
          = MethodType.methodType(void.class, String.class);
  
      private final Map&lt;String, MethodHandle&gt; handleMap
          = new HashMap&lt;&gt;();
  
      public PathMatcherProvider()
      {
          registerPathMatcher("glob", GlobPathMatcher.class);
          registerPathMatcher("regex", RegexPathMatcher.class);
      }
  
      public final PathMatcher getPathMatcher(final String name, final String arg)
      {
          Objects.requireNonNull(name);
          Objects.requireNonNull(arg);
  
          final MethodHandle handle = handleMap.get(name);
          if (handle == null)
              throw new UnsupportedOperationException();
  
          try {
              return (PathMatcher) handle.invokeExact(arg);
          } catch (Throwable throwable) {
              throw new RuntimeException("Unhandled exception", throwable);
          }
      }
  
      protected final void registerPathMatcher(@Nonnull final String name,
          @Nonnull final Class&lt;? extends PathMatcher&gt; matcherClass)
      {
          Objects.requireNonNull(name);
          Objects.requireNonNull(matcherClass);
  
          final MethodHandle handle;
          final MethodType type;
  
          try {
              handle = LOOKUP.findConstructor(matcherClass, CONSTRUCTOR_TYPE);
              type = handle.type().changeReturnType(PathMatcher.class);
              handleMap.put(name, handle.asType(type));
          } catch (NoSuchMethodException | IllegalAccessException e) {
              throw new RuntimeException("cannot find constructor", e);
          }
      }
  }
  </code></pre>