From 31e3772c21d2d77d89b236284cce620e1b19e2cb Mon Sep 17 00:00:00 2001 From: Laird Nelson Date: Tue, 6 Feb 2024 19:50:49 -0800 Subject: [PATCH] Refactors and improves (#10) Signed-off-by: Laird Nelson --- README.md | 2 +- pom.xml | 2 +- .../interceptor/InterceptorMethod.java | 49 ++++++++++++------- .../interceptor/TestLambdaMetafactory.java | 33 ++++++------- 4 files changed, 48 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 5370b59..6bbc865 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Maven dependency: org.microbean microbean-interceptor - 0.2.1 + 0.2.2 ``` diff --git a/pom.xml b/pom.xml index 2a7fa40..c3c6039 100644 --- a/pom.xml +++ b/pom.xml @@ -283,7 +283,7 @@ false https://docs.oracle.com/en/java/javase/11/docs/api,https://jakarta.ee/specifications/interceptors/2.1/apidocs/ - + deploy,post-site,scm-publish:publish-scm scm:git:git@github.com:microbean/microbean-interceptor.git diff --git a/src/main/java/org/microbean/interceptor/InterceptorMethod.java b/src/main/java/org/microbean/interceptor/InterceptorMethod.java index 50fe829..27d3515 100644 --- a/src/main/java/org/microbean/interceptor/InterceptorMethod.java +++ b/src/main/java/org/microbean/interceptor/InterceptorMethod.java @@ -1,6 +1,6 @@ /* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- * - * Copyright © 2023 microBean™. + * Copyright © 2023–2024 microBean™. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -47,14 +47,15 @@ public interface InterceptorMethod { /* - * Static methods. + * Public static methods. */ /** * Returns a new {@link InterceptorMethod} that adapts the supplied {@code static} {@link Method}. * - * @param staticMethod a {@code static} {@link Method}; must not be {@code null} + * @param staticMethod a {@code static} {@link Method}; must not be {@code null}; must accept exactly one {@link + * InvocationContext}-typed argument * * @return a new {@link InterceptorMethod}; never {@code null} * @@ -68,23 +69,24 @@ public static InterceptorMethod of(final Method staticMethod) { * Returns a new {@link InterceptorMethod} that adapts the supplied {@link Method} and the supplied {@link Supplier} * of its receiver. * - * @param m a {@link Method}; must not be {@code null} + * @param m a {@link Method}; must not be {@code null}; must accept exactly one {@link InvocationContext}-typed + * argument * - * @param targetSupplier a {@link Supplier} of the supplied {@link Method}'s receiver; may be {@code null} in which - * case the supplied {@link Method} must be {@code static} + * @param targetSupplier a {@link Supplier} of the supplied {@link Method}'s receiver; often memoized; may be {@code + * null} in which case the supplied {@link Method} must be {@code static} * * @return a new {@link InterceptorMethod}; never {@code null} * * @exception NullPointerException if {@code m} is {@code null} * - * @exception IllegalStateException if {@linkplain java.lang.invoke.MethodHandles.Lookup#unreflect(Method) + * @exception InterceptorException if {@linkplain java.lang.invoke.MethodHandles.Lookup#unreflect(Method) * unreflecting} fails */ public static InterceptorMethod of(final Method m, final Supplier targetSupplier) { try { return of(privateLookupIn(m.getDeclaringClass(), lookup()).unreflect(m), targetSupplier); } catch (final IllegalAccessException e) { - throw new IllegalStateException(e.getMessage(), e); + throw new InterceptorException(e.getMessage(), e); } } @@ -92,7 +94,8 @@ public static InterceptorMethod of(final Method m, final Supplier targetSuppl * Returns a new {@link InterceptorMethod} that adapts the supplied {@link MethodHandle}. * * @param receiverlessOrBoundMethodHandle a {@link MethodHandle}; must not be {@code null}; must either not require a - * receiver or must be already {@linkplain MethodHandle#bindTo(Object) bound} to one + * receiver or must be already {@linkplain MethodHandle#bindTo(Object) bound} to one; must accept exactly one {@link + * InvocationContext}-typed argument * * @return a new {@link InterceptorMethod}; never {@code null} * @@ -106,11 +109,13 @@ public static InterceptorMethod of(final MethodHandle receiverlessOrBoundMethodH * Returns a new {@link InterceptorMethod} that adapts the supplied {@link MethodHandle} and the supplied {@link * Supplier of its receiver}. * - * @param mh a {@link MethodHandle}; must not be {@code null} + * @param mh a {@link MethodHandle}; must not be {@code null}; must either accept two arguments where the first + * argument's type is a valid receiver type and the second argument's type is {@link InvocationContext}, or one + * argument whose type is {@link InvocationContext} * - * @param receiverSupplier a {@link Supplier} of the supplied {@link MethodHandle}'s receiver; may be {@code null} in - * which case the supplied {@link MethodHandle} must either not require a receiver or must be already {@linkplain - * MethodHandle#bindTo(Object) bound} to one + * @param receiverSupplier a {@link Supplier} of the supplied {@link MethodHandle}'s receiver; often memoized; may be + * {@code null} in which case the supplied {@link MethodHandle} must either not require a receiver or must be already + * {@linkplain MethodHandle#bindTo(Object) bound} to one * * @return a new {@link InterceptorMethod}; never {@code null} * @@ -130,9 +135,9 @@ public static InterceptorMethod of(final MethodHandle mh, final Supplier rece throw e; } catch (final InterruptedException e) { Thread.currentThread().interrupt(); - throw new IllegalStateException(e.getMessage(), e); + throw new InterceptorException(e.getMessage(), e); } catch (final Throwable e) { - throw new IllegalStateException(e.getMessage(), e); + throw new InterceptorException(e.getMessage(), e); } return null; }; @@ -143,6 +148,12 @@ public static InterceptorMethod of(final MethodHandle mh, final Supplier rece return ic -> invokeExact(unboundInterceptorMethod, receiverSupplier, ic); } + + /* + * Private static methods. + */ + + private static Object invokeExact(final MethodHandle mh, final InvocationContext ic) { try { return mh.invokeExact(ic); @@ -150,9 +161,9 @@ private static Object invokeExact(final MethodHandle mh, final InvocationContext throw e; } catch (final InterruptedException e) { Thread.currentThread().interrupt(); - throw new IllegalStateException(e.getMessage(), e); + throw new InterceptorException(e.getMessage(), e); } catch (final Throwable e) { - throw new IllegalStateException(e.getMessage(), e); + throw new InterceptorException(e.getMessage(), e); } } @@ -163,9 +174,9 @@ private static Object invokeExact(final MethodHandle mh, final Supplier recei throw e; } catch (final InterruptedException e) { Thread.currentThread().interrupt(); - throw new IllegalStateException(e.getMessage(), e); + throw new InterceptorException(e.getMessage(), e); } catch (final Throwable e) { - throw new IllegalStateException(e.getMessage(), e); + throw new InterceptorException(e.getMessage(), e); } } diff --git a/src/test/java/org/microbean/interceptor/TestLambdaMetafactory.java b/src/test/java/org/microbean/interceptor/TestLambdaMetafactory.java index ab17bf6..34931d8 100644 --- a/src/test/java/org/microbean/interceptor/TestLambdaMetafactory.java +++ b/src/test/java/org/microbean/interceptor/TestLambdaMetafactory.java @@ -1,6 +1,6 @@ /* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- * - * Copyright © 2023 microBean™. + * Copyright © 2023–2024 microBean™. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -37,6 +37,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertNotNull; +// This is really more of an exploratory class than a test of anything in the org.microbean.interceptor package. final class TestLambdaMetafactory { private TestLambdaMetafactory() { @@ -112,7 +113,7 @@ private final Function frobnicate2(f } else if (aroundInvokeMethodType.parameterType(1) != InvocationContext.class) { throw new IllegalArgumentException("aroundInvokeMethodType.methodType().parameterType(0) != InvocationContext.class: " + aroundInvokeMethodType); } - + final ConstantCallSite metafactory = (ConstantCallSite)metafactory(lookup, "apply", @@ -126,7 +127,7 @@ private final Function frobnicate2(f } // See https://stackoverflow.com/a/77060967/208288 - // + // // If we want to use invokeExact() on target/factory, which we do here because we don't know how often the Function // we return will be invoked, we need to change the type of its receiver parameter to permit the invokeExact call to // work in this use case. Normally the symbolic type descriptor kind of does this for you if I understand right, but @@ -150,10 +151,10 @@ private final Function frobnicate2(f } }; } - - private final Function> frobnicate(final Lookup lookup, - final MethodHandle aroundInvokeMethod, - final Class receiverType) + + private final Function frobnicate(final Lookup lookup, + final MethodHandle aroundInvokeMethod, + final Class receiverType) throws Throwable { Objects.requireNonNull(receiverType); // for now final MethodType aroundInvokeMethodType = aroundInvokeMethod.type(); @@ -172,18 +173,18 @@ private final Function> frobnicate(fi } else if (aroundInvokeMethodType.parameterType(1) != InvocationContext.class) { throw new IllegalArgumentException("aroundInvokeMethodType.methodType().parameterType(0) != InvocationContext.class: " + aroundInvokeMethodType); } - + final ConstantCallSite ccs = (ConstantCallSite)metafactory(lookup, - "apply", - methodType(Function.class, receiverType), // Function is the functional interface we want. receiverType is a capture. - methodType(Object.class, Object.class), // Function erasure + "intercept", + methodType(InterceptorMethod.class, receiverType), // InterceptorMethod is the functional interface we want. receiverType is a capture. + methodType(Object.class, InvocationContext.class), aroundInvokeMethod, methodType(Object.class, InvocationContext.class)); final MethodHandle factory = ccs.getTarget(); return t -> { try { - return (Function)factory.invoke(t); + return (InterceptorMethod)factory.invoke(t); } catch (RuntimeException | Error e) { throw e; } catch (final InterruptedException e) { @@ -193,18 +194,16 @@ private final Function> frobnicate(fi throw new IllegalStateException(e.getMessage(), e); } }; - // return ccs.getTarget(); } @Test final void testFrobnicate() throws Throwable { final Lookup lookup = lookup(); MethodHandle mh = lookup.findVirtual(this.getClass(), "aroundInvokeVirtual", methodType(Object.class, InvocationContext.class)); - Function> factory = frobnicate(lookup, mh, TestLambdaMetafactory.class); - final Function f = factory.apply(this); - // final Function f = (Function)mh.invokeExact(this); + Function factory = frobnicate(lookup, mh, TestLambdaMetafactory.class); + final InterceptorMethod f = factory.apply(this); assertNotNull(f); - f.apply(new SimpleInvocationContext()); + f.intercept(new SimpleInvocationContext()); } @Test