From 3bc6ace6e402e478ab9f4d7685412258337cb610 Mon Sep 17 00:00:00 2001
From: ribeaudc <ribeaudc>
Date: Fri, 7 Dec 2007 09:29:34 +0000
Subject: [PATCH] change: - 'ClassUtils.create' might accept not only
 'Properties' as parameter. - throws an 'IllegalArgumentException' instead of
 'ConfigurationFailureException'.

SVN: 2980
---
 .../cisd/common/utilities/ClassUtils.java     | 70 +++++++++++----
 .../cisd/common/utilities/ClassUtilsTest.java | 85 ++++++++++++-------
 2 files changed, 106 insertions(+), 49 deletions(-)

diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/ClassUtils.java b/common/source/java/ch/systemsx/cisd/common/utilities/ClassUtils.java
index f539f121acf..69ce8b93938 100644
--- a/common/source/java/ch/systemsx/cisd/common/utilities/ClassUtils.java
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/ClassUtils.java
@@ -21,13 +21,13 @@ import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
 import ch.systemsx.cisd.common.annotation.Mandatory;
 import ch.systemsx.cisd.common.exceptions.CheckedExceptionTunnel;
-import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
 
 /**
  * Operations on classes using reflection.
@@ -149,11 +149,12 @@ public final class ClassUtils
      * 
      * @param superClazz Super class <code>className</code> has to be implemented or extended.
      * @param className Fully-qualified class name.
-     * @param initargs Optional constructor argument. If not <code>null</code> an constructor with one single
-     *            <code>Properties</code> argument is expected. Otherwise the default constructor will used.
+     * @param argumentsOrNull Optional constructor arguments. If <code>(Object[]) null</code> then the empty
+     *            constructor will be used. Note that <code>(Object) null</code> is not interpreted as
+     *            <code>null</code> arguments but rather as <code>new Object[]{null}</code>.
      * @return an instance of type <code>interface</code>.
      */
-    public static <T> T create(final Class<T> superClazz, final String className, final Object... initargs)
+    public static <T> T create(final Class<T> superClazz, final String className, final Object... argumentsOrNull)
     {
         assert superClazz != null : "Missing super class";
         assert className != null : "Missing class name";
@@ -165,18 +166,31 @@ public final class ClassUtils
                     + "' can not be instanciated as it is an interface.";
             assert superClazz.isAssignableFrom(clazz) : "Class '" + clazz.getName() + "' does not implements/extends '"
                     + superClazz.getName() + "'.";
-            // (Object[]) null ||Ê(Object) null
-            if (initargs == null || (initargs.length == 1 && initargs[0] == null))
+            if (argumentsOrNull == null)
             {
                 return createInstance(clazz);
             }
-            final Class<?>[] classes = getClasses(initargs);
-            final Constructor<?> constructor = clazz.getConstructor(classes);
-            return createInstance(constructor, initargs);
-        } catch (Exception ex)
+            final Class<?>[] classes = getClasses(argumentsOrNull);
+            final Constructor<T> constructor = getConstructor(clazz, classes);
+            if (constructor == null)
+            {
+                throw new IllegalArgumentException(String.format("No constructor could be found for classes '%s'.",
+                        Arrays.asList(classes)));
+            }
+            return constructor.newInstance(argumentsOrNull);
+        } catch (ClassNotFoundException e)
+        {
+        } catch (InstantiationException ex)
+        {
+        } catch (IllegalAccessException ex)
+        {
+        } catch (InvocationTargetException ex)
+        {
+        } catch (NoSuchMethodException ex)
         {
-            throw new ConfigurationFailureException("Cannot instantiate class '" + className + "'.", ex);
         }
+        throw new IllegalArgumentException(String.format("Cannot instantiate class '%s' with given arguments '%s'.",
+                className, Arrays.asList(argumentsOrNull)));
     }
 
     private final static Class<?>[] getClasses(final Object... initargs)
@@ -191,17 +205,39 @@ public final class ClassUtils
     }
 
     @SuppressWarnings("unchecked")
