Fix the issue Felix-739.
Visible annotations on methods are now moved to iPOJO methods replacing those methods.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@701987 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
index 4a3f354..71b3837 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
@@ -23,6 +23,7 @@
import java.util.List;
import java.util.Map;
+import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
@@ -71,6 +72,12 @@
* List of visited inner class owned by the implementation class.
*/
private List m_inners = new ArrayList();
+
+ /**
+ * <code>true</code> if the class supports annotations.
+ * This enables the analysis of the code to find and moves annotations.
+ */
+ private boolean m_supportAnnotation = false;
/**
* Check if the _cm field already exists.
@@ -150,6 +157,8 @@
*/
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
+
+ m_supportAnnotation = version > V1_4 && version < V1_1;
if (! superName.equals("java/lang/Object")) {
m_superClass = superName.replace('/', '.');
@@ -180,18 +189,27 @@
if (!name.equals("<clinit>")) {
if (name.equals("<init>")) {
- m_methods.add(new MethodDescriptor("$init", desc));
+ final MethodDescriptor md = new MethodDescriptor("$init", desc);
+ m_methods.add(md);
+ if (m_supportAnnotation) {
+ return new AnnotationCollector(md);
+ }
} else {
// Avoid 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
- m_methods.add(new MethodDescriptor(name, desc));
+ final MethodDescriptor md = new MethodDescriptor(name, desc);
+ m_methods.add(md);
+ if (m_supportAnnotation) {
+ return new AnnotationCollector(md);
+ }
}
}
- }
+ }
+
return null;
}
@@ -226,5 +244,413 @@
public List getInnerClasses() {
return m_inners;
}
+
+ /**
+ * This class collects annotations in a method.
+ * This class creates an {@link AnnotationDescriptor}
+ * if an annotation is found during the visit.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+ private final class AnnotationCollector extends EmptyVisitor {
+ /**
+ * The method descriptor of the visited method.
+ */
+ private MethodDescriptor m_method;
+
+ /**
+ * Creates an annotation collector.
+ * @param md the method descriptor of the visited method.
+ */
+ private AnnotationCollector(MethodDescriptor md) {
+ m_method = md;
+ }
+
+ /**
+ * Visits an annotation.
+ * This class checks the visibility. If the annotation is visible,
+ * creates the {@link AnnotationDescriptor} corresponding to this annotation
+ * to visit this annotation. This {@link AnnotationDescriptor} is added to
+ * the {@link MethodDescriptor} of the visited method.
+ * @param name the name of the annotation
+ * @param visible is the annotation visible at runtime
+ * @return the {@link AnnotationDescriptor} to visit this annotation or
+ * <code>null</code> if the annotation is not visible.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitAnnotation(java.lang.String, boolean)
+ */
+ public AnnotationVisitor visitAnnotation(String name, boolean visible) {
+ if (visible) {
+ AnnotationDescriptor ann = new AnnotationDescriptor(name, visible);
+ m_method.addAnnotation(ann);
+ return ann;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Describes a method or constructor annotation.
+ * This allows creating a copy of the annotations found in the original class
+ * to move them on inserted method. This class implements an
+ * {@link AnnotationVisitor} in order to create the copy.
+ * This class contains a <code>visit</code> method re-injecting the
+ * annotation in the generated method.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+ public class AnnotationDescriptor implements AnnotationVisitor {
+ /**
+ * The name of the annotation.
+ */
+ private String m_name;
+ /**
+ * Is the annotation visible at runtime?
+ */
+ private boolean m_visible;
+ /**
+ * The description of the annotation.
+ * This attribute is set only for nested annotations.
+ */
+ private String m_desc;
+ /**
+ * The list of 'simple' attributes.
+ */
+ private List m_simples = new ArrayList(0);
+ /**
+ * The list of attribute containing an
+ * enumeration value.
+ */
+ private List m_enums = new ArrayList(0);
+ /**
+ * The list of attribute which are
+ * annotations.
+ */
+ private List m_nested = new ArrayList(0);
+ /**
+ * The list of attribute which are
+ * arrays.
+ */
+ private List m_arrays = new ArrayList(0);
+
+
+ /**
+ * Creates an annotation descriptor.
+ * This constructor is used for 'root' annotations.
+ * @param name the name of the annotation
+ * @param visible the visibility of the annotation at runtime
+ */
+ public AnnotationDescriptor(String name, boolean visible) {
+ m_name = name;
+ m_visible = visible;
+ }
+
+ /**
+ * Creates an annotation descriptor.
+ * This constructor is used for nested annotations.
+ * @param name the name of the annotation
+ * @param desc the descriptor of the annotation
+ */
+ public AnnotationDescriptor(String name, String desc) {
+ m_name = name;
+ m_visible = true;
+ m_desc = desc;
+ }
+
+
+ /**
+ * Visits a simple attribute.
+ * @param arg0 the attribute name
+ * @param arg1 the attribute value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String arg0, Object arg1) {
+ m_simples.add(new SimpleAttribute(arg0, arg1));
+ }
+
+
+ /**
+ * Visits a nested annotation.
+ * @param arg0 the attribute name
+ * @param arg1 the annotation descriptor
+ * @return the annotation visitor parsing the nested annotation
+ * @see org.objectweb.asm.AnnotationVisitor#visitAnnotation(java.lang.String, java.lang.String)
+ */
+ public AnnotationVisitor visitAnnotation(String arg0, String arg1) {
+ AnnotationDescriptor ad = new AnnotationDescriptor(arg0, arg1);
+ m_nested.add(ad);
+ return ad;
+ }
+
+
+ /**
+ * Visits an array attribute.
+ * @param arg0 the name of the attribute
+ * @return the annotation visitor parsing the content of the array,
+ * uses a specific {@link ArrayAttribute} to parse this array
+ * @see org.objectweb.asm.AnnotationVisitor#visitArray(java.lang.String)
+ */
+ public AnnotationVisitor visitArray(String arg0) {
+ ArrayAttribute aa = new ArrayAttribute(arg0);
+ m_arrays.add(aa);
+ return aa;
+ }
+
+
+ /**
+ * End of the visit.
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() { }
+
+
+ /**
+ * Visits an enumeration attribute.
+ * @param arg0 the attribute name
+ * @param arg1 the enumeration descriptor
+ * @param arg2 the attribute value
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnum(java.lang.String, java.lang.String, java.lang.String)
+ */
+ public void visitEnum(String arg0, String arg1, String arg2) {
+ m_enums.add(new EnumAttribute(arg0, arg1, arg2));
+ }
+
+ /**
+ * Methods allowing to recreate the visited (stored) annotation
+ * into the destination method.
+ * This method recreate the annotations itself and any other
+ * attributes.
+ * @param mv the method visitor visiting the destination method.
+ */
+ public void visit(MethodVisitor mv) {
+ AnnotationVisitor av = mv.visitAnnotation(m_name, m_visible);
+ for (int i = 0; i < m_simples.size(); i++) {
+ ((SimpleAttribute) m_simples.get(i)).visit(av);
+ }
+ for (int i = 0; i < m_enums.size(); i++) {
+ ((EnumAttribute) m_enums.get(i)).visit(av);
+ }
+ for (int i = 0; i < m_nested.size(); i++) {
+ ((AnnotationDescriptor) m_nested.get(i)).visit(av);
+ }
+ for (int i = 0; i < m_arrays.size(); i++) {
+ ((ArrayAttribute) m_arrays.get(i)).visit(av);
+ }
+ av.visitEnd();
+ }
+
+ /**
+ * Method allowing to recreate the visited (stored) annotation
+ * into the destination annotation. This method is used only
+ * for nested annotation.
+ * @param mv the annotation visitor to populate with the stored
+ * annotation
+ */
+ public void visit(AnnotationVisitor mv) {
+ AnnotationVisitor av = mv.visitAnnotation(m_name, m_desc);
+ for (int i = 0; i < m_simples.size(); i++) {
+ ((SimpleAttribute) m_simples.get(i)).visit(av);
+ }
+ for (int i = 0; i < m_enums.size(); i++) {
+ ((EnumAttribute) m_enums.get(i)).visit(av);
+ }
+ for (int i = 0; i < m_nested.size(); i++) {
+ ((AnnotationDescriptor) m_nested.get(i)).visit(av);
+ }
+ for (int i = 0; i < m_arrays.size(); i++) {
+ ((ArrayAttribute) m_arrays.get(i)).visit(av);
+ }
+ av.visitEnd();
+ }
+
+
+ }
+
+ /**
+ * Describes an array attribute.
+ * This class is able to visit an annotation array attribute, and to
+ * recreate this array on another annotation.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+ public class ArrayAttribute implements AnnotationVisitor {
+ /**
+ * The name of the attribute.
+ */
+ private String m_name;
+ /**
+ * The content of the parsed array.
+ */
+ private List m_content = new ArrayList();
+
+ /**
+ * Creates an array attribute.
+ * @param name the name of the attribute.
+ */
+ public ArrayAttribute(String name) {
+ m_name = name;
+ }
+
+ /**
+ * Visits the content of the array. This method is called for
+ * simple values.
+ * @param arg0 <code>null</code>
+ * @param arg1 the value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String arg0, Object arg1) {
+ m_content.add(arg1);
+ }
+
+ /**
+ * Visits the content of the array. This method is called for
+ * nested annotations (annotations contained in the array).
+ * @param arg0 <code>null</code>
+ * @param arg1 the annotation descriptor
+ * @return an {@link AnnotationDescriptor} which creates a copy of
+ * the contained annotation.
+ * @see org.objectweb.asm.AnnotationVisitor#visitAnnotation(String, String)
+ */
+ public AnnotationVisitor visitAnnotation(String arg0, String arg1) {
+ AnnotationDescriptor ad = new AnnotationDescriptor(null, arg1);
+ m_content.add(ad);
+ return ad;
+ }
+
+ /**
+ * Visits the content of the array. This method is called for
+ * nested arrays (arrays contained in the array).
+ * @param arg0 <code>null</code>
+ * @return an {@link ArrayDescriptor} which creates a copy of
+ * the contained array.
+ * @see org.objectweb.asm.AnnotationVisitor#visitArray(String)
+ */
+ public AnnotationVisitor visitArray(String arg0) {
+ ArrayAttribute aa = new ArrayAttribute(null);
+ m_content.add(aa);
+ return aa;
+ }
+
+ /**
+ * End of the array attribute visit.
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() { }
+
+ /**
+ * Visits the content of the array. This method is called for
+ * enumeration values.
+ * @param arg0 <code>null</code>
+ * @param arg1 the enumeration descriptor
+ * @param arg2 the value
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnum(String, String, String)
+ */
+ public void visitEnum(String arg0, String arg1, String arg2) {
+ EnumAttribute ea = new EnumAttribute(null, arg1, arg2);
+ m_content.add(ea);
+ }
+
+ /**
+ * Recreates the visited array attribute. This method
+ * handle the generation of the object embedded in the
+ * array.
+ * @param av the annotation visitor on which the array attribute
+ * needs to be injected.
+ */
+ public void visit(AnnotationVisitor av) {
+ AnnotationVisitor content = av.visitArray(m_name);
+ for (int i = 0; i < m_content.size(); i++) {
+ Object component = m_content.get(i);
+ if (component instanceof AnnotationDescriptor) {
+ ((AnnotationDescriptor) component).visit(content);
+ } else if (component instanceof EnumAttribute) {
+ ((EnumAttribute) component).visit(content);
+ } else if (component instanceof ArrayAttribute) {
+ ((ArrayAttribute) component).visit(content);
+ } else { // Simple
+ content.visit(null, component);
+ }
+ }
+ content.visitEnd();
+ }
+
+ }
+
+ /**
+ * Describes a simple attribute.
+ * This class is able to visit an annotation simple attribute, and to
+ * recreate this attribute on another annotation.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+ public final class SimpleAttribute {
+ /**
+ * The name of the attribute.
+ */
+ private String m_name;
+ /**
+ * The value of the attribute.
+ */
+ private Object m_value;
+
+ /**
+ * Creates a simple attribute.
+ * @param name the name of the attribute
+ * @param object the value of the attribute
+ */
+ private SimpleAttribute(String name, Object object) {
+ m_name = name;
+ m_value = object;
+ }
+
+ /**
+ * Recreates the attribute on the given annotation.
+ * @param visitor the visitor on which the attribute needs
+ * to be injected.
+ */
+ public void visit(AnnotationVisitor visitor) {
+ visitor.visit(m_name, m_value);
+ }
+ }
+
+ /**
+ * Describes an attribute. The value of this attribute is an enumerated
+ * value.
+ * This class is able to visit an annotation enumeration attribute, and to
+ * recreate this attribute on another annotation.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+ public final class EnumAttribute {
+ /**
+ * The name of the attribute.
+ */
+ private String m_name;
+ /**
+ * The descriptor of the enumeration.
+ */
+ private String m_desc;
+ /**
+ * The value of the attribute.
+ */
+ private String m_value;
+
+ /**
+ * Creates a enumeration attribute.
+ * @param name the name of the attribute.
+ * @param desc the descriptor of the {@link Enum}
+ * @param value the enumerated value
+ */
+ private EnumAttribute(String name, String desc, String value) {
+ m_name = name;
+ m_value = value;
+ m_desc = desc;
+ }
+
+ /**
+ * Recreates the attribute on the given annotation.
+ * @param visitor the visitor on which the attribute needs
+ * to be injected.
+ */
+ public void visit(AnnotationVisitor visitor) {
+ visitor.visitEnum(m_name, m_desc, m_value);
+ }
+
+ }
+
}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
index 1841ad5..844ab9a 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
@@ -20,6 +20,7 @@
import java.util.Set;
+import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -65,6 +66,26 @@
m_superDetected = false;
m_fields = fields;
}
+
+ /**
+ * Visits an annotation.
+ * 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 visible the annotation visibility
+ * @return the <code>null</code> if the annotation is visible, otherwise returns
+ * {@link GeneratorAdapter#visitAnnotation(String, boolean)}
+ * @see org.objectweb.asm.MethodAdapter#visitAnnotation(java.lang.String, boolean)
+ */
+ public AnnotationVisitor visitAnnotation(String name, boolean visible) {
+ // Annotations are moved to the injected constructor.
+ if (visible) {
+ return null;
+ } else {
+ return super.visitAnnotation(name, visible);
+ }
+ }
/**
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
index f2cebf7..c572169 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
@@ -96,7 +96,7 @@
ClassReader cr0 = new ClassReader(is2);
ClassWriter cw0 = new ClassWriter(ClassWriter.COMPUTE_MAXS);
//CheckClassAdapter ch = new CheckClassAdapter(cw0);
- MethodCreator preprocess = new MethodCreator(cw0, m_fields);
+ MethodCreator preprocess = new MethodCreator(cw0, m_fields, m_methods);
cr0.accept(preprocess, ClassReader.SKIP_FRAMES);
is2.close();
finalWriter = cw0;
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java
index c698a6b..06e72ed 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java
@@ -20,6 +20,7 @@
import java.util.Set;
+import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.GeneratorAdapter;
@@ -78,5 +79,25 @@
}
super.visitFieldInsn(opcode, owner, name, desc);
}
+
+ /**
+ * Visits an annotation.
+ * 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 visible the annotation visibility
+ * @return the <code>null</code> if the annotation is visible, otherwise returns
+ * {@link GeneratorAdapter#visitAnnotation(String, boolean)}
+ * @see org.objectweb.asm.MethodAdapter#visitAnnotation(java.lang.String, boolean)
+ */
+ public AnnotationVisitor visitAnnotation(String name, boolean visible) {
+ // Annotations are moved to the injected constructor.
+ if (visible) {
+ return null;
+ } else {
+ return super.visitAnnotation(name, visible);
+ }
+ }
}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java
index c81e3f8..8495f4a 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java
@@ -24,6 +24,7 @@
import java.util.Map;
import java.util.Set;
+import org.apache.felix.ipojo.manipulation.ClassChecker.AnnotationDescriptor;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
@@ -112,19 +113,28 @@
* This set contains field name generate from method id.
*/
private List m_methodFlags = new ArrayList();
+
+ /**
+ * The list of methods visited during the previous analysis.
+ * This list allows getting annotations to move to generated
+ * method.
+ */
+ private List m_visitedMethods = new ArrayList();
/**
* Constructor.
* @param arg0 : class visitor.
* @param fields : fields map detected during the previous class analysis.
+ * @param methods : the list of the detected method during the previous class analysis.
*/
- public MethodCreator(ClassVisitor arg0, Map fields) {
+ public MethodCreator(ClassVisitor arg0, Map fields, List methods) {
super(arg0);
m_fields = fields.keySet();
+ m_visitedMethods = methods;
}
/**
- * Vist method.
+ * Visit method.
* This method store the current class name.
* Moreover the POJO interface is added to the list of implemented interface.
* Then the Instance manager field is added.
@@ -161,16 +171,16 @@
if (name.equals("<clinit>") || name.equals("class$")) { return super.visitMethod(access, name, desc, signature, exceptions); }
// The constructor is manipulated separately
if (name.equals("<init>")) {
-
+ MethodDescriptor md = getMethodDescriptor("$init", desc);
// 1) change the constructor descriptor (add a component manager arg as first argument)
String newDesc = desc.substring(1);
newDesc = "(Lorg/apache/felix/ipojo/InstanceManager;" + newDesc;
Type[] args = Type.getArgumentTypes(desc);
if (args.length == 0) {
- generateEmptyConstructor(access, signature, exceptions);
+ generateEmptyConstructor(access, signature, exceptions, md.getAnnotations());
} else if (args.length == 1 && args[0].getClassName().equals("org.osgi.framework.BundleContext")) {
- generateBCConstructor(access, signature, exceptions);
+ generateBCConstructor(access, signature, exceptions, md.getAnnotations());
} else {
// Do nothing, the constructor does not match.
return cv.visitMethod(access, name, desc, signature, exceptions);
@@ -188,9 +198,8 @@
if ((access & ACC_STATIC) == ACC_STATIC) { return super.visitMethod(access, name, desc, signature, exceptions); }
-
- generateMethodHeader(access, name, desc, signature, exceptions);
-
+ MethodDescriptor md = getMethodDescriptor(name, desc);
+ generateMethodHeader(access, name, desc, signature, exceptions, md.getAnnotations());
String id = generateMethodFlag(name, desc);
if (! m_methodFlags.contains(id)) {
@@ -204,6 +213,24 @@
}
/**
+ * Gets the method descriptor for the specified name and descriptor.
+ * The method descriptor is looked inside the
+ * {@link MethodCreator#m_visitedMethods}
+ * @param name the name of the method
+ * @param desc the descriptor of the method
+ * @return the method descriptor or <code>null</code> if not found.
+ */
+ private MethodDescriptor getMethodDescriptor(String name, String desc) {
+ for (int i = 0; i < m_visitedMethods.size(); i++) {
+ MethodDescriptor md = (MethodDescriptor) m_visitedMethods.get(i);
+ if (md.getName().equals(name) && md.getDescriptor().equals(desc)) {
+ return md;
+ }
+ }
+ return null;
+ }
+
+ /**
* Visit a Field.
* This field access is replaced by an invocation to the getter method or to the setter method.
* (except for static field).
@@ -252,14 +279,26 @@
* @param access : access flag
* @param signature : method signature
* @param exceptions : declared exception
+ * @param annotations : the annotations to move to this constructor.
*/
- private void generateEmptyConstructor(int access, String signature, String[] exceptions) {
+ private void generateEmptyConstructor(int access, String signature, String[] exceptions, List annotations) {
MethodVisitor mv = cv.visitMethod(access, "<init>", "()V", signature, exceptions);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitInsn(ACONST_NULL);
mv.visitMethodInsn(INVOKESPECIAL, m_owner, "<init>", "(Lorg/apache/felix/ipojo/InstanceManager;)V");
mv.visitInsn(RETURN);
+
+ // Move annotations
+ if (annotations != null) {
+ for (int i = 0; i < annotations.size(); i++) {
+ AnnotationDescriptor ad = (AnnotationDescriptor) annotations.get(i);
+ ad.visit(mv);
+ System.out.println("Inject annotation : " + ad);
+ }
+ }
+
+
mv.visitMaxs(0, 0);
mv.visitEnd();
}
@@ -271,8 +310,9 @@
* @param access : access flag
* @param signature : method signature
* @param exceptions : declared exception
+ * @param annotations : the annotations to move to this constructor.
*/
- private void generateBCConstructor(int access, String signature, String[] exceptions) {
+ private void generateBCConstructor(int access, String signature, String[] exceptions, List annotations) {
MethodVisitor mv = cv.visitMethod(access, "<init>", "(Lorg/osgi/framework/BundleContext;)V", signature, exceptions);
mv.visitCode();
Label l0 = new Label();
@@ -282,6 +322,15 @@
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKESPECIAL, m_owner, "<init>", "(Lorg/apache/felix/ipojo/InstanceManager;Lorg/osgi/framework/BundleContext;)V");
mv.visitInsn(RETURN);
+
+ // Move annotations
+ if (annotations != null) {
+ for (int i = 0; i < annotations.size(); i++) {
+ AnnotationDescriptor ad = (AnnotationDescriptor) annotations.get(i);
+ ad.visit(mv);
+ }
+ }
+
mv.visitMaxs(0, 0);
mv.visitEnd();
}
@@ -295,8 +344,9 @@
* @param desc : method descriptor.
* @param signature : method signature.
* @param exceptions : declared exceptions.
+ * @param annotations : the annotations to move to this method.
*/
- private void generateMethodHeader(int access, String name, String desc, String signature, String[] exceptions) {
+ private void generateMethodHeader(int access, String name, String desc, String signature, String[] exceptions, List annotations) {
GeneratorAdapter mv = new GeneratorAdapter(cv.visitMethod(access, name, desc, signature, exceptions), access, name, desc);
mv.visitCode();
@@ -385,6 +435,15 @@
mv.visitVarInsn(returnType.getOpcode(ILOAD), result);
}
mv.visitInsn(returnType.getOpcode(IRETURN));
+
+ // Move annotations
+ if (annotations != null) {
+ for (int i = 0; i < annotations.size(); i++) {
+ AnnotationDescriptor ad = (AnnotationDescriptor) annotations.get(i);
+ ad.visit(mv);
+ System.out.println("Inject annotation : " + ad);
+ }
+ }
mv.visitMaxs(0, 0);
mv.visitEnd();
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java
index bd6056c..6e975f9 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java
@@ -18,6 +18,10 @@
*/
package org.apache.felix.ipojo.manipulation;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulation.ClassChecker.AnnotationDescriptor;
import org.apache.felix.ipojo.metadata.Attribute;
import org.apache.felix.ipojo.metadata.Element;
import org.objectweb.asm.Type;
@@ -42,6 +46,18 @@
* Argument types.
*/
private String[] m_arguments;
+
+ /**
+ * The descriptor of the method.
+ */
+ private String m_desc;
+
+
+ /**
+ * The list of {@link AnnotationDescriptor} attached to this
+ * method.
+ */
+ private List m_annotations;
/**
* Constructor.
@@ -50,6 +66,7 @@
*/
public MethodDescriptor(String name, String desc) {
m_name = name;
+ m_desc = desc;
Type ret = Type.getReturnType(desc);
Type[] args = Type.getArgumentTypes(desc);
@@ -59,6 +76,25 @@
m_arguments[i] = getType(args[i]);
}
}
+
+ /**
+ * Add an annotation to the current method.
+ * @param ann annotation to add
+ */
+ public void addAnnotation(AnnotationDescriptor ann) {
+ if (m_annotations == null) {
+ m_annotations = new ArrayList();
+ }
+ m_annotations.add(ann);
+ }
+
+ public List getAnnotations() {
+ return m_annotations;
+ }
+
+ public String getDescriptor() {
+ return m_desc;
+ }
/**
* Compute method manipulation metadata.
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java
index d4534c4..aafd81f 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java
@@ -31,6 +31,8 @@
*/
public class CustomAnnotationVisitor extends EmptyVisitor implements AnnotationVisitor {
+ //TODO manage enum annotations.
+
/**
* PArent element.
*/
@@ -96,7 +98,7 @@
}
/**
- * Visit an 'simple' annotation attribute.
+ * Visit a 'simple' annotation attribute.
* This method is used for primitive arrays too.
* @param arg0 : attribute name
* @param arg1 : attribute value
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
index 15c2b93..0cc1181 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
@@ -52,8 +52,6 @@
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
-import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator;
-
/**
* Pojoization allows creating an iPOJO bundle from a "normal" bundle.
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java
index c583f8c..855b7b2 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java
@@ -246,6 +246,14 @@
}
+ /**
+ * An error occurs during the XML-Schema checking.
+ * This method propagates the error except if the error concerns
+ * no XML-Schemas are used (<code>cvc-elt.1</code>).
+ * @param saxparseexception the checking error
+ * @throws SAXException the propagated exception
+ * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
+ */
public void error(SAXParseException saxparseexception) throws SAXException {
if (saxparseexception.getMessage().contains("cvc-elt.1")) {
return; // Do not throw an exception when no schema defined.
@@ -254,13 +262,27 @@
}
+ /**
+ * A fatal error occurs during the XML-Schema checking.
+ * This method always propagates the error.
+ * @param saxparseexception the checking error
+ * @throws SAXException the propagated exception
+ * @see org.xml.sax.ErrorHandler#fatalError(SAXParseException)
+ */
public void fatalError(SAXParseException saxparseexception)
throws SAXException {
System.err.println("Fatal error during XML-Schema parsing : " + saxparseexception);
throw saxparseexception;
}
-
+ /**
+ * A warning was detected during the XML-Schema checking.
+ * This method always propagate the warning message to
+ * {@link System#out}.
+ * @param saxparseexception the checking error
+ * @throws SAXException nothing.
+ * @see org.xml.sax.ErrorHandler#warning(SAXParseException)
+ */
public void warning(SAXParseException saxparseexception)
throws SAXException {
System.err.println("Warning : an error was detected in the metadata file : " + saxparseexception);