java.lang.UnsupportedClassVersionError: JVMCFRE003 bad major version; class=org/slf4j/impl/StaticLoggerBinder, offset=6

java.lang.UnsupportedClassVersionError: JVMCFRE003 bad major version; class=org/slf4j/impl/StaticLoggerBinder, offset=6

有趣的是,我的 war 文件中的 slf4j 依赖项抱怨

java.lang.UnsupportedClassVersionError: JVMCFRE003 bad major version; class=org/slf4j/impl/StaticLoggerBinder, offset=6

这是 Websphere 8.5

中使用的 Java 版本
Java version = 1.6.0, Java Compiler = j9jit26, Java VM name = IBM J9 VM

slf4j-api-1.7.5.jar 的 MANIFEST.MF 和 slf4j-simple-1.7.5.jar

Build-Jdk: 1.6.0_23

我只能想到 IBM JDK 与 Sun JDK 不同,但它们仍然在相同的 java 版本 (6) 中,怎么还会出现异常?

我认为错误是由于 运行 环境在旧 JDK 上,但文件在新 JDK 中编译。

查看 this link,我认为您没有找到合适的 jar。

slf4j-api-1.7.5.jar 仅包含 api,不包含实现。您需要找到哪个jar 包含StaticLoggerBinder 的实现,并且是在更高版本上编译的jar。

  1. slf4j-api-1.7.5.jar不包含StaticLoggerBinderclass。 寻找合适的罐子。
  2. 您应该在 MANIFEST 上看到 X-Compile-Target-JDK 属性,而不是 Build-jdk

(另请参阅此答案,它直接说明 java class 资源的主要版本和次要版本:List of Java class file format major version numbers?。)

很可能,class 的主要版本高于您的环境所支持的版本。

您需要查看实际的 class 字节来判断 "StaticLoggerBinder" 的主要版本是什么,以便准确了解异常发生的原因。即这个条目的字节数:

org/slf4j/impl/StaticLoggerBinder.class

JAR 文件的:

slf4j-simple-1.7.5.jar

这些清单属性可能会提供来自构建步骤的有用信息,这些信息是在打包 JAR 时使用的,但它们不是异常所关注的内容。例外情况是查看存储在原始 class 字节中的主要和次要版本值。

使用十六进制编辑器(例如,十六进制模式下的 emacs)查看 class 文件的前几个字节,将显示如下内容:

00000000: cafe babe 0000 0032 0071 0a00 0f00 4809  .......2.q....H.
00000010: 001f 0049 0900 4a00 4b0a 004c 004d 0800  ...I..J.K..L.M..

使用来自 Oracle 的 class 格式文档:

https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];

我们看到前八个字节必须是 "magic" 值 0xcafebabe,接下来的四个字节是次要版本(通常是 0x00),接下来的四个字节是主要版本。通过 J2SE 9,定义的有效主要和次要版本值为:

    JDK_11(45, 3, "JDK 1.1"), // "0x2D"
    JDK_12(46, 0, "JDK 1.2"), // "0x2E"
    JDK_13(47, 0, "JDK 1.3"), // "0x2F"
    JDK_14(48, 0, "JDK 1.4"), // "0x30"
    JDK_50(49, 0, "J2SE 5.0"),// "0x31"
    JDK_60(50, 0, "J2SE 6.0"),// "0x32"
    JDK_7 (51, 0, "J2SE 7"),  // "0x33"
    JDK_8 (52, 0, "J2SE 8"),  // "0x34"
    JDK_9 (53, 0, "J2SE 9");  // "0x35"

示例字节显示 0x32 或 J2SE 6.0 的主要版本。

table 取自此实用程序枚举:

public enum JDKVersion {
    JDK_11(45, 3, "JDK 1.1"), // "0x2D"
    JDK_12(46, 0, "JDK 1.2"), // "0x2E"
    JDK_13(47, 0, "JDK 1.3"), // "0x2F"
    JDK_14(48, 0, "JDK 1.4"), // "0x30"
    JDK_50(49, 0, "J2SE 5.0"),// "0x31"
    JDK_60(50, 0, "J2SE 6.0"),// "0x32"
    JDK_7 (51, 0, "J2SE 7"),  // "0x33"
    JDK_8 (52, 0, "J2SE 8"),  // "0x34"
    JDK_9 (53, 0, "J2SE 9");  // "0x35"

    private JDKVersion(int majorVersion, int minorVersion, String textValue) {
        this.majorVersion = majorVersion;
        this.minorVersion = minorVersion;
        this.textValue = textValue;
    }

    private final int majorVersion;
    private final int minorVersion;
    private final String textValue;

    // getters omitted ...
}

使用 "majorVersion" 和 "minorVersion" 从正在检查的 class 资源的原始字节值中获得。

如果您使用的是 WAS v8.5.5,您需要安装 JDK 1.7 或 1.8(如果 v8.5.5 已更新为某些修复包)以及 WAS v8.5.5 并配置您的服务器以使用它