【问题标题】:java.lang.VerifyError thrown when creating a method using JavaAssist使用 JavaAssist 创建方法时抛出 java.lang.VerifyError
【发布时间】:2016-10-02 11:06:05
【问题描述】:

我正在尝试使用 JavaAssist 版本 3.12.1.GA 生成使用 Java 8 实现接口的 Pojo 的一些运行时代码。尝试创建返回类型为 Object 的方法时遇到错误。

错误:

Caused by: java.lang.VerifyError: (class: person, method: getColumnByIndex signature: (I)Ljava/lang/Object;) Wrong return type in function

在添加 getColumnByIndex 方法时被抛出。

这是完整的示例类:

public class Example {

    public interface Domain {
        public int getIdentifier();
        public Object getColumnByIndex(int i);
    }

    public static void main(final String[] args) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException {

        final ClassPool pool = ClassPool.getDefault();
        final CtClass cc = pool.makeClass("Person");
        cc.addInterface(resolveCtClass(Domain.class));

        final CtField idField = new CtField(CtClass.intType, "id", cc);
        final CtMethod idGetter = CtNewMethod.getter("getId", idField);
        final CtMethod idSetter = CtNewMethod.setter("setId", idField);
        cc.addField(idField);
        cc.addMethod(idGetter);
        cc.addMethod(idSetter);

        final CtField firstNameField = new CtField(resolveCtClass(String.class), "firstName", cc);
        final CtMethod firstNameGetter = CtNewMethod.getter("getFirstName", firstNameField);
        final CtMethod firstNameSetter = CtNewMethod.setter("setFirstName", firstNameField);
        cc.addField(firstNameField);
        cc.addMethod(firstNameSetter);
        cc.addMethod(firstNameGetter);

        final CtMethod getIdentifier = CtNewMethod.make("public int getIdentifier () { return id; }", cc);
        cc.addMethod(getIdentifier);            

        final CtMethod getColumnByIndex = CtNewMethod.make(
                    "public Object getColumnByIndex(int i) {"
                    +   "switch (i) {"
                    +       "case 0:"
                    +           "return id;"
                    +       "case 1:"
                    +           "return firstName;"
                    +       "default: "
                    +           "throw new IllegalArgumentException(\"Tried getting column index i, but this column index does not exist\");"
                    +   "}"
                    + "}", cc);
        cc.addMethod(getColumnByIndex);
        final Class<?> dynamicClass = cc.toClass();

        final Domain domainImpl = (Domain) dynamicClass.newInstance();
        System.out.println(domainImpl.getIdentifier());
        System.out.println(domainImpl.getColumnByIndex(0));
    }

    private static CtClass resolveCtClass(final Class<?> clazz) throws NotFoundException {
        final ClassPool pool = ClassPool.getDefault();
        return pool.get(clazz.getName());
    }

如何解决 java.lang.VeryifyError?

【问题讨论】:

    标签: java code-generation javassist verifyerror


    【解决方案1】:

    显然int 类型的id 字段不会自动装箱到Integer,所以你要么手动完成:

    switch (i) {
      case 0: return Integer.valueOf(id);
      case 1: return firstName;
      default: throw new IllegalArgumentException("...");
    }
    

    或者您将所有内容都转换为Integer,包括Domain.getIdentifier() 的返回类型。 Java 中的原始类型不是Object 的!包装器类型的存在是为了在 JVM 中伪造单个根层次结构,编译器会在适当的时候静默插入 Integer.valueOf(int)Integer.intValue() 之类的调用,但有时抽象会泄露给用户。

    由于您正在编写的代码似乎是数据库访问的东西,我更喜欢第二个选项,以便所有内容都可以为空 - 否则要表示尚未插入的记录,您必须依赖一些金丝雀值,例如零、-1 或其他任何值。

    可运行的gist

    【讨论】:

    • 太棒了,感谢您的解释和 gist 中的编写代码。该代码确实是一个数据库,因此我将遵循您关于包装的建议。实际上,我确实在将整数类型的数据库(到平面文件)中的列映射时遇到了麻烦。当整数为空时,它由 0 表示,而不仅仅是一个空字段。
    猜你喜欢
    • 2012-07-04
    • 1970-01-01
    • 1970-01-01
    • 2013-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-16
    相关资源
    最近更新 更多