简体   繁体   中英

How do I add a dynamic number of annotated parameters to a new method in Bytebuddy?

I'm attempting to create a number of classes at runtime using ByteBuddy. So far I've managed to create the classes, add methods and annotate them. It's a great tool and I've enjoyed using it so far.

But now I'm stuck. I have my class, with a method and there are n number of parameters (dynamically controlled by config). This works something like...

DynamicType.Builder<?> builder = new ByteBuddy().subclass(Object.class)
                                .name(newClassName)
                                .annotateType(AnnotationDescription.Builder.ofType(Controller.class).build());

// loop for all methods to create
for (final MethodDefinition methodDefinition : methodDefinitions) {

    final List<TypeDefinition> parameters = new ArrayList<>();

    for (final MethodParameterDefinition methodParamDef : methodDefinition.getMethodParameterDefinitions()) {
        parameters.add( TypeDescription.Generic.Builder.rawType(methodParamDef.getType()).build() );
    }

    // define the method
    builder = builder
        .defineMethod(methodDefinition.getName(), outputValueObjectClass, Modifier.PUBLIC)
        .withParameters(parameters)                            
        .annotateMethod(AnnotationDescription.Builder.ofType(RequestMapping.class)
            .defineEnumerationArray("method", RequestMethod.class, RequestMethod.valueOf(methodDefinition.getHttpMethod()))
            .defineArray("path", methodDefinition.getUrl()).build())
        .annotateMethod(AnnotationDescription.Builder.ofType(ResponseBody.class).build())
}

final DynamicType.Unloaded unloadedClass = builder.make();

But when I attempt to add an annotation to one of the parameters by using the following code...

for (final MethodParameterDefinition methodParamDef : methodDefinition.getMethodParameterDefinitions()) {
    parameters.add( TypeDescription.Generic.Builder.rawType(methodParamDef.getType())
        .annotate(AnnotationDescription.Builder.ofType(PathVariable.class).define("name", methodParamDef.getName()).build())
        .build() );
}

...I get the following exception....

java.lang.IllegalStateException: Illegal type annotations return type class... 

If I know the number of method parameters I can add these using code like...

builder = builder
    .defineMethod(methodDefinition.getName(), outputValueObjectClass, Modifier.PUBLIC)
    .withParameter(methodParameterClass).annotateParameter(AnnotationDescription.Builder.ofType(ModelAttribute.class).build())
    .annotateMethod(AnnotationDescription.Builder.ofType(RequestMapping.class)
        .defineEnumerationArray("method", RequestMethod.class, RequestMethod.valueOf(methodDefinition.getHttpMethod()))
        .defineArray("path", methodDefinition.getUrl()).build())
    .annotateMethod(AnnotationDescription.Builder.ofType(ResponseBody.class).build())

But this doesn't work for a dynamic approach.

Does anyone know how to add a dynamic number of parameters (with annotations) to a method?

Thanks in advance!

I just checked the code and the exception message is misleading due to a copy-paste error. The error message should tell you that you are annotating a type with an annotation that is not a type annotation.

Note the difference between the annotation and the annotateParameter in the code generation DSL. The former annotates the type, the other one the parameter. This might seem confusing as the syntax is ambigous:

void foo(@Bar List<?> qux) { ... }

can mean both in Java, if @Bar is a type annotation, it annotates the List type, if it is a parameter annotation, it annotates the parameter qux , if it is both, the type and the parameter will be annotated. On the byte code level, you can choose what element to annotate. But since your annotation is only compatible to parameters, the (misleading, this is now fixed on master) error message is shown.

If you want to add a dynamic number of parameters, just run the loop on the DynamicType.Builder and add the parameters like this:

MethodDefinition.ParameterDefinition builder = ...
for (...) {
  builder = builder.withParameter(...).annotateParameter(...);
}

This should do the trick.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM