嗨,这与您的应用程序中的某些字节码有关。(有关Java
7兼容性更改的注释,请参见http://www.oracle.com/technetwork/java/javase/compatibility-417013.html#incompatibilities,有关JSR
202,请看以下几行)
你可以
- 用JDK 7重新编译所有源
- 或者如果您无权访问源
java
与参数一起使用-XX:-UseSplitVerifier
- 或如果遇到使用开关的问题,则切换到Java 6
编辑 甚至答案已经有点老了。由于当前情况,我添加一些更详细的解释。
StackMapTableJava引入了类文件中的属性,即使当时没有记录。
Foo.java
public class Foo { public static boolean bar(String s) { if (s.length() == 0) { return true; } return false; }}$ java -versionjava version "1.6.0"Java(TM) SE Runtime Environment (build 1.6.0-b105)$ javac Foo.java$ javap -c -v FooCompiled 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 }类验证器不检查属性是否在类中。
以下创建
Foo.class不带
StackMatTable属性的文件。
FooDump.java
import org.objectweb.asm.*;import java.io.*;public class FooDump implements Oppres { 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(Oppres.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 Foopublic 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 -versionjava 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)。
使用
FooJava 6 的类版本运行检查。
$ java -versionjava version "1.7.0"Java(TM) SE Runtime Environment (build 1.7.0-b147)$ javap -c -v FooClassfile /home/suboptimal/playground/Foo.class Last modified Jun 9, 2017; size 232 bytes MD5 checksum 5a7ea4a5dd2f6d1bcfddb9ffd720f9c9public class Foo minor version: 0 major version: 50 <-- class file Java 6...$ javac FooDemo.java$ java FooDemooutput: true
对于类文件版本51(Java 7)不再发生此故障转移。
要创建
FooJava 7 的类版本,请修改的代码
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 -versionjava version "1.7.0"Java(TM) SE Runtime Environment (build 1.7.0-b147)$ javap -c -v FooClassfile /home/suboptimal/playground/Foo.class Last modified Jun 9, 2017; size 232 bytes MD5 checksum cfd57fb547ac98a1b2808549f5e9e8c1public class Foo minor version: 0 major version: 51 <-- class file Java 7...$ javac FooDemo.java$ java FooDemoException 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 -versionjava version "1.7.0"Java(TM) SE Runtime Environment (build 1.7.0-b147)$ java -XX:-UseSplitVerifier FooDemooutput: true
在Java 8中,
StackMapTable必须对属性进行验证,并且
UseSplitVerifier删除了该选项。
$ java -versionjava version "1.8.0"Java(TM) SE Runtime Environment (build 1.8.0-b132)$ javap -c -v FooClassfile /home/suboptimal/playground/Foo.class Last modified Jun 9, 2017; size 232 bytes MD5 checksum cfd57fb547ac98a1b2808549f5e9e8c1public class Foo minor version: 0 major version: 51 <-- class file Java 7...$ javac FooDemo.java$ java FooDemoException in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch target 9$ java -XX:-UseSplitVerifier FooDemoJava HotSpot(TM) 64-Bit Server VM warning: ignoring option UseSplitVerifier; support was removed in 8.0Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch target 9
note注意 始终使用Java 6/7/8的初始版本是为了表明从一开始就存在这种行为。
您可能会发现一些建议,以使其在Java 8中运行。
$ java -noverify FooDemooutput: true$ java -Xverify:none FooDemooutput: true
注意 这将禁用字节码验证程序。请记住,切勿在生产系统中禁用字节码验证。



