feat: Introduce black-reflection and compiler modules, integrate reflection utilities, and update core components.

This commit is contained in:
alex5402
2026-01-30 18:24:57 +05:30
parent 5a557f1521
commit e779247466
70 changed files with 2424 additions and 6069 deletions
@@ -0,0 +1,25 @@
package top.niunaijun.blackreflection;
public class BlackReflectionInfo {
// 反射指向的类
private String realClass;
// 当前注解的className
private String className;
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getRealClass() {
return realClass;
}
public void setRealClass(String realClass) {
this.realClass = realClass;
}
}
@@ -0,0 +1,27 @@
package top.niunaijun.blackreflection;
import javax.lang.model.element.ExecutableElement;
public class BlackReflectionInterfaceInfo {
// 方法element
private ExecutableElement executableElement;
// 是否是字段
private boolean isField;
public boolean isField() {
return isField;
}
public void setField(boolean field) {
isField = field;
}
public ExecutableElement getExecutableElement() {
return executableElement;
}
public void setExecutableElement(ExecutableElement executableElement) {
this.executableElement = executableElement;
}
}
@@ -0,0 +1,190 @@
package top.niunaijun.blackreflection;
import com.google.auto.service.AutoService;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.MirroredTypeException;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import top.niunaijun.blackreflection.annotation.BClass;
import top.niunaijun.blackreflection.annotation.BConstructor;
import top.niunaijun.blackreflection.annotation.BField;
import top.niunaijun.blackreflection.annotation.BMethod;
import top.niunaijun.blackreflection.annotation.BStaticField;
import top.niunaijun.blackreflection.annotation.BStaticMethod;
import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.proxy.BlackReflectionInterfaceProxy;
import top.niunaijun.blackreflection.proxy.BlackReflectionProxy;
@AutoService(Processor.class)
public class BlackReflectionProcessor extends AbstractProcessor {
private Map<String, BlackReflectionProxy> mBlackReflectionProxies;
private Map<String, BlackReflectionInterfaceProxy> mBlackReflectionInterfaceProxies;
private Map<String, String> mRealMaps = new HashMap<>();
private Messager mMessager;
private Elements mElementUtils; //元素相关的辅助类
private Filer mFiler;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
mMessager = processingEnv.getMessager();
mElementUtils = processingEnv.getElementUtils();
mFiler = processingEnv.getFiler();
mBlackReflectionProxies = new Hashtable<>();
mBlackReflectionInterfaceProxies = new Hashtable<>();
mRealMaps = new Hashtable<>();
}
@Override
public Set<String> getSupportedAnnotationTypes() {
HashSet<String> supportTypes = new LinkedHashSet<>();
supportTypes.add(BClass.class.getCanonicalName());
supportTypes.add(BClassName.class.getCanonicalName());
supportTypes.add(BField.class.getCanonicalName());
supportTypes.add(BStaticField.class.getCanonicalName());
supportTypes.add(BMethod.class.getCanonicalName());
supportTypes.add(BStaticMethod.class.getCanonicalName());
supportTypes.add(BConstructor.class.getCanonicalName());
return supportTypes;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.RELEASE_8;
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
mBlackReflectionProxies.clear();
mBlackReflectionInterfaceProxies.clear();
mRealMaps.clear();
for (Element element : roundEnv.getElementsAnnotatedWith(BClassName.class)) {
BClassName annotation = element.getAnnotation(BClassName.class);
doProcess(element, annotation.value());
}
for (Element element : roundEnv.getElementsAnnotatedWith(BClass.class)) {
BClass annotation = element.getAnnotation(BClass.class);
String aClass = getClass(annotation).toString();
doProcess(element, aClass);
}
for (Element element : roundEnv.getElementsAnnotatedWith(BStaticMethod.class)) {
doInterfaceProcess(element, true, false);
}
for (Element element : roundEnv.getElementsAnnotatedWith(BMethod.class)) {
doInterfaceProcess(element, false, false);
}
for (Element element : roundEnv.getElementsAnnotatedWith(BStaticField.class)) {
doInterfaceProcess(element, true, true);
}
for (Element element : roundEnv.getElementsAnnotatedWith(BField.class)) {
doInterfaceProcess(element, false, true);
}
for (Element element : roundEnv.getElementsAnnotatedWith(BConstructor.class)) {
doInterfaceProcess(element, true, false);
}
for (BlackReflectionInterfaceProxy value : mBlackReflectionInterfaceProxies.values()) {
try {
value.setRealMap(mRealMaps);
value.generateInterfaceCode().writeTo(mFiler);
} catch (IOException e) {
e.printStackTrace();
}
}
for (BlackReflectionProxy value : mBlackReflectionProxies.values()) {
try {
value.generateJavaCode().writeTo(mFiler);
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}
private void doInterfaceProcess(Element element, boolean isStatic, boolean isField) {
String className = element.getEnclosingElement().asType().toString();
ExecutableElement executableElement = (ExecutableElement) element;
String packageName = mElementUtils.getPackageOf(executableElement).getQualifiedName().toString();
BlackReflectionInterfaceInfo interfaceInfo = new BlackReflectionInterfaceInfo();
interfaceInfo.setExecutableElement(executableElement);
interfaceInfo.setField(isField);
BlackReflectionInterfaceProxy reflectionInterfaceProxy = getReflectionInterfaceProxy(packageName,
className + (isStatic ? "Static" : "Context"),
className);
reflectionInterfaceProxy.add(interfaceInfo);
}
private void doProcess(Element element, String realClassName) {
String packageName = mElementUtils.getPackageOf(element).getQualifiedName().toString();
String className = element.asType().toString();
BlackReflectionInfo info = new BlackReflectionInfo();
info.setRealClass(realClassName);
info.setClassName(className);
getReflectionProxy(packageName, className, info);
// 创建两个基本类
getReflectionInterfaceProxy(packageName, className + "Context",
className);
getReflectionInterfaceProxy(packageName, className + "Static",
className);
mRealMaps.put(className, realClassName);
}
private static TypeMirror getClass(BClass annotation) {
try {
annotation.value(); // this should throw
} catch (MirroredTypeException mte) {
return mte.getTypeMirror();
}
return null; // can this ever happen ??
}
public BlackReflectionProxy getReflectionProxy(String packageName, String className, BlackReflectionInfo info) {
BlackReflectionProxy blackReflectionProxy = mBlackReflectionProxies.get(className);
if (blackReflectionProxy == null) {
blackReflectionProxy = new BlackReflectionProxy(packageName, info);
mBlackReflectionProxies.put(className, blackReflectionProxy);
}
return blackReflectionProxy;
}
public BlackReflectionInterfaceProxy getReflectionInterfaceProxy(String packageName, String className, String origClassName) {
BlackReflectionInterfaceProxy blackReflectionProxy = mBlackReflectionInterfaceProxies.get(className);
if (blackReflectionProxy == null) {
blackReflectionProxy = new BlackReflectionInterfaceProxy(packageName, className, origClassName);
mBlackReflectionInterfaceProxies.put(className, blackReflectionProxy);
}
return blackReflectionProxy;
}
}
@@ -0,0 +1,202 @@
package top.niunaijun.blackreflection.proxy;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.MirroredTypeException;
import javax.lang.model.type.TypeMirror;
import top.niunaijun.blackreflection.BlackReflectionInterfaceInfo;
import top.niunaijun.blackreflection.annotation.BConstructor;
import top.niunaijun.blackreflection.annotation.BConstructorNotProcess;
import top.niunaijun.blackreflection.annotation.BFieldCheckNotProcess;
import top.niunaijun.blackreflection.annotation.BFieldNotProcess;
import top.niunaijun.blackreflection.annotation.BFieldSetNotProcess;
import top.niunaijun.blackreflection.annotation.BMethodCheckNotProcess;
import top.niunaijun.blackreflection.annotation.BParamClass;
import top.niunaijun.blackreflection.annotation.BClassNameNotProcess;
import top.niunaijun.blackreflection.annotation.BParamClassName;
/**
* Created by sunwanquan on 2020/1/8.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
* 此处无Bug
*/
public class BlackReflectionInterfaceProxy {
private final List<BlackReflectionInterfaceInfo> mReflections = new ArrayList<>();
// fake.android.app.ActivityThreadStatic or ActivityThreadContext
private final String mClassName;
// fake.android.app
private final String mPackageName;
// fake.android.app.ActivityThread
private final String mOrigClassName;
private Map<String, String> realMaps;
public BlackReflectionInterfaceProxy(String packageName, String className, String origClassName) {
mPackageName = packageName;
mClassName = className;
mOrigClassName = origClassName;
}
public JavaFile generateInterfaceCode() {
String finalClass = mClassName
.replace(mPackageName + ".", "")
.replace(".", "");
AnnotationSpec annotationSpec = AnnotationSpec.builder(BClassNameNotProcess.class)
.addMember("value","$S", realMaps.get(mOrigClassName))
.build();
// generaClass
TypeSpec.Builder interfaceBuilder = TypeSpec.interfaceBuilder(finalClass)
.addAnnotation(annotationSpec)
.addModifiers(Modifier.PUBLIC);
for (BlackReflectionInterfaceInfo reflection : mReflections) {
MethodSpec.Builder method = MethodSpec.methodBuilder(reflection.getExecutableElement().getSimpleName().toString())
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT);
List<ParameterSpec> parameterSpecs = new ArrayList<>();
for (VariableElement typeParameter : reflection.getExecutableElement().getParameters()) {
ParameterSpec.Builder builder = ParameterSpec.builder(ClassName.get(typeParameter.asType()), typeParameter.getSimpleName().toString());
if (typeParameter.getAnnotation(BParamClassName.class) != null) {
BParamClassName annotation = typeParameter.getAnnotation(BParamClassName.class);
builder.addAnnotation(AnnotationSpec.get(annotation));
}
if (typeParameter.getAnnotation(BParamClass.class) != null) {
BParamClass annotation = typeParameter.getAnnotation(BParamClass.class);
String annotationValue = getClass(annotation).toString();
Class<?> aClass = parseBaseClass(annotationValue);
if (aClass != null) {
builder.addAnnotation(AnnotationSpec.builder(BParamClass.class)
.addMember("value", "$T.class", aClass).build());
} else {
builder.addAnnotation(AnnotationSpec.builder(BParamClass.class)
.addMember("value", annotationValue + ".class").build());
}
}
ParameterSpec build = builder.build();
parameterSpecs.add(build);
method.addParameter(build);
}
TypeName typeName = TypeName.get(reflection.getExecutableElement().getReturnType());
method.returns(typeName.box());
if (reflection.isField()) {
method.addAnnotation(AnnotationSpec.builder(BFieldNotProcess.class).build());
// set field
interfaceBuilder.addMethod(generateFieldSet(reflection));
// check field
interfaceBuilder.addMethod(generateFieldCheck(reflection));
} else {
BConstructor annotation = reflection.getExecutableElement().getAnnotation(BConstructor.class);
if (annotation != null) {
method.addAnnotation(AnnotationSpec.builder(BConstructorNotProcess.class).build());
} else {
// check method
interfaceBuilder.addMethod(generateMethodCheck(reflection, parameterSpecs));
}
}
interfaceBuilder.addMethod(method.build());
}
return JavaFile.builder(mPackageName, interfaceBuilder.build()).build();
}
private MethodSpec generateFieldSet(BlackReflectionInterfaceInfo reflection) {
MethodSpec.Builder method = MethodSpec.methodBuilder("_set_" + reflection.getExecutableElement().getSimpleName().toString())
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addParameter(ClassName.get("java.lang", "Object"), "value", Modifier.FINAL)
.addAnnotation(AnnotationSpec.builder(BFieldSetNotProcess.class).build());
return method.build();
}
private MethodSpec generateFieldCheck(BlackReflectionInterfaceInfo reflection) {
MethodSpec.Builder method = MethodSpec.methodBuilder("_check_" + reflection.getExecutableElement().getSimpleName().toString())
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addAnnotation(AnnotationSpec.builder(BFieldCheckNotProcess.class).build())
.returns(Field.class);
return method.build();
}
private MethodSpec generateMethodCheck(BlackReflectionInterfaceInfo reflection, List<ParameterSpec> parameterSpecs) {
MethodSpec.Builder method = MethodSpec.methodBuilder("_check_" + reflection.getExecutableElement().getSimpleName().toString())
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addAnnotation(AnnotationSpec.builder(BMethodCheckNotProcess.class).build())
.returns(Method.class);
for (ParameterSpec parameterSpec : parameterSpecs) {
method.addParameter(parameterSpec);
}
return method.build();
}
public void add(BlackReflectionInterfaceInfo interfaceInfo) {
mReflections.add(interfaceInfo);
}
public void setRealMap(Map<String, String> realMaps) {
this.realMaps = realMaps;
}
private static TypeMirror getClass(BParamClass annotation) {
try {
annotation.value(); // this should throw
} catch (MirroredTypeException mte) {
return mte.getTypeMirror();
}
return null; // can this ever happen ??
}
private static Class<?> parseBaseClass(String className) {
switch (className) {
case "int":
return int.class;
case "byte":
return byte.class;
case "short":
return short.class;
case "long":
return long.class;
case "float":
return float.class;
case "double":
return double.class;
case "boolean":
return boolean.class;
case "char":
return char.class;
case "int[]":
return int[].class;
case "byte[]":
return byte[].class;
case "short[]":
return short[].class;
case "long[]":
return long[].class;
case "float[]":
return float[].class;
case "double[]":
return double[].class;
case "boolean[]":
return boolean[].class;
case "char[]":
return char[].class;
}
return null;
}
}
@@ -0,0 +1,97 @@
package top.niunaijun.blackreflection.proxy;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import javax.lang.model.element.Modifier;
import top.niunaijun.blackreflection.BlackReflectionInfo;
import top.niunaijun.blackreflection.utils.ClassUtils;
/**
* Created by sunwanquan on 2020/1/8.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
* 此处无Bug
*/
public class BlackReflectionProxy {
private static final ClassName BR = ClassName.get("top.niunaijun.blackreflection", "BlackReflection");
private final BlackReflectionInfo mReflection;
private final ClassName mContextInterface;
private final ClassName mStaticInterface;
private final String mPackageName;
public BlackReflectionProxy(String packageName, BlackReflectionInfo reflection) {
mReflection = reflection;
mPackageName = packageName;
String finalClass = mReflection.getClassName()
.replace(packageName + ".", "")
.replace(".", "");
mContextInterface = ClassName.get(ClassUtils.getPackage(finalClass), ClassUtils.getName(finalClass + "Context"));
mStaticInterface = ClassName.get(ClassUtils.getPackage(finalClass), ClassUtils.getName(finalClass + "Static"));
}
public JavaFile generateJavaCode() {
String finalClass = "BR" + mReflection.getClassName()
.replace(mPackageName + ".", "")
.replace(".", "");
// generaClass
TypeSpec reflection = TypeSpec.classBuilder(finalClass)
.addModifiers(Modifier.PUBLIC)
.addMethod(generaNotCallerMethod(true))
.addMethod(generaNotCallerMethod(false))
.addMethod(generaCallerMethod(true))
.addMethod(generaCallerMethod(false))
.addMethod(generaIsLoadMethod())
.build();
return JavaFile.builder(mPackageName, reflection).build();
}
private MethodSpec generaNotCallerMethod(boolean withException) {
MethodSpec.Builder builder = MethodSpec.methodBuilder("get" + (withException ? "WithException" : ""))
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(mStaticInterface);
String statement = "return $T.create($T.class, null, $L)";
builder.addStatement(statement,
BR,
mStaticInterface,
withException
);
return builder.build();
}
private MethodSpec generaCallerMethod(boolean withException) {
MethodSpec.Builder builder = MethodSpec.methodBuilder("get" + (withException ? "WithException" : ""))
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(ClassName.get("java.lang", "Object"), "caller", Modifier.FINAL)
.returns(mContextInterface);
String statement = "return $T.create($T.class, caller, $L)";
builder.addStatement(statement,
BR,
mContextInterface,
withException
);
return builder.build();
}
private MethodSpec generaIsLoadMethod() {
MethodSpec.Builder builder = MethodSpec.methodBuilder("getRealClass")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(ClassName.get(Class.class));
String statement = "return top.niunaijun.blackreflection.utils.ClassUtil.classReady($T.class)";
builder.addStatement(statement,
mContextInterface
);
return builder.build();
}
}
@@ -0,0 +1,30 @@
package top.niunaijun.blackreflection.utils;
/**
* Created by sunwanquan on 2020/1/8.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
* 此处无Bug
*/
public class ClassUtils {
public static String getPackage(String className) {
String[] sp = className.split("[.]");
StringBuilder builder = new StringBuilder();
for (int i = 0; i < sp.length - 1; i++) {
builder.append(sp[i]);
if (i != sp.length - 2) {
builder.append(".");
}
}
return builder.toString();
}
public static String getName(String className) {
String[] sp = className.split("[.]");
return sp[sp.length - 1];
}
}