META-INF/versions/9/module-info.class: неработающий файл класса? (Для этой функции требуется ASM6)

У меня проблемы с Bouncycastle, которые возникают только при выполнении задачи :lint.

Как правило, это конфликт версий байт-кода Java 9 версии 53.0 / ASM.

Это зависимости:

// https://mvnrepository.com/artifact/org.bouncycastle
implementation "org.bouncycastle:bcprov-jdk15on:1.64"
implementation "org.bouncycastle:bcpkix-jdk15on:1.64"

Из-за чего задача :lint выдает ошибки обработки:

> Task :mobile:lint
Error processing bcpkix-jdk15on-1.64.jar:META-INF/versions/9/module-info.class: broken class file? (This feature requires ASM6)
Error processing bcprov-jdk15on-1.64.jar:META-INF/versions/9/module-info.class: broken class file? (This feature requires ASM6)

META-INF/versions/9/module-info.class: поврежденный файл класса? (Для этой функции требуется ASM6)

То же самое касается:

// https://mvnrepository.com/artifact/com.google.code.gson/gson
implementation "com.google.code.gson:gson:2.8.6"

После обновления с 1.4.1 до 1.4.2-native-mt опять то же самое:

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2-native-mt"

kotlin-stdlib-1.4.0.jar: META-INF\versions\9\module-info.class: неработающий файл класса? (Для модуля требуется ASM6)


person Martin Zeitler    schedule 09.03.2020    source источник


Ответы (5)


Как уже упоминалось, это было введено в Java 9, которую Android не поддерживает. Вы можете просто использовать packagingOptions для удаления этих классов.

android {
    packagingOptions {
        exclude "**/module-info.class"
    }
}

Это не должно повлиять на фактически исполняемый код, а также должно удалить классы для проверки lint, поскольку lint работает с байт-кодом.

person Blaz    schedule 17.03.2020
comment
Уже попробовал это, прежде чем спрашивать (во всех возможных вариациях), это не работает... потому что упаковка явно происходит после обработки. - person Martin Zeitler; 28.03.2020

Обновление: см. мой текущий ответ, который решает проблему.
Этот ответ хранится только в качестве примера для сценариев Gradle.


При использовании старых версий (вероятно, построенных с Java 8) таких ошибок обработки нет:

// https://mvnrepository.com/artifact/org.bouncycastle
implementation "org.bouncycastle:bcprov-jdk15on:1.60"
implementation "org.bouncycastle:bcpkix-jdk15on:1.60"

// https://mvnrepository.com/artifact/com.google.code.gson/gson
implementation "com.google.code.gson:gson:2.8.5"

Проблема, очевидно, возникла в версии 1.61/2.8.6 (вероятно, построенной на Java 9).


Это раздражает, когда Google возвращает человека к собственному ответу, который на самом деле не является ответом. Вместо того, чтобы сохранять версию или редактировать JAR, я написал DeleteModuleInfoTask и сценарий оболочки, который автоматизирует удаление module-info.class из любой заданной зависимости Java.

Поскольку commandLine принимает только одну команду, почти приходится вызывать скрипт. И это должно послужить хорошим примером для пользовательской задачи Exec.

Для Linux: module_info.sh учитывает versions/9/module-info.class и module-info.class:

