Skip to content

Commit

Permalink
refactor(WrapperAdapterUtils): use Clazz.class.getMethod(...) ins…
Browse files Browse the repository at this point in the history
…tead of lonely method name constants; the former is IDE aware, so safer and refactor friendly 🤖
  • Loading branch information
oldratlee committed Mar 31, 2024
1 parent 599e7e8 commit 0b5348e
Showing 1 changed file with 59 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 <T> the type of instances that be wrapped
* @param bizInterface the class of instances that be wrapped
Expand All @@ -43,8 +47,8 @@ public static <T> T createWrapperAdapter(Class<T> 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 <T> the type of instances that be wrapped
* @param bizInterface the class of instances that be wrapped
Expand All @@ -58,7 +62,8 @@ public static <T> T createWrapperAdapter(Class<T> bizInterface, T underlying, T
* @see Attachable#setAttachment(Object, Object)
*/
@NonNull
public static <T> T createWrapperAdapter(Class<T> bizInterface, T underlying, T adaptee, Attachable<?, ?> attachable) {
public static <T> T createWrapperAdapter(
Class<T> bizInterface, T underlying, T adaptee, Attachable<?, ?> attachable) {
return createWrapperAdapter0(
requireNonNull(bizInterface, "bizInterface is null"),
requireNonNull(underlying, "underlying is null"),
Expand All @@ -67,14 +72,16 @@ public static <T> T createWrapperAdapter(Class<T> bizInterface, T underlying, T
}

@SuppressWarnings({"unchecked", "rawtypes"})
private static <T> T createWrapperAdapter0(Class<T> bizInterface, T underlying, T adaptee, @Nullable Attachable<?, ?> attachable) {
private static <T> T createWrapperAdapter0(
Class<T> 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;
}
Expand All @@ -90,31 +97,50 @@ private static <T> T createWrapperAdapter0(Class<T> 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> 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());
}
}

0 comments on commit 0b5348e

Please sign in to comment.