Byte Buddy:java.lang.AbstractMethodError:调用方法时出错



编辑

原始问题中的实际接口和示例域存在缺陷。下面是正确的例子。

import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy;
import static net.bytebuddy.matcher.ElementMatchers.isGetter;
import static net.bytebuddy.matcher.ElementMatchers.isSetter;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.FieldAccessor;
public class Example {
    public interface Domain {
        int getIdentifier();
    }
    public class Person implements Domain {
        private int personId;
        private String firstName;
        private String lastName;
        @Override
        public int getIdentifier() {
            return personId;
        }
        public int getPersonId() {
            return personId;
        }
        public void setPersonId(final int personId) {
            this.personId = personId;
        }
        // further  getters and setters ommitted
    }
    public static void main(final String[] args) throws InstantiationException, IllegalAccessException {
        final Domain domain = new ByteBuddy()
                .subclass(Domain.class)
                .name("Person")
                .method(isGetter().or(isSetter())).intercept(FieldAccessor.ofBeanProperty())
                .defineField("personId", int.class, Visibility.PRIVATE)           
                .defineField("firstName", String.class, Visibility.PRIVATE)           
                .defineField("lastName", String.class, Visibility.PRIVATE)           
                .method(isDeclaredBy(Domain.class))
                  .intercept(FieldAccessor.ofField("personId"))
                .make()
                .load(Example.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                .getLoaded()
                .newInstance();
        System.out.println(domain.getIdentifier());     
    }
}

Byte Buddy代码是否生成上面代码中所述的Person类?(我该如何检查?(

预编辑

我正在尝试在运行时生成一些类,这些类使用ByteBuddy API(http://bytebuddy.net/#/(

应用程序从外部源获得一些输入,我想将这些输入(比如类的名称、一些变量的名称(转换为实现接口的POJO。在下面的示例代码中,输入由域名字符串数组表示。

成功生成代码后,我想使用那些在运行时生成的类来映射文件(例如,解析行并将它们映射到生成的POJO(。

下面的代码(clazz.setIdentifier(1);(抛出Exception in thread "main" java.lang.AbstractMethodError: Person.setIdentifier(I)V

public class Sample {
    public interface Domain {
        void setIdentifier(int i);
        int getIdentifier();
    }
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        String[] domainNames = {"Person", "City", "Country"};   
        for (String domainName : domainNames) {
            Class<?> domain = new ByteBuddy()
                    .subclass(Domain.class)
                    .name(domainName)
                    .method(ElementMatchers.named("getIdentifier"))
                    .intercept(FixedValue.value(1))                 
                    .make()
                    .load(Sample.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                    .getLoaded();
            Domain clazz = (Domain) domain.newInstance();
            clazz.setIdentifier(1);
            System.out.println(clazz.getIdentifier());
        }
    }   
}

现在我正在使用Roaster生成以下类:

public class Adres implements Domain {
    @Parsed(index = 0)
    private int id;
    @Parsed(index = 1)
    private String plaatsNaam;
    @Parsed(index = 2)
    private String straatNaam;
    @Parsed(index = 3)
    private String huisnummer;
    @Parsed(index = 4)
    private String postcode;
    @Override
    public int getIdentifier() {
        return id;
    }
}

但是来自外部源的输入的不断变化的性质使得运行时代码生成比源代码生成更可取。所以理想情况下,我想在运行时创建上面的代码,然后使用这些代码(显然(。

的字段和方法部分http://bytebuddy.net/#/tutorial确实提到了ElementMatchers和Interceptors的使用,但坦率地说,我不知道如何让它们发挥作用。

问题:如何创建一个使用Byte Buddy实现接口的POJO,然后对生成的代码调用方法

您从未实现过setIdentifier方法。因此,该方法保持抽象,并抛出AbstractMethodError。虽然javac禁止这样做,但虚拟机允许您加载这样的类型,因此Byte Buddy也允许这样做。在您的情况下,这当然不是理想的结果。使用FieldAccessor实现,您可能想要做的事情如下:

Domain domain = new ByteBuddy()
  .subclass(Domain.class)
  .method(isDeclaredBy(Domain.class))
  .intercept(FieldAccessor.ofField("id").defineAs(int.class, Visibility.PRIVATE))
  .make()
  .load(Sample.class.getClassLoader())
  .getLoaded()
  .newInstance();
  domain.setIdentifier(42);
  System.out.println(domain.getIdentifier());

在上面的Adres示例中,也缺少setter实现;我想你已经忘记了,但如果不是这样的话,请要求澄清。

编辑:您更新的示例仍然建议使用这种方法,但您需要手动定义setter和getter。我计划在某个时候为此添加一个方便的API,但您应该能够在一个属性列表的循环中这样做。您可以在生成的类上使用反射API进行验证,或者使用Java反编译器查看生成的类文件的反汇编。

最新更新