All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.flyjingfish.android_aop_annotation.impl.ProceedJoinPointImpl Maven / Gradle / Ivy

package com.flyjingfish.android_aop_annotation.impl;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.flyjingfish.android_aop_annotation.AopMethod;
import com.flyjingfish.android_aop_annotation.ProceedJoinPoint;
import com.flyjingfish.android_aop_annotation.base.OnBaseSuspendReturnListener;
import com.flyjingfish.android_aop_annotation.ex.AndroidAOPIllegalArgumentException;
import com.flyjingfish.android_aop_annotation.utils.AndroidAopBeanUtils;
import com.flyjingfish.android_aop_annotation.utils.InvokeMethod;
import com.flyjingfish.android_aop_annotation.utils.Utils;

import java.lang.reflect.Method;

/**
 * 切点相关信息类,wiki 文档使用说明
 */
class ProceedJoinPointImpl implements ProceedJoinPoint {
    /**
     * wiki 文档使用说明
     */
    @Nullable
    private final Object[] args;
    @Nullable
    private final Object[] originalArgs;
    @Nullable
    private final Object target;
    @NonNull
    private final Class targetClass;
    private final Method targetMethod;
    private final InvokeMethod targetInvokeMethod;
    private final AopMethod targetAopMethod;
    private final int argCount;
    private final boolean isSuspend;
    private final Object suspendContinuation;
    private OnInvokeListener onInvokeListener;
    private boolean hasNext;

    ProceedJoinPointImpl(@NonNull Class targetClass, Object[] args, @Nullable Object target, boolean isSuspend,
                         Method targetMethod, InvokeMethod invokeMethod, AopMethod aopMethod) {
        this.targetClass = targetClass;
        this.target = target;
        this.isSuspend = isSuspend;
        this.targetMethod = targetMethod;
        this.targetInvokeMethod = invokeMethod;
        this.targetAopMethod = aopMethod;

        Object[] fakeArgs;
        if (isSuspend && args != null) {
            fakeArgs = new Object[args.length - 1];
            System.arraycopy(args, 0, fakeArgs, 0, args.length - 1);
            suspendContinuation = args[args.length - 1];
        } else {
            fakeArgs = args;
            suspendContinuation = null;
        }
        this.args = fakeArgs;

        if (fakeArgs != null) {
            this.originalArgs = fakeArgs.clone();
        } else {
            this.originalArgs = null;
        }
        this.argCount = fakeArgs != null ? fakeArgs.length : 0;
    }

    @Nullable
    @Override
    public Object[] getArgs() {
        return args;
    }

    /**
     * 调用切点方法内代码
     *
     * @return 返回切点方法返回值 wiki 文档使用说明
     */
    @Nullable
    @Override
    public Object proceed() {
        return proceed(args);
    }

    /**
     * 调用切点方法内代码
     *
     * @param args 切点方法参数数组
     * @return 返回切点方法返回值 wiki 文档使用说明
     */
    @Nullable
    @Override
    public Object proceed(Object... args) {
        return realProceed(null, args);
    }

    /**
     * @return 切点方法相关信息
     */
    @NonNull
    @Override
    public AopMethod getTargetMethod() {
        return targetAopMethod;
    }

    /**
     * @return 切点方法所在对象,如果方法为静态的,此值为null
     */
    @Nullable
    @Override
    public Object getTarget() {
        return target;
    }

    /**
     * @return 切点方法所在类 Class
     */
    @NonNull
    @Override
    public Class getTargetClass() {
        return targetClass;
    }

    /**
     * 和 {@link ProceedJoinPointImpl#args} 相比,返回的引用地址不同,但数组里边的对象一致
     *
     * @return 最开始进入方法时的参数  wiki 文档使用说明
     */
    @Nullable
    @Override
    public Object[] getOriginalArgs() {
        return originalArgs;
    }


    @Nullable
    Object realProceed(OnBaseSuspendReturnListener onSuspendReturnListener, Object... args) {
        if (argCount > 0) {
            if (args == null || args.length != argCount) {
                throw new AndroidAOPIllegalArgumentException("proceed 所参数个数不对");
            }
        }

        Object[] realArgs;
        if (isSuspend) {
            realArgs = new Object[argCount + 1];
            if (args != null) {
                System.arraycopy(args, 0, realArgs, 0, args.length);
            }
            realArgs[argCount] = suspendContinuation;
        } else {
            realArgs = args;
        }

        if (realArgs != null && this.args != null) {
            System.arraycopy(realArgs, 0, this.args, 0, this.args.length);
        }

        try {
            Object returnValue = null;
            setReturnListener(onSuspendReturnListener);
            if (!hasNext) {
                if (targetInvokeMethod != null) {
                    returnValue = targetInvokeMethod.invoke(target, realArgs);
                } else {
                    returnValue = targetMethod.invoke(target, realArgs);
                }
            } else if (onInvokeListener != null) {
                returnValue = onInvokeListener.onInvoke();
            }

            return returnValue;
        } catch (Throwable e) {
            throw Utils.INSTANCE.getRealRuntimeException(e);
        }
    }

    private void setReturnListener(OnBaseSuspendReturnListener onSuspendReturnListener) {
        if (isSuspend && onSuspendReturnListener != null && suspendContinuation != null) {
            Object key1 = suspendContinuation;
            AndroidAopBeanUtils.INSTANCE.addSuspendReturnListener(key1, onSuspendReturnListener);
            try {
                Method method = suspendContinuation.getClass().getMethod("getCompletion");
                method.setAccessible(true);
                Object key2 = method.invoke(suspendContinuation);
                if (key2 != null) {
                    AndroidAopBeanUtils.INSTANCE.addSuspendReturnListener(key2, onSuspendReturnListener);
                    AndroidAopBeanUtils.INSTANCE.saveReturnKey(key1, key2);
                }
            } catch (Throwable ignored) {
            }

        }
    }

    interface OnInvokeListener {
        Object onInvoke();
    }

    void setOnInvokeListener(OnInvokeListener onInvokeListener) {
        this.onInvokeListener = onInvokeListener;
    }

    void setHasNext(boolean hasNext) {
        this.hasNext = hasNext;
    }

    @Override
    public String toString() {
        StringBuilder buf = new StringBuilder();
        buf.append("JoinPoint[").append(targetClass.getName())
                .append(".")
                .append(targetAopMethod.getName())
                .append("(");
        Class[] paramsClasses = targetAopMethod.getParameterTypes();
        for (Class paramsClass : paramsClasses) {
            buf.append(paramsClass.getName()).append(",");
        }
        if (paramsClasses.length > 0){
            buf.setLength(buf.length() - 1);
        }
        buf.append(")]");
        return buf.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy