META-INF/versions/9/module-info.class: broken class file? (This feature requires ASM6)

11,969

Solution 1

There is a more simple workaround. Basically the problem can be identified as "running Gradle with Java 8, while handling files which were built with Java 9". My new approach is building with Java 11 (GitHub Actions also builds with Java 11 and Gradle 6.7.1 would currently support up to Java 15).

  • After installing Java 11 with sudo dnf install java-11-openjdk

  • alternatives --display java will list the JDK to use.

For example: /usr/lib/jvm/java-11-openjdk-11.0.11.0.9-0.el8_3.x86_64:

Android Studio Screenshot


On a side note, building with JDK 11 also fixes this warning:

Current JDK version 1.8.0_172-b11 has a bug (https://bugs.openjdk.java.net/browse/JDK-8007720) that prevents Room from being incremental. Consider using JDK 11+ or the embedded JDK shipped with Android Studio 3.5+.

The "embedded JDK shipped with Android Studio 3.5+" is still Java 8 ...

Solution 2

As already mentioned this was introduced in Java 9, that Android does not support. You could just use packagingOptions to remove those classes.

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

This should not affect actual executed code and should also remove classes for lint checks as lint is working on bytecode.

Solution 3

Update: Please see my current answer, which nails the problem.
This answer is only being kept as an example for Gradle scripting.


When using old versions (likely built with Java 8), there are no such processing errors:

// 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"

The issue obviously was introduced with version 1.61 / 2.8.6 (likely built with Java 9).


It's annoying when Google brings one back to the own answer, which is not really an answer. Instead of keeping back the version or editing the JAR, I've wrote a DeleteModuleInfoTask and a shell script, which automates the deletion of module-info.class from any given Java dependency.

Since commandLine only accepts a single command, one almost has to call a script. And this should serve as a good example for a custom Exec task.

For Linux: module_info.sh considers versions/9/module-info.class and 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

For Windows: module_info.bat depends on 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:
  )
) 

Update: After some testing I came to the conclusion that it may be better to manually edit the file when developing on Windows, because Android Studio and Java will lock the JAR, which will subsequently prevent the edit and leave the temp file behind.


File tasks.gradle provides the 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()}"
            }
        }
    }
}

Example Usage:

// 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

Make sure to register these tasks only for a single module.

According to resmon "Resource Monitor" > "Associated Handles", studio64 and java may hold a lock on the JAR file, therefore 7-Zip may only be able to edit the archive when Android Studio and Java had been closed; at least it nicely works for CI on Linux.

Solution 4

The file module-info.class is part of the Java module system which was introduced since Java 9. As per this issue on Android IssueTracker, the bug has been be fixed since Android Studio 3.4.

Solution 5

I have got the following error message:

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)

This error occurs without using a development system like Android Studio. I use Gradle 6.1.1.

I prevented the mistake as follows:

  1. Open the file gson-2.8.6.jar which is named in the error message
  2. Removing of the file module-info.class, which is located in the root
Share:
11,969

Related videos on Youtube

Martin Zeitler
Author by

Martin Zeitler

I'm usually available for hire on PPH. Favorite Cartoon: Are You Lost in the World Like Me? (Animated Short Film by Steve Cutts) Open Source Projects: Android Image Builder for Google Cloud Build & Cloud KMS Google Cloud Functions - PHP Quickstart PHP SDK for Huawei REST API Android GitHub API Client

Updated on June 04, 2022

Comments

  • Martin Zeitler
    Martin Zeitler almost 2 years

    I'm having issues with Bouncycastle, which only arise when running the :lint task.

    Generally it seems to be a Java 9 byte-code version 53.0 / ASM version conflict.

    These are the dependencies:

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

    Which cause the :lint task to throw processing errors:

    > 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: broken class file? (This feature requires ASM6)

    The same goes for:

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

    Since upgrading from 1.4.1 to 1.4.2-native-mt, it's the same again:

    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: broken class file? (Module requires ASM6)

  • Martin Zeitler
    Martin Zeitler about 4 years
    Have already tried that before asking (in all possible variations), it's not working... because the packaging obviously happens after the processing.
  • Evgenii Vorobei
    Evgenii Vorobei about 4 years
    What about plain command line Gradle? We don't use Android Studio on CI server.
  • Martin Zeitler
    Martin Zeitler over 3 years
    Editing cached files is not reliable; this should be automated.
  • Martin Zeitler
    Martin Zeitler about 3 years
    @EvgeniiVorobei See my updated answer, I've wrote a task which can accomplish that.
  • moster67
    moster67 about 3 years
    How would I execute this (I am on Windows)? Do I create the various files in for instance notepad++? If yes, where do I save them? Do I run them from Terminal in Android Studio? Sorry for my ignorance.
  • Martin Zeitler
    Martin Zeitler about 3 years
    Android Studio was used as editor. The Gradle task is platform-independent - for Windows you'd need module_info.bat and 7-Zip. When building remotely, module_info.sh still may be required.