2017-05-29 4 views
0

Je joue avec la bibliothèque ByteBuddy depuis un moment et je me retrouve coincé. J'avais cette méthode fonctionnant quand les classes examinées étaient dans le même dossier (en tant que classes internes statiques), mais maintenant que j'ai séparé la logique dans un dossier séparé, il ne fonctionne plus.Comment étendre dynamiquement les classes de béton avec ByteBuddy

Si elle aide (et peut-être que je prends la mauvaise approche), mon objectif est de faire une sous-classe dynamique de la classe d'entrée originalClazz et stocker une référence à l'objet originalClazz de classe, en plus d'une référence à l'objet d'entrée original . J'utilise la méthode ProxyHandler.execute pour appeler directement des méthodes sur l'objet original et envelopper la valeur de retour dans un proxy (également en utilisant proxyMe).

Le bloc suivant est dans un fichier java:

private static final String ORIGINAL_OBJECT_FIELD_NAME = "_original_object_"; 
private static final String ORIGINAL_CLASS_FIELD_NAME = "_original_class_"; 

public static <T> T proxyMe(final T original, final Class<?> originalClazz) { 
    if (originalClazz != null && isNotFinal(originalClazz) && hasDefaultConstructor(originalClazz)) { 
     try { 
      final Class<?> newSubClass = new ByteBuddy() 
        .subclass(originalClazz, ConstructorStrategy.Default.NO_CONSTRUCTORS) 
        .defineField(ORIGINAL_OBJECT_FIELD_NAME, Object.class, Visibility.PUBLIC) 
        .defineField(ORIGINAL_CLASS_FIELD_NAME, Class.class, Visibility.PUBLIC) 
        .method(any()) 
         .intercept(to(ProxyHandler.class)) 
        .defineConstructor(Visibility.PUBLIC) 
         .intercept(MethodCall.invoke(originalClazz.getConstructor())) 
        .make()        // <-- exception thrown here 
        .load(originalClazz.getClassLoader()) 
        .getLoaded(); 

      final Object result = newSubClass.newInstance(); 
      setField(result, ORIGINAL_OBJECT_FIELD_NAME, original); 
      setField(result, ORIGINAL_CLASS_FIELD_NAME, originalClazz); 
      return (T) result; 
     } catch (NoSuchMethodException | InstantiationException | IllegalAccessException e) { 
      e.printStackTrace(); 
     } 
    } 
    return original; 
} 

public static class ProxyHandler { 
    @RuntimeType 
    public static Object execute(
     @SuperCall Callable<Object> callable, 
     @This Object obj, 
     @Origin Method method, 
     @AllArguments Object[] arguments 
    ) { 
     ... 
    } 
} 

Et dans ma classe de test ...

@Test 
public void makeProxy() throws Exception { 
    final Foo foo = new Foo(new Bar("str")); 
    proxyMe(foo, Foo.class); 
} 

public static class Bar { 
    private String name; 
    public Bar() {} 
    public Bar(final String name) { this.name = name; } 
    public String getName() { return name; } 
} 

public static class Foo { 
    private Bar bar; 
    public Foo() {} 
    public Foo(final Bar bar) { this.bar = bar; } 
    public Bar getBar() { return bar; } 
} 

Exception levée:

None of [ 
    TargetMethodAnnotationDrivenBinder.Record{ 
    , 
    candidate=public static java.lang.Object somepackage.Utils$ProxyHandler.execute(
     java.util.concurrent.Callable, 
     java.lang.Object, 
     java.lang.reflect.Method, 
     java.lang.Object[] 
    ), 
    handlers=[ 
     TargetMethodAnnotationDrivenBinder.DelegationProcessor.Handler.Bound{ 
     parameterBinder=SuperCall.Binder.INSTANCE, 
     [email protected]ll(
      serializableProxy=false, 
      nullIfImpossible=false, 
      fallbackToDefault=true 
     ), 
     target=java.util.concurrent.Callable arg0, 
     typing=Assigner.Typing.STATIC 
     }, 
     TargetMethodAnnotationDrivenBinder.DelegationProcessor.Handler.Bound{ 
     parameterBinder=This.Binder.INSTANCE, 
     [email protected](
      optional=false 
     ), 
     target=java.lang.Object arg1, 
     typing=Assigner.Typing.STATIC 
     }, 
     TargetMethodAnnotationDrivenBinder.DelegationProcessor.Handler.Bound{ 
     parameterBinder=Origin.Binder.INSTANCE, 
     [email protected](
      cache=true 
     ), 
     target=java.lang.reflect.Method arg2, 
     typing=Assigner.Typing.STATIC 
     }, 
     TargetMethodAnnotationDrivenBinder.DelegationProcessor.Handler.Bound{ 
     parameterBinder=AllArguments.Binder.INSTANCE, 
     annotation= 
      @net.bytebuddy.implementation.bind.annotation.AllArguments(
      value=STRICT, 
      includeSelf=false 
     ), 
     target=[Ljava.lang.Object; arg3, typing=Assigner.Typing.STATIC}], 
     typing=Assigner.Typing.DYNAMIC 
     } 
    ] 
    allows for delegation from public somepackage.UtilsTest$Bar somepackage.UtilsTest$Foo.getBar() 
+0

avez-vous importé les annotations pour les méthodes d'intercepteur à partir de 'net.bytebuddy.implementation.bind.annotation.' bytebuddy a une certaine annotation nommée dans plusieurs paquets. –

Répondre

0

La classe ProxyHandler apparaît être private. Cela signifie probablement qu'il n'est pas visible pour votre code instrumenté et ne peut donc pas être appelé en tant que gestionnaire. Rendre la classe publique et tout devrait fonctionner comme prévu.

+0

Merci pour la réponse rapide. Malheureusement, cela n'a pas résolu le problème. Fait tout public juste pour être sûr, toujours pas de chance - même erreur :( –