@Override T newInstance(Object... params) { return Unchecked.<Object[], T>function(constructor::newInstance).apply(params); }
@Override public T build() { return defn.cast(Unchecked.function(builderBuild::invoke).apply(b)); } };
private static Object invoke(Object target, Method method, Object[] args) { if (Proxy.isProxyClass(target.getClass())) { InvocationHandler handler = Proxy.getInvocationHandler(target); return Unchecked.<Object[], Object>function((params) -> handler.invoke(target, method, params)).apply(args); } else { MethodHandle handle = Unchecked.function(MethodHandles.lookup()::unreflect).apply(method).bindTo(target); return Unchecked.<Object[], Object>function(handle::invokeWithArguments).apply(args); } } }
@Override public Object invoke(Object target, Object[] args, HandleSupplier handle) { return Unchecked.<Object[], Object>function(methodHandle.bindTo(target)::invokeWithArguments).apply(args); }
static MethodHandles.Lookup lookupFor(Class<?> clazz) { if (PRIVATE_LOOKUP_IN != null) { try { return (MethodHandles.Lookup) PRIVATE_LOOKUP_IN.invoke(null, clazz, MethodHandles.lookup()); } catch (IllegalAccessException | InvocationTargetException e) { String message = String.format( "Error invoking MethodHandles.privateLookupIn(%s.class, MethodHandles.lookup()) in JDK 9+ runtime", clazz); throw new RuntimeException(message, e); } } // TERRIBLE, HORRIBLE, NO GOOD, VERY BAD HACK // Courtesy of: // https://rmannibucau.wordpress.com/2014/03/27/java-8-default-interface-methods-and-jdk-dynamic-proxies/ // We can use MethodHandles to look up and invoke the super method, but since this class is not an // implementation of method.getDeclaringClass(), MethodHandles.Lookup will throw an exception since // this class doesn't have access to the super method, according to Java's access rules. This horrible, // awful workaround allows us to directly invoke MethodHandles.Lookup's private constructor, bypassing // the usual access checks. // This workaround is only used in JDK 8.x runtimes. JDK 9+ runtimes use MethodHandles.privateLookupIn() // above. return PRIVATE_LOOKUPS.computeIfAbsent(clazz, Unchecked.function(DefaultMethodHandler::getConstructorLookup)); }
@Override public Optional<Handler> buildHandler(Class<?> sqlObjectType, Method method) { if (!method.isBridge()) { return Optional.empty(); } return Stream.of(sqlObjectType.getMethods()) .filter(candidate -> !candidate.isBridge() && Objects.equals(candidate.getName(), method.getName()) && candidate.getParameterCount() == method.getParameterCount()) .filter(candidate -> { Class<?>[] candidateParamTypes = candidate.getParameterTypes(); Class<?>[] methodParamTypes = method.getParameterTypes(); return IntStream.range(0, method.getParameterCount()) .allMatch(i -> methodParamTypes[i].isAssignableFrom(candidateParamTypes[i])); }) .<Handler>map(m -> { final MethodHandle mh = unreflect(sqlObjectType, m); return (target, args, handle) -> Unchecked.<Object[], Object>function(mh.bindTo(target)::invokeWithArguments).apply(args); }) .findFirst(); }