com.xiaoleilu.hutool.lang.Caller Maven / Gradle / Ivy
package com.xiaoleilu.hutool.lang;
import com.xiaoleilu.hutool.exceptions.UtilException;
/**
* 调用者。可以通过此类的方法获取调用者、多级调用者以及判断是否被调用
*
* @author Looly
* @since 3.0.9
*/
public class Caller {
private static final ICaller CALLER_INSTANCE;
static {
CALLER_INSTANCE = tryCreateCaller();
}
/**
* 获得调用者
*
* @return 调用者
*/
public static Class> getCaller() {
return CALLER_INSTANCE.getCaller();
}
/**
* 获得调用者的调用者
*
* @return 调用者的调用者
*/
public static Class> getCallerCaller() {
return CALLER_INSTANCE.getCallerCaller();
}
/**
* 获得调用者,指定第几级调用者
* 调用者层级关系:
*
* 0 {@link Caller}
* 1 调用{@link Caller}中方法的类
* 2 调用者的调用者
* ...
*
*
* @param depth 层级。0表示{@link Caller}本身,1表示调用{@link Caller}的类,2表示调用者的调用者,依次类推
* @return 第几级调用者
*/
public static Class> getCaller(int depth) {
return CALLER_INSTANCE.getCaller(depth);
}
/**
* 是否被指定类调用
*
* @param clazz 调用者类
* @return 是否被调用
*/
public static boolean isCalledBy(Class> clazz) {
return CALLER_INSTANCE.isCalledBy(clazz);
}
/**
* 尝试创建{@link ICaller}实现
*
* @return {@link ICaller}实现
*/
private static ICaller tryCreateCaller() {
ICaller caller;
try {
caller = new ReflectionCaller();
} catch (Exception e) {
try {
caller = new SecurityManagerCaller();
} catch (Exception e2) {
caller = new StackTraceCaller();
}
}
return caller;
}
// ---------------------------------------------------------------------------------------------- static interface and class
/**
* 调用者接口
* 可以通过此接口的实现类方法获取调用者、多级调用者以及判断是否被调用
*
* @author Looly
*
*/
private static interface ICaller {
/**
* 获得调用者
*
* @return 调用者
*/
Class> getCaller();
/**
* 获得调用者的调用者
*
* @return 调用者的调用者
*/
Class> getCallerCaller();
/**
* 获得调用者,指定第几级调用者
* 调用者层级关系:
*
* 0 {@link Caller}
* 1 调用{@link Caller}中方法的类
* 2 调用者的调用者
* ...
*
*
* @param depth 层级。0表示{@link Caller}本身,1表示调用{@link Caller}的类,2表示调用者的调用者,依次类推
* @return 第几级调用者
*/
Class> getCaller(int depth);
/**
* 是否被指定类调用
*
* @param clazz 调用者类
* @return 是否被调用
*/
boolean isCalledBy(Class> clazz);
}
/**
* {@link SecurityManager} 方式获取调用者
*
* @author Looly
*/
private static class SecurityManagerCaller extends SecurityManager implements ICaller {
private static final int OFFSET = 1;
@Override
public Class> getCaller() {
return getClassContext()[OFFSET +1];
}
@Override
public Class> getCallerCaller() {
return getClassContext()[OFFSET +2];
}
@Override
public Class> getCaller(int depth) {
final Class>[] context = getClassContext();
if ((OFFSET + depth) < context.length) {
return context[OFFSET + depth];
}
return null;
}
@Override
public boolean isCalledBy(Class> clazz) {
final Class>[] classes = getClassContext();
for (Class> contextClass : classes) {
if (contextClass.equals(clazz)) {
return true;
}
}
return false;
}
}
/**
* 通过sun.reflect.Reflection 获取调用者
*
* @author Looly
*
*/
@SuppressWarnings({ "deprecation", "restriction" })
private static class ReflectionCaller extends SecurityManagerCaller {
private static final int OFFSET = 2;
@Override
public Class> getCaller() {
return sun.reflect.Reflection.getCallerClass(OFFSET + 1);
}
@Override
public Class> getCallerCaller() {
return sun.reflect.Reflection.getCallerClass(OFFSET + 2);
}
@Override
public Class> getCaller(int depth) {
return sun.reflect.Reflection.getCallerClass(OFFSET + depth);
}
}
/**
* 通过StackTrace方式获取调用者。此方式效率最低,不推荐使用
*
* @author Looly
*/
private static class StackTraceCaller implements ICaller {
private static final int OFFSET = 2;
@Override
public Class> getCaller() {
final String className = Thread.currentThread().getStackTrace()[OFFSET + 1].getClassName();
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new UtilException(e, "[{}] not found!", className);
}
}
@Override
public Class> getCallerCaller() {
final String className = Thread.currentThread().getStackTrace()[OFFSET + 2].getClassName();
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new UtilException(e, "[{}] not found!", className);
}
}
@Override
public Class> getCaller(int depth) {
final String className = Thread.currentThread().getStackTrace()[OFFSET + depth].getClassName();
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new UtilException(e, "[{}] not found!", className);
}
}
@Override
public boolean isCalledBy(Class> clazz) {
for (final StackTraceElement element : Thread.currentThread().getStackTrace()) {
if (element.getClassName().equals(clazz.getName())) {
return true;
}
}
return false;
}
}
}