[jboss-user] [Javassist user questions] - Re: adding annotations
The beauty of a Java agent is it gets passed every loaded class, regardless of classloader. So although you need to filter the list as quickly as possible (you'll get thousands of calls from java.* classes for instance) it is the best way to do the instrumentation. I have happily got annotation adding working in my code base recently so thought it might help you if I explained roughly how I do it. First up getting a CtClass: byte[] byteCode = ClassPool pool = CtClass clazz = pool.makeClass(new ByteArrayInputStream(byteCode)); If your using a Java agent it will give you the bytes directly, if you load them yourself in a custom classloader. Next up you the annotations adding to a CtClass: CtClass clazz = ClassFile classFile = clazz.getClassFile(); ConstPool cp = classFile.getConstPool(); AnnotationsAttribute attr = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag); Annotation theAnnotation = new Annotation("org.package.AnnotationType",cp); annotation.addMemberValue("name", new StringMemberValue("Paul",cp)); attr.setAnnotation(theAnnotation); clazz.getClassInfo().addAttribute(attr); That worked well for me as an approach. If you want to see a working version (the far more complicated version based on methods and arrays of values) you can see the latest version of my code at JEMM Git MethodAnnotationTransformation.java View the original post : http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4241818#4241818 Reply to the post : http://www.jboss.org/index.html?module=bb&op=posting&mode=reply&p=4241818 ___ jboss-user mailing list jboss-user@lists.jboss.org https://lists.jboss.org/mailman/listinfo/jboss-user
[jboss-user] [Javassist user questions] - Re: Adding annotations to methods
In the end I managed to work it out and answer my own question. The key was understanding that you need to add the AnnotationsAttribute instance to the Info of the method. That is the rough solution is: | CtClass clazz = | ClassFile classFile = clazz.getClassFile(); | ConstPool cp = classFile.getConstPool(); | AnnotationsAttribute attr = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag); | | Annotation useAnnotation = new Annotation("org.package.AnnotationType",cp); | annotation.addMemberValue("name", new StringMemberValue("Paul",cp)); | | attr.setAnnotation(useAnnotation); | | m.getMethodInfo().addAttribute(attr); | | So the only real difference between the CtClass, CtMethod and even parameters is I needed to do the appropriate getXXXInfo and then add the attribute directly. View the original post : http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4241819#4241819 Reply to the post : http://www.jboss.org/index.html?module=bb&op=posting&mode=reply&p=4241819 ___ jboss-user mailing list jboss-user@lists.jboss.org https://lists.jboss.org/mailman/listinfo/jboss-user
[jboss-user] [Javassist user questions] - Re: adding annotations
After a lot I found that the following is the code that works for me: | ClassFile classFile = newProxyClass.getClassFile(); | ConstPool constantPool = classFile.getConstPool(); | AnnotationsAttribute attr = new AnnotationsAttribute(constantPool, AnnotationsAttribute.visibleTag); | javassist.bytecode.annotation.Annotation a = new javassist.bytecode.annotation.Annotation(this.annotationClassName, constantPool); | attr.setAnnotation(a); | classFile.addAttribute(attr); | classFile.setVersionToJava5(); | | | ByteArrayOutputStream bos = new ByteArrayOutputStream(); | DataOutputStream os = new DataOutputStream( bos ); | classFile.write( os ); | os.close(); | | // all done | return bos.toByteArray(); | the above produces the byte code for a class with the added annotation. Thanks, Luca View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4140550#4140550 Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4140550 ___ jboss-user mailing list jboss-user@lists.jboss.org https://lists.jboss.org/mailman/listinfo/jboss-user
[jboss-user] [Javassist user questions] - Re: adding annotations
Hi, I'm still fighting with the annotation problem. I've made a code clean up, and now I've got the following piece of code: | // make a new class | CtClass newProxyClass = pool.makeClass( subProxyClassName ); | newProxyClass.setSuperclass( baseProxyClass ); | | // place a default constructor in the new class | CtConstructor constructor = new CtConstructor(null, newProxyClass ); | constructor.setBody(";"); | newProxyClass.addConstructor(constructor); | | // get the class file and add the annotation | ClassFile classFile = newProxyClass.getClassFile(); | ConstPool constantPool = classFile.getConstPool(); | AnnotationsAttribute attr = new AnnotationsAttribute(constantPool, AnnotationsAttribute.visibleTag); | javassist.bytecode.annotation.Annotation a = new javassist.bytecode.annotation.Annotation(this.annotationClassName, constantPool); | attr.setAnnotation(a); | classFile.addAttribute(attr); | classFile.setVersionToJava5(); | | // transform the classfile into bytecode | ByteArrayOutputStream bos = new ByteArrayOutputStream(); | DataOutputStream os = new DataOutputStream( bos ); | classFile.write( os ); | os.close(); | | // load the class | return this.defineClass(subProxyClassName, bytecode, 0, bytecode.length); | at runtime no exception are thrown, but the new class still has no annotation added! Then I saved the bytecode to a file in two cases, the above piece of code and the one without the addAttribute, and I can see they are different, so it seems as the annotation is added, but it is not visible to the runtime system. Please, any suggestion is appreciated!!! Thanks, Luca View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4135894#4135894 Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4135894 ___ jboss-user mailing list jboss-user@lists.jboss.org https://lists.jboss.org/mailman/listinfo/jboss-user
[jboss-user] [Javassist user questions] - Re: adding annotations
I'm going mad, anyone with a suggestion? I've found that the following piece of code: | ByteArrayOutputStream aos = new ByteArrayOutputStream(); | AnnotationsWriter aw = new AnnotationsWriter(aos, constantPool); | aw.numAnnotations(1); | aw.annotation(this.annotationClassName, 0); | aw.close(); | byte ab[] = aos.toByteArray(); | System.out.println("\n\tAnnotation bytecode for annotation " + this.annotationClassName + ""); | System.out.println(new String(ab) ); | System.out.println("\n\t++\n"); | attribute = new AnnotationsAttribute(constantPool, AnnotationsAttribute.visibleTag, ab); | that should create the annotation specified, prints the following: | | Annotation bytecode for annotation whitecat.example.DBRoleAnnotation | | |+++ | | So I'm pretty sure that the bytecode generated for the annotation is empty, and that the annotation is regularly added to my class, but without a bytecode I cannot access it. Anyone can explain why the bytecode is null? View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4134189#4134189 Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4134189 ___ jboss-user mailing list jboss-user@lists.jboss.org https://lists.jboss.org/mailman/listinfo/jboss-user
[jboss-user] [Javassist user questions] - Re: adding annotations
I've made another experiment: using an AnnotationsWriter as follows does not work too: | | ByteArrayOutputStream aos = new ByteArrayOutputStream(); | AnnotationsWriter aw = new AnnotationsWriter(aos, constantPool); | aw.numAnnotations(1); | aw.annotation(this.annotationClassName, 0); | aw.close(); | byte ab[] = aos.toByteArray(); | attribute = new AnnotationsAttribute(constantPool, AnnotationsAttribute.visibleTag, ab); | | System.out.println("Annotation attribute " + attribute.getName() + " " + attribute.getAnnotations().length); | classFile.addAttribute( attribute ); | The class can be loaded and instantiated, but I cannot access its annotations. In both cases, if I print the classfile content with a ClassFileWriter I got a message that lets me think I've got the annotations: | attribute: SourceFile (2 byte): javassist.bytecode.SourceFileAttribute | attribute: RuntimeVisibleAnnotations (6 byte): javassist.bytecode.AnnotationsAttribute | Moreover, in the case in which I use an AnnotationsWriter I got the following run-time exception when I try to access the annotations thru the Class.getAnnotations() method: | Exception in thread "Thread-Example-Main" java.lang.reflect.GenericSignatureFormatError | at sun.reflect.generics.parser.SignatureParser.error(SignatureParser.java:103) | at sun.reflect.generics.parser.SignatureParser.parseFieldTypeSignature(SignatureParser.java:233) | at sun.reflect.generics.parser.SignatureParser.parseTypeSignature(SignatureParser.java:359) | at sun.reflect.generics.parser.SignatureParser.parseTypeSig(SignatureParser.java:157) | at sun.reflect.annotation.AnnotationParser.parseSig(AnnotationParser.java:367) | at sun.reflect.annotation.AnnotationParser.parseAnnotation(AnnotationParser.java:181) | at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:69) | at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:52) | at java.lang.Class.initAnnotationsIfNecessary(Class.java:3072) | at java.lang.Class.getAnnotations(Class.java:3052) | I cannot find whre I'm doing something wrong. View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4133207#4133207 Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4133207 ___ jboss-user mailing list jboss-user@lists.jboss.org https://lists.jboss.org/mailman/listinfo/jboss-user
[jboss-user] [Javassist user questions] - Re: adding annotations
I've found how to make the ClassFile working for defining my new class, but I'm still unable to add the annotation. Now I work as follows: 1) I create a CtClass object and set the inheritance chain on that; 2) I get the byte[] from the CtClass and place them into a ByteArrayInputStream, used to create a ClassFile; 3) I add the annotation to the classfile; 4) I get the byte[] from the classfile thru a ByteArrayOutputStream; 5) I load the class thru the defineClass method. Now the class is of the right type, but it has no the annotation. The following is my code; anyone has an idea of which is my error adding the annotation? | subProxyClassName += this.getSubClassNameSuffix(); | | // make a new class and prepare the annotation | CtClass newProxyClass = pool.makeClass(subProxyClassName); | newProxyClass.setSuperclass( baseProxyClass ); | ByteArrayInputStream is = new ByteArrayInputStream( newProxyClass.toBytecode() ); | DataInputStream dis = new DataInputStream( is ); | ClassFile classFile = new ClassFile( dis ); | newProxyClass.defrost(); | ConstPool constantPool = classFile.getConstPool(); | AnnotationsAttribute attribute = new AnnotationsAttribute( constantPool, AnnotationsAttribute.visibleTag ); | javassist.bytecode.annotation.Annotation annotation = new javassist.bytecode.annotation.Annotation( this.annotationClassName, constantPool ); | attribute.setAnnotation( annotation ); | classFile.addAttribute( attribute ); | classFile.setVersionToJava5(); | ByteArrayOutputStream bos = new ByteArrayOutputStream(); | DataOutputStream os = new DataOutputStream( bos ); | classFile.write( os ); | new javassist.bytecode.annotation.Annotation( constantPool, subProxy ); | bytecode = bos.toByteArray(); | baseProxyClass = null; | | ... | | Class clazz = this.defineClass(subProxyClassName, bytecode, 0, bytecode.length); | | Thanks, Luca View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4133098#4133098 Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4133098 ___ jboss-user mailing list jboss-user@lists.jboss.org https://lists.jboss.org/mailman/listinfo/jboss-user
[jboss-user] [Javassist user questions] - Re: adding annotations
I've made another try: I've tried to get the classfile from a CtClass object instantied with the class name of the base class: | // make a new class and prepare the annotation | CtClass newProxyClass = pool.makeClass(subProxyClassName); | ClassFile classFile = newProxyClass.getClassFile(); //new ClassFile( false, subProxyClassName, baseProxyClass.getName() ); | ConstPool constantPool = classFile.getConstPool(); | AnnotationsAttribute attribute = new AnnotationsAttribute( constantPool, AnnotationsAttribute.visibleTag ); | javassist.bytecode.annotation.Annotation annotation = new javassist.bytecode.annotation.Annotation( this.annotationClassName, constantPool ); | attribute.setAnnotation( annotation ); | classFile.addAttribute( attribute ); | classFile.setVersionToJava5(); | classFile.setName(subProxyClassName); | classFile.setSuperclass( baseProxyClass.getName() ); | ByteArrayOutputStream bos = new ByteArrayOutputStream(); | DataOutputStream os = new DataOutputStream( bos ); | classFile.write( os ); | bytecode = bos.toByteArray(); | but again, when I try to instantiate this class, that is of kind "proxy", I got an instantiation error: | Class clazz = this.defineClass(subProxyClassName, bytecode, 0, bytecode.length); | AgentProxy aProxy = (AgentProxy) clazz.newInstance(); | I got the same instantiation exception of the previous post. Any idea? View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4132254#4132254 Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4132254 ___ jboss-user mailing list jboss-user@lists.jboss.org https://lists.jboss.org/mailman/listinfo/jboss-user
[jboss-user] [Javassist user questions] - Re: adding annotations
I've tried to define the class within the class loader, introspecting it in place to see what happens. In other words, I added the following code: | subProxyClassName += this.getSubClassNameSuffix(); | | // make a new class and prepare the annotation | ClassFile classFile = new ClassFile( false, subProxyClassName, baseProxyClass.getName() ); | ConstPool constantPool = classFile.getConstPool(); | AnnotationsAttribute attribute = new AnnotationsAttribute( constantPool, AnnotationsAttribute.visibleTag ); | javassist.bytecode.annotation.Annotation annotation = new javassist.bytecode.annotation.Annotation( this.annotationClassName, constantPool ); | attribute.setAnnotation( annotation ); | classFile.addAttribute( attribute ); | classFile.setVersionToJava5(); | classFile.setSuperclass( baseProxyClass.getName() ); | ByteArrayOutputStream bos = new ByteArrayOutputStream(); | DataOutputStream os = new DataOutputStream( bos ); | classFile.write( os ); | bytecode = bos.toByteArray(); | baseProxyClass = null; | | Class clazz = this.defineClass(subProxyClassName, bytecode, 0, bytecode.length); | System.out.println("Class " + clazz.getName()); | System.out.println("Superclass " + clazz.getSuperclass()); | System.out.println("Annotations"); | try { | AgentProxy aProxy = (AgentProxy) clazz.newInstance(); | } catch (InstantiationException e) { | // TODO Auto-generated catch block | e.printStackTrace(); | } catch (IllegalAccessException e) { | // TODO Auto-generated catch block | e.printStackTrace(); | } | for(Annotation a : clazz.getAnnotations()) | System.out.println("annotazione " + a); | I believe that the way I'm using the ClassFile is wrong, since I'm not able to load the class, or better the class that is loaded is unable to be instantied as child of the parent class. The class hierarchy is the following: proxy ^ | proxy_roled_1_24325842 <- when creating this class I need to inject an annotation | Class whitecat.proxy_roled_1_24325842 | Superclass class whitecat.proxy | Annotations | java.lang.InstantiationException: whitecat.proxy_roled_1_24325842 | at java.lang.Class.newInstance0(Class.java:340) | at java.lang.Class.newInstance(Class.java:308) | at whitecat.core.RoleEngine.findClass(RoleEngine.java:701) | at whitecat.core.RoleEngine.injectAnnotation(RoleEngine.java:538) | at whitecat.example.ExampleMain.run(ExampleMain.java:132) | at java.lang.Thread.run(Thread.java:619) | Any suggestion about this? View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4131943#4131943 Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4131943 ___ jboss-user mailing list jboss-user@lists.jboss.org https://lists.jboss.org/mailman/listinfo/jboss-user
[jboss-user] [Javassist user questions] - Re: adding annotations
This is what I've tried to do in my class loader: | subProxyClassName += this.getSubClassNameSuffix(); | | // make a new class and prepare the annotation | ClassFile classFile = new ClassFile( false, subProxyClassName, baseProxyClass.getName() ); | ConstPool constantPool = classFile.getConstPool(); | AnnotationsAttribute attribute = new AnnotationsAttribute( constantPool, AnnotationsAttribute.visibleTag ); | javassist.bytecode.annotation.Annotation annotation = new javassist.bytecode.annotation.Annotation( this.annotationClassName, constantPool ); | attribute.setAnnotation( annotation ); | classFile.addAttribute( attribute ); | classFile.setVersionToJava5(); | classFile.setSuperclass( baseProxyClass.getName() ); | ByteArrayOutputStream bos = new ByteArrayOutputStream(); | DataOutputStream os = new DataOutputStream( bos ); | classFile.write( os ); | bytecode = bos.toByteArray(); | return this.defineClass(subProxyClassName, bytecode, 0, bytecode.length); | The above is the findClass method of my class loader. The idea is that I have to create a subclass of the baseProxyClass (a CtClass object) and I have to add to it the annotation indicated by annotationClassName. When I return from the findClass method, the Class object I've got says me that it is a subclass of my proxy, but it cannot be instantiated as a proxy object (InstantiationError), as well as the getAnnotations() method returns an empty array. What am I doing wrong? Thanks, Luca View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4131820#4131820 Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4131820 ___ jboss-user mailing list jboss-user@lists.jboss.org https://lists.jboss.org/mailman/listinfo/jboss-user
[jboss-user] [Javassist user questions] - Re: adding annotations
Just to make it more clear: I've got a special class loader that is going to subclass a class that it must load to add specific behaviours, one of such behaviour should be an annotation. That is why I'm searching to do them thru Javassist. Any suggestion? View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4131290#4131290 Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4131290 ___ jboss-user mailing list jboss-user@lists.jboss.org https://lists.jboss.org/mailman/listinfo/jboss-user
[jboss-user] [Javassist user questions] - Re: adding annotations
I'm not sure about the use of an agent, because it will perform the annotation addition at the program load time, while I have to perform it depending on run-time conditions at class loading time, and most important I could have separate class loaders that add or not the annotations to the class they are loading. Is this possible with the agents? View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4131005#4131005 Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4131005 ___ jboss-user mailing list jboss-user@lists.jboss.org https://lists.jboss.org/mailman/listinfo/jboss-user
[jboss-user] [Javassist user questions] - Re: adding annotations
To add annotation to a class on load time the cleaner way to do it is to use javaagent. See: http://javahowto.blogspot.com/2006/07/javaagent-option.html Guy View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4130933#4130933 Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4130933 ___ jboss-user mailing list jboss-user@lists.jboss.org https://lists.jboss.org/mailman/listinfo/jboss-user
[jboss-user] [Javassist user questions] - Re: adding annotations
Hi, thanks for your reply, I was having a look at annotation_attribute, annotationwriter and annotationattribute, and now I've got a doubt: is the annotation only stored in the class file? Because what I'd like to obtain is to "inject" an annotation into a class (Runtime retention) when the class is loaded, without modifying the class file. But if I use the ClassFile object I have to modify the class file on the disk, is this correct? Is there a way to add an annotation at load time? Thanks, Luca View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4130748#4130748 Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4130748 ___ jboss-user mailing list jboss-user@lists.jboss.org https://lists.jboss.org/mailman/listinfo/jboss-user
[jboss-user] [Javassist user questions] - Re: adding annotations
Hi Luca, Check the AnnotationsAttribute JDoc. ClassFile cf = ... ; ConstPool cp = cf.getConstPool(); AnnotationsAttribute attr = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag); Annotation a = new Annotation("Author", cp); a.addMemberValue("name", new StringMemberValue("Chiba", cp)); attr.setAnnotation(a); cf.addAttribute(attr); cf.setVersionToJava5(); Guy View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4130552#4130552 Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4130552 ___ jboss-user mailing list jboss-user@lists.jboss.org https://lists.jboss.org/mailman/listinfo/jboss-user