Search code examples
javajavassist

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.


Solution

  • 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!