Jdk16中JcTree的使用问题
因为jdk16进行了强制的模块化使用限制, 需要增加add-opens去进行模块的放开, 但是如果每次都需要在项目pom文件或者启动命令中增加,非常不优雅。而且很多重复的命令。
所以想有没有更好的办法去解决。
看了lombok1.18.20中的解决方法,这边来总结一下。lombok这个问题的讨论
pom文件时候添加
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
<fork>true</fork>
<compilerArgs>
<!-- <arg>-Werror</arg>-->
<arg>-Xlint:all</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
注解解析器添加
public abstract class Example extends AbstractProcessor {
@Override
public final synchronized void init(ProcessingEnvironment processingEnv) {
}
static {
addOpens();
}
public static void addOpens() {
Class<?> cModule;
try {
cModule = Class.forName("java.lang.Module");
} catch (ClassNotFoundException e) {
return; //jdk8-; this is not needed.
}
Unsafe unsafe = getUnsafe();
Object jdkCompilerModule = getJdkCompilerModule();
Object ownModule = getOwnModule();
String[] allPkgs = {
"com.sun.tools.javac.code",
"com.sun.tools.javac.comp",
"com.sun.tools.javac.file",
"com.sun.tools.javac.main",
"com.sun.tools.javac.model",
"com.sun.tools.javac.parser",
"com.sun.tools.javac.processing",
"com.sun.tools.javac.tree",
"com.sun.tools.javac.util",
"com.sun.tools.javac.jvm",
"com.sun.tools.javac.api",
};
try {
Method m = cModule.getDeclaredMethod("implAddOpens", String.class, cModule);
long firstFieldOffset = getFirstFieldOffset(unsafe);
unsafe.putBooleanVolatile(m, firstFieldOffset, true);
for (String p : allPkgs) {
m.invoke(jdkCompilerModule, p, ownModule);
}
} catch (Exception ignore) {}
}
private static Unsafe getUnsafe() {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
return (Unsafe) theUnsafe.get(null);
} catch (Exception e) {
return null;
}
}
private static Object getJdkCompilerModule() {
try {
Class<?> cModuleLayer = Class.forName("java.lang.ModuleLayer");
Method mBoot = cModuleLayer.getDeclaredMethod("boot");
Object bootLayer = mBoot.invoke(null);
Class<?> cOptional = Class.forName("java.util.Optional");
Method mFindModule = cModuleLayer.getDeclaredMethod("findModule", String.class);
Object oCompilerO = mFindModule.invoke(bootLayer, "jdk.compiler");
return cOptional.getDeclaredMethod("get").invoke(oCompilerO);
} catch (Exception e) {
return null;
}
}
private static Object getOwnModule() {
try {
Method m = Permit.getMethod(Class.class, "getModule");
return m.invoke(BaseProcessor.class);
} catch (Exception e) {
return null;
}
}
private static long getFirstFieldOffset(Unsafe unsafe) {
try {
return unsafe.objectFieldOffset(Parent.class.getDeclaredField("first"));
} catch (NoSuchFieldException e) {
// can't happen.
throw new RuntimeException(e);
} catch (SecurityException e) {
// can't happen
throw new RuntimeException(e);
}
}
public static class Parent {
boolean first;
}
}
其中调用了
long firstFieldOffset = getFirstFieldOffset(unsafe);
unsafe.putBooleanVolatile(m, firstFieldOffset, true);
其中的含义不太能清楚,看起来是个激活模块的初始化操作,去除之后添加模块权限的操作是会失效的。
有懂的大佬希望可以告知一下是不是这样
在注解解析器中添加上诉代码后就可以正常在java16中使用jcTree啦