chelazo
chelazo

Reputation: 63

Add annotation to a parameter on a new method created with Javassist

I am in need to add an annotation to a method parameter. The method is previously created with javassist like:

CtClass cc2 = pool.makeClass("Dummy");
CtMethod method = CtNewMethod.make("public java.lang.String dummyMethod( java.lang.String oneparam){ return null; }", cc2);

The annotation I want to add is quite simple:

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)

public @interface Param {
    /** Name of the parameter */
    String name() default "";
}

1) writting the annotation in the method creation throws

javassist.CannotCompileException: [source error] syntax error near "myMethod(@Param

2) found this solution but it is based on a line which in my case returns null:

AttributeInfo paramAtrributeInfo = methodInfo.getAttribute(ParameterAnnotationsAttribute.visibleTag); // or inVisibleTag

I am getting lost on how to accomplish this; has anyone found a way to create a new method and add any annotation to its parameters?

Thanks in advance.

Upvotes: 3

Views: 2556

Answers (1)

chelazo
chelazo

Reputation: 63

Found a workaround based on the solution I mentioned in the original question. I could not create a class, and add a method to it and insert an annotation to its parameter with javassist. But using a real class as a template, the parameter annotation can be found and edited.

1) First, create a class with a method with the desired annotation

public class TemplateClass {
    public String templateMethod(@Param String paramOne) {
        return null;
    }
}

2) Load it

ClassPool pool = ClassPool.getDefault();
CtClass liveClass = null;
try {
     liveClass = pool.get("your.package.path.Dummyclass");
} catch (NotFoundException e) {
     logger.error("Template class not found.", e);
}

3) Work it

// -- Get method template
    CtMethod dummyMethod = liveClass.getMethods()[2];
    // -- Get the annotation
    AttributeInfo parameterAttributeInfo = dummyMethod.getMethodInfo().getAttribute(ParameterAnnotationsAttribute.visibleTag);
    ConstPool parameterConstPool = parameterAttributeInfo.getConstPool();
    ParameterAnnotationsAttribute parameterAtrribute = ((ParameterAnnotationsAttribute) parameterAttributeInfo);
    Annotation[][] paramArrays = parameterAtrribute.getAnnotations();
    Annotation[] addAnno = paramArrays[0];
    //-- Edit the annotation adding values
    addAnno[0].addMemberValue("value", new StringMemberValue("This is the value of the annotation", parameterConstPool));
    addAnno[0].addMemberValue("required", new BooleanMemberValue(Boolean.TRUE, parameterConstPool));
    paramArrays[0] = addAnno;
    parameterAtrribute.setAnnotations(paramArrays);

Then change the name of the CtClass and/or CtMethod before building the result class. It is not as flexible as expected, but at least some scenarios can be solved with an approach like this. Any other workaround is welcome!

Upvotes: 1

Related Questions