访问自定义库时出现 NoSuchMetodError 异常



我有一个关于java.lang.NoSuchMethodError的问题。这个程序是关于编译器API(JSR 199)的。当我为此创建原型时,它会运行工作,但是当我尝试使其成为库时,它会抛出 NoSuchMethodError 异常。

这是第一个原型:

public class DynaCompTest {
    public static void main(String[] args) {
        String fullName = "HelloWorld";
        StringBuilder sourceCode = new StringBuilder();
        sourceCode.append("public class HelloWorld {n")
            .append("tpublic static void main(String[] args) {n")
            .append("ttSystem.out.println("Hello World")n")
            .append("t}n")
            .append("}");
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        JavaFileManager fileManager = new ClassFileManager(compiler.getStandardFileManager(null, null, null));
        DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
        List<JavaFileObject> jFiles = new ArrayList<>();
        jFiles.add(new CharSequenceJavaFileObject(fullName, sourceCode));
        compiler.getTask(null, fileManager, diagnostics, null, null, jFiles).call();
        for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
            System.out.format("Error on line %d in %sn", diagnostic.getLineNumber(), diagnostic);
        }
    }
}
public class CharSequenceJavaFileObject extends SimpleJavaFileObject {
    private CharSequence content;
    public CharSequenceJavaFileObject(String className, CharSequence content) {
        super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
        this.content = content;
    }
    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        return content;
    }
}
public class ClassFileManager extends ForwardingJavaFileManager {
    private JavaClassObject jClassObject;
    public ClassFileManager(StandardJavaFileManager standardManager) {
        super(standardManager);
    }
    @Override
    public ClassLoader getClassLoader(Location location) {
        return new SecureClassLoader() {
            @Override
            protected Class<?> findClass(String name) throws ClassNotFoundException {
                byte[] b = jClassObject.getBytes();
                return super.defineClass(name, jClassObject.getBytes(), 0, b.length);
            }
        };
    }
    @Override
    public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
        jClassObject = new JavaClassObject(className, kind);
        return jClassObject;
    }
}
public class JavaClassObject extends SimpleJavaFileObject {
    protected final ByteArrayOutputStream bos = new ByteArrayOutputStream();
    public JavaClassObject(String name, Kind kind) {
        super(URI.create("string:///" + name.replace('.', '/') + kind.extension), kind);
    }
    public byte[] getBytes() {
        return bos.toByteArray();
    }
    @Override
    public OutputStream openOutputStream() {
        return bos;
    }
}

我将 DynaCompTest 更改为库的 DynamicCompiler:

public class DynamicCompiler {
    private JavaCompiler compiler;
    private JavaFileManager fileManager;
    private List<JavaFileObject> jFiles;
    private DiagnosticCollector<JavaFileObject> diagnostics;
    public DiagnosticCollector<JavaFileObject> getDiagnostics() {
        return diagnostics;
    }
    public DynamicCompiler(String className, StringBuilder sourceCode) {
        compiler = ToolProvider.getSystemJavaCompiler();
        fileManager = new ClassFileManager(compiler.getStandardFileManager(null, null, null));
        diagnostics = new DiagnosticCollector<>();
        jFiles = new ArrayList<>();
        jFiles.add(new CharSequenceJavaFileObject(className, sourceCode));
    }
    public boolean doCompilation() {
        return compiler.getTask(null, fileManager, diagnostics, null, null, jFiles).call();
    }
}

我创建了第二个原型来测试库:

public class Compiler {
    private static StringBuilder sourceCode = new StringBuilder();
    public static void main(String[] args) {
        boolean status;
        sourceCode.append("public class HelloWorld {n")
            .append("tpublic static void main(String[] args) {n")
            .append("ttSystem.out.println("Hello World");n")
            .append("t}n")
            .append("}");
        DynamicCompiler compiler = new DynamicCompiler("HelloWorld", sourceCode);
        status = compiler.doCompilation();
        StringBuilder messages = new StringBuilder();
        if (!status) {
            for (Diagnostic diagnostic : compiler.getDiagnostics().getDiagnostics()) {
                messages.append("Error on line ")
                    .append(diagnostic.getLineNumber())
                    .append(" in ")
                    .append(diagnostic)
                    .append("n");
            }
        } else {
            messages.append("BUILD SUCCESSFUL ");
        }
        System.out.println(messages.toString());
    }
}

当我使用上面的代码进行测试时,它运行良好并打印BUILD SUCCESSFUL但是当我尝试使其出错时,例如我删除了分号;,就像第一个原型一样,它在访问循环内的compiler.getDiagnostics().getDiagnostics()时会引发 NoSuchMethodError 异常。

问题是,为什么在第一个原型中,当尝试出错时它运行良好,但当我尝试使用自己的库时,它变成了异常?

编辑

下面是堆栈跟踪:

/HelloWorld.java:3: error: ';' expected
    System.out.println("Hello World")
                                     ^
1 error
Exception in thread "main" java.lang.NoSuchMethodError: org.ert.lib.DynamicCompiler.getDiagnostics()Ljavax/tools/DiagnosticCollector;
at org.ert.exp.Compiler.main(Compiler.java:28)
Java Result: 1

它应该是这样的:

Error on line 3 in /HelloWorld.java:3: error: ';' expected
    System.out.println("Hello World")
                                     ^

尝试调试它时,它显示错误:

public DiagnosticCollector<JavaFileObject> getDiagnostics() {
    return diagnostics; // Set Breakpoint here
}

以下是错误消息:

Not able to submit breakpoint LineBreakpoint DynamicCompiler.java : 25, reason: No executable location available at line 25 in class org.ert.lib.DynamicCompiler.
Invalid LineBreakpoint DynamicCompiler.java : 25

更新

遇到了问题,如果我们添加整个项目而不是构建库的 jar,就会出现此问题。因此,当我构建库罐时,它可以工作。但是任何人都可以解释为什么当我尝试添加整个项目而不是 jar 文件时会发生这种情况?

注意

我正在使用:

  • 来自甲骨文的JDK 1.7
  • Netbeans 7.1.1

似乎您在两个不同的库(jar)中存在类似的类。例如

com.test.Example.class in a.jar
com.test.Example.class in b.jar

现在类加载器将加载第一个示例.class似乎您需要 b.jar 中的类。然后它不会抛出诸如NoMethodFound之类的异常,而是抛出NoSuchMethodFound的异常,因为类仍然存在于内存中,但找不到所需的方法。

这些问题可以通过更改库顺序来解决。您需要提高所需库的顺序。你可以从日食中做到这一点

Project Setting -> Java Build Path -> Order and Export.

希望这是有帮助的。

在我尝试使用 Eclipse Indigo 后,我发现它在添加项目或添加 jar 文件时有效。在 Netbeans 7.1.1 中,如果添加项目,则会出现错误,但如果添加 jar 文件,则有效。

也许它是Netbeans的错误之一...

感谢您的关注...

相关内容

  • 没有找到相关文章

最新更新