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("\t\tSystem.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 %s\n", 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("\t\tSystem.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
но когда я попытался сделать ошибку, например, я удалил точку с запятой ;
как и первый прототип, он генерирует исключение NoSuchMethodError при доступе к compiler.getDiagnostics().getDiagnostics()
внутри петли.
Вопрос в том, почему в первом прототипе он работает хорошо при попытке сделать ошибку, но когда я пытался с моей собственной библиотекой, это стало исключением?
редактировать
Вот трассировка стека:
/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?
Заметка
Я использую:
- JDK 1.7 от Oracle
- Netbeans 7.1.1
2 ответа
После того, как я попробовал с Eclipse Indigo, я обнаружил, что он работает, когда добавляешь проект или добавляешь файл jar. В то время как в Netbeans 7.1.1 выдается ошибка, если добавить проект, но работает, если добавить файл JAR.
Может быть, это одна из ошибок Netbeans...
Спасибо за внимание...
Похоже, у вас похожий класс существует в двух разных библиотеках (jars). например
com.test.Example.class in a.jar
com.test.Example.class in b.jar
Теперь загрузчик классов загрузит первый первый Example.class и, похоже, вам нужен класс, который есть в b.jar. Тогда он не сгенерирует исключение, такое как NoMethodFound, но сгенерирует исключение, которое NoSuchMethodFound, потому что класс все еще существует в памяти, но не может найти требуемый метод.
Такие проблемы могут быть решены путем изменения порядка библиотек. Вам нужно сделать заказ необходимой библиотеки выше. Вы можете сделать это из затмения
Project Setting -> Java Build Path -> Order and Export.
Надеюсь, это полезно.