From 0b5348ee3db0ddeb6662b34df8158095a49cd5a6 Mon Sep 17 00:00:00 2001 From: Jerry Lee Date: Sat, 30 Mar 2024 23:19:37 +0800 Subject: [PATCH] =?UTF-8?q?refactor(`WrapperAdapterUtils`):=20=20use=20`Cl?= =?UTF-8?q?azz.class.getMethod(...)`=20instead=20of=20lonely=20method=20na?= =?UTF-8?q?me=20constants;=20the=20former=20is=20IDE=20aware,=20so=20safer?= =?UTF-8?q?=20and=20refactor=20friendly=20=F0=9F=A4=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../utils/WrapperAdapterUtils.java | 92 ++++++++++++------- 1 file changed, 59 insertions(+), 33 deletions(-) diff --git a/src/main/java/io/foldright/inspectablewrappers/utils/WrapperAdapterUtils.java b/src/main/java/io/foldright/inspectablewrappers/utils/WrapperAdapterUtils.java index ad9b270..3565db0 100644 --- a/src/main/java/io/foldright/inspectablewrappers/utils/WrapperAdapterUtils.java +++ b/src/main/java/io/foldright/inspectablewrappers/utils/WrapperAdapterUtils.java @@ -6,24 +6,28 @@ import io.foldright.inspectablewrappers.Wrapper; import io.foldright.inspectablewrappers.WrapperAdapter; +import javax.annotation.ParametersAreNonnullByDefault; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; +import java.util.concurrent.Callable; +import static io.foldright.inspectablewrappers.utils.WrapperAdapterProxyRelatedMethods.*; import static java.util.Objects.requireNonNull; /** * Utility class for creating {@link WrapperAdapter} instances - * without writing boilerplate code of creating a new adapter class. + * without writing the boilerplate code to create a new adapter class. * * @author Jerry Lee (oldratlee at gmail dot com) */ +@ParametersAreNonnullByDefault public final class WrapperAdapterUtils { /** - * Creates a {@link WrapperAdapter} instance of the given biz interface type - * by the adapted/existed wrapper instance and the underlying instance that be wrapped. + * Creates a {@link WrapperAdapter} instance with the given biz interface type + * by the underlying instance that be wrapped and the adapted/existed wrapper instance. * * @param the type of instances that be wrapped * @param bizInterface the class of instances that be wrapped @@ -43,8 +47,8 @@ public static T createWrapperAdapter(Class bizInterface, T underlying, T } /** - * Creates a {@link WrapperAdapter} instance of the given biz interface type with attachable interface - * by the adapted/existed wrapper instance, the underlying instance that be wrapped and an attachable instance. + * Creates a {@link WrapperAdapter} instance with the given biz interface type and {@link Attachable} type + * by the underlying instance that be wrapped, the adapted/existed wrapper instance and an attachable instance. * * @param the type of instances that be wrapped * @param bizInterface the class of instances that be wrapped @@ -58,7 +62,8 @@ public static T createWrapperAdapter(Class bizInterface, T underlying, T * @see Attachable#setAttachment(Object, Object) */ @NonNull - public static T createWrapperAdapter(Class bizInterface, T underlying, T adaptee, Attachable attachable) { + public static T createWrapperAdapter( + Class bizInterface, T underlying, T adaptee, Attachable attachable) { return createWrapperAdapter0( requireNonNull(bizInterface, "bizInterface is null"), requireNonNull(underlying, "underlying is null"), @@ -67,14 +72,16 @@ public static T createWrapperAdapter(Class bizInterface, T underlying, T } @SuppressWarnings({"unchecked", "rawtypes"}) - private static T createWrapperAdapter0(Class bizInterface, T underlying, T adaptee, @Nullable Attachable attachable) { + private static T createWrapperAdapter0( + Class bizInterface, T underlying, T adaptee, @Nullable Attachable attachable) { final InvocationHandler handler = (proxy, method, args) -> { - if (isMethodUnwrap(method)) return underlying; - if (isMethodAdaptee(method)) return adaptee; + if (UNWRAP.sameSignatureAs(method)) return underlying; + if (ADAPTEE.sameSignatureAs(method)) return adaptee; - if (attachable != null && isMethodGetAttachment(method)) + if (attachable != null && GET_ATTACHMENT.sameSignatureAs(method)) { return ((Attachable) attachable).getAttachment(args[0]); - if (attachable != null && isMethodSetAttachment(method)) { + } + if (attachable != null && SET_ATTACHMENT.sameSignatureAs(method)) { ((Attachable) attachable).setAttachment(args[0], args[1]); return null; } @@ -90,31 +97,50 @@ private static T createWrapperAdapter0(Class bizInterface, T underlying, handler); } - private static boolean isMethodAdaptee(Method method) { - return checkMethod(method, "adaptee"); - } - - private static boolean isMethodUnwrap(Method method) { - return checkMethod(method, "unwrap"); - } - - private static boolean isMethodGetAttachment(Method method) { - return checkMethod(method, "getAttachment", Object.class); - } - - private static boolean isMethodSetAttachment(Method method) { - return checkMethod(method, "setAttachment", Object.class, Object.class); - } - - private static boolean checkMethod(Method method, String methodName, Class... parameterTypes) { - return method.getName().equals(methodName) - && method.getParameterCount() == parameterTypes.length - && Arrays.equals(method.getParameterTypes(), parameterTypes); - } - /** * NO need to create instance at all */ private WrapperAdapterUtils() { } } + +/** + * Use {@code Clazz.class.getMethod(...)} rather than lonely method name constants; + * The former is IDE aware, so safer and refactor friendly. + */ +enum WrapperAdapterProxyRelatedMethods { + /** + * {@link WrapperAdapter#adaptee()} + */ + UNWRAP(() -> Wrapper.class.getMethod("unwrap")), + /** + * {@link Wrapper#unwrap()} + */ + ADAPTEE(() -> WrapperAdapter.class.getMethod("adaptee")), + /** + * {@link Attachable#getAttachment(Object)} + */ + GET_ATTACHMENT(() -> Attachable.class.getMethod("getAttachment", Object.class)), + /** + * {@link Attachable#setAttachment(Object, Object)} + */ + SET_ATTACHMENT(() -> Attachable.class.getMethod("setAttachment", Object.class, Object.class)), + ; + + private final String methodName; + private final Class[] parameterTypes; + + WrapperAdapterProxyRelatedMethods(Callable method) { + try { + Method m = method.call(); + this.methodName = m.getName(); + this.parameterTypes = m.getParameterTypes(); + } catch (Exception e) { + throw new ExceptionInInitializerError(e); + } + } + + boolean sameSignatureAs(Method method) { + return methodName.equals(method.getName()) && Arrays.equals(parameterTypes, method.getParameterTypes()); + } +}