lundi 4 mai 2020

Map class and field annotations with byte-buddy

I'm building a framework which hides annotations used by internal libraries and I'm using byte-buddy to do this.

The goal I'd like to achieve is that developers can define classes like this:

@ClassAnnotation(name = "Hello World", description = "A simple Hello World example")
public class HelloWorld {

    @FieldAnnotation(a = "foo", b = "bar")
    private String something;

}

The annotations I'm hiding are the following:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface InjectedClassAnnotation {
    String name() default "";

    String[] description() default "";
}

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface InjectedFieldAnnotation {
    String a() default "";

    String b() default "";

    String c() default "baz";
}

I'm able to replace the class level annotation in the following way:

final Class<HelloWorld> clazz = HelloWorld.class;
final ClassAnnotation classAnnotation = clazz.getAnnotation(ClassAnnotation.class);
final AnnotationDescription annotationDescription = AnnotationDescription.Builder.ofType(InjectedClassAnnotation.class)
                                                                                 .define("name", classAnnotation.name())
                                                                                 .defineArray("description", classAnnotation.description())
                                                                                 .build();
new ByteBuddy()
            .redefine(clazz)
            .annotateType(annotationDescription)
            // todo: Get all fields annotated with @FieldAnnotation and add the @InjectedFieldAnnotation with mapped values.
            .make()
            .load(clazz.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());

But I would also like to scan for occurrences of @FieldAnnotation on fields and if they exist, I would like to add an @InjectedFieldAnnotation to that field and map the values from @FieldAnnotation to those of @InjectedFieldAnnotation.

The expected end-result after byte-buddy has done it's magic would be:

@ClassAnnotation(name = "Hello World", description = "A simple Hello World example")
@InjectedClassAnnotation(name = "Hello World", description = "A simple Hello World example")
public class HelloWorld {

    @FieldAnnotation(a = "foo", b = "bar")
    @InjectedFieldAnnotation(a = "foo", b = "bar", c = "baz")
    private String something;

}

I've found some things like AsmVisitorWrapper and Class-/Method-/Field-/Annotation- Visitors etc. But I'm not sure what would be the best way to achieve this. Help & thoughts are greatly appreciated!

PS: For clarity, the class annotation injection is working. I'm stuck on the field annotation.





Aucun commentaire:

Enregistrer un commentaire