Skip to content

Commit

Permalink
Distinguish CCE and NPE from exceptions thrown by the default method
Browse files Browse the repository at this point in the history
Signed-off-by: Alexander Pinčuk <alexander.v.pinchuk@gmail.com>
  • Loading branch information
avpinchuk committed Apr 17, 2023
1 parent 25b13a1 commit aa2e64d
Showing 1 changed file with 36 additions and 3 deletions.
Expand Up @@ -27,6 +27,19 @@ final class ProxyHelper {

private static final Object[] NO_ARGS = new Object[0];

private static final MethodHandle EXCEPTION_HANDLER;
static {
try {
EXCEPTION_HANDLER = MethodHandles.lookup().findStatic(
ProxyHelper.class,
"exceptionHandler",
MethodType.methodType(Object.class, Throwable.class));
} catch (NoSuchMethodException | IllegalAccessException e) {
// Should never be thrown
throw new IllegalStateException(e);
}
}

private ProxyHelper() {
throw new AssertionError();
}
Expand All @@ -48,8 +61,15 @@ public static Object invokeDefault(Object proxy, Method method, Object... args)

MethodHandle mh = defaultMethodHandle(proxyClass, method);

Object[] params = args != null ? args : NO_ARGS;
return mh.invokeExact(proxy, params);
try {
Object[] params = args != null ? args : NO_ARGS;
return mh.invokeExact(proxy, params);
} catch (ClassCastException | NullPointerException e) {
throw new IllegalArgumentException(e.getMessage(), e);
} catch (ProxyInvocationException e) {
// unwrap and throw the default method exception
throw e.getCause();
}
}

private static MethodHandle defaultMethodHandle(Class<? extends Proxy> proxyClass, Method method) {
Expand All @@ -66,6 +86,8 @@ private static MethodHandle defaultMethodHandle(Class<? extends Proxy> proxyClas
}

mh = mh.asType(mh.type().changeReturnType(Object.class));
// Wrap an exception thrown by the default method
mh = MethodHandles.catchException(mh, Throwable.class, EXCEPTION_HANDLER);
mh = mh.asSpreader(1, Object[].class, mt.parameterCount());
mh = mh.asType(MethodType.methodType(Object.class, Object.class, Object[].class));

Expand All @@ -79,7 +101,18 @@ private static Class<?> findProxyInterface(Class<? extends Proxy> proxyClass, Me
}
// Because all of our configuration proxies directly implements
// only one interface annotated @Configured, we simply return
// this interface
// this interface, without search
return proxyClass.getInterfaces()[0];
}

private static Object exceptionHandler(Throwable cause) throws ProxyInvocationException {
throw new ProxyInvocationException(cause);
}

private static class ProxyInvocationException extends ReflectiveOperationException {

ProxyInvocationException(Throwable cause) {
super(cause);
}
}
}

0 comments on commit aa2e64d

Please sign in to comment.