FELIX-4403 Implement parameter checking and setting for lifecycle methods

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1616079 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/ActivateMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/ActivateMethod.java
index ac59407..1d7e7db 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/ActivateMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/ActivateMethod.java
@@ -21,28 +21,36 @@
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
 
 import org.apache.felix.scr.impl.metadata.DSVersion;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
 import org.osgi.service.log.LogService;
 
 
 public class ActivateMethod extends BaseMethod<ActivatorParameter>
 {
 
-    private static final Class[] ACTIVATE_TYPES_DS11 =
-        { COMPONENT_CONTEXT_CLASS, BUNDLE_CONTEXT_CLASS, MAP_CLASS };
-    static final Class[] ACTIVATE_TYPES_DS10 =
-        { COMPONENT_CONTEXT_CLASS };
+    protected static final Class<?> COMPONENT_CONTEXT_CLASS = ComponentContext.class;
+    protected static final Class<?> BUNDLE_CONTEXT_CLASS = BundleContext.class;
+    protected static final Class<?> INTEGER_CLASS = Integer.class;
+
+    protected final boolean m_supportsInterfaces = false; //TODO configure
 
 
     public ActivateMethod( final String methodName,
-            final boolean methodRequired, final Class componentClass, final DSVersion dsVersion, final boolean configurableServiceProperties )
+            final boolean methodRequired, final Class<?> componentClass, final DSVersion dsVersion, final boolean configurableServiceProperties )
     {
         super( methodName, methodRequired, componentClass, dsVersion, configurableServiceProperties );
     }
 
 
-    protected Method doFindMethod( Class targetClass, boolean acceptPrivate, boolean acceptPackage, SimpleLogger logger )
+    protected Method doFindMethod( Class<?> targetClass, boolean acceptPrivate, boolean acceptPackage, SimpleLogger logger )
         throws SuitableMethodNotAccessibleException, InvocationTargetException
     {
 
@@ -50,54 +58,109 @@
 
         try
         {
-            final Method method = getSingleParameterMethod( targetClass, acceptPrivate, acceptPackage, logger );
+            // find the declared method in this class
+            final Method method = getMethod( targetClass, getMethodName(), new Class[]
+                { COMPONENT_CONTEXT_CLASS }, acceptPrivate, acceptPackage, logger );
             if ( method != null )
             {
                 return method;
             }
         }
-        catch ( SuitableMethodNotAccessibleException smnae )
+        catch ( SuitableMethodNotAccessibleException thrown )
         {
+            logger.log( LogService.LOG_DEBUG, "SuitableMethodNotAccessible", thrown );
             suitableMethodNotAccessible = true;
         }
-
-        if ( getDSVersion().isDS11() )
+        if (getDSVersion().isDS11())
         {
-            // check methods with MethodTester
-            Method[] methods = targetClass.getDeclaredMethods();
-            for ( int i = 0; i < methods.length; i++ )
+            List<Method> methods = getSortedMethods( targetClass);
+            for (Method m: methods)
             {
-                if ( methods[i].getName().equals( getMethodName() ) && isSuitable( methods[i] ) )
+                final Class<?>[] parameterTypes = m.getParameterTypes();
+                if (parameterTypes.length == 1)
                 {
-                    if ( accept( methods[i], acceptPrivate, acceptPackage, returnValue() ) )
+                    Class<?> type = parameterTypes[0];
+                    //single parameter method with parameter ComponentContext will already have been found.
+                    if (type == BUNDLE_CONTEXT_CLASS)
                     {
-                        // check modifiers etc.
-                        return methods[i];
+                        if ( accept( m, acceptPrivate, acceptPackage, returnValue() ) )
+                        {
+                            return m;
+                        }
+                        suitableMethodNotAccessible = true;                   
                     }
-
-                    // method is suitable but not accessible, flag it
-                    suitableMethodNotAccessible = true;
+                    if (getDSVersion().isDS13() && isAnnotation(type))
+                    {
+                        if ( accept( m, acceptPrivate, acceptPackage, returnValue() ) )
+                        {
+                            return m;
+                        }
+                        suitableMethodNotAccessible = true;                   
+                    }
+                    if (type == MAP_CLASS)
+                    {
+                        if ( accept( m, acceptPrivate, acceptPackage, returnValue() ) )
+                        {
+                            return m;
+                        }
+                        suitableMethodNotAccessible = true;                   
+                    }
+                    if (type == int.class)
+                    {
+                        if ( accept( m, acceptPrivate, acceptPackage, returnValue() ) )
+                        {
+                            return m;
+                        }
+                        suitableMethodNotAccessible = true;                   
+                    }
+                    if (type == Integer.class)
+                    {
+                        if ( accept( m, acceptPrivate, acceptPackage, returnValue() ) )
+                        {
+                            return m;
+                        }
+                        suitableMethodNotAccessible = true;                   
+                    }
+                    
                 }
-            }
-
-            // finally check method with no arguments
-            if ( acceptEmpty() )
-            {
-                try
+                else if (parameterTypes.length > 1)
                 {
-                    // find the declared method in this class
-                    Method m = getMethod( targetClass, getMethodName(), null, acceptPrivate, acceptPackage, logger );
-                    if ( m != null ) {
+                    boolean accept = true;
+                    for (Class<?> type: parameterTypes)
+                    {
+                        accept = type == COMPONENT_CONTEXT_CLASS
+                            || type == BUNDLE_CONTEXT_CLASS
+                            || type == MAP_CLASS
+                            || ( isDeactivate() && ( type == int.class || type == Integer.class))
+                            || ( getDSVersion().isDS13() && isAnnotation(type));
+                        if ( !accept ) 
+                        {
+                            break;
+                        }
+                            
+                    }
+                    if (accept)
+                    {
+                        if ( accept( m, acceptPrivate, acceptPackage, returnValue() ) )
+                        {
+                            return m;
+                        }
+                        suitableMethodNotAccessible = true;                                           
+                    }
+                    
+                }
+                else //no parameters
+                {
+                    if ( accept( m, acceptPrivate, acceptPackage, returnValue() ) )
+                    {
                         return m;
                     }
+                    suitableMethodNotAccessible = true;                   
                 }
-                catch ( SuitableMethodNotAccessibleException smnae )
-                {
-                    suitableMethodNotAccessible = true;
-                }
+                
             }
         }
-
+        
         if ( suitableMethodNotAccessible )
         {
             throw new SuitableMethodNotAccessibleException();
@@ -107,9 +170,77 @@
     }
 
 
+    boolean isDeactivate()
+    {
+        return false;
+    }
+
+
+    /**
+     * returns the declared methods of the target class, with the correct name, sorted by number of parameters ( no parameters last)
+     * @param targetClass class to examine methods of
+     * @return sorted methods of correct name;
+     */
+    List<Method> getSortedMethods(Class<?> targetClass)
+    {
+        List<Method> result = new ArrayList<Method>();
+        Method[] methods = targetClass.getDeclaredMethods();
+        for (Method m: methods)
+        {
+            if (m.getName().equals(getMethodName()))
+            {
+                result.add(m);
+            }
+        }
+        Collections.sort(result, new Comparator<Method>(){
+
+            public int compare(Method m1, Method m2)
+            {
+                final int l1 = m1.getParameterTypes().length;
+                final int l2 = m2.getParameterTypes().length;
+                if ( l1 == 0)
+                {
+                    return l2;
+                }
+                if ( l2 == 0)
+                {
+                    return -l1;
+                }
+                if (l1 == 1 && l2 == 1)
+                {
+                    final Class<?> t1 = m1.getParameterTypes()[0];
+                    final Class<?> t2 = m2.getParameterTypes()[0];
+                    //t1, t2 can't be equal
+                    if (t1 == COMPONENT_CONTEXT_CLASS) return -1;
+                    if (t2 == COMPONENT_CONTEXT_CLASS) return 1;
+                    if (t1 == BUNDLE_CONTEXT_CLASS) return -1;
+                    if (t2 == BUNDLE_CONTEXT_CLASS) return 1;
+                    if (isAnnotation(t1)) return isAnnotation(t2)? 0: -1;
+                    if (isAnnotation(t2)) return 1;
+                    if (t1 == MAP_CLASS) return -1;
+                    if (t2 == MAP_CLASS) return 1;
+                    if (t1 == int.class) return -1;
+                    if (t2 == int.class) return 1;
+                    if (t1 == Integer.class) return -1;
+                    if (t2 == Integer.class) return 1;
+                    return 0;
+                }
+                return l1 - l2;
+            }
+
+        });
+        return result;
+    }
+
+    private boolean isAnnotation(final Class<?> t1)
+    {
+        return t1.isAnnotation() || (m_supportsInterfaces && t1.isInterface() && !(t1 == MAP_CLASS));
+    }
+    
+
     protected Object[] getParameters( Method method, ActivatorParameter rawParameter )
     {
-        final Class[] parameterTypes = method.getParameterTypes();
+        final Class<?>[] parameterTypes = method.getParameterTypes();
         final ActivatorParameter ap = ( ActivatorParameter ) rawParameter;
         final Object[] param = new Object[parameterTypes.length];
         for ( int i = 0; i < param.length; i++ )
@@ -130,6 +261,12 @@
             else if ( parameterTypes[i] == INTEGER_CLASS || parameterTypes[i] == Integer.TYPE )
             {
                 param[i] = ap.getReason();
+            } 
+            else
+            {
+                param[i] = Annotations.toObject(parameterTypes[i], 
+                    (Map<String, Object>) ap.getComponentContext().getProperties(),
+                    ap.getComponentContext().getBundleContext().getBundle());
             }
         }
 
@@ -151,99 +288,4 @@
         return null;
     }
 
-    /**
-     * Returns a method taking a single parameter of one of the
-     * {@link #getAcceptedParameterTypes()} or <code>null</code> if no such
-     * method exists.
-     *
-     *
-     * @param targetClass The class in which to look for the method. Only this
-     *      class is searched for the method.
-     * @param acceptPrivate <code>true</code> if private methods should be
-     *      considered.
-     * @param acceptPackage <code>true</code> if package private methods should
-     *      be considered.
-     * @param logger
-     * @return The requested method or <code>null</code> if no acceptable method
-     *      can be found in the target class.
-     * @throws SuitableMethodNotAccessibleException If a suitable method was
-     *      found which is not accessible
-     * @throws InvocationTargetException If an unexpected Throwable is caught
-     *      trying to find the requested method.
-     */
-    private Method getSingleParameterMethod( final Class targetClass, final boolean acceptPrivate,
-            final boolean acceptPackage, SimpleLogger logger ) throws SuitableMethodNotAccessibleException, InvocationTargetException
-    {
-        SuitableMethodNotAccessibleException ex = null;
-        Method singleParameterMethod = null;
-        final Class[] acceptedTypes = getAcceptedParameterTypes();
-        for ( int i = 0; singleParameterMethod == null && i < acceptedTypes.length; i++ )
-        {
-            try
-            {
-                // find the declared method in this class
-                singleParameterMethod = getMethod( targetClass, getMethodName(), new Class[]
-                    { acceptedTypes[i] }, acceptPrivate, acceptPackage, logger );
-            }
-            catch ( SuitableMethodNotAccessibleException thrown )
-            {
-                logger.log( LogService.LOG_DEBUG, "SuitableMethodNotAccessible", thrown );
-                ex = thrown;
-            }
-        }
-
-        // rethrow if we looked for all method signatures and only found
-        // one or more which would be suitable but not accessible
-        if ( singleParameterMethod == null && ex != null )
-        {
-            throw ex;
-        }
-
-        // no method with a matching single parameter has been found
-        return singleParameterMethod;
-    }
-
-
-    private boolean isSuitable( Method method )
-    {
-        // require two or more arguments
-        final Class[] types = method.getParameterTypes();
-        if ( types.length < 2 )
-        {
-            return false;
-        }
-
-        // check for argument types
-        final Class[] acceptedTypes = getAcceptedParameterTypes();
-        OUTER: for ( int i = 0; i < types.length; i++ )
-        {
-            final Class type = types[i];
-            for ( int j = 0; j < acceptedTypes.length; j++ )
-            {
-                if ( type == acceptedTypes[j] )
-                {
-                    continue OUTER;
-                }
-            }
-
-            // get here if type is not contained in the array
-            return false;
-        }
-
-        // all parameters are acceptable
-        return true;
-    }
-
-
-    protected Class[] getAcceptedParameterTypes()
-    {
-        return getDSVersion().isDS11() ? ACTIVATE_TYPES_DS11 : ACTIVATE_TYPES_DS10;
-    }
-
-
-    protected boolean acceptEmpty()
-    {
-        return getDSVersion().isDS11();
-    }
-
 }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/Annotations.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/Annotations.java
index 8e5b3e8..ae7fbf3 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/Annotations.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/Annotations.java
@@ -29,7 +29,7 @@
 public class Annotations
 {
     
-    public <T> T toObject(Class<T> clazz, Map<String, Object> props, Bundle b )
+    static public <T> T toObject(Class<T> clazz, Map<String, Object> props, Bundle b )
     {     
         Map<String, Object> m = new HashMap<String, Object>();
         
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
index f12e370..05ec96b 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
@@ -41,10 +41,7 @@
 {
 
     // class references to simplify parameter checking
-    protected static final Class<?> COMPONENT_CONTEXT_CLASS = ComponentContext.class;
-    protected static final Class<?> BUNDLE_CONTEXT_CLASS = BundleContext.class;
     protected static final Class<?> MAP_CLASS = Map.class;
-    protected static final Class<?> INTEGER_CLASS = Integer.class;
 
     private final DSVersion dsVersion;
     private final boolean configurableServiceProperties;
@@ -100,7 +97,7 @@
         return m_methodName;
     }
 
-    protected final Method getMethod()
+    final Method getMethod()
     {
         return m_method;
     }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/DeactivateMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/DeactivateMethod.java
index d5b7754..6040dbd 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/DeactivateMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/DeactivateMethod.java
@@ -24,8 +24,11 @@
 public class DeactivateMethod extends ActivateMethod
 {
 
-    private static final Class[] DEACTIVATE_TYPES_DS11 =
-        { COMPONENT_CONTEXT_CLASS, BUNDLE_CONTEXT_CLASS, MAP_CLASS, Integer.TYPE, INTEGER_CLASS };
+    @Override
+    boolean isDeactivate()
+    {
+        return true;
+    }
 
 
     public DeactivateMethod( final String methodName,
@@ -34,13 +37,6 @@
         super( methodName, methodRequired, componentClass, dsVersion, configurableServiceProperties );
     }
 
-
-    protected Class[] getAcceptedParameterTypes()
-    {
-        return getDSVersion().isDS11() ? DEACTIVATE_TYPES_DS11 : ACTIVATE_TYPES_DS10;
-    }
-
-
     protected String getMethodNamePrefix()
     {
         return "deactivate";
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/helper/ActivateMethodTest.java b/scr/src/test/java/org/apache/felix/scr/impl/helper/ActivateMethodTest.java
index 5cd7af1..93214af 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/helper/ActivateMethodTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/helper/ActivateMethodTest.java
@@ -22,6 +22,8 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
 
 import junit.framework.TestCase;
 
@@ -36,7 +38,10 @@
 import org.apache.felix.scr.impl.metadata.instances.Level1Object;
 import org.apache.felix.scr.impl.metadata.instances.Level3Object;
 import org.apache.felix.scr.impl.metadata.instances2.Level2Object;
+import org.apache.felix.scr.integration.components.ActivatorComponent;
 import org.easymock.EasyMock;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
 import org.osgi.service.component.ComponentContext;
 
 
@@ -58,11 +63,15 @@
     protected void setUp() throws Exception
     {
         super.setUp();
+        Bundle bundle = ( Bundle ) EasyMock.createNiceMock( Bundle.class );
+        BundleContext context = ( BundleContext ) EasyMock.createNiceMock( BundleContext.class );
+        EasyMock.expect( context.getBundle() ).andReturn( bundle ).anyTimes();
 
         m_ctx = (ComponentContext) EasyMock.createNiceMock(ComponentContext.class);
         EasyMock.expect( m_ctx.getProperties() ).andReturn( new Hashtable() ).anyTimes();
+        EasyMock.expect( m_ctx.getBundleContext() ).andReturn( context ).anyTimes();
         EasyMock.replay( new Object[]
-            { m_ctx } );
+            { m_ctx, context } );
 
     }
 
@@ -224,7 +233,7 @@
 
     public void test_precedence() throws Exception
     {
-        //All tested methods are only in base.  They differ in argurments and visibility.
+        //All tested methods are only in base.  They differ in arguments and visibility.
         //R4.2 compendium  112.5.8
         //private method, arg ComponentContext
         checkMethod( base, "activate_precedence_1", "activate_precedence_1_comp" );
@@ -253,7 +262,7 @@
      */
     private void checkMethod( BaseObject obj, String methodName )
     {
-        checkMethod( obj, methodName, methodName );
+        checkMethod( obj, methodName, methodName, DSVersion.DS11 );
     }
 
     /**
@@ -267,11 +276,27 @@
      */
     private void checkMethod( BaseObject obj, String methodName, String methodDesc )
     {
-        ComponentContainer container = newContainer();
-        SingleComponentManager icm = new SingleComponentManager( container, new ComponentMethods() );
-        ActivateMethod am = new ActivateMethod( methodName, methodName != null, obj.getClass(), DSVersion.DS11, false );
+        checkMethod(obj, methodName, methodDesc, DSVersion.DS11);
+    }
+
+
+    /**
+     * Checks whether a method with the given name can be found for the
+     * activate/deactivate method parameter list and whether the method returns
+     * the expected description when called.
+     *
+     * @param obj
+     * @param methodName
+     * @param methodDesc
+     * @param version DSVersion tested
+     */
+    private void checkMethod( BaseObject obj, String methodName, String methodDesc, DSVersion version )
+    {
+        ComponentContainer<?> container = newContainer();
+        SingleComponentManager<?> icm = new SingleComponentManager( container, new ComponentMethods() );
+        ActivateMethod am = new ActivateMethod( methodName, methodName != null, obj.getClass(), version, false );
         am.invoke( obj, new ActivatorParameter( m_ctx, -1 ), null, icm );
-        Method m = get(am, "m_method");
+        Method m = am.getMethod();
         assertNotNull( m );
         assertEquals( methodName, m.getName() );
         assertEquals( methodDesc, obj.getCalledMethod() );
@@ -322,11 +347,28 @@
      */
     private void ensureMethodNotFoundMethod( BaseObject obj, String methodName )
     {
+        ensureMethodNotFoundMethod(obj, methodName, DSVersion.DS11);
+    }
+
+
+    /**
+     * Ensures no method with the given name accepting any of the
+     * activate/deactive method parameters can be found.
+     *
+     * @param obj
+     * @param methodName
+     * @param version DS version tested
+     * @throws InvocationTargetException
+     * @throws IllegalAccessException
+     */
+    private void ensureMethodNotFoundMethod( BaseObject obj, String methodName, DSVersion version )
+    {
         ComponentContainer container = newContainer();
         SingleComponentManager icm = new SingleComponentManager( container, new ComponentMethods() );
-        ActivateMethod am = new ActivateMethod( methodName, methodName != null, obj.getClass(), DSVersion.DS11, false );
+        ActivateMethod am = new ActivateMethod( methodName, methodName != null, obj.getClass(), version, false );
         am.invoke( obj, new ActivatorParameter( m_ctx, -1 ), null, icm );
-        assertNull( get( am, "m_method" ) );
+        Method m = am.getMethod();
+        assertNull( m );
         assertNull( obj.getCalledMethod() );
     }
 
@@ -338,27 +380,45 @@
         boolean accepted = BaseMethod.accept( method, acceptPrivate, acceptPackage, false );
         assertEquals( expected, accepted );
     }
-
-
-    private static Method get( final BaseMethod baseMethod, final String fieldName )
+    
+    private static @interface Ann{}
+    private static class Sort
     {
-        try
-        {
-            Field field = BaseMethod.class.getDeclaredField( fieldName );
-            field.setAccessible( true );
-            Object value = field.get( baseMethod );
-            if ( value == null || value instanceof Method )
-            {
-                return ( Method ) value;
-            }
-            fail( "Field " + field + " is not of type Method" );
-        }
-        catch ( Throwable t )
-        {
-            fail( "Failure accessing field " + fieldName + " in " + baseMethod + ": " + t );
-        }
-
-        // Compiler does not know about fail()
-        return null;
+        public void a(Ann ann) {};
+        public void a(int c) {};
+        public void a(Integer c) {};
+        public void a(BundleContext c) {};
+        public void a(Map m) {};
+        public void a() {};
+        public void a(ComponentContext cc) {};
+        public void a(ComponentContext cc, BundleContext c) {};
+        public void b() {};
+        
     }
+    public void testMethodSorting() throws Exception
+    {
+        ActivateMethod am = new ActivateMethod( "a", true, Sort.class, DSVersion.DS11, false );
+        List<Method> ms = am.getSortedMethods(Sort.class);
+        assertEquals(8, ms.size());
+        assertEquals(1, ms.get(0).getParameterTypes().length);
+        assertEquals(ComponentContext.class, ms.get(0).getParameterTypes()[0]);
+        assertEquals(1, ms.get(1).getParameterTypes().length);
+        assertEquals(BundleContext.class, ms.get(1).getParameterTypes()[0]);
+        assertEquals(1, ms.get(2).getParameterTypes().length);
+        assertEquals(Ann.class, ms.get(2).getParameterTypes()[0]);
+        assertEquals(1, ms.get(3).getParameterTypes().length);
+        assertEquals(Map.class, ms.get(3).getParameterTypes()[0]);
+        assertEquals(1, ms.get(4).getParameterTypes().length);
+        assertEquals(int.class, ms.get(4).getParameterTypes()[0]);
+        assertEquals(1, ms.get(5).getParameterTypes().length);
+        assertEquals(Integer.class, ms.get(5).getParameterTypes()[0]);
+        assertEquals(2, ms.get(6).getParameterTypes().length);
+        assertEquals(0, ms.get(7).getParameterTypes().length);
+    }
+    
+    public void test_13_annos() throws Exception
+    {
+        checkMethod(base, "activate_13_2_annotations", "activate_13_2_annotations", DSVersion.DS13 );
+    }
+    
 }
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/helper/AnnotationTest.java b/scr/src/test/java/org/apache/felix/scr/impl/helper/AnnotationTest.java
index a515d65..a2d228c 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/helper/AnnotationTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/helper/AnnotationTest.java
@@ -54,7 +54,7 @@
     {
         Map<String, Object> values = allValues();
         
-        Object o = new Annotations().toObject( A1.class, values, mockBundle());
+        Object o = Annotations.toObject( A1.class, values, mockBundle());
         assertTrue("expected an A1", o instanceof A1);
         
         A1 a = (A1) o;
@@ -103,7 +103,7 @@
     {
         Map<String, Object> values = allValues();
         
-        Object o = new Annotations().toObject( A2.class, values, mockBundle());
+        Object o = Annotations.toObject( A2.class, values, mockBundle());
         assertTrue("expected an A2", o instanceof A2);
         
         A2 a = (A2) o;
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/BaseObject.java b/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/BaseObject.java
index 81b194c..98fa63d 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/BaseObject.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/BaseObject.java
@@ -104,4 +104,10 @@
     }
 
 
+    public @interface Ann1 { }
+    public @interface Ann2 { }
+   
+    void activate_13_2_annotations(ComponentContext cc, Ann1 a1, BundleContext c, Ann2 a2, Map<String, Object> map, ComponentContext cc2) {
+        setCalledMethod("activate_13_2_annotations");
+    }
 }