Java 使用注释处理在内存中编译和加载类时出错

Java 使用注释处理在内存中编译和加载类时出错,java,annotation-processing,java-compiler-api,Java,Annotation Processing,Java Compiler Api,我正在使用JavaCompiler在内存中编译和加载类 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); JavaCompiler.CompilationTask compile = compiler.getTask(null, inMemoryFileManager, diagnostics, null, annotationClasses, compilationUnits); if (!compile.call())

我正在使用
JavaCompiler
在内存中编译和加载类

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
JavaCompiler.CompilationTask compile = compiler.getTask(null, inMemoryFileManager, diagnostics, null, annotationClasses, compilationUnits);
if (!compile.call()) {
   diagnostics.getDiagnostics().forEach(System.err::println);
}
我使用的是与中类似的
Filemanager
SimpleJavaObject
。我稍微修改了它,以便能够处理多个文件。如果你需要我的源代码,请让我知道

只要
annotationClasses
为空,上述代码就可以正常运行。 但是,当我尝试将类添加到注释处理时,出现以下错误:

Class names, '<classNames>', are only accepted if annotation processing is explicitly requested
只有在明确请求注释处理时才接受类名称“” 对于类名,我尝试了MainMain.javapackage.Mainpackage.Main.java。它们都会导致相同的错误

我知道这是一个非常具体的场景。有没有人尝试过做类似的事情,可以帮助我

编辑

    /* Container for a Java compilation unit (ie Java source) in memory. */
    private static class CompilationUnit extends SimpleJavaFileObject {
        private final String source;

        public CompilationUnit(String className, String source) {
            super(URI.create("file:///" + className.replaceAll("\\.", "/") + ".java"), Kind.SOURCE);
            this.source = source;
        }

        @Override
        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
            return source;
        }

        @Override
        public OutputStream openOutputStream() {
            throw new IllegalStateException();
        }

        @Override
        public InputStream openInputStream() {
            return new ByteArrayInputStream(source.getBytes());
        }
    }

    /* Container for Java byte code in memory. */
    private static class ByteJavaFileObject extends SimpleJavaFileObject {
        private ByteArrayOutputStream byteArrayOutputStream;

        public ByteJavaFileObject(String className) {
            super(URI.create("byte:///" + className.replaceAll("\\.", "/") + ".class"), Kind.CLASS);
        }

        @Override
        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
            return null;
        }

        @Override
        public OutputStream openOutputStream() {
            byteArrayOutputStream = new ByteArrayOutputStream();
            return byteArrayOutputStream;
        }

        @Override
        public InputStream openInputStream() {
            return null;
        }

        public byte[] getByteCode() {
            return byteArrayOutputStream.toByteArray();
        }
    }

    private static class InMemoryFileManager extends ForwardingJavaFileManager {
        private final InMemoryClassLoader inMemoryClassLoader;

        public InMemoryFileManager(JavaCompiler compiler, Map<String, ByteJavaFileObject> fileObjects) {
            super(compiler.getStandardFileManager(null, null, null));
            inMemoryClassLoader = new InMemoryClassLoader(fileObjects);
        }

        @Override
        public JavaFileObject getJavaFileForOutput(Location notUsed, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
            return inMemoryClassLoader.getFileObject(className);
        }

        @Override
        public ClassLoader getClassLoader(Location location) {
            return inMemoryClassLoader;
        }

        public InMemoryClassLoader getClassLoader() {
            return inMemoryClassLoader;
        }
    }

    private static class InMemoryClassLoader extends ClassLoader {
        private final Map<String, ByteJavaFileObject> fileObjects;

        public InMemoryClassLoader(Map<String, ByteJavaFileObject> fileObjects) {
            this.fileObjects = fileObjects;
        }

        @Override
        protected Class<?> findClass(String className) throws ClassNotFoundException {
            ByteJavaFileObject fileObject = fileObjects.get(className);
            return defineClass(className, fileObject.getByteCode(), 0, fileObject.getByteCode().length);
        }

        JavaFileObject getFileObject(String className) {
            return fileObjects.get(className);
        }
    }
/*内存中Java编译单元(即Java源代码)的容器*/
私有静态类编译单元扩展SimpleJavaFileObject{
私有最终字符串源;
公共编译单元(字符串类名称、字符串源){
super(URI.create(“文件://“+className.replaceAll”(“\\\.”,“/”+“.java”)、Kind.SOURCE);
this.source=源;
}
@凌驾
public CharSequence getCharContent(布尔ignoreEncodingErrors){
返回源;
}
@凌驾
public OutputStream openOutputStream(){
抛出新的非法状态异常();
}
@凌驾
公共输入流openInputStream(){
返回新的ByteArrayInputStream(source.getBytes());
}
}
/*内存中Java字节码的容器*/
私有静态类ByteJavaFileObject扩展了SimpleJavaFileObject{
私有ByteArrayOutputStream ByteArrayOutputStream;
公共字节JavaFileObject(字符串类名称){
super(URI.create(“byte://“+className.replaceAll”(“\\.”,“/”+”.class”)、Kind.class);
}
@凌驾
public CharSequence getCharContent(布尔ignoreEncodingErrors){
返回null;
}
@凌驾
public OutputStream openOutputStream(){
byteArrayOutputStream=新建byteArrayOutputStream();
通过tearrayoutputstream返回;
}
@凌驾
公共输入流openInputStream(){
返回null;
}
公共字节[]getByteCode(){
返回byteArrayOutputStream.toByteArray();
}
}
MemoryFileManager中的私有静态类扩展了ForwardingJavaFileManager{
私有最终InMemoryClassLoader InMemoryClassLoader;
公共InMemoryFileManager(JavaCompiler编译器,映射文件对象){
super(compiler.getStandardFileManager(null,null,null));
inMemoryClassLoader=新的inMemoryClassLoader(文件对象);
}
@凌驾
公共JavaFileObject getJavaFileForOutput(位置未使用,字符串类名,JavaFileObject.Kind种类,FileObject同级)引发IOException{
返回inMemoryClassLoader.getFileObject(类名);
}
@凌驾
公共类加载器getClassLoader(位置){
在memoryclassloader中返回;
}
public InMemoryClassLoader getClassLoader(){
在memoryclassloader中返回;
}
}
MemoryClassLoader中的私有静态类扩展了ClassLoader{
私有最终映射文件对象;
公共InMemoryClassLoader(映射文件对象){
this.fileObjects=fileObjects;
}
@凌驾
受保护类findClass(字符串className)引发ClassNotFoundException{
ByteJavaFileObject fileObject=fileObjects.get(className);
返回defineClass(className,fileObject.getByteCode(),0,fileObject.getByteCode().length);
}
JavaFileObject getFileObject(字符串类名称){
返回fileObjects.get(className);
}
}

您尝试过package/Main.java吗?是的,它给出的类名无效。好的。你想完成什么?如果你能分享一些源代码,那会很有帮助。我正在尝试编译和加载带有注释处理的jpa类。如果我能在记忆中做到这一点,那就太好了。我将编辑我的问题以显示源代码。有意义。通过将AnnotationClass设置为null以外的值,您试图实现什么?我之所以问这个问题,只是因为在我使用这个api的几次中,我不相信我曾经为这个参数传递过任何信息。