Я пытаюсь разобрать байт-код из Java 16 (версия байт-кода 60), используя ObjectWeb ASM. Я написал следующий код:
@Test
void parseBytecode() {
try (InputStream stream = this.getClass()
.getClassLoader()
.getResourceAsStream("MethodByte.class")) {
//MethodByte.class has 60 version (Java 16)
new ClassReader(stream).accept(new ClassPrinter(), 0);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
private class ClassPrinter extends ClassVisitor {
protected ClassPrinter() {
super(Opcodes.ASM9);
}
}
Когда я запускаю код, я получаю IllegalArgumentException:
Caused by: java.lang.IllegalArgumentException
at org.objectweb.asm.ClassReader.<init>(ClassReader.java:262)
at org.objectweb.asm.ClassReader.<init>(ClassReader.java:180)
at org.objectweb.asm.ClassReader.<init>(ClassReader.java:166)
at org.objectweb.asm.ClassReader.<init>(ClassReader.java:287)
Версия библиотеки ASM 9.5 (от pom.xml):
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.5</version>
<scope>compile</scope>
</dependency>
Кроме того, стоит отметить, что я проверил, что MethodByte.class лежит в правильном месте. Я распечатал его содержимое, чтобы убедиться, что оно доступно в тесте.
Насколько я понимаю, ASM 9 должен поддерживать java 16. Я подозреваю, что ошибка может быть связана с версией ASM, которую я использую, и ее несовместимостью с байт-кодом Java 16, поэтому я попробовал Opcodes.V16 вместо Opcodes.ASM9, и это не помогло.
Также я попытался разобрать байт-код с 52 версией (Java 8), и это тоже не помогло.
Кто-нибудь сталкивался с этим раньше?
Обновление: как я получаю MethodByte.class.
Я использую maven для сборки проекта и запуска тестов. Итак, у меня есть следующий конвейер:
package org.eolang.jeo;
public class MethodByte {
public static void main(String[] args) {
System.out.println(method());
System.out.println("passed");
}
static byte method() {
return 52;
}
}
mvn clean compile, чтобы построить этот класс. Для этого я использую следующие свойства конфигурации maven:<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
cp target/classes/org/eolang/jeo/MethodByte.class src/test/resources/.
Пожалуйста, узнайте как задать вопрос на SO и предоставьте минимальный, полный и проверяемый пример. Спасибо. Вы даже не упомянули точную версию ASM и не показали исходный код скомпилированного кода.
@Olivier Я попытался запустить еще один пример с версией 52 (Java 8), и исключение такое же.
@kriegaex Я добавил немного контекста. Спасибо за ваш комментарий.
@JohannesKuhn Знаете ли вы, как я могу проверить «действительность»? Я пытался использовать javap, и он успешно анализирует байт-код
Отладка. Вы пытались установить точку останова в том месте, где возникает исключение? Какова ценность тега? Какой это индекс? Что javap говорит об этом постоянном индексе пула?
@JohannesKuhn Место, где выдается исключение: currentCpInfoOffset = 10 тег (classFileBuffer[currentCpInfoOffset]) = -65 На самом деле первые двенадцать байтов отрицательные: [-17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, 0, 0, 0, 60, 0, 41, 10, 0, +more]
А как же индекс? Что javap говорит о постоянном пуле по этому индексу? Кроме того, файл класса должен начинаться с 0xCAFEBABE.
@JohannesKuhn javap постоянная запись в пул: #10 = Utf8 java/lang/System
@JohannesKuhn hexdump -n 16 -C MethodByte.class дает мне: 00000000 ca fe ba be 00 00 00 3c 00 29 0a 00 02 00 03 07
Мне это кажется неправильным. По какой-то причине шестнадцатеричный дамп не соответствует содержимому показанного вами массива. Шестнадцатеричный дамп выглядит как действительный файл класса, массив - нет.
Что непонятного в моем комментарии? MCVE предназначен для полного воспроизведения. Боюсь, «немного контекста» здесь не работает. Где файл класса, который вы пытаетесь проанализировать, или исходный код, который вы скомпилировали для его создания? Это не дискуссионный форум, где проблемы должны обсуждаться в нескольких итерациях. Просто задайте четкий вопрос и будьте рады получить прямой и точный ответ.
@JohannesKuhn Я добавил контент класса MethodByte и шаги, которые я выполняю. Может быть, это поможет?
@kriegaex Я старался сделать вопрос как можно меньше ценой неполноты. Итак, я добавил исходный код файла, чтобы сделать пример полностью завершенным. Надеюсь, это поможет. Спасибо за ваш комментарий.




Как упомянул Йоханнес Кун , двоичное представление исходного класса не соответствовало массиву байтов, переданному в класс org.objectweb.asm.ClassReader. Корень проблемы кроется в механизме Maven Resource Filtering. Проще говоря, Maven запускает цель resources:3.3.1:testResources во время фазы generate-test-sources, которая заменяет заполнители в файлах ресурсов фактическими значениями. Когда Maven пытается применить эту фильтрацию к двоичным файлам, он может столкнуться с проблемами кодирования, что приводит к исключению, о котором я упоминал в своем вопросе.
Хотя папка src/test/resources содержала правильный байт-код, она была повреждена, когда я запускал тесты (используя команду mvn clean test), что впоследствии вызывало ошибку IllegalArgumentException.
Чтобы решить эту проблему, я исключил .class файлы из фильтрации:
<build>
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>false</filtering>
<includes>
<include>**/*.class</include>
</includes>
</testResource>
</testResources>
</build>
С этой конфигурацией теперь все работает как положено без исключений.
Работает ли это для классов, скомпилированных в более ранней версии?