#!/usr/bin/env bash
GRADLE_CACHE_DIR=$HOME/.gradle/caches/modules-2/files-2.1
ZIP_PATHS=(META-INF/versions/9/module-info.class module-info.class)   
if [[ $# -ne 3 ]]; then
  echo "Illegal number of parameters"
  exit 1
else
  if [ -d "$GRADLE_CACHE_DIR" ]; then
    DIRNAME=${GRADLE_CACHE_DIR}/$1/$2/$3
    if [ -d "$DIRNAME" ]; then
      cd ${DIRNAME} || exit 1
      find . -name ${2}-${3}.jar | (
        read ITEM;
        for ZIP_PATH in "${ZIP_PATHS[@]}"; do
          INFO=$(zipinfo ${ITEM} ${ZIP_PATH} 2>&1)
          if [ "${INFO}" != "caution: filename not matched:  ${ZIP_PATH}" ]; then
            zip ${ITEM} -d ${ZIP_PATH} # > /dev/null 2>&1
          fi
        done
      )
      exit 0
    fi
  fi
fi

Для Windows: module_info.bat зависит от 7-Zip:

@echo off
REM delete module.info from JAR file - may interfere with the local IDE.
for /R %USERPROFILE%\.gradle\caches\modules-2\files-2.1\%1\%2\%3\ %%G in (%2-%3.jar) do (
  if exist %%G (
      7z d  %%G META-INF\versions\9\module-info.class > NUL:
      7z d  %%G versions\9\module-info.class > NUL:
      7z d  %%G module-info.class > NUL:
  )
) 

Обновление: после некоторого тестирования я пришел к выводу, что может быть лучше вручную отредактировать файл при разработке в Windows, потому что Android Studio и Java заблокируют JAR, что впоследствии предотвратит редактирование и оставит временный файл позади.


Файл tasks.gradle содержит DeleteModuleInfoTask:

import javax.inject.Inject

abstract class DeleteModuleInfoTask extends Exec {
    @Inject
    DeleteModuleInfoTask(String dependency) {
        def os = org.gradle.internal.os.OperatingSystem.current()
        def stdout = new ByteArrayOutputStream()
        def stderr = new ByteArrayOutputStream()
        ignoreExitValue true
        standardOutput stdout
        errorOutput stderr
        workingDir "${getProject().getGradle().getGradleUserHomeDir()}${File.separator}caches${File.separator}modules-2${File.separator}files-2.1${File.separator}${dependency.replace(":", File.separator).toString()}"
        String script = "${getProject().getRootDir().getAbsolutePath()}${File.separator}scripts${File.separator}"
        def prefix = ""; def suffix = "sh"
        if (os.isWindows()) {prefix = "cmd /c "; suffix = "bat"}
        String[] item = dependency.split(":")
        commandLine "${prefix}${script}module_info.${suffix} ${item[0]} ${item[1]} ${item[2]}".split(" ")
        // doFirst {println "${commandLine}"}
        doLast {
            if (execResult.getExitValue() == 0) {
                if (stdout.toString() != "") {
                    println "> Task :${project.name}:${name} ${stdout.toString()}"
                }
            } else {
                println "> Task :${project.name}:${name} ${stderr.toString()}"
            }
        }
    }
}

Пример использования:

// Bouncycastle
tasks.register("lintFixModuleInfoBcPkix", DeleteModuleInfoTask, "org.bouncycastle:bcpkix-jdk15on:1.64")
lint.dependsOn lintFixModuleInfoBcPkix

tasks.register("lintFixModuleInfoBcProv", DeleteModuleInfoTask, "org.bouncycastle:bcprov-jdk15on:1.64")
lint.dependsOn lintFixModuleInfoBcProv

// GSON
tasks.register("lintFixModuleInfoGson", DeleteModuleInfoTask, "com.google.code.gson:gson:2.8.6")
lint.dependsOn lintFixModuleInfoGson

// Kotlin Standard Library
tasks.register("lintFixModuleInfoKotlinStdLib", DeleteModuleInfoTask, "org.jetbrains.kotlin:kotlin-stdlib:1.4.32")
lint.dependsOn lintFixModuleInfoKotlinStdLib

Обязательно зарегистрируйте эти задачи только для одного модуля.

Согласно resmon Resource Monitor › Associated Handles, studio64 и java могут блокировать файл JAR, поэтому 7-Zip может редактировать архив только тогда, когда Android Studio и Java закрыты; по крайней мере, это хорошо работает для CI в Linux.

person Martin Zeitler    schedule 12.03.2020
comment
Как мне это выполнить (у меня Windows)? Создаю ли я различные файлы, например, в блокноте ++? Если да, то где их сохранить? Я запускаю их из терминала в Android Studio? Извините за мое невежество. - person moster67; 07.03.2021
comment
В качестве редактора использовалась Android Studio. Задача Gradle не зависит от платформы — для Windows вам понадобятся module_info.bat и 7-Zip. При удаленной сборке может потребоваться module_info.sh. - person Martin Zeitler; 07.03.2021

Файл module-info.class является частью системы модулей Java, которая была представлена ​​начиная с Java 9. Согласно этой проблеме в Android IssueTracker ошибка была исправлена, начиная с Android Studio 3.4.

person Eng.Fouad    schedule 12.03.2020
comment
Как насчет простой командной строки Gradle? Мы не используем Android Studio на сервере CI. - person Evgenii Vorobei; 13.04.2020
comment
@EvgeniiVorobei Смотрите мой обновленный ответ, я написал задачу, которая может это выполнить. - person Martin Zeitler; 02.03.2021

Я получил следующее сообщение об ошибке:

Error processing C:\Users\mypc\.gradle\caches\modules-2\files-2.1\com.google.code.gson\gson\2.8.6\9180733b7df8542621dc12e21e87557e8c99b8cb\gson-2.8.6.jar:module-info.class: broken class file? (This feature requires ASM6)

Эта ошибка возникает без использования системы разработки, такой как Android Studio. Я использую Gradle 6.1.1.

Я предотвратил ошибку следующим образом:

  1. Откройте файл gson-2.8.6.jar, имя которого указано в сообщении об ошибке.
  2. Удаление файла module-info.class, находящегося в корне
person gotwo    schedule 02.10.2020
comment
Редактирование кэшированных файлов ненадежно; это должно быть автоматизировано. - person Martin Zeitler; 09.02.2021

Есть более простой обходной путь. По сути, проблема может быть определена как запуск Gradle с Java 8 при обработке файлов, созданных с помощью Java 9. Мой новый подход — сборка с Java 11 (GitHub Actions также строится с Java 11, а Gradle 6.7.1 в настоящее время поддерживает до Java 15).

  • После установки Java 11 с sudo dnf install java-11-openjdk

  • alternatives --display java перечислит JDK для использования.

Например: /usr/lib/jvm/java-11-openjdk-11.0.11.0.9-0.el8_3.x86_64:

Снимок экрана Android Studio


Кстати, сборка с JDK 11 также устраняет это предупреждение:

Текущая версия JDK 1.8.0_172-b11 содержит ошибку (https://bugs.openjdk.java.net/browse/JDK-8007720), который предотвращает инкрементное использование Room. Рассмотрите возможность использования JDK 11+ или встроенного JDK, поставляемого с Android Studio 3.5+.

Встроенный JDK, поставляемый с Android Studio 3.5+, по-прежнему является Java 8...

person Martin Zeitler    schedule 20.05.2021