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()
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. –