[bcel] runtime visible annotation attribute support for class fields and method

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[bcel] runtime visible annotation attribute support for class fields and method

Tomas Lukošius
Hello bcel developers,

I’m sorry in advance if I’m writing to a wrong place.

I use bcel to annotate some specific fields and methods in already compiled code. Currently I work on task to migrate from version 6.0 to 6.2. I run into some issues and seek for advice:

1.       org.apache.bcel.util.BCELifier does not support runtime annotations for class fields and methods (I did not test class annotations). Should it support them? When debugging I found that i.e. field object in method org.apache.bcel.util.BCELifier#visitField does contain attribute of type org.apache.bcel.classfile.RuntimeVisibleAnnotations and its table is filled appropriately. It seems org.apache.bcel.util.BCELifier#visitField is missing some code for annotation support. Basically same thing applies to org.apache.bcel.util.BCELifier#visitMethod as well.

2.       org.apache.bcel.generic.FieldGenOrMethodGen#addAnnotationEntry method is now protected. Should it be deprecated? Seems now correct way to read/write annotations is to use org.apache.bcel.classfile.RuntimeVisibleAnnotations attribute.

3.       While trying to implement code that adds runtime annotation to a field I noticed that org.apache.bcel.classfile.RuntimeVisibleAnnotations has a constructor only for reading from input. Should it have one for creating the attribute? I.e. it could provide the second constructor from its superclass: org.apache.bcel.classfile.Annotations#Annotations(byte, int, int, org.apache.bcel.classfile.AnnotationEntry[], org.apache.bcel.classfile.ConstantPool, boolean) to avoid unnecessary complicated implementation on user end. I temporarily solved it by copying org.apache.bcel.classfile.RuntimeVisibleAnnotations class to my source base and providing the appropriate constructor. Also when creating org.apache.bcel.classfile.AnnotationEntry I run into NullPointerException. None of its constructors initialize org.apache.bcel.classfile.AnnotationEntry#element_value_pairs collection, only method org.apache.bcel.classfile.AnnotationEntry#read does. This issue I had to solve via reflection. Should it initialize the collection? Maybe it could be initialized on demand if not already. Here’s a simple fragment of code that adds runtime annotation to a field for the version 6.2:

private static void addTestAnnotation(FieldGen field)
{
   ConstantPoolGen cp = field.getConstantPool();

   ObjectType objectType = new ObjectType("com.nomagic.tools.ant.annotator.TestAnnotation");
   AnnotationEntry annotationEntry = new AnnotationEntry(cp.addUtf8(objectType.getSignature()), cp.getConstantPool(), true);
   fixUninitializedLists(annotationEntry);
   SimpleElementValueGen value = new SimpleElementValueGen(ElementValueGen.STRING, cp, "Some test text");
   ElementValuePairGen pairGen = new ElementValuePairGen("testMessage", value, cp);
   annotationEntry.addElementNameValuePair(pairGen.getElementNameValuePair());
   AnnotationEntry[] annotation_table = new AnnotationEntry[]{annotationEntry};

   int nameIndex = cp.addUtf8(Const.getAttributeName(Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS));
   // RuntimeVisibleAnnotations is copy of original class with changed constructor
   RuntimeVisibleAnnotations runtimeVisibleAnnotations = new RuntimeVisibleAnnotations(nameIndex, annotation_table.length, annotation_table, cp.getConstantPool());
   field.addAttribute(runtimeVisibleAnnotations);
}

private static void fixUninitializedLists(AnnotationEntry annotationEntry)
{
   java.lang.reflect.Field[] fields = annotationEntry.getClass().getDeclaredFields();
   for (java.lang.reflect.Field field : fields)
   {
      field.setAccessible(true);
      if(field.getType().equals(List.class))
      {
         try
         {
            Object value = field.get(annotationEntry);
            if (value == null)
            {
               field.set(annotationEntry, new ArrayList());
            }
         }
         catch (Exception e)
         {
            e.printStackTrace();
         }
      }
   }
}

Maybe org.apache.bcel.generic.FieldGenOrMethodGen class could have a method like addRuntimeVisibleAnnotation(AnnotationEntryGen) and inside it could check if it has special annotations attribute (create if not) and then add annotation to the attribute.

Seems like adding annotation to a class field or method is no longer supported. Or maybe implementation is not complete. Or maybe I’m using wrong API.
If you need, I can provide sample intellij project.

Please let me know what you think about this.

Sincerely,
--
Tomas Lukosius
Software Developer
No Magic Europe
Savanoriu ave. 363, LT-51480, Kaunas, Lithuania
Phone: +370 37 324032, fax: +370 37 320670
E-mail: [hidden email]<mailto:[hidden email]>
www.nomagic.com<http://www.nomagic.com/>
www.magicdraw.com<http://www.magicdraw.com/>

Important change to No Magic e-mail addresses. Following No Magic acquisition by Dassault Systèmes, please use my Dassault Systèmes email address [hidden email]<mailto:[hidden email]> to contact me. Don't forget to add the new address to your Safe Senders list, to ensure you will continue to receive my e-mails.