-    private final static <T> T createInstance(final Class<?> clazz) throws InstantiationException,
-            IllegalAccessException
+    private final static <T> Constructor<T> getConstructor(final Class<?> clazz, final Class<?>[] classes)
+            throws NoSuchMethodException
     {
-        return (T) clazz.newInstance();
+        final Constructor<T>[] constructors = clazz.getConstructors();
+        Constructor<T> returned = null;
+        for (final Constructor<T> constructor : constructors)
+        {
+            final Class<?>[] parameterTypes = constructor.getParameterTypes();
+            final int len = parameterTypes.length;
+            if (len != classes.length)
+            {
+                continue;
+            }
+            boolean match = true;
+            for (int i = 0; i < len; i++)
+            {
+                final Class<?> parameterType = parameterTypes[i];
+                final Class<?> c = classes[i];
+                match &= parameterType.equals(c) || parameterType.isAssignableFrom(c);
+            }
+            if (match)
+            {
+                returned = constructor;
+            }
+        }
+        return returned;
     }
 
     @SuppressWarnings("unchecked")
-    private final static <T> T createInstance(final Constructor<?> constructor, final Object... initargs)
-            throws InstantiationException, IllegalAccessException, InvocationTargetException
+    private final static <T> T createInstance(final Class<?> clazz) throws InstantiationException,
+            IllegalAccessException
     {
-        return (T) constructor.newInstance(initargs);
+        return (T) clazz.newInstance();
     }
 
 }
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ClassUtilsTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ClassUtilsTest.java
index 9fc609a1e25..b313078776b 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ClassUtilsTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ClassUtilsTest.java
@@ -23,6 +23,8 @@ import static org.testng.AssertJUnit.assertTrue;
 import static org.testng.AssertJUnit.fail;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Properties;
 
 import org.testng.annotations.Test;
@@ -93,38 +95,7 @@ public final class ClassUtilsTest
         Properties properties = new Properties();
         Appendable appendable = ClassUtils.create(Appendable.class, MyClass.class.getName(), properties);
         assertTrue(appendable instanceof MyClass);
-        assertSame(properties, ((MyClass) appendable).getProperties());
-    }
-
-    public static class MyClass implements Appendable
-    {
-        private final Properties properties;
-
-        public MyClass(Properties properties)
-        {
-            this.properties = properties;
-        }
-
-        public final Properties getProperties()
-        {
-            return properties;
-        }
-
-        public Appendable append(char c) throws IOException
-        {
-            return null;
-        }
-
-        public Appendable append(CharSequence csq, int start, int end) throws IOException
-        {
-            return null;
-        }
-
-        public Appendable append(CharSequence csq) throws IOException
-        {
-            return null;
-        }
-
+        assertSame(properties, ((MyClass) appendable).properties);
     }
 
     @Test
@@ -153,4 +124,54 @@ public final class ClassUtilsTest
                     .getMessage());
         }
     }
+
+    @Test
+    public final void testCreateInstanceWithAnInterfaceAsConstructorArgument()
+    {
+        final List<String> list = new ArrayList<String>();
+        list.add("Hello");
+        final Appendable appendable = ClassUtils.create(Appendable.class, MyClass.class.getName(), list);
+        assertSame(list, ((MyClass) appendable).iterable);
+    }
+
+    //
+    // Helper Classes
+    //
+
+    public final static class MyClass implements Appendable
+    {
+        Properties properties;
+
+        Iterable<String> iterable;
+
+        public MyClass(final Properties properties)
+        {
+            this.properties = properties;
+        }
+
+        public MyClass(final Iterable<String> iterable)
+        {
+            this.iterable = iterable;
+        }
+
+        //
+        // Appendable
+        //
+
+        public Appendable append(char c) throws IOException
+        {
+            return null;
+        }
+
+        public Appendable append(CharSequence csq, int start, int end) throws IOException
+        {
+            return null;
+        }
+
+        public Appendable append(CharSequence csq) throws IOException
+        {
+            return null;
+        }
+
+    }
 }
-- 
GitLab