logo
Published on

Java Downgrader在Gradle中的使用

Authors
  • avatar
    Name
    RE
    Twitter

前言

随着Java的不断更新,越来越多的项目也迁移到了新的Java版本,然而,在某些特定领域,我们仍然需要编译出来的字节码使用较低的 版本,从而可以在不同版本的Java中运行。

例如,在Minecraft Java服务端插件开发中,很多时候需要兼容 1.8.8 到最新的服务端版本,然而,1.8.8的服务端仍然使用Java8, 最新的服务端版本则通常会跟随Java LTS版本,例如1.21.x使用Java 21。

我们期望编译出来的字节码可以在Java 8到Java 21中运行,一个办法是直接设置语言版本为Java 8,但是很多时候我们又需要依赖于最新的Paper API,而Paper API通常使用最新的Java LTS, 这会导致无法编译。

如果尝试编译,Gradle通常会给出类似的错误:

> Could not resolve all files for configuration ':compileClasspath'.
   > Could not resolve io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT.
     Required by:
         root project :
      > Dependency resolution is looking for a library compatible with JVM runtime version 8, but 'io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT:20250110.134712-81' is only compatible with JVM runtime version 21 or newer.

* Try:
> Change the dependency on 'io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT:20250110.134712-81' to an earlier version that supports JVM runtime version 8.

解决方案

其实前端开发中,也有类似的场景,例如,我们期望编译出来的JavaScript代码可以在ES5中运行,但是很多时候我们又需要使用ES6的语法, 这时候,我们就可以使用Babel将ES6的代码转换为ES5的代码。

那么Java这边是不是也可以使用类似的方式呢?

答案是肯定的,经过搜索,发现了以下工具:

因此,我们选择使用Java Downgrader来实现Java字节码的降级。

使用

参考Java Downgrader的文档,我们可以使用它的Gradle插件来实现Java字节码的降级。

plugins {
    id("xyz.wagyourtail.jvmdowngrader") version "1.2.1"
}

tasks {
    withType(DowngradeJar::class.java) {
        // 降级为 Java 8
        downgradeTo.set(JavaVersion.VERSION_1_8)
    }

    withType(ShadeJar::class.java) {
        // 降级为 Java 8
        downgradeTo.set(JavaVersion.VERSION_1_8)
    }

    assemble {
        // 因为降级需要依赖一下兼容的API,所以最好打包进去
        dependsOn(shadeDowngradedApi)
    }
}

以上代码配置了Java Downgrader的Gradle插件,并指定了降级到的Java版本为1.8。

依赖降级

为了依赖更多的现代jars, 我们可以对依赖也进行降级

?
// 创建一个新的configuration
val compileOnlyDowngrade by configurations.creating

configurations {
    compileOnly {
        extendsFrom(compileOnlyDowngrade) // 继承compileOnly
    }
}

jvmdg.dg(compileOnlyDowngrade) {
    downgradeTo = JavaVersion.VERSION_1_8 // default
}

dependencies {
    // compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")

    // 使用新的configuration来添加依赖
    compileOnlyDowngrade("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
}

这样,Java Downgrader会自动将依赖降级到Java 8

总结

通过使用Java Downgrader,我们可以方便地对Java字节码进行降级,从而在不同的Java版本中运行,对于有兼容性要求的项目, 可以考虑使用这种方式来实现。