2017-09-29 3 views
3

j'ai une classe telle que:Byte Buddy - définir constructeur avec appel à super classe et initialiser champ

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

Je veux créer une classe dynamique qui inhibera de la classe de l'échantillon, et ajouter des champs à elle (Champs de chaîne).

J'ai essayé de le faire:

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

mais quand j'ai essayé de créer une instance de cette classe:

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

il est lancer une exception:

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

Que suis-je mal faire? Je veux créer une classe telle que:

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

Comme indiqué dans la réponse: Byte Buddy est entièrement immuable. Vous devez chaîner tous les appels dans la bibliothèque. –

Répondre

2

Vous ne définissez pas de champ c avant de commencer à l'utiliser dans la définition du constructeur.

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

Remarque: vous devez également la chaîne tous les appels de méthode selon l » javadoc ByteBuddy.

+0

Création du champ: classBuilder.defineField ("c", String.class, Visibility.PRIVATE); J'ai également essayé de créer un constructeur plus simple et il a échoué: classBuilder.defineConstructor (Visibility.PUBLIC) .withParameters (String.class, String.class). interception (MethodCall.invoke (Sample.class.getConstructor (String.class, String.class)). WithArgument (0,1)); –

+0

@Rotemben Selon le javadoc de 'ByteBuddy', tous les appels de méthode _must_ doivent être chaînés comme dans mon exemple. –

+0

@ Luciano van der Veekens a travaillé :) merci beaucoup !!! –