From 432556fba6e015fe91d92692fc5e0ddb39bf1dc4 Mon Sep 17 00:00:00 2001 From: felmer <felmer> Date: Tue, 7 Aug 2007 14:05:20 +0000 Subject: [PATCH] add general purpose create method (with test) SVN: 1268 --- .../cisd/common/utilities/ClassUtils.java | 48 +++++++++++ .../cisd/common/utilities/ClassUtilsTest.java | 85 ++++++++++++++++++- 2 files changed, 131 insertions(+), 2 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 71670c9604b..625fde0bf8b 100644 --- a/common/source/java/ch/systemsx/cisd/common/utilities/ClassUtils.java +++ b/common/source/java/ch/systemsx/cisd/common/utilities/ClassUtils.java @@ -16,13 +16,17 @@ package ch.systemsx.cisd.common.utilities; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import java.util.Properties; 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. @@ -125,4 +129,48 @@ public final class ClassUtils return null; } + /** + * Creates a new instance of a class specified by its fully-qualified name. + * + * @param superClazz Super class <code>className</code> has to be implemented or extended. + * @param className Fully-qualified class name. + * @param properties 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. + * @return an instance of type <code>interfaze</code>. + */ + public static <T> T create(Class<T> superClazz, String className, Properties properties) + { + assert superClazz != null : "Missing super class"; + assert className != null : "Missing class name"; + + try + { + final Class<?> clazz = Class.forName(className); + assert clazz.isInterface() == false : clazz + " can not be instanciated"; + assert superClazz.isAssignableFrom(clazz) : clazz + " does not implements/extends " + superClazz.getName(); + if (properties == null) + { + return createInstance(clazz); + } + final Constructor<?> constructor = clazz.getConstructor(new Class[] {Properties.class}); + return createInstance(constructor, properties); + } catch (Exception ex) + { + throw new ConfigurationFailureException("Cannot instanitate class " + className, ex); + } + } + + @SuppressWarnings("unchecked") + private static <T> T createInstance(final Class<?> clazz) throws InstantiationException, IllegalAccessException + { + return (T) clazz.newInstance(); + } + + @SuppressWarnings("unchecked") + private static <T> T createInstance(final Constructor<?> constructor, Properties properties) + throws InstantiationException, IllegalAccessException, InvocationTargetException + { + return (T) constructor.newInstance(new Object[] {properties}); + } + } 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 8cfb894e4c0..50ac8d2142f 100644 --- a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ClassUtilsTest.java +++ b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ClassUtilsTest.java @@ -16,7 +16,14 @@ package ch.systemsx.cisd.common.utilities; -import static org.testng.AssertJUnit.*; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNull; +import static org.testng.AssertJUnit.assertSame; +import static org.testng.AssertJUnit.assertTrue; +import static org.testng.AssertJUnit.fail; + +import java.io.IOException; +import java.util.Properties; import org.testng.annotations.Test; @@ -71,4 +78,78 @@ public final class ClassUtilsTest // we will have 'ch.systemsx.cisd.common.utilities.ClassUtilsTest.privateMethodOnStack()' here. assertNull(ClassUtils.getMethodOnStack(1)); } -} \ No newline at end of file + + @Test + public void testCreateWithDefaultConstructor() + { + CharSequence cs = ClassUtils.create(CharSequence.class, StringBuffer.class.getName(), null); + assertTrue(cs instanceof StringBuffer); + assertEquals(0, cs.length()); + } + + @Test + public void testCreateWithPropertiesConstructor() + { + 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; + } + + } + + @Test + public void testCreateWithIncompatibleSuperclass() + { + try + { + ClassUtils.create(Float.class, Integer.class.getName(), null); + fail("AssertionError expected."); + } catch (AssertionError e) + { + assertEquals("class java.lang.Integer does not implements/extends java.lang.Float", e.getMessage()); + } + } + + @Test + public void testCreateInstanceOfAnInterface() + { + try + { + ClassUtils.create(Float.class, CharSequence.class.getName(), null); + fail("AssertionError expected."); + } catch (AssertionError e) + { + assertEquals("interface java.lang.CharSequence can not be instanciated", e.getMessage()); + } + } +} -- GitLab