您好,这与您的应用程序中的某些字节码有关。 (请参阅有关 Java 7 http://www.oracle.com/technetwork/java/javase/compatibility-417013.html#incompatibilities 兼容性更改的注释,请参阅下面的 JSR 202 行)
你可以
- 使用 JDK 7 重新编译所有源代码
- 或者如果您无权访问源
- 使用
java 和参数-XX:-UseSplitVerifier
- 如果您在使用开关时遇到问题,请切换到 Java 6
edit 甚至答案已经有点老了。由于当前的案例,我添加了一些更详细的解释。
类文件中的 StackMapTable 属性在 Java 6 中被引入,甚至当时没有记录。
Foo.java
public class Foo {
public static boolean bar(String s) {
if (s.length() == 0) {
return true;
}
return false;
}
}
$ java -version
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
$ javac Foo.java
$ javap -c -v Foo
Compiled from "Foo.java"
public class Foo extends java.lang.Object
SourceFile: "Foo.java"
minor version: 0
major version: 50
...
public static boolean bar(java.lang.String);
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: invokevirtual #2; //Method java/lang/String.length:()I
4: ifne 9
7: iconst_1
8: ireturn
9: iconst_0
10: ireturn
LineNumberTable:
line 3: 0
line 4: 7
line 6: 9
StackMapTable: number_of_entries = 1
frame_type = 9 /* same */
}
类验证器没有检查属性是否在类中。
以下创建不带StackMatTable 属性的文件Foo.class。
FooDump.java
import org.objectweb.asm.*;
import java.io.*;
public class FooDump implements Opcodes {
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("Foo.class");
fos.write(dump());
fos.close();
}
public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(0);
FieldVisitor fv;
cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, "Foo", null, "java/lang/Object",
null);
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null,
null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V",
false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "bar",
"(Ljava/lang/String;)Z", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "length", "()I",
false);
Label l0 = new Label();
mv.visitJumpInsn(IFNE, l0);
mv.visitInsn(ICONST_1);
mv.visitInsn(IRETURN);
mv.visitLabel(l0);
// this line would generate the StackMapTable attribute
// mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitInsn(ICONST_0);
mv.visitInsn(IRETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
cw.visitEnd();
return cw.toByteArray();
}
}
编译运行
$ javac -cp asm-5.2.jar:asm-util-5.2.jar:. FooDump.java
$ java -cp asm-5.2.jar:asm-util-5.2.jar:. FooDump
检查StackMapTable 属性是否不在文件中
$ javap -c -v Foo
public class Foo extends java.lang.Object
minor version: 0
major version: 50
...
public static boolean bar(java.lang.String);
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: invokevirtual #16; //Method java/lang/String.length:()I
4: ifne 9
7: iconst_1
8: ireturn
9: iconst_0
10: ireturn
}
FooDemo.java
public class FooDemo {
public static void main(String[] args) {
System.out.println("output: " + Foo.bar(""));
}
}
$ java -version
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
$ javac FooDemo.java
$java FooDemo
output: true
在 Java 7 中,类验证发生了变化。
对于版本 50 (Java 6) 的类文件,如果 StackMapTable 丢失或错误,检查将进行故障转移(请参阅:jvms-4.10.1)。
使用 Java 6 的 Foo 类版本运行检查。
$ java -version
java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)
$ javap -c -v Foo
Classfile /home/suboptimal/playground/Foo.class
Last modified Jun 9, 2017; size 232 bytes
MD5 checksum 5a7ea4a5dd2f6d1bcfddb9ffd720f9c9
public class Foo
minor version: 0
major version: 50 <-- class file Java 6
...
$ javac FooDemo.java
$ java FooDemo
output: true
类文件版本 51 (Java 7) 不再发生此故障转移。
要创建Java 7 的Foo 类版本,请修改FooDump.java 的代码。
// cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, "Foo", null, "java/lang/Object", null);
cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, "Foo", null, "java/lang/Object", null);
编译运行
$ javac -cp asm-5.2.jar:asm-util-5.2.jar:. FooDump.java
$ java -cp asm-5.2.jar:asm-util-5.2.jar:. FooDump
检查它是否是类版本 51
$ java -version
java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)
$ javap -c -v Foo
Classfile /home/suboptimal/playground/Foo.class
Last modified Jun 9, 2017; size 232 bytes
MD5 checksum cfd57fb547ac98a1b2808549f5e9e8c1
public class Foo
minor version: 0
major version: 51 <-- class file Java 7
...
$ javac FooDemo.java
$ java FooDemo
Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch target 9 in method Foo.bar(Ljava/lang/String;)Z at offset 4
在 Java 7 中,可以禁用 StackMapTable 属性的类型检查,以使用选项 UseSplitVerifier 退回到 Java 6 故障转移机制。
$ java -version
java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)
$ java -XX:-UseSplitVerifier FooDemo
output: true
在 Java 8 中,StackMapTable 属性的验证成为强制性的,UseSplitVerifier 选项已被删除。
$ java -version
java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)
$ javap -c -v Foo
Classfile /home/suboptimal/playground/Foo.class
Last modified Jun 9, 2017; size 232 bytes
MD5 checksum cfd57fb547ac98a1b2808549f5e9e8c1
public class Foo
minor version: 0
major version: 51 <-- class file Java 7
...
$ javac FooDemo.java
$ java FooDemo
Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch target 9
$ java -XX:-UseSplitVerifier FooDemo
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option UseSplitVerifier; support was removed in 8.0
Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch target 9
注意始终使用 Java 6/7/8 的初始版本是为了表明该行为从一开始就存在。
您可能会找到一些建议让它在 Java 8 上运行 ...
$ java -noverify FooDemo
output: true
$ java -Xverify:none FooDemo
output: true
note 这将禁用字节码验证器。请记住never disable bytecode verification in a production system。