diff --git a/testable-processor/src/main/java/com/alibaba/testable/processor/EnablePrivateAccessProcessor.java b/testable-processor/src/main/java/com/alibaba/testable/processor/EnablePrivateAccessProcessor.java index c3dc5fb..becddc8 100644 --- a/testable-processor/src/main/java/com/alibaba/testable/processor/EnablePrivateAccessProcessor.java +++ b/testable-processor/src/main/java/com/alibaba/testable/processor/EnablePrivateAccessProcessor.java @@ -4,6 +4,7 @@ import com.alibaba.testable.processor.annotation.EnablePrivateAccess; import com.alibaba.testable.processor.constant.ConstPool; import com.alibaba.testable.processor.model.TestableContext; import com.alibaba.testable.processor.translator.EnablePrivateAccessTranslator; +import com.alibaba.testable.processor.util.JavacUtil; import com.alibaba.testable.processor.util.TestableLogger; import com.sun.tools.javac.api.JavacTrees; import com.sun.tools.javac.code.Symbol; @@ -46,14 +47,6 @@ public class EnablePrivateAccessProcessor extends AbstractProcessor { cx.logger.info("Testable processor initialized"); } - private Context getJavacProcessingContext(ProcessingEnvironment processingEnv) { - try { - return ((JavacProcessingEnvironment)processingEnv).getContext(); - } catch (Exception e) { - return null; - } - } - @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { if (cx.names == null) { @@ -74,6 +67,15 @@ public class EnablePrivateAccessProcessor extends AbstractProcessor { return SourceVersion.values()[SourceVersion.values().length - 1]; } + private Context getJavacProcessingContext(ProcessingEnvironment processingEnv) { + try { + JavacProcessingEnvironment javacProcessingEnv = JavacUtil.getJavacProcessingEnvironment(processingEnv); + return javacProcessingEnv.getContext(); + } catch (Exception e) { + return null; + } + } + private boolean isTestClass(Name name) { return name.toString().endsWith(ConstPool.TEST_POSTFIX); } diff --git a/testable-processor/src/main/java/com/alibaba/testable/processor/util/JavacUtil.java b/testable-processor/src/main/java/com/alibaba/testable/processor/util/JavacUtil.java new file mode 100644 index 0000000..13cf11a --- /dev/null +++ b/testable-processor/src/main/java/com/alibaba/testable/processor/util/JavacUtil.java @@ -0,0 +1,78 @@ +package com.alibaba.testable.processor.util; + +import com.sun.tools.javac.processing.JavacProcessingEnvironment; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; + +/** + * @author flin + */ +public class JavacUtil { + + /** + * Refer from Lombok `LombokProcessor.java` + * This class casts the given processing environment to a JavacProcessingEnvironment. In case of + * gradle incremental compilation, the delegate ProcessingEnvironment of the gradle wrapper is returned. + */ + public static JavacProcessingEnvironment getJavacProcessingEnvironment(Object procEnv) { + if (procEnv instanceof JavacProcessingEnvironment) { + return (JavacProcessingEnvironment) procEnv; + } + // try to find a "delegate" field in the object, and use this to try to obtain a JavacProcessingEnvironment + for (Class procEnvClass = procEnv.getClass(); procEnvClass != null; procEnvClass = procEnvClass.getSuperclass()) { + Object delegate = tryGetDelegateField(procEnvClass, procEnv); + if (delegate == null) { + delegate = tryGetProxyDelegateToField(procEnvClass, procEnv); + } + if (delegate == null) { + delegate = tryGetProcessingEnvField(procEnvClass, procEnv); + } + if (delegate != null) { + return getJavacProcessingEnvironment(delegate); + } + // delegate field was not found, try on superclass + } + return null; + } + + /** + * InteliJ >= 2020.3 + */ + private static Object tryGetProxyDelegateToField(Class delegateClass, Object instance) { + try { + InvocationHandler handler = Proxy.getInvocationHandler(instance); + return getField(handler.getClass(), "val$delegateTo").get(handler); + } catch (Exception e) { + return null; + } + } + + /** + * Gradle incremental processing + */ + private static Object tryGetDelegateField(Class delegateClass, Object instance) { + try { + return getField(delegateClass, "delegate").get(instance); + } catch (Exception e) { + return null; + } + } + + /** + * Kotlin incremental processing + */ + private static Object tryGetProcessingEnvField(Class delegateClass, Object instance) { + try { + return getField(delegateClass, "processingEnv").get(instance); + } catch (Exception e) { + return null; + } + } + + private static Field getField(Class clazz, String field) { + return null; + } + +}