extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java
@Override
  public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
    // If we setup a method handle earlier for this method, call it.
    // This is necessary for default methods that java8 creates, so we
    // can call the default method implementation (and not our proxied version of it).
    if (methodHandleByMethod.containsKey(method)) {
      return methodHandleByMethod.get(method).invokeWithArguments(args);
    }

    if (method.getDeclaringClass().equals(Object.class)) {
      if ("equals".equals(method.getName())) {
        return proxy == args[0];
      } else if ("hashCode".equals(method.getName())) {
        return System.identityHashCode(proxy);
      } else {
        return method.invoke(this, args);
      }
    }

    AssistData data = assistDataByMethod.get(method);
    checkState(data != null, "No data for method: %s", method);
    Provider<?> provider;
    if (data.cachedBinding != null) { // Try to get optimized form...
      provider = data.cachedBinding.getProvider();
    } else {
      provider = getBindingFromNewInjector(method, args, data).getProvider();
    }
    try {
      int p = 0;
      for (ThreadLocalProvider tlp : data.providers) {
        tlp.set(args[p++]);
      }
      return provider.get();
    } catch (ProvisionException e) {
      // if this is an exception declared by the factory method, throw it as-is
      if (e.getErrorMessages().size() == 1) {
        Message onlyError = getOnlyElement(e.getErrorMessages());
        Throwable cause = onlyError.getCause();
        if (cause != null && canRethrow(method, cause)) {
          throw cause;
        }
      }
      throw e;
    } finally {
      for (ThreadLocalProvider tlp : data.providers) {
        tlp.remove();
      }
    }
  }
@Override
  public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
    // If we setup a method handle earlier for this method, call it.
    // This is necessary for default methods that java8 creates, so we
    // can call the default method implementation (and not our proxied version of it).
    if (methodHandleByMethod.containsKey(method)) {
      return methodHandleByMethod.get(method).invokeWithArguments(args);
    }

    if (method.getDeclaringClass().equals(Object.class)) {
      if ("equals".equals(method.getName())) {
        return proxy == args[0];
      } else if ("hashCode".equals(method.getName())) {
        return System.identityHashCode(proxy);
      } else {
        return method.invoke(this, args);
      }
    }

    AssistData data = assistDataByMethod.get(method);
    checkState(data != null, "No data for method: %s", method);
    Provider<?> provider;
    if (data.cachedBinding != null) { // Try to get optimized form...
      provider = data.cachedBinding.getProvider();
    } else {
      provider = getBindingFromNewInjector(method, args, data).getProvider();
    }
    try {
      int p = 0;
      for (ThreadLocalProvider tlp : data.providers) {
        tlp.set(args[p++]);
      }
      return provider.get();
    } catch (ProvisionException e) {
      // if this is an exception declared by the factory method, throw it as-is
      if (e.getErrorMessages().size() == 1) {
        Message onlyError = getOnlyElement(e.getErrorMessages());
        Throwable cause = onlyError.getCause();
        if (cause != null && canRethrow(method, cause)) {
          throw cause;
        }
      }
      throw e;
    } finally {
      for (ThreadLocalProvider tlp : data.providers) {
        tlp.remove();
      }
    }
  }
@ Override public Object invoke ( Object proxy , final Method method , final Object [ ] args ) throws Throwable { // If we setup a method handle earlier for this method, call it. // This is necessary for default methods that java8 creates, so we // can call the default method implementation (and not our proxied version of it). if ( methodHandleByMethod . containsKey ( method ) ) { return methodHandleByMethod . get ( method ) . invokeWithArguments ( args ) ; } if ( method . getDeclaringClass ( ) . equals ( Object . class ) ) { if ( "equals" . equals ( method . getName ( ) ) ) { return proxy == args [ 0 ] ; } else if ( "hashCode" . equals ( method . getName ( ) ) ) { return System . identityHashCode ( proxy ) ; } else { return method . invoke ( this , args ) ; } } AssistData data = assistDataByMethod . get ( method ) ; checkState ( data != null , "No data for method: %s" , method ) ; Provider < ? > provider ; if ( data . cachedBinding != null ) { // Try to get optimized form... provider = data . cachedBinding . getProvider ( ) ; } else { provider = getBindingFromNewInjector ( method , args , data ) . getProvider ( ) ; } try { int p = 0 ; for ( ThreadLocalProvider tlp : data . providers ) { tlp . set ( args [ p ++ ] ) ; } return provider . get ( ) ; } catch ( ProvisionException e ) { // if this is an exception declared by the factory method, throw it as-is if ( e . getErrorMessages ( ) . size ( ) == 1 ) { Message onlyError = getOnlyElement ( e . getErrorMessages ( ) ) ; Throwable cause = onlyError . getCause ( ) ; if ( cause != null && canRethrow ( method , cause ) ) { throw cause ; } } throw e ; } finally { for ( ThreadLocalProvider tlp : data . providers ) { tlp . remove ( ) ; } } }
When a factory method is invoked, we create a child injector that binds all parameters, then
use that to get an instance of the return type.
When a factory method is invoked we create a child injector that binds all parameters then use that to get an instance of the return type .