Merge branch 'master' into 331383
diff --git a/framework/bundles/org.eclipse.ecf.sharedobject/src/org/eclipse/ecf/core/util/reflection/ClassUtil.java b/framework/bundles/org.eclipse.ecf.sharedobject/src/org/eclipse/ecf/core/util/reflection/ClassUtil.java
index faca891..61f6105 100644
--- a/framework/bundles/org.eclipse.ecf.sharedobject/src/org/eclipse/ecf/core/util/reflection/ClassUtil.java
+++ b/framework/bundles/org.eclipse.ecf.sharedobject/src/org/eclipse/ecf/core/util/reflection/ClassUtil.java
@@ -11,7 +11,7 @@
 package org.eclipse.ecf.core.util.reflection;
 
 import java.lang.reflect.Method;
-import java.util.Arrays;
+import java.util.*;
 
 /**
  * @since 2.2
@@ -19,6 +19,19 @@
  */
 public class ClassUtil {
 
+	private static Map convertor = new HashMap();
+
+	static {
+		convertor.put(boolean.class, Boolean.class);
+		convertor.put(byte.class, Byte.class);
+		convertor.put(char.class, Character.class);
+		convertor.put(double.class, Double.class);
+		convertor.put(float.class, Float.class);
+		convertor.put(int.class, Integer.class);
+		convertor.put(long.class, Long.class);
+		convertor.put(short.class, Short.class);
+	}
+
 	/**
 	 * @param aClass The Class providing method under question (Must not be null)
 	 * @param aMethodName The method name to search for (Must not be null)
@@ -54,25 +67,63 @@
 		final int parameterCount = someParameterTypes.length;
 		aMethodName = aMethodName.intern();
 
+		final TreeSet matches = new TreeSet(new MethodComparator(someParameterTypes));
 		OUTER: for (int i = 0; i < candidates.length; i++) {
-			Method candidate = candidates[i];
-			String candidateMethodName = candidate.getName().intern();
-			Class[] candidateParameterTypes = candidate.getParameterTypes();
-			int candidateParameterCount = candidateParameterTypes.length;
+			final Method candidate = candidates[i];
+			final String candidateMethodName = candidate.getName().intern();
+			final Class[] candidateParameterTypes = candidate.getParameterTypes();
+			final int candidateParameterCount = candidateParameterTypes.length;
 			if (candidateParameterCount == parameterCount && aMethodName == candidateMethodName) {
 				for (int j = 0; j < candidateParameterCount; j++) {
-					Class clazzA = candidateParameterTypes[j];
-					Class clazzB = someParameterTypes[j];
-					// clazzA must be non-null, but clazzB could be null (null given as parameter value)
-					// so in that case we consider it a match and continue
-					if (!(clazzB == null || clazzA.isAssignableFrom(clazzB))) {
+					final Class clazzA = candidateParameterTypes[j];
+					final Class clazzB = someParameterTypes[j];
+					if (clazzB != null && !isAssignableFrom(clazzA, clazzB)) {
 						continue OUTER;
 					}
 				}
-				return candidate;
+				matches.add(candidate);
 			}
 		}
+
 		// if no match has been found, fail with NSME
-		throw new NoSuchMethodException("No such method: " + aMethodName + "(" + Arrays.asList(someParameterTypes) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		if (matches.size() == 0) {
+			throw new NoSuchMethodException("No such method: " + aMethodName + "(" + Arrays.asList(someParameterTypes) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		}
+		return (Method) matches.first();
+	}
+
+	// extends Class.isAssingable(Class) with autoboxing
+	private static boolean isAssignableFrom(Class clazzA, Class clazzB) {
+		if (!(clazzA.isPrimitive() ^ clazzB.isPrimitive())) {
+			return clazzA.isAssignableFrom(clazzB);
+		} else if (clazzA.isPrimitive()) {
+			final Class oClazzA = (Class) convertor.get(clazzA);
+			return oClazzA.isAssignableFrom(clazzB);
+		} else {
+			final Class oClazzB = (Class) convertor.get(clazzB);
+			return clazzA.isAssignableFrom(oClazzB);
+		}
+	}
+
+	private static class MethodComparator implements Comparator {
+
+		private final Class[] parameterTypes;
+
+		public MethodComparator(Class[] someParameterTypes) {
+			parameterTypes = someParameterTypes;
+		}
+
+		public int compare(Object object1, Object object2) {
+			final Class[] pt1 = ((Method) object1).getParameterTypes();
+			final Class[] pt2 = ((Method) object2).getParameterTypes();
+
+			if (Arrays.equals(pt1, pt2)) {
+				return 0;
+			} else if (Arrays.equals(parameterTypes, pt1)) {
+				return -1;
+			} else {
+				return 1;
+			}
+		}
 	}
 }
diff --git a/tests/bundles/org.eclipse.ecf.tests.sharedobject/src/org/eclipse/ecf/tests/sharedobject/util/reflection/ClassUtilTest.java b/tests/bundles/org.eclipse.ecf.tests.sharedobject/src/org/eclipse/ecf/tests/sharedobject/util/reflection/ClassUtilTest.java
new file mode 100644
index 0000000..d70a7a5
--- /dev/null
+++ b/tests/bundles/org.eclipse.ecf.tests.sharedobject/src/org/eclipse/ecf/tests/sharedobject/util/reflection/ClassUtilTest.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Markus Alexander Kuppe.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Markus Alexander Kuppe (ecf-dev_eclipse.org <at> lemmster <dot> de) - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ecf.tests.sharedobject.util.reflection;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+import org.eclipse.ecf.core.util.reflection.ClassUtil;
+
+public class ClassUtilTest extends TestCase {
+
+	/**
+	 * Test method for {@link org.eclipse.ecf.core.util.reflection.ClassUtil#getMethod(java.lang.Class, java.lang.String, java.lang.Class[])}.
+	 */
+	public void testGetPrimitiveMethodWithPrimitive() {
+		testGetMethod(new Class[] {int.class}, new Class[] {int.class}, new Object[]{new Integer(1)});		
+	}
+	
+	/**
+	 * Test method for {@link org.eclipse.ecf.core.util.reflection.ClassUtil#getMethod(java.lang.Class, java.lang.String, java.lang.Class[])}.
+	 */
+	public void testGetPrimitiveMethodWithObject() {
+		testGetMethod(new Class[] {Integer.class}, new Class[] {int.class}, new Object[]{new Integer(1)});
+	}
+
+	/**
+	 * Test method for {@link org.eclipse.ecf.core.util.reflection.ClassUtil#getMethod(java.lang.Class, java.lang.String, java.lang.Class[])}.
+	 */
+	public void testGetObjectMethodWithObject() {
+		testGetMethod(new Class[] {Long.class}, new Class[]{Long.class}, new Object[]{new Long(1L)});
+	}
+
+	/**
+	 * Test method for {@link org.eclipse.ecf.core.util.reflection.ClassUtil#getMethod(java.lang.Class, java.lang.String, java.lang.Class[])}.
+	 */
+	public void testGetObjectMethodWithPrimitive() {
+		testGetMethod(new Class[] {long.class}, new Class[]{Long.class}, new Object[]{new Long(1L)});
+	}
+	
+	/**
+	 * Test method for {@link org.eclipse.ecf.core.util.reflection.ClassUtil#getMethod(java.lang.Class, java.lang.String, java.lang.Class[])}.
+	 */
+	public void testGetObjectMethodWhenBoth() {
+		testGetMethod(new Class[] {Boolean.class}, new Class[]{Boolean.class}, new Object[]{new Boolean(true)});
+	}
+	
+	/**
+	 * Test method for {@link org.eclipse.ecf.core.util.reflection.ClassUtil#getMethod(java.lang.Class, java.lang.String, java.lang.Class[])}.
+	 */
+	public void testGetPrimitiveMethodWhenBoth() {
+		testGetMethod(new Class[] {boolean.class}, new Class[]{boolean.class}, new Object[]{new Boolean(true)});
+	}
+	
+	/**
+	 * Test method for {@link org.eclipse.ecf.core.util.reflection.ClassUtil#getMethod(java.lang.Class, java.lang.String, java.lang.Class[])}.
+	 */
+	public void testGetMethodWithoutParams() {
+		testGetMethod(new Class[]{}, new Class[]{}, null);
+	}
+	
+	/**
+	 * Test method for {@link org.eclipse.ecf.core.util.reflection.ClassUtil#getMethod(java.lang.Class, java.lang.String, java.lang.Class[])}.
+	 */
+	public void testGetObjectMethodFromSuperclassWithPrimitive() {
+		testGetMethod(new Class[]{float.class}, new Class[]{Float.class}, new Object[]{new Float(1.0)});
+	}
+	
+	/**
+	 * Test method for {@link org.eclipse.ecf.core.util.reflection.ClassUtil#getMethod(java.lang.Class, java.lang.String, java.lang.Class[])}.
+	 */
+	public void testGetPrimitiveMethodFromSuperclassWithObject() {
+		testGetMethod(new Class[]{Float.class}, new Class[]{Float.class}, new Object[]{new Float(1.0)});
+	}
+	
+	// helper
+	private void testGetMethod(Class[] searchParameterTypes, Class[] expectedParameterTypes, Object[] params) {
+		Method method = null;
+		try {
+			method = ClassUtil.getMethod(TestClass.class, "foo", searchParameterTypes);
+		} catch (NoSuchMethodException e) {
+			fail("failed to match expected the method: " + e.getMessage());
+		}
+		
+		final Class[] someParameterTypes = method.getParameterTypes();
+		assertTrue("Parameters don't match", Arrays.equals(expectedParameterTypes, someParameterTypes));
+		
+		try {
+			assertNotNull("executed method from superclass", method.invoke(new TestClass(), params));
+		} catch (IllegalArgumentException e) {
+			fail(e.getMessage());
+		} catch (IllegalAccessException e) {
+			fail(e.getMessage());
+		} catch (InvocationTargetException e) {
+			fail(e.getMessage());
+		}
+	}
+
+	// helper class 
+	class TestClass extends AbstractTestClass {
+		public String foo() {return "";}
+		public String foo(final int i) {return "";}
+		public String foo(final Long i) {return "";}
+		public String foo(final boolean b) {return "";}
+		public String foo(final Boolean b) {return "";}
+	}
+	
+	abstract class AbstractTestClass {
+		public String foo(final Float f) {return "";}
+		public String foo() {throw new UnsupportedOperationException();}
+		public String foo(final int i) {throw new UnsupportedOperationException();}
+		public String foo(final Long i) {throw new UnsupportedOperationException();}
+		public String foo(final boolean b) {throw new UnsupportedOperationException();};
+		public String foo(final Boolean b) {throw new UnsupportedOperationException();};
+	}
+}