【问题标题】:META-INF/versions/9/module-info.class: broken class file? (This feature requires ASM6)META-INF/versions/9/module-info.class:损坏的类文件? (此功能需要 ASM6)
【发布时间】:2020-06-21 04:46:09
【问题描述】:

我在使用 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)

【问题讨论】:

标签: java android gson bouncycastle android-lint


【解决方案1】:

更新:请查看我当前的answer,它解决了问题。
此答案仅作为 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 和一个 shell 脚本,它可以自动从任何给定的 Java 依赖项中删除 module-info.class

因为 commandLine 只接受一个命令,几乎必须调用一个脚本。这应该是自定义Exec 任务的一个很好的例子。

对于 Linux:module_info.sh 考虑 versions/9/module-info.classmodule-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",studio64java 可能会锁定 JAR 文件,因此 7-Zip 可能只能在 Android Studio 和Java 已关闭;至少它很好地适用于 Linux 上的 CI。

【讨论】:

  • 我将如何执行这个(我在 Windows 上)?我是否在例如记​​事本++中创建各种文件?如果是,我在哪里保存它们?我是否从 Android Studio 的终端运行它们?对不起我的无知。
  • Android Studio 被用作编辑器。 Gradle 任务与平台无关 - 对于 Windows,您需要 module_info.bat 和 7-Zip。远程构建时,可能仍需要module_info.sh
【解决方案2】:

文件module-info.class 是自Java 9 以来引入的Java 模块系统的一部分。根据Android IssueTracker 上的this issue,该错误已从Android Studio 3.4 开始修复。

【讨论】:

  • 纯命令行 Gradle 怎么样?我们不在 CI 服务器上使用 Android Studio。
  • @EvgeniiVorobei 查看我更新的答案,我写了一个可以完成的任务。
【解决方案3】:

如前所述,这是在 Java 9 中引入的,Android 不支持。您可以使用 packagingOptions 删除这些类。

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

这不应影响实际执行的代码,并且还应删除用于 lint 检查的类,因为 lint 正在处理字节码。

【讨论】:

  • 在询问之前已经尝试过(在所有可能的变化中),它不起作用......因为包装显然是在处理之后发生的。
【解决方案4】:

我收到以下错误消息:

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

【讨论】:

  • 编辑缓存文件不靠谱;这应该是automated
【解决方案5】:

有一个更简单的解决方法。基本上可以将问题确定为“使用 Java 8 运行 Gradle,同时处理使用 Java 9 构建的文件”。我的新方法是使用 Java 11 构建(GitHub Actions 也使用 Java 11 构建,Gradle 6.7.1 目前最高支持 Java 15)。

  • 使用sudo dnf install java-11-openjdk安装Java 11后

  • alternatives --display java 将列出要使用的 JDK。

例如:/usr/lib/jvm/java-11-openjdk-11.0.11.0.9-0.el8_3.x86_64:


附带说明,使用 JDK 11 构建也可以修复此警告:

当前 JDK 版本 1.8.0_172-b11 有一个错误 (https://bugs.openjdk.java.net/browse/JDK-8007720) 会阻止 Room 增量。考虑使用 JDK 11+ 或 Android Studio 3.5+ 附带的嵌入式 JDK。

“Android Studio 3.5+ 附带的嵌入式 JDK”仍然是 Java 8 ...

【讨论】:

    猜你喜欢
    • 2021-08-18
    • 1970-01-01
    • 2019-01-30
    • 2019-04-18
    • 2022-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-02
    相关资源
    最近更新 更多