in archaius2-core/src/main/java/com/netflix/archaius/ConfigProxyFactory.java [436:480]
private static <T> Function<Object[], T> createDefaultMethodSupplier(Method method, Class<T> proxyObjectType, T proxyObject) {
final MethodHandle methodHandle;
try {
if (SystemUtils.IS_JAVA_1_8) {
Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
.getDeclaredConstructor(Class.class, int.class);
constructor.setAccessible(true);
methodHandle = constructor.newInstance(proxyObjectType, MethodHandles.Lookup.PRIVATE)
.unreflectSpecial(method, proxyObjectType)
.bindTo(proxyObject);
}
else {
// Java 9 onwards
methodHandle = MethodHandles.lookup()
.findSpecial(proxyObjectType,
method.getName(),
MethodType.methodType(method.getReturnType(), method.getParameterTypes()),
proxyObjectType)
.bindTo(proxyObject);
}
} catch (ReflectiveOperationException e) {
throw new RuntimeException("Failed to create temporary object for " + proxyObjectType.getName(), e);
}
return (args) -> {
try {
if (methodHandle.type().parameterCount() == 0) {
//noinspection unchecked
return (T) methodHandle.invokeWithArguments();
} else if (args != null) {
//noinspection unchecked
return (T) methodHandle.invokeWithArguments(args);
} else {
// This is a handle to a method WITH arguments, being called with none. This happens when toString()
// is trying to build a representation of a proxy that has a parameterized property AND the interface
// provides a default method for it. There's no good default to return here, so we'll just use null
return null;
}
} catch (Throwable e) {
maybeWrapThenRethrow(e);
return null; // Unreachable, but the compiler doesn't know
}
};
}