diff --git a/src/main/java/io/foldright/inspectablewrappers/utils/WrapperAdapterUtils.java b/src/main/java/io/foldright/inspectablewrappers/utils/WrapperAdapterUtils.java index ad9b270..e468fce 100644 --- a/src/main/java/io/foldright/inspectablewrappers/utils/WrapperAdapterUtils.java +++ b/src/main/java/io/foldright/inspectablewrappers/utils/WrapperAdapterUtils.java @@ -6,20 +6,24 @@ 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 + * Utility class for creating {@link io.foldright.inspectablewrappers.WrapperAdapter} instances * without writing boilerplate code of creating 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 @@ -69,12 +73,12 @@ 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) { 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 +94,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()); + } +}