package org.dromara.common.mybatis.aspect;

import lombok.extern.slf4j.Slf4j;
import org.dromara.common.mybatis.annotation.DataPermission;
import org.springframework.aop.support.StaticMethodMatcherPointcut;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 数据权限匹配切点
 *
 * @author 秋辞未寒
 */
@Slf4j
@SuppressWarnings("all")
public class DataPermissionPointcut extends StaticMethodMatcherPointcut {

    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        // 优先匹配方法
        // 数据权限注解不对继承生效，所以检查当前方法是否有注解即可，不再往上匹配父类或接口
        if (method.isAnnotationPresent(DataPermission.class)) {
            return true;
        }

        // MyBatis 的 Mapper 就是通过 JDK 动态代理实现的，所以这里需要检查是否匹配 JDK 的动态代理
        Class<?> targetClassRef = targetClass;
        if (Proxy.isProxyClass(targetClassRef)) {
            // 数据权限注解不对继承生效，但由于 SpringIOC 容器拿到的实际上是 MyBatis 代理过后的 Mapper，而 targetClass.isAnnotationPresent 实际匹配的是 Proxy 类的注解，不会查找代理类。
            // 所以这里不能用 targetClass.isAnnotationPresent，只能用 AnnotatedElementUtils.hasAnnotation 或 targetClass.getInterfaces()[0].isAnnotationPresent 去做匹配，以检查被代理的 MapperClass 是否具有注解
            // 原理：JDK 动态代理本质上就是对接口进行实现然后对具体的接口实现做代理，所以直接通过接口可以拿到实际的 MapperClass
            targetClassRef = targetClass.getInterfaces()[0];

        }
        return targetClassRef.isAnnotationPresent(DataPermission.class);
    }

}
