5

I have a class such as:

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;}
}

I want to create a dynamic class which will inherit from Sample class, and add fields to it (String fields).

I tried to do:

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)));

but when I tried to create a instance from this class:

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

it throws an exception:

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

What am I doing wrong? I want to create a class such that:

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;}
}
exception
  • 569
  • 7
  • 20
Rotem ben
  • 156
  • 2
  • 13

1 Answers1

3

You do not define field c before you start using it in the constructor definition.

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();

Note: you also need to chain all method calls according to ByteBuddy's javadoc.

Luciano van der Veekens
  • 6,307
  • 4
  • 26
  • 30
  • Im creating the field: classBuilder.defineField("c", String.class, Visibility.PRIVATE); I tried also to create a simpler constructor and it failed: classBuilder.defineConstructor(Visibility.PUBLIC).withParameters(String.class, String.class). intercept(MethodCall.invoke(Sample.class.getConstructor(String.class, String.class)).withArgument(0,1)); – Rotem ben Sep 29 '17 at 08:44
  • @Rotemben According to `ByteBuddy`'s javadoc, all method calls _must_ be chained like in my example. – Luciano van der Veekens Sep 29 '17 at 08:51