2016-07-01 2 views
1

J'essaie de comprendre comment définir la valeur d'un champ d'instance en utilisant Byte Buddy. La documentation dit:Définir un instanceField dans Byte Buddy

N'oubliez pas d'attribuer une valeur à ce champ avant d'appeler des méthodes sur une instance d'une telle classe dynamique. Sinon, une délégation de méthode aboutira à une exception NullPointerException.

Mais je ne vois nulle part dans la documentation ou les tests unitaires sur la façon de procéder.

Ma classe est dynamique:

new ByteBuddy().subclass(AbstractService.class) 
     .name(serviceName) 
     .method(ElementMatchers.named("start").and(
       ElementMatchers.takesArguments(0))) 
     .intercept(
       MethodDelegation.toInstanceField(service, "consumer") 
        .filter(ElementMatchers.isAnnotatedWith(Start.class))) 
     .method(ElementMatchers.named("stop").and(
       ElementMatchers.takesArguments(0))) 
     .intercept(
       MethodDelegation.to(instance).filter(
         ElementMatchers.isAnnotatedWith(Stop.class))) 
     .make(); 

Je vois un autre poste avec une réponse à intercepter tout constructeur et utiliser @FieldProxy avec un MethodDelegation mais je ne vois pas comment le faire. Tout ce que j'ai essayé en termes de résultats dans une certaine variation de .constructor(ElementMatchers.any()).intercept(...) résultats dans:

java.lang.IllegalArgumentException: Aucun [] permet délégation de ...

Répondre

0

En fait, lorsque vous utilisent MethodDelegation.toInstanceField, Byte Buddy ajoute un champ du nom donné à la classe générée. Dans votre cas, Byte Buddy a ajouté un champ de type service nommé "consumer".

Vous devez maintenant décider comment vous souhaitez affecter une valeur à ce champ car le champ n'a pas de valeur, c'est-à-dire null avant l'affectation. Si vous avez appelé une méthode qui est annotée avec @Start avant de le faire, vous rencontrerez un NullPointerException.

La méthode la plus simple pour affecter le champ serait la réflexion. Une alternative de type sécurisé serait de mettre en œuvre une interface de

interface SetterIFace { 
    void setConsumer(MyType myType); 
} 

étant donné que le type service est un Class<MyType>. Vous pouvez ensuite ajouter:

.implement(SetterIFace.class).intercept(FieldAccessor.ofBeanProperty()) 

à mettre en œuvre SetterIFace comme un setter du champ en question après avoir elle définie dans le MethodDelegation.