001package ball.lang.reflect;
002/*-
003 * ##########################################################################
004 * Utilities
005 * %%
006 * Copyright (C) 2008 - 2022 Allen D. Ball
007 * %%
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *      http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 * ##########################################################################
020 */
021import java.lang.reflect.Method;
022import lombok.Getter;
023import lombok.RequiredArgsConstructor;
024import lombok.ToString;
025
026import static org.apache.commons.lang3.reflect.MethodUtils.invokeMethod;
027
028/**
029 * "Intercepting" {@link java.lang.reflect.InvocationHandler}
030 * implementation.
031 *
032 * @param       <T>     The type of the "wrapped" target.
033 *
034 * {@bean.info}
035 *
036 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball}
037 */
038@RequiredArgsConstructor @ToString
039public class InterceptingInvocationHandler<T> extends DefaultInvocationHandler {
040    @Getter private final T target;
041
042    /**
043     * Subclasses may declare methods with the same signature of a proxied
044     * interface method which will be invoked (as a sort of listener) before
045     * invoking the target method.  If the invoked {@link Method}'s
046     * declaring class is assignable from the target's class, the
047     * {@link Method} is invoked on the target.
048     *
049     * @param   proxy           The proxy instance.
050     * @param   method          The {@link Method}.
051     * @param   argv            The argument array.
052     *
053     * @return  The value to return from the {@link Method} invocation.
054     *
055     * @throws  Exception       If the {@link Method} cannot be invoked.
056     */
057    @Override
058    public Object invoke(Object proxy, Method method, Object[] argv) throws Throwable {
059        try {
060            invokeMethod(this, true, method.getName(), argv, method.getParameterTypes());
061        } catch (Exception exception) {
062        }
063
064        Object result = null;
065
066        if (method.isDefault()) {
067            result = super.invoke(proxy, method, argv);
068        } else if (method.getDeclaringClass().isAssignableFrom(target.getClass())) {
069            result = method.invoke(target, argv);
070        } else {
071            result = super.invoke(proxy, method, argv);
072        }
073
074        return result;
075    }
076}