Byte Buddy - определить конструктор с вызовом суперкласса и инициализировать поле

У меня есть такой класс, как:

public class Sample{

private String a;
private String b;

public Sample(String a, String b)
{
    this.a = a;
    this.b = b;
}
 public String getA() {return a;}
 public String getB() {return b;}
}

Я хочу создать динамический класс, который будет наследовать от класса Sample, и добавить к нему поля (строковые поля).

Я пытался сделать:

DynamicType.Builder<? extends Sample> classBuilder = new ByteBuddy()
        .subclass(Sample.class, ConstructorStrategy.Default.NO_CONSTRUCTORS)
        .name("sampleSon");

classBuilder.defineConstructor(Visibility.PUBLIC)
        .withParameters(String.class, String.class, String.class)
        .intercept(MethodCall.invoke(Sample.class.getConstructor(String.class, String.class))
                .withArgument(0, 1)
                .andThen(FieldAccessor.ofField("c").setsArgumentAt(2)));

но когда я попытался создать экземпляр из этого класса:

Class<? extends Sample> newSampleClass= classBuilder.make().load(ClassLoader.getSystemClassLoader()).getLoaded();
Sample sample = newSampleClass.getConstructor(String.class, String.class, String.class).newInstance("a", "b", "c");

это вызывает исключение:

java.lang.NoSuchMethodException: sampleSon.<init>(java.lang.String, java.lang.String, java.lang.String)

Что я делаю неправильно? Я хочу создать класс такой, что:

public class SampleSon extends Sample {
     private String c;
     public SampleSon(String a, String b, String c) {
       super(a,b);
       this.c = c;
     }

     public String getC() { return c;}
}

1 ответ

Вы не определяете поле c прежде чем начать использовать его в определении конструктора.

Class<? extends Sample> clazz = new ByteBuddy()
        .subclass(Sample.class, ConstructorStrategy.Default.NO_CONSTRUCTORS)
        .name("SampleSon")
        .defineField("c", String.class, Visibility.PRIVATE)
        .defineConstructor(Visibility.PUBLIC)
        .withParameters(String.class, String.class, String.class)
        .intercept(MethodCall.invoke(Sample.class.getConstructor(String.class, String.class))
                .withArgument(0, 1)
                .andThen(FieldAccessor.ofField("c").setsArgumentAt(2)))
        .make()
        .load(ClassLoader.getSystemClassLoader())
        .getLoaded();

Примечание: вам также нужно объединить все вызовы методов в соответствии с ByteBuddy ага

Другие вопросы по тегам