felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From clem...@apache.org
Subject svn commit: r1327153 - in /felix/trunk/ipojo/manipulator/manipulator: ./ src/main/java/org/apache/felix/ipojo/manipulation/ src/main/java/org/apache/felix/ipojo/manipulation/annotations/ src/test/java/org/apache/felix/ipojo/manipulation/ src/test/java/...
Date Tue, 17 Apr 2012 16:06:56 GMT
Author: clement
Date: Tue Apr 17 16:06:55 2012
New Revision: 1327153

URL: http://svn.apache.org/viewvc?rev=1327153&view=rev
Log:
Fix FELIX-3461 - Issue with collected metadata and manipulation metadata on re-manipulation

* Fix the constructor argument shift by not moving the annotations
* Fix the method name when it is a manipulated method
* Cleanup the manipulation metadata


Added:
    felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ClassCheckerTestCase.java
    felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/FakeAnnotation.java
Modified:
    felix/trunk/ipojo/manipulator/manipulator/pom.xml
    felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
    felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
    felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java
    felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java
    felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MethodCollector.java
    felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ManipulatorTest.java
    felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/AnnotatedComponent.java

Modified: felix/trunk/ipojo/manipulator/manipulator/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/pom.xml?rev=1327153&r1=1327152&r2=1327153&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/pom.xml (original)
+++ felix/trunk/ipojo/manipulator/manipulator/pom.xml Tue Apr 17 16:06:55 2012
@@ -55,12 +55,18 @@
             <artifactId>org.apache.felix.ipojo.annotations</artifactId>
             <version>1.8.0</version>
         </dependency>
-        <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-all</artifactId>
-            <version>1.8.5</version>
-            <scope>test</scope>
-        </dependency>
+      <dependency>
+          <groupId>org.mockito</groupId>
+          <artifactId>mockito-all</artifactId>
+          <version>1.8.5</version>
+          <scope>test</scope>
+      </dependency>
+      <dependency>
+          <groupId>org.osgi</groupId>
+          <artifactId>org.osgi.core</artifactId>
+          <version>4.2.0</version>
+          <scope>test</scope>
+      </dependency>
     </dependencies>
     <build>
         <plugins>
@@ -140,9 +146,10 @@
                 <directory>.</directory>
                 <targetPath>META-INF</targetPath>
                 <includes>
-                    <include>LICENSE*</include>
-                    <include>NOTICE*</include>
-                    <include>DEPENDENCIES*</include>
+                    <include>LICENSE</include>
+                    <include>LICENSE.asm</include>
+                    <include>NOTICE</include>
+                    <include>DEPENDENCIES</include>
                 </includes>
             </resource>
         </resources>

Modified: felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java?rev=1327153&r1=1327152&r2=1327153&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java (original)
+++ felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java Tue Apr 17 16:06:55 2012
@@ -102,6 +102,10 @@ public class ClassChecker extends EmptyV
             return null;
         }
 
+        if (isManipulatedField(name)) {
+            return null;
+        }
+
         Type type = Type.getType(desc);
         if (type.getSort() == Type.ARRAY) {
             if (type.getInternalName().startsWith("L")) {
@@ -120,6 +124,12 @@ public class ClassChecker extends EmptyV
         return null;
     }
 
+    private boolean isManipulatedField(String name) {
+        return ((MethodCreator.IM_FIELD.equals(name))
+                || (name.startsWith(MethodCreator.FIELD_FLAG_PREFIX))
+                || (name.startsWith(MethodCreator.METHOD_FLAG_PREFIX)));
+    }
+
     /**
      * Add the inner class to the list of inner class to manipulate.
      * The method checks that the inner class is really owned by the implementation class.
@@ -189,17 +199,16 @@ public class ClassChecker extends EmptyV
         if (!name.equals("<clinit>")) {
 
             if (name.equals("<init>")) {
-                final MethodDescriptor md = new MethodDescriptor("$init", desc);
-                m_methods.add(md);
-                if (m_supportAnnotation) {
-                    return new AnnotationCollector(md);
+                if (!isGeneratedConstructor(name, desc)) {
+                    final MethodDescriptor md = new MethodDescriptor("$init", desc);
+                    m_methods.add(md);
+                    if (m_supportAnnotation) {
+                        return new AnnotationCollector(md);
+                    }
                 }
             } else {
                 // no constructors.
-                if (!(name.startsWith("_get") || // Avoid getter method
-                        name.startsWith("_set") || // Avoid setter method
-                        name.equals("_setComponentManager") || // Avoid the set method
-                        name.equals("getComponentInstance"))) { // Avoid the getComponentInstance method
+                if (!isGeneratedMethod(name, desc)) {
                     final MethodDescriptor md = new MethodDescriptor(name, desc);
                     m_methods.add(md);
                     if (m_supportAnnotation) {
@@ -213,6 +222,56 @@ public class ClassChecker extends EmptyV
         return null;
     }
 
+    private boolean isGeneratedConstructor(String name, String desc) {
+        return ("<init>".equals(name) && isFirstArgumentInstanceManager(desc));
+    }
+
+    private boolean isFirstArgumentInstanceManager(String desc) {
+        Type[] types = Type.getArgumentTypes(desc);
+        if (types != null && (types.length >= 1)) {
+            return Type.getType("Lorg/apache/felix/ipojo/InstanceManager;")
+                            .equals(types[0]);
+        }
+        return false;
+    }
+
+    private boolean isGeneratedMethod(String name, String desc) {
+        return isGetterMethod(name, desc)
+                || isSetterMethod(name, desc)
+                || isSetInstanceManagerMethod(name)
+                || isGetComponentInstanceMethod(name, desc)
+                || isManipulatedMethod(name);
+    }
+
+    private boolean isGetterMethod(String name, String desc) {
+        // TYPE __getXXX()
+        Type[] arguments = Type.getArgumentTypes(desc);
+        return (name.startsWith("__get")
+                && (arguments.length == 0)
+                && !Type.VOID_TYPE.equals(Type.getReturnType(desc)));
+    }
+
+    private boolean isSetterMethod(String name, String desc) {
+        // void __setXXX(TYPE)
+        Type[] arguments = Type.getArgumentTypes(desc);
+        return (name.startsWith("__set")
+                && (arguments.length == 1)
+                && Type.VOID_TYPE.equals(Type.getReturnType(desc)));
+    }
+
+    private boolean isSetInstanceManagerMethod(String name) {
+        return name.startsWith("_setInstanceManager");
+    }
+
+    private boolean isGetComponentInstanceMethod(String name, String desc) {
+        return (name.startsWith("getComponentInstance")
+                && Type.getType("Lorg/apache/felix/ipojo/ComponentInstance;").equals(Type.getReturnType(desc)));
+    }
+
+    private boolean isManipulatedMethod(String name) {
+        return (name.startsWith(MethodCreator.PREFIX));
+    }
+
     /**
      * Get collected interfaces.
      * @return the interfaces implemented by the component class.
@@ -293,6 +352,18 @@ public class ClassChecker extends EmptyV
                 m_method.addParameterAnnotation(id, ann);
                 return ann;
             }
+            
+            /*
+             * It is harmless to keep injected parameter annotations on original constructor
+             * for correct property resolution in case of re-manipulation
+             */
+            if(m_method.getName().equals("$init"))
+            {
+            	AnnotationDescriptor ann = new AnnotationDescriptor(name, visible);
+                m_method.addParameterAnnotation(id, ann);
+                return ann;
+            }
+            
             return null;
         }
 

Modified: felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java?rev=1327153&r1=1327152&r2=1327153&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java (original)
+++ felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java Tue Apr 17 16:06:55 2012
@@ -20,10 +20,14 @@ package org.apache.felix.ipojo.manipulat
 
 import java.util.Set;
 
+import org.apache.felix.ipojo.manipulation.ClassChecker.AnnotationDescriptor;
+import org.apache.felix.ipojo.manipulation.annotations.CustomAnnotationVisitor;
+import org.apache.felix.ipojo.manipulation.annotations.MetadataCollector;
 import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
 import org.objectweb.asm.commons.GeneratorAdapter;
 
 
@@ -32,6 +36,7 @@ import org.objectweb.asm.commons.Generat
  * This class adds an instance manager argument (so switch variable index).
  * Moreover, it adapts field accesses to delegate accesses to the instance
  * manager if needed.
+ *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class ConstructorCodeAdapter extends GeneratorAdapter implements Opcodes {
@@ -61,12 +66,13 @@ public class ConstructorCodeAdapter exte
     /**
      * PropertyCodeAdapter constructor.
      * A new FiledCodeAdapter should be create for each method visit.
-     * @param mv the MethodVisitor
-     * @param owner the name of the class
+     *
+     * @param mv     the MethodVisitor
+     * @param owner  the name of the class
      * @param fields the list of contained fields
      * @param access the constructor access
-     * @param desc the constructor descriptor
-     * @param name the name
+     * @param desc   the constructor descriptor
+     * @param name   the name
      */
     public ConstructorCodeAdapter(final MethodVisitor mv, final String owner, Set<String> fields, int access, String name, String desc, String superClass) {
         super(mv, access, name, desc);
@@ -81,10 +87,11 @@ public class ConstructorCodeAdapter exte
      * If the annotation is visible, the annotation is removed. In fact
      * the annotation was already moved to the method replacing this one.
      * If the annotation is not visible, this annotation is kept on this method.
-     * @param name the name of the annotation
+     *
+     * @param name    the name of the annotation
      * @param visible the annotation visibility
      * @return the <code>null</code> if the annotation is visible, otherwise returns
-     * {@link GeneratorAdapter#visitAnnotation(String, boolean)}
+     *         {@link GeneratorAdapter#visitAnnotation(String, boolean)}
      * @see org.objectweb.asm.MethodAdapter#visitAnnotation(java.lang.String, boolean)
      */
     public AnnotationVisitor visitAnnotation(String name, boolean visible) {
@@ -96,6 +103,37 @@ public class ConstructorCodeAdapter exte
         }
     }
 
+    /**
+     * Visits a parameter annotation.
+     * Parameter annotations are moved to replacing constructor except
+     * they are injection annotations(-@Property and -@Requires).
+     * Because injection annotations shouldn't be copied to generated one
+     * in case of re-manipulation, since this is caused to wrong type resolution
+     * of injected parameters.
+     *
+     * @param parameter parameter index
+     * @param desc      annotation description(annotation name)
+     * @param visible   is parameter annotation visible
+     * @return @AnnotationVisitor
+     */
+    public AnnotationVisitor visitParameterAnnotation(
+            final int parameter,
+            final String desc,
+            final boolean visible) {
+
+        /*
+         * Generated constructor shouldn't inherit injection annotations
+         */
+        if (desc.equals("Lorg/apache/felix/ipojo/annotations/Property;")
+                || desc.equals("Lorg/apache/felix/ipojo/annotations/Requires;")
+                || CustomAnnotationVisitor.isCustomAnnotation(desc)) {
+            return null;
+        } else {
+            return super.visitParameterAnnotation(parameter, desc, visible);
+        }
+
+    }
+
 
     /**
      * Adapts field accesses.
@@ -104,11 +142,12 @@ public class ConstructorCodeAdapter exte
      * <li><code>GETFIELD</code> are changed to a <code>__getX</code> invocation.</li>
      * <li><code>SETFIELD</code> are changed to a <code>__setX</code> invocation.</li>
      * </ul>
-     * @see org.objectweb.asm.MethodVisitor#visitFieldInsn(int, String, String, String)
+     *
      * @param opcode the visited operation code
-     * @param owner the owner of the field
-     * @param name the name of the field
-     * @param desc the descriptor of the field
+     * @param owner  the owner of the field
+     * @param name   the name of the field
+     * @param desc   the descriptor of the field
+     * @see org.objectweb.asm.MethodVisitor#visitFieldInsn(int, String, String, String)
      */
     public void visitFieldInsn(
             final int opcode,
@@ -120,12 +159,11 @@ public class ConstructorCodeAdapter exte
                 String gDesc = "()" + desc;
                 mv.visitMethodInsn(INVOKEVIRTUAL, owner, "__get" + name, gDesc);
                 return;
-            } else
-                if (opcode == PUTFIELD) {
-                    String sDesc = "(" + desc + ")V";
-                    mv.visitMethodInsn(INVOKEVIRTUAL, owner, "__set" + name, sDesc);
-                    return;
-                }
+            } else if (opcode == PUTFIELD) {
+                String sDesc = "(" + desc + ")V";
+                mv.visitMethodInsn(INVOKEVIRTUAL, owner, "__set" + name, sDesc);
+                return;
+            }
         }
         super.visitFieldInsn(opcode, owner, name, desc);
     }
@@ -134,23 +172,24 @@ public class ConstructorCodeAdapter exte
      * Visits a method invocation instruction.
      * After the super constructor invocation, insert the _setComponentManager invocation.
      * Otherwise, the method invocation doesn't change
+     *
      * @param opcode the opcode
-     * @param owner the class owning the invoked method
-     * @param name the method name
-     * @param desc the method descriptor
+     * @param owner  the class owning the invoked method
+     * @param name   the method name
+     * @param desc   the method descriptor
      * @see org.objectweb.asm.MethodAdapter#visitMethodInsn(int, java.lang.String, java.lang.String, java.lang.String)
      */
     public void visitMethodInsn(int opcode, String owner, String name, String desc) {
 
         // A method call is detected, check if it is the super call :
         // the first init is not necessary the super call, so check that it is really the super class.
-        if (!m_superDetected && name.equals("<init>")  && owner.equals(m_superClass)) {
+        if (!m_superDetected && name.equals("<init>") && owner.equals(m_superClass)) {
             m_superDetected = true;
             // The first invocation is the super call
             // 1) Visit the super constructor :
 
             //mv.visitVarInsn(ALOAD, 0); The ALOAD 0 was already visited. This previous visit allows
-                                         // Super constructor parameters.
+            // Super constructor parameters.
             mv.visitMethodInsn(opcode, owner, name, desc); // Super constructor invocation
 
             // 2) Load the object and the component manager argument
@@ -171,8 +210,9 @@ public class ConstructorCodeAdapter exte
      * it is not <code>this</code> (i.e. 0). This increment
      * is due to the instance manager parameter added in the method
      * signature.
+     *
      * @param opcode the opcode
-     * @param var the variable index
+     * @param var    the variable index
      * @see org.objectweb.asm.MethodAdapter#visitVarInsn(int, int)
      */
     public void visitVarInsn(int opcode, int var) {
@@ -180,7 +220,7 @@ public class ConstructorCodeAdapter exte
             mv.visitVarInsn(opcode, var); // ALOAD 0 (THIS)
         } else {
             mv.visitVarInsn(opcode, var + 1); // All other variable index must be incremented (due to
-                                              // the instance manager argument
+            // the instance manager argument
         }
 
     }
@@ -191,7 +231,8 @@ public class ConstructorCodeAdapter exte
      * it is not <code>this</code> (i.e. 0). This increment
      * is due to the instance manager parameter added in the method
      * signature.
-     * @param var the variable index
+     *
+     * @param var       the variable index
      * @param increment the increment
      * @see org.objectweb.asm.MethodAdapter#visitIincInsn(int, int)
      */
@@ -208,12 +249,13 @@ public class ConstructorCodeAdapter exte
      * Adds _manager and increment others variable indexes.
      * This variable has the same scope than <code>this</code> and
      * has the <code>1</code> index.
-     * @param name the variable name
-     * @param desc the variable descriptor
+     *
+     * @param name      the variable name
+     * @param desc      the variable descriptor
      * @param signature the variable signature
-     * @param start the beginning label
-     * @param end the ending label
-     * @param index the variable index
+     * @param start     the beginning label
+     * @param end       the ending label
+     * @param index     the variable index
      * @see org.objectweb.asm.MethodAdapter#visitLocalVariable(java.lang.String, java.lang.String, java.lang.String, org.objectweb.asm.Label, org.objectweb.asm.Label, int)
      */
     public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
@@ -228,7 +270,8 @@ public class ConstructorCodeAdapter exte
      * Visit max method.
      * The stack size is incremented of 1. The
      * local variable count is incremented of 2.
-     * @param maxStack the stack size.
+     *
+     * @param maxStack  the stack size.
      * @param maxLocals the local variable count.
      * @see org.objectweb.asm.MethodAdapter#visitMaxs(int, int)
      */

Modified: felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java?rev=1327153&r1=1327152&r2=1327153&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java (original)
+++ felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java Tue Apr 17 16:06:55 2012
@@ -59,12 +59,12 @@ public class MethodCreator extends Class
     /**
      * Filed flag prefix.
      */
-    private static final  String FIELD_FLAG_PREFIX = "__F";
+    public static final  String FIELD_FLAG_PREFIX = "__F";
 
     /**
      * Method flag prefix.
      */
-    private static final  String METHOD_FLAG_PREFIX = "__M";
+    public static final  String METHOD_FLAG_PREFIX = "__M";
 
     /**
      * onEntry method name.

Modified: felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java?rev=1327153&r1=1327152&r2=1327153&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java (original)
+++ felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java Tue Apr 17 16:06:55 2012
@@ -100,7 +100,7 @@ public class CustomAnnotationVisitor ext
      * @param root is the annotation a root
      * @param clazz the annotation is a class annotation.
      * @param index the index of the argument
-     * @param the descriptor of the method
+     * @param descriptor the descriptor of the method
      */
     public CustomAnnotationVisitor(Element elem, MetadataCollector collector, boolean root, boolean clazz, int index, String descriptor) {
         m_elem = elem;

Modified: felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MethodCollector.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MethodCollector.java?rev=1327153&r1=1327152&r2=1327153&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MethodCollector.java (original)
+++ felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MethodCollector.java Tue Apr 17 16:06:55 2012
@@ -18,6 +18,7 @@
  */
 package org.apache.felix.ipojo.manipulation.annotations;
 
+import org.apache.felix.ipojo.manipulation.MethodCreator;
 import org.apache.felix.ipojo.metadata.Attribute;
 import org.apache.felix.ipojo.metadata.Element;
 import org.objectweb.asm.AnnotationVisitor;
@@ -26,6 +27,7 @@ import org.objectweb.asm.commons.EmptyVi
 
 /**
  * This class collects method annotations, and give them to the metadata collector.
+ *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class MethodCollector extends EmptyVisitor {
@@ -47,7 +49,8 @@ public class MethodCollector extends Emp
 
     /**
      * Constructor.
-     * @param name : name of the method.
+     *
+     * @param name      : name of the method.
      * @param collector : parent collector.
      */
     public MethodCollector(String name, String descriptor, MetadataCollector collector) {
@@ -58,10 +61,11 @@ public class MethodCollector extends Emp
 
     /**
      * Visit a parameter annotation.
+     *
      * @see org.objectweb.asm.commons.EmptyVisitor#visitParameterAnnotation(int, java.lang.String, boolean)
      */
     public AnnotationVisitor visitParameterAnnotation(int index, String annotation,
-            boolean visible) {
+                                                      boolean visible) {
         if (m_name.equals("<init>")) {
             if (annotation.equals("Lorg/apache/felix/ipojo/annotations/Property;")) {
                 return processProperty(true, index);
@@ -80,9 +84,9 @@ public class MethodCollector extends Emp
     }
 
 
-
     /**
      * Visit method annotations.
+     *
      * @param arg0 : annotation name.
      * @param arg1 : is the annotation visible at runtime.
      * @return the visitor paring the visited annotation.
@@ -119,7 +123,7 @@ public class MethodCollector extends Emp
 
         if (CustomAnnotationVisitor.isCustomAnnotation(arg0)) {
             Element elem = CustomAnnotationVisitor.buildElement(arg0);
-            elem.addAttribute(new Attribute("method", m_name));
+            elem.addAttribute(new Attribute("method", computeEffectiveMethodName(m_name)));
             return new CustomAnnotationVisitor(elem, m_collector, true, false);
         }
 
@@ -128,11 +132,12 @@ public class MethodCollector extends Emp
 
     /**
      * Process @Updated annotation.
+     *
      * @return null.
      */
     private AnnotationVisitor processUpdated() {
         Element parent = null;
-        if (! m_collector.getIds().containsKey("properties")) {
+        if (!m_collector.getIds().containsKey("properties")) {
             parent = new Element("Properties", "");
             m_collector.getIds().put("properties", parent);
             m_collector.getElements().put(parent, null);
@@ -147,6 +152,7 @@ public class MethodCollector extends Emp
 
     /**
      * Process @PostRegistration annotation.
+     *
      * @return null.
      */
     private AnnotationVisitor processPostRegistration() {
@@ -163,6 +169,7 @@ public class MethodCollector extends Emp
 
     /**
      * Process @PostRegistration annotation.
+     *
      * @return null.
      */
     private AnnotationVisitor processPostUnregistration() {
@@ -179,6 +186,7 @@ public class MethodCollector extends Emp
 
     /**
      * Process @bind, @modified, @unbind.
+     *
      * @param type : bind or unbind
      * @return the visitor parsing @bind & @unbind annotations.
      */
@@ -188,37 +196,40 @@ public class MethodCollector extends Emp
 
     /**
      * Process @validate annotation.
+     *
      * @return null.
      */
     private AnnotationVisitor processValidate() {
         Element cb = new Element("callback", "");
         cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("transition", "validate"));
-        cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("method", m_name));
+        cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("method", computeEffectiveMethodName(m_name)));
         m_collector.getElements().put(cb, null);
         return null;
     }
 
     /**
      * Process @invalidate annotation.
+     *
      * @return null.
      */
     private AnnotationVisitor processInvalidate() {
         Element cb = new Element("callback", "");
         cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("transition", "invalidate"));
-        cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("method", m_name));
+        cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("method", computeEffectiveMethodName(m_name)));
         m_collector.getElements().put(cb, null);
         return null;
     }
 
     /**
      * Process @property annotation.
+     *
      * @param parameter true if we're processing a parameter
-     * @param index the index, meaningful only if parameter is true
+     * @param index     the index, meaningful only if parameter is true
      * @return the visitor parsing the visited annotation.
      */
     private AnnotationVisitor processProperty(boolean parameter, int index) {
         Element prop = null;
-        if (! m_collector.getIds().containsKey("properties")) {
+        if (!m_collector.getIds().containsKey("properties")) {
             prop = new Element("Properties", "");
             m_collector.getIds().put("properties", prop);
             m_collector.getElements().put(prop, null);
@@ -291,6 +302,7 @@ public class MethodCollector extends Emp
 
         /**
          * Constructor.
+         *
          * @param bind : method name.
          * @param type : is the callback a bind or an unbind method.
          */
@@ -305,6 +317,7 @@ public class MethodCollector extends Emp
 
         /**
          * Visit annotation attribute.
+         *
          * @param arg0 : annotation name
          * @param arg1 : annotation value
          * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
@@ -349,20 +362,23 @@ public class MethodCollector extends Emp
         /**
          * End of the visit.
          * Create or append the requirement info to a created or already existing "requires" element.
+         *
          * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
          */
         public void visitEnd() {
             if (m_id == null) {
-                if (m_name != null  && m_name.startsWith("bind")) {
-                    m_id = m_name.substring("bind".length());
-                } else if (m_name != null  && m_name.startsWith("unbind")) {
-                    m_id = m_name.substring("unbind".length());
-                } else if (m_name != null  && m_name.startsWith("modified")) {
-                    m_id = m_name.substring("modified".length());
+                String effectiveName = computeEffectiveMethodName(m_name);
+
+                if (effectiveName != null && effectiveName.startsWith("bind")) {
+                    m_id = effectiveName.substring("bind".length());
+                } else if (effectiveName != null && effectiveName.startsWith("unbind")) {
+                    m_id = effectiveName.substring("unbind".length());
+                } else if (effectiveName != null && effectiveName.startsWith("modified")) {
+                    m_id = effectiveName.substring("modified".length());
                 } else if (m_index != -1) {
                     m_id = "" + m_index;
                 } else {
-                    System.err.println("Cannot determine the id of the " + m_type + " method : " + m_name);
+                    System.err.println("Cannot determine the id of the " + m_type + " method : " + effectiveName);
                     return;
                 }
             }
@@ -407,7 +423,7 @@ public class MethodCollector extends Emp
                 if (m_specification != null) {
                     if (itf == null) {
                         req.addAttribute(new Attribute("specification", m_specification));
-                    } else if (! m_specification.equals(itf)) {
+                    } else if (!m_specification.equals(itf)) {
                         System.err.println("The required specification is not the same as previouly : " + m_specification + " & " + itf);
                         return;
                     }
@@ -416,7 +432,7 @@ public class MethodCollector extends Emp
                 if (m_optional != null) {
                     if (optional == null) {
                         req.addAttribute(new Attribute("optional", m_optional));
-                    } else if (! m_optional.equals(optional)) {
+                    } else if (!m_optional.equals(optional)) {
                         System.err.println("The optional attribute is not always the same");
                         return;
                     }
@@ -425,7 +441,7 @@ public class MethodCollector extends Emp
                 if (m_aggregate != null) {
                     if (aggregate == null) {
                         req.addAttribute(new Attribute("aggregate", m_aggregate));
-                    } else if (! m_aggregate.equals(aggregate)) {
+                    } else if (!m_aggregate.equals(aggregate)) {
                         System.err.println("The aggregate attribute is not always the same");
                         return;
                     }
@@ -434,7 +450,7 @@ public class MethodCollector extends Emp
                 if (m_filter != null) {
                     if (filter == null) {
                         req.addAttribute(new Attribute("filter", m_filter));
-                    } else if (! m_filter.equals(filter)) {
+                    } else if (!m_filter.equals(filter)) {
                         System.err.println("The filter attribute is not always the same");
                         return;
                     }
@@ -443,7 +459,7 @@ public class MethodCollector extends Emp
                 if (m_policy != null) {
                     if (policy == null) {
                         req.addAttribute(new Attribute("policy", m_policy));
-                    } else if (! m_policy.equals(policy)) {
+                    } else if (!m_policy.equals(policy)) {
                         System.err.println("The policy attribute is not always the same");
                         return;
                     }
@@ -452,7 +468,7 @@ public class MethodCollector extends Emp
                 if (m_comparator != null) {
                     if (comparator == null) {
                         req.addAttribute(new Attribute("comparator", m_comparator));
-                    } else if (! m_comparator.equals(comparator)) {
+                    } else if (!m_comparator.equals(comparator)) {
                         System.err.println("The comparator attribute is not always the same");
                         return;
                     }
@@ -461,7 +477,7 @@ public class MethodCollector extends Emp
                 if (m_from != null) {
                     if (from == null) {
                         req.addAttribute(new Attribute("from", m_from));
-                    } else if (! m_from.equals(from)) {
+                    } else if (!m_from.equals(from)) {
                         System.err.println("The from attribute is not always the same");
                         return;
                     }
@@ -470,7 +486,7 @@ public class MethodCollector extends Emp
             }
             if (m_name != null) {
                 Element method = new Element("callback", "");
-                method.addAttribute(new Attribute("method", m_name));
+                method.addAttribute(new Attribute("method", computeEffectiveMethodName(m_name)));
                 method.addAttribute(new Attribute("type", m_type));
                 req.addElement(method);
             } else {
@@ -527,10 +543,11 @@ public class MethodCollector extends Emp
 
         /**
          * Constructor.
+         *
          * @param parent : parent element.
          * @param method : attached method.
-         * @param param : we're processing a parameter
-         * @param index : the parameter index
+         * @param param  : we're processing a parameter
+         * @param index  : the parameter index
          */
         private PropertyAnnotationParser(Element parent, String method, boolean param, int index) {
             m_parent = parent;
@@ -541,6 +558,7 @@ public class MethodCollector extends Emp
 
         /**
          * Visit annotation attributes.
+         *
          * @param arg0 : annotation name
          * @param arg1 : annotation value
          * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
@@ -567,17 +585,20 @@ public class MethodCollector extends Emp
         /**
          * End of the visit.
          * Append the computed element to the parent element.
+         *
          * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
          */
         public void visitEnd() {
+            m_method = computeEffectiveMethodName(m_method);
+
             // If neither name not id, try to extract the name
-            if (m_name == null && m_id == null  && m_method.startsWith("set")) {
+            if (m_name == null && m_id == null && m_method.startsWith("set")) {
                 m_name = m_method.substring("set".length());
                 m_id = m_name;
-            // Else align the two values
-            } else if (m_name != null  && m_id == null) {
+                // Else align the two values
+            } else if (m_name != null && m_id == null) {
                 m_id = m_name;
-            } else if (m_id != null  && m_name == null) {
+            } else if (m_id != null && m_name == null) {
                 m_name = m_id;
             }
 
@@ -615,4 +636,19 @@ public class MethodCollector extends Emp
 
         }
     }
+
+    /**
+     * Computes the real method name. This method is useful when the annotation is collected on an manipulated method
+     * (prefixed by <code>__M_</code>). This method just removes the prefix if found.
+     * @param name the collected method name
+     * @return the effective method name, can be the collected method name if the method name does not start with
+     * the prefix.
+     */
+    public static String computeEffectiveMethodName(String name) {
+        if (name != null && name.startsWith(MethodCreator.PREFIX)) {
+            return name.substring(MethodCreator.PREFIX.length());
+        } else {
+            return name;
+        }
+    }
 }

Added: felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ClassCheckerTestCase.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ClassCheckerTestCase.java?rev=1327153&view=auto
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ClassCheckerTestCase.java (added)
+++ felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ClassCheckerTestCase.java Tue Apr 17 16:06:55 2012
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulation;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.EmptyVisitor;
+import org.osgi.framework.BundleContext;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ClassCheckerTestCase extends TestCase {
+
+    public void testIsAlreadyManipulatedWithNotManipulatedResource() throws Exception {
+        ClassChecker checker = check(resource("test/SimplePojo.class"));
+        assertFalse(checker.isalreadyManipulated());
+    }
+
+    public void testIsAlreadyManipulatedWithManipulatedResource() throws Exception {
+        ClassChecker checker = check(manipulate(resource("test/SimplePojo.class")));
+        assertTrue(checker.isalreadyManipulated());
+    }
+
+    public void testMetadataForAlreadyManipulatedClassAreCleaned() throws Exception {
+        ClassChecker checker = check(manipulate(resource("test/AnnotatedComponent.class")));
+
+        // Check implemented interfaces
+        List<String> interfaces = checker.getInterfaces();
+        assertTrue(interfaces.isEmpty());
+
+        // Check super class
+        assertNull(checker.getSuperClass());
+
+        // Check inner classes
+        List<String> inner = checker.getInnerClasses();
+        assertTrue(inner.isEmpty());
+
+        // Ensure fields are correctly filtered
+        Map<String, String> fields = checker.getFields();
+        assertEquals(1, fields.size());
+        assertEquals("java.lang.String", fields.get("prop"));
+
+        // Ensure methods are also correctly filtered
+        List<MethodDescriptor> descriptors = checker.getMethods();
+        assertEquals(2, descriptors.size());
+
+        // AnnotatedComponent(BundleContext)
+        MethodDescriptor constructor = searchMethod("$init", descriptors);
+        assertNotNull(constructor);
+        Type[] arguments = Type.getArgumentTypes(constructor.getDescriptor());
+        assertEquals(1, arguments.length);
+        assertEquals(Type.getType(BundleContext.class), arguments[0]);
+
+        // @FakeAnnotation
+        // AnnotatedComponent.annotatedMethod():Void
+        MethodDescriptor method = searchMethod("annotatedMethod", descriptors);
+        assertNotNull(method);
+        assertEquals("()V", method.getDescriptor()); // return void + no params
+        assertAnnotationIsAlone(method, "Ltest/FakeAnnotation;");
+
+
+    }
+
+    private void assertAnnotationIsAlone(MethodDescriptor method, String desc) {
+        List<ClassChecker.AnnotationDescriptor> annotations = method.getAnnotations();
+
+        assertEquals(1, annotations.size());
+        ClassChecker.AnnotationDescriptor annotationDescriptor = annotations.get(0);
+        MethodVisitor mv = mock(MethodVisitor.class);
+        when(mv.visitAnnotation(desc, true)).thenReturn(new EmptyVisitor());
+        annotationDescriptor.visitAnnotation(mv);
+    }
+
+    private MethodDescriptor searchMethod(String methodName, List<MethodDescriptor> descriptors) {
+        for (MethodDescriptor descriptor : descriptors) {
+            if (methodName.equals(descriptor.getName())) {
+                return descriptor;
+            }
+        }
+
+        return null;
+    }
+
+    private byte[] manipulate(byte[] input) throws Exception {
+        Manipulator manipulator = new Manipulator();
+        return manipulator.manipulate(input);
+    }
+
+    private byte[] resource(String name) throws Exception {
+        return ManipulatorTest.getBytesFromFile(new File("target/test-classes/" + name));
+    }
+
+    private ClassChecker check(byte[] resource) throws Exception {
+        ClassChecker checker = new ClassChecker();
+        ByteArrayInputStream is = new ByteArrayInputStream(resource);
+        try {
+            ClassReader classReader = new ClassReader(is);
+            classReader.accept(checker, ClassReader.SKIP_FRAMES);
+        } finally {
+            Streams.close(is);
+        }
+        return checker;
+    }
+}

Modified: felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ManipulatorTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ManipulatorTest.java?rev=1327153&r1=1327152&r2=1327153&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ManipulatorTest.java (original)
+++ felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ManipulatorTest.java Tue Apr 17 16:06:55 2012
@@ -29,7 +29,6 @@ import junit.framework.TestCase;
 
 import org.apache.felix.ipojo.InstanceManager;
 import org.apache.felix.ipojo.Pojo;
-import org.apache.felix.ipojo.manipulation.annotations.MetadataCollector;
 import org.mockito.Mockito;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.util.CheckClassAdapter;
@@ -39,7 +38,7 @@ public class ManipulatorTest extends Tes
     public void testClusterDaemon() throws Exception {
         Manipulator manipulator = new Manipulator();
         byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/ClusterDaemon.class")));
-        TestClassLoader classloader = new TestClassLoader("test.ClusterDaemon", clazz);
+        ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.ClusterDaemon", clazz);
 
         //Assert.assertNotNull(manipulator.getManipulationMetadata());
 
@@ -62,7 +61,7 @@ public class ManipulatorTest extends Tes
     public void testManipulatingTheSimplePojo() throws Exception {
         Manipulator manipulator = new Manipulator();
         byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/SimplePojo.class")));
-        TestClassLoader classloader = new TestClassLoader("test.SimplePojo", clazz);
+        ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.SimplePojo", clazz);
         Class cl = classloader.findClass("test.SimplePojo");
         Assert.assertNotNull(cl);
         Assert.assertNotNull(manipulator.getManipulationMetadata());
@@ -113,7 +112,7 @@ public class ManipulatorTest extends Tes
     public void testManipulatingChild() throws Exception {
         Manipulator manipulator = new Manipulator();
         byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/Child.class")));
-        TestClassLoader classloader = new TestClassLoader("test.Child", clazz);
+        ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.Child", clazz);
         Class cl = classloader.findClass("test.Child");
         Assert.assertNotNull(cl);
         Assert.assertNotNull(manipulator.getManipulationMetadata());
@@ -160,7 +159,7 @@ public class ManipulatorTest extends Tes
     public void _testManipulatingTheInner() throws Exception {
         Manipulator manipulator = new Manipulator();
         byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/PojoWithInner.class")));
-        TestClassLoader classloader = new TestClassLoader("test.PojoWithInner", clazz);
+        ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.PojoWithInner", clazz);
         Class cl = classloader.findClass("test.PojoWithInner");
         Assert.assertNotNull(cl);
         Assert.assertNotNull(manipulator.getManipulationMetadata());
@@ -214,7 +213,7 @@ public class ManipulatorTest extends Tes
     public void testManipulatingWithConstructorModification() throws Exception {
         Manipulator manipulator = new Manipulator();
         byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/Child.class")));
-        TestClassLoader classloader = new TestClassLoader("test.Child", clazz);
+        ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.Child", clazz);
         Class cl = classloader.findClass("test.Child");
         Assert.assertNotNull(cl);
         Assert.assertNotNull(manipulator.getManipulationMetadata());
@@ -279,7 +278,7 @@ public class ManipulatorTest extends Tes
     public void testManipulatingWithNoValidConstructor() throws Exception {
         Manipulator manipulator = new Manipulator();
         byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/NoValidConstructor.class")));
-        TestClassLoader classloader = new TestClassLoader("test.NoValidConstructor", clazz);
+        ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.NoValidConstructor", clazz);
         Class cl = classloader.findClass("test.NoValidConstructor");
         Assert.assertNotNull(cl);
         Assert.assertNotNull(manipulator.getManipulationMetadata());
@@ -322,7 +321,7 @@ public class ManipulatorTest extends Tes
 //        fos.write(clazz);
 //        fos.close();
 
-        TestClassLoader classloader = new TestClassLoader("test.ConstructorCheck", clazz);
+        ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.ConstructorCheck", clazz);
         Class cl = classloader.findClass("test.ConstructorCheck");
         Assert.assertNotNull(cl);
         Assert.assertNotNull(manipulator.getManipulationMetadata());
@@ -337,6 +336,8 @@ public class ManipulatorTest extends Tes
         Assert.assertEquals("toto", f.get(o));
      }
 
+
+
     public static byte[] getBytesFromFile(File file) throws IOException {
         InputStream is = new FileInputStream(file);
         long length = file.length();
@@ -360,29 +361,6 @@ public class ManipulatorTest extends Tes
         return bytes;
     }
 
-    class TestClassLoader extends ClassLoader {
 
-        private String name;
-        private byte[] clazz;
-
-        public TestClassLoader(String name, byte[] clazz) {
-            this.name = name;
-            this.clazz = clazz;
-        }
-
-        public Class findClass(String name) throws ClassNotFoundException {
-            if (name.equals(this.name)) {
-                return defineClass(name, clazz, 0, clazz.length);
-            }
-            return super.findClass(name);
-        }
-
-        public Class loadClass(String arg0) throws ClassNotFoundException {
-            return super.loadClass(arg0);
-        }
-
-
-
-    }
 
 }

Modified: felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/AnnotatedComponent.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/AnnotatedComponent.java?rev=1327153&r1=1327152&r2=1327153&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/AnnotatedComponent.java (original)
+++ felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/AnnotatedComponent.java Tue Apr 17 16:06:55 2012
@@ -20,10 +20,19 @@ package test;
 
 import org.apache.felix.ipojo.annotations.Component;
 import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.osgi.framework.BundleContext;
 
 @Component
 public class AnnotatedComponent {
 
     @Property
     private String prop;
+
+    public AnnotatedComponent(BundleContext bundleContext) {}
+
+    @FakeAnnotation
+    public void annotatedMethod() {
+
+    }
 }

Added: felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/FakeAnnotation.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/FakeAnnotation.java?rev=1327153&view=auto
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/FakeAnnotation.java (added)
+++ felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/FakeAnnotation.java Tue Apr 17 16:06:55 2012
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package test;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A {@code FakeAnnotation} is ...
+ *
+ * @author Guillaume Sauthier
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface FakeAnnotation {
+}



Mime
View raw message