Fixed https://issues.apache.org/jira/browse/FELIX-3144

The MethodInterceptors receive a Member instead of a Method. The received object can be either a Method or a Constructor.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1179231 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/core/pom.xml b/ipojo/core/pom.xml
index 9ded33b..4bd0792 100644
--- a/ipojo/core/pom.xml
+++ b/ipojo/core/pom.xml
@@ -30,7 +30,10 @@
   <version>1.9.0-SNAPSHOT</version>
 
   <properties>
-    <ipojo.package.version>1.8.0</ipojo.package.version>
+    <!--
+        * 1.8.1 : change in the MethodInterceptor interface (FELIX-3144)
+     -->
+    <ipojo.package.version>1.8.1</ipojo.package.version>
   </properties>
 
   <description>
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java
index 836614a..1d9c6b9 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java
@@ -21,6 +21,7 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Dictionary;
@@ -1090,7 +1091,7 @@
             return;
         }
         MethodInterceptor[] list = (MethodInterceptor[]) m_methodRegistration.get(methodId);
-        Method method = getMethodById(methodId);
+        Member method = getMethodById(methodId);
         // In case of a constructor, the method is null, and the list is null too.
         for (int i = 0; list != null && i < list.length; i++) {
             list[i].onEntry(pojo, method, args); // Outside a synchronized block.
@@ -1113,7 +1114,7 @@
             return;
         }
         MethodInterceptor[] list = (MethodInterceptor[]) m_methodRegistration.get(methodId);
-        Method method = getMethodById(methodId);
+        Member method = getMethodById(methodId);
         for (int i = 0; list != null && i < list.length; i++) {
             list[i].onExit(pojo, method, result);
         }
@@ -1137,7 +1138,7 @@
             return;
         }
         MethodInterceptor[] list = (MethodInterceptor[]) m_methodRegistration.get(methodId);
-        Method method = getMethodById(methodId);
+        Member method = getMethodById(methodId);
         for (int i = 0; list != null && i < list.length; i++) {
             list[i].onError(pojo, method, error);
         }
@@ -1153,10 +1154,12 @@
      * @param methodId the method id
      * @return the method object or <code>null</code> if the method cannot be found.
      */
-    private Method getMethodById(String methodId) {
+    private Member getMethodById(String methodId) {
         // Not necessary synchronized as recomputing the methodID will give the same Method twice.
-        Method method = (Method) m_methods.get(methodId);
-        if (method == null  && m_clazz != null) {
+        Member member = (Member) m_methods.get(methodId);
+        if (member == null  && m_clazz != null) {
+
+            // First try on methods.
             Method[] mets = m_clazz.getDeclaredMethods();
             for (int i = 0; i < mets.length; i++) {
                 // Check if the method was not already computed. If not, compute the Id and check.
@@ -1166,16 +1169,25 @@
                     return mets[i];
                 }
             }
-            // If not found, it is a constructor, return null in this case.
+
+            // If not found, it is a constructor, return the constructor object in this case.
             if (methodId.startsWith(MethodMetadata.CONSTRUCTOR_PREFIX)) {
-                // Constructor.
-                return null;
+                Constructor[] constructors = m_clazz.getDeclaredConstructors();
+                for (int i = 0; i < constructors.length; i++) {
+                    // Check if the constructor was not already computed. If not, compute the Id and check.
+                    if (!m_methods.containsValue(constructors[i]) && (MethodMetadata.computeMethodId(constructors[i]).equals(methodId))) {
+                        // Store the new methodId
+                        m_methods.put(methodId, constructors[i]);
+                        return constructors[i];
+                    }
+                }
             }
+
             // Cannot happen
-            m_logger.log(Logger.ERROR, "A methodID cannot be associated with a method from the POJO class: " + methodId);
+            m_logger.log(Logger.INFO, "A methodID cannot be associated with a method from the POJO class: " + methodId);
             return null;
         } else {
-            return method;
+            return member;
         }
     }
 
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/MethodInterceptor.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/MethodInterceptor.java
index c74a11c..15560fe 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/MethodInterceptor.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/MethodInterceptor.java
@@ -1,4 +1,4 @@
-/* 

+/*

  * 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

@@ -18,21 +18,26 @@
  */

 package org.apache.felix.ipojo;

 

+import java.lang.reflect.Constructor;

+import java.lang.reflect.Member;

 import java.lang.reflect.Method;

 

 /**

 * Method interceptor.

 * A class implementing this interface is able to be notified of method invocations (

 * i.e. entries, exits, and errors).

-* The listener needs to be register on the instance manager with the 

+* The listener needs to be register on the instance manager with the

 * {@link InstanceManager#register(org.apache.felix.ipojo.parser.MethodMetadata, MethodInterceptor)}

-* method. 

-* Events are sent before the method entry (onEntry), after the method returns (onExit), 

-* when an error is thrown by the method (onError), and before the after either a returns or an error (onFinally)

+* method.

+* Events are sent before the method entry (onEntry), after the method returns (onExit),

+* when an error is thrown by the method (onError), and before the after either a returns or an error (onFinally).

+*

+* Instead of a {@link Method} object, the callbacks received a {@link Member} object which can be either a {@link Method}

+* or a {@link Constructor}.

 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

 */

 public interface MethodInterceptor {

-    

+

     /**

      * This method is called when a thread enters in a method.

      * The given argument array is created from the method argument.

@@ -40,36 +45,36 @@
      * @param method the invoked method.

      * @param args the arguments array.

      */

-    void onEntry(Object pojo, Method method, Object[] args);

+    void onEntry(Object pojo, Member method, Object[] args);

 

     /**

      * This method is called when the execution exits a method :

      * before a <code>return</code>.

-     * If the given returned object is <code>null</code>, either the method is 

+     * If the given returned object is <code>null</code>, either the method is

      * <code>void</code>, or it returns <code>null</code>.

      * This method must not modify the returned object.

      * @param pojo the pojo on which the method exits.

      * @param method the exiting method.

      * @param returnedObj the the returned object (boxed for primitive type)

      */

-    void onExit(Object pojo, Method method, Object returnedObj);

-    

+    void onExit(Object pojo, Member method, Object returnedObj);

+

     /**

-     * This method is called when the execution throws an exception in the given 

+     * This method is called when the execution throws an exception in the given

      * method.

      * @param pojo the pojo on which the method was accessed.

      * @param method the invoked method.

      * @param throwable the thrown exception

      */

-    void onError(Object pojo, Method method, Throwable throwable);

-    

+    void onError(Object pojo, Member method, Throwable throwable);

+

     /**

-     * This method is called when the execution of a method is going to terminate : 

+     * This method is called when the execution of a method is going to terminate :

      * just before to throw an exception or before to return.

      * (onError or onExit was already called).

      * @param pojo the pojo on which the method was accessed.

      * @param method the invoked method.

      */

-    void onFinally(Object pojo, Method method);

+    void onFinally(Object pojo, Member method);

 

 }

diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/PrimitiveHandler.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/PrimitiveHandler.java
index 1e5069c..2d70f25 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/PrimitiveHandler.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/PrimitiveHandler.java
@@ -18,6 +18,7 @@
  */

 package org.apache.felix.ipojo;

 

+import java.lang.reflect.Member;

 import java.lang.reflect.Method;

 

 import org.apache.felix.ipojo.parser.PojoMetadata;

@@ -34,7 +35,7 @@
 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

 */

 public abstract class PrimitiveHandler extends Handler implements FieldInterceptor, MethodInterceptor,

-	ConstructorInjector {

+    ConstructorInjector {

 

     /**

      * The "Primitive" Handler type (value).

@@ -52,10 +53,10 @@
      */

     private ComponentFactory m_factory;

 

-	/**

-	 * Instance Logger used by the handler.

-	 */

-	private Logger m_instanceLogger;

+    /**

+     * Instance Logger used by the handler.

+     */

+    private Logger m_instanceLogger;

 

     /**

      * Attaches the current handler to the given instance.

@@ -83,9 +84,9 @@
      * @see org.apache.felix.ipojo.Handler#getLogger()

      */

     public Logger getLogger() {

-    	if (m_instanceLogger == null) {

-    		return m_factory.getLogger();

-    	}

+        if (m_instanceLogger == null) {

+            return m_factory.getLogger();

+        }

         return m_instanceLogger;

     }

 

@@ -167,7 +168,7 @@
      * @see org.apache.felix.ipojo.ConstructorInjector#getConstructorParameter(int)

      */

     public Object getConstructorParameter(int index) {

-    	return null;

+        return null;

     }

 

     /**

@@ -182,7 +183,7 @@
      * @see org.apache.felix.ipojo.ConstructorInjector#getConstructorParameterType(int)

      */

     public Class getConstructorParameterType(int index) {

-    	return null;

+        return null;

     }

 

     /**

@@ -193,7 +194,7 @@
      * @param args the arguments array.

      * @see MethodInterceptor#onEntry(Object, Method, Object[])

      */

-    public void onEntry(Object pojo, Method method, Object[] args) {

+    public void onEntry(Object pojo, Member method, Object[] args) {

         // Nothing to do in the default implementation

     }

 

@@ -209,7 +210,7 @@
      * @param returnedObj the returned object (boxed for primitive type)

      * @see MethodInterceptor#onExit(Object, Method, Object)

      */

-    public void onExit(Object pojo, Method method, Object returnedObj) {

+    public void onExit(Object pojo, Member method, Object returnedObj) {

         // Nothing to do in the default implementation

     }

 

@@ -223,7 +224,7 @@
      * @param throwable the thrown exception

      * @see org.apache.felix.ipojo.MethodInterceptor#onError(java.lang.Object, java.lang.reflect.Method, java.lang.Throwable)

      */

-    public void onError(Object pojo, Method method, Throwable throwable) {

+    public void onError(Object pojo, Member method, Throwable throwable) {

         // Nothing to do in the default implementation

     }

 

@@ -237,7 +238,7 @@
      * @param pojo the pojo on which the method was accessed.

      * @param method the invoked method.

      */

-    public void onFinally(Object pojo, Method method) {

+    public void onFinally(Object pojo, Member method) {

         // Nothing to do in the default implementation

     }

 

diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
index c6419ba..eb45ae7 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
@@ -22,6 +22,7 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 import java.util.ArrayList;
@@ -50,7 +51,7 @@
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class Dependency extends DependencyModel implements FieldInterceptor, MethodInterceptor,
-	ConstructorInjector {
+    ConstructorInjector {
 
     /**
      * Reference on the Dependency Handler.
@@ -213,9 +214,9 @@
 
 
     protected void addConstructorInjection(int index) throws ConfigurationException {
-    	m_index = index;
-    	m_usage = new ServiceUsage();
-    	m_handler.getInstanceManager().register(index, this);
+        m_index = index;
+        m_usage = new ServiceUsage();
+        m_handler.getInstanceManager().register(index, this);
     }
 
     /**
@@ -268,7 +269,7 @@
         // This may happen during refresh.
         // So we just return.
         if (refs == null) {
-        	return;
+            return;
         }
 
         // Call bind callback.
@@ -358,9 +359,9 @@
     }
 
     private Object createNullableObject() {
-    	 // To load the proxy we use the POJO class loader. Indeed, this classloader imports iPOJO (so can access to Nullable) and has
+         // To load the proxy we use the POJO class loader. Indeed, this classloader imports iPOJO (so can access to Nullable) and has
         // access to the service specification.
-    	try {
+        try {
             ClassLoader cl = new NullableClassLoader(
                     getHandler().getInstanceManager().getClazz().getClassLoader(),
                     getSpecification().getClassLoader());
@@ -391,7 +392,7 @@
             if (m_di == null) {
                 // If nullable are supported, create the nullable object.
                 if (m_supportNullable) {
-                	createNullableObject();
+                    createNullableObject();
                 }
             } else {
                 // Create the default-implementation object.
@@ -414,20 +415,20 @@
             if (isAggregate()) {
                 m_proxyObject = new ServiceCollection(this);
             } else {
-            	// Can we really proxy ? We can proxy only interfaces.
-            	if (getSpecification().isInterface()) {
-	                String type = getHandler().getInstanceManager().getContext().getProperty(DependencyHandler.PROXY_TYPE_PROPERTY);
-	                if (type == null || type.equals(DependencyHandler.SMART_PROXY)) {
-	                    SmartProxyFactory proxyFactory = new SmartProxyFactory(this.getClass().getClassLoader());
-	                    m_proxyObject = proxyFactory.getProxy(getSpecification(), this);
-	                } else {
-	                    DynamicProxyFactory proxyFactory = new DynamicProxyFactory();
-	                    m_proxyObject = proxyFactory.getProxy(getSpecification());
-	                }
-            	} else {
-            		m_handler.warn("Cannot create a proxy for a service dependency which is not an interface " +
-            				"- disabling proxy for " + getId());
-            	}
+                // Can we really proxy ? We can proxy only interfaces.
+                if (getSpecification().isInterface()) {
+                    String type = getHandler().getInstanceManager().getContext().getProperty(DependencyHandler.PROXY_TYPE_PROPERTY);
+                    if (type == null || type.equals(DependencyHandler.SMART_PROXY)) {
+                        SmartProxyFactory proxyFactory = new SmartProxyFactory(this.getClass().getClassLoader());
+                        m_proxyObject = proxyFactory.getProxy(getSpecification(), this);
+                    } else {
+                        DynamicProxyFactory proxyFactory = new DynamicProxyFactory();
+                        m_proxyObject = proxyFactory.getProxy(getSpecification());
+                    }
+                } else {
+                    m_handler.warn("Cannot create a proxy for a service dependency which is not an interface " +
+                            "- disabling proxy for " + getId());
+                }
             }
         }
 
@@ -737,7 +738,7 @@
      * @param args : arguments
      * @see org.apache.felix.ipojo.MethodInterceptor#onEntry(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
      */
-    public void onEntry(Object pojo, Method method, Object[] args) {
+    public void onEntry(Object pojo, Member method, Object[] args) {
         if (m_usage != null) {
             Usage usage = (Usage) m_usage.get();
             usage.incComponentStack(); // Increment the number of component access.
@@ -756,7 +757,7 @@
      * @param throwable : thrown error
      * @see org.apache.felix.ipojo.MethodInterceptor#onError(java.lang.Object, java.lang.reflect.Method, java.lang.Throwable)
      */
-    public void onError(Object pojo, Method method, Throwable throwable) {
+    public void onError(Object pojo, Member method, Throwable throwable) {
         // Nothing to do  : wait onFinally
     }
 
@@ -767,7 +768,7 @@
      * @param returnedObj : returned object (null for void method)
      * @see org.apache.felix.ipojo.MethodInterceptor#onExit(java.lang.Object, java.lang.reflect.Method, java.lang.Object)
      */
-    public void onExit(Object pojo, Method method, Object returnedObj) {
+    public void onExit(Object pojo, Member method, Object returnedObj) {
         // Nothing to do  : wait onFinally
     }
 
@@ -777,7 +778,7 @@
      * @param method : Method object.
      * @see org.apache.felix.ipojo.MethodInterceptor#onFinally(java.lang.Object, java.lang.reflect.Method)
      */
-    public void onFinally(Object pojo, Method method) {
+    public void onFinally(Object pojo, Member method) {
         if (m_usage != null) {
             Usage usage = (Usage) m_usage.get();
             usage.decComponentStack();
@@ -891,10 +892,10 @@
          */
         protected Class getProxyClass(Class clazz) {
             byte[] clz = ProxyGenerator.dumpProxy(clazz); // Generate the proxy.
-        	// Turn around the VM changes (FELIX-2716) about java.* classes.
+            // Turn around the VM changes (FELIX-2716) about java.* classes.
             String cn = clazz.getName();
             if (cn.startsWith("java.")) {
-            	cn = "$" + cn;
+                cn = "$" + cn;
             }
             return defineClass(cn + "$$Proxy", clz, 0, clz.length);
         }
@@ -1015,52 +1016,52 @@
 
     }
 
-	/**
-	 * Gets the constructor parameter.
-	 * @return the index of the constructor parameter,
-	 * or <code>-1</code> if not set.
-	 */
-	public int getConstructorParameterIndex() {
-		return m_index;
-	}
+    /**
+     * Gets the constructor parameter.
+     * @return the index of the constructor parameter,
+     * or <code>-1</code> if not set.
+     */
+    public int getConstructorParameterIndex() {
+        return m_index;
+    }
 
-	/**
-	 * Gets the object to inject in the constructor parameter.
-	 * @param index the index of the parameter
-	 * @return the created proxy object
-	 * @see org.apache.felix.ipojo.ConstructorInjector#getConstructorParameter(int)
-	 */
-	public Object getConstructorParameter(int index) {
-		if (m_index == index  && m_proxyObject != null) {
-			return m_proxyObject;
-		}
-		return null;
-	}
+    /**
+     * Gets the object to inject in the constructor parameter.
+     * @param index the index of the parameter
+     * @return the created proxy object
+     * @see org.apache.felix.ipojo.ConstructorInjector#getConstructorParameter(int)
+     */
+    public Object getConstructorParameter(int index) {
+        if (m_index == index  && m_proxyObject != null) {
+            return m_proxyObject;
+        }
+        return null;
+    }
 
-	/**
-	 * Gets the type of the constructor parameter.
-	 * @param index the parameter index
-	 * @return the class of the object. For scalar dependency, it's the
-	 * specification, for aggregate it depends of the container object:
-	 * {@link List} or {@link Set}.
-	 * @see org.apache.felix.ipojo.ConstructorInjector#getConstructorParameterType(int)
-	 */
-	public Class getConstructorParameterType(int index) {
-		if (m_index == index  && m_proxyObject != null) {
-			if (isAggregate()) {
-				switch (m_type) {
-				case DependencyHandler.LIST: return List.class;
-				case DependencyHandler.SET : return Set.class;
-				//TODO We should also manage the Collection type.
-				default: return null; // Should never happen, it was checked before.
-				}
-			} else {
-				return getSpecification();
-			}
-		} else {
-			return null;
-		}
-	}
+    /**
+     * Gets the type of the constructor parameter.
+     * @param index the parameter index
+     * @return the class of the object. For scalar dependency, it's the
+     * specification, for aggregate it depends of the container object:
+     * {@link List} or {@link Set}.
+     * @see org.apache.felix.ipojo.ConstructorInjector#getConstructorParameterType(int)
+     */
+    public Class getConstructorParameterType(int index) {
+        if (m_index == index  && m_proxyObject != null) {
+            if (isAggregate()) {
+                switch (m_type) {
+                case DependencyHandler.LIST: return List.class;
+                case DependencyHandler.SET : return Set.class;
+                //TODO We should also manage the Collection type.
+                default: return null; // Should never happen, it was checked before.
+                }
+            } else {
+                return getSpecification();
+            }
+        } else {
+            return null;
+        }
+    }