From 5071454173dc1b48c4a16aeab07f2e6594f490a1 Mon Sep 17 00:00:00 2001
From: ribeaudc <ribeaudc>
Date: Fri, 7 Mar 2008 14:53:35 +0000
Subject: [PATCH] [LMS-265] change: - annotation 'BeanProperty' used now for
 setter methods (and no longer for fields). - get rid of 'PropertyDescriptor'
 in 'AbstractParserObjectFactory' as the parser only works with BeanProperty
 labels. - 'NewSample.code' renamed to 'NewSample.sampleCriteria' (and
 removing so the badly formatted TODO). - 'BeanAnalyzer' made more intelligent
 and checks whether we use correctly the BeanProperty annotation (using
 assertions). add: - 'AnnotationUtils' and its test.

SVN: 4684
---
 .../cisd/common/annotation/BeanProperty.java  |   8 +-
 .../parser/AbstractParserObjectFactory.java   |  22 ++--
 .../cisd/common/parser/BeanAnalyzer.java      |  48 ++++++--
 .../common/utilities/AnnotationUtils.java     | 115 ++++++++++++++++++
 .../cisd/common/utilities/ClassUtils.java     |  43 -------
 .../AbstractParserObjectFactoryTest.java      |  42 ++++---
 .../common/utilities/AnnotationUtilsTest.java | 113 +++++++++++++++++
 .../cisd/common/utilities/ClassUtilsTest.java |  32 -----
 8 files changed, 300 insertions(+), 123 deletions(-)
 create mode 100644 common/source/java/ch/systemsx/cisd/common/utilities/AnnotationUtils.java
 create mode 100644 common/sourceTest/java/ch/systemsx/cisd/common/utilities/AnnotationUtilsTest.java

diff --git a/common/source/java/ch/systemsx/cisd/common/annotation/BeanProperty.java b/common/source/java/ch/systemsx/cisd/common/annotation/BeanProperty.java
index 258ea2e58d7..ea044e95a8c 100644
--- a/common/source/java/ch/systemsx/cisd/common/annotation/BeanProperty.java
+++ b/common/source/java/ch/systemsx/cisd/common/annotation/BeanProperty.java
@@ -22,7 +22,7 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 /**
- * Marks a field in a <i>Java</i> bean class that should be considered by the parser.
+ * Marks a setter method in a <i>Java</i> bean class that should be considered by the parser.
  * <p>
  * By default, each property annotated with <code>BeanProperty</code> is mandatory.
  * </p>
@@ -31,13 +31,13 @@ import java.lang.annotation.Target;
  * @author Christian Ribeaud
  */
 @Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.FIELD)
+@Target(ElementType.METHOD)
 public @interface BeanProperty
 {
     /**
      * Whether this bean property is optional or not.
      * <p>
-     * Default is <code>false</code> meaning that any field annotated with this is mandatory.
+     * Default is <code>false</code> meaning that any field set by annotated method is mandatory.
      * </p>
      */
     public boolean optional() default false;
@@ -45,7 +45,7 @@ public @interface BeanProperty
     /**
      * Static label (or alias) for this annotated field.
      * <p>
-     * This <b>must</b> be specified as the parser prefers to work with the label than with the field name.
+     * This <b>must</b> not be empty (as the parser works with labelled methods).
      * </p>
      */
     public String label() default "";
diff --git a/common/source/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactory.java b/common/source/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactory.java
index cf40aa78a7b..ef5d540015e 100644
--- a/common/source/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactory.java
+++ b/common/source/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactory.java
@@ -16,7 +16,6 @@
 
 package ch.systemsx.cisd.common.parser;
 
-import java.beans.PropertyDescriptor;
 import java.lang.reflect.Method;
 import java.util.LinkedHashSet;
 import java.util.Map;
@@ -25,7 +24,6 @@ import java.util.TreeSet;
 
 import ch.systemsx.cisd.common.converter.Converter;
 import ch.systemsx.cisd.common.converter.ConverterPool;
-import ch.systemsx.cisd.common.utilities.BeanUtils;
 import ch.systemsx.cisd.common.utilities.ClassUtils;
 
 /**
@@ -42,11 +40,6 @@ public abstract class AbstractParserObjectFactory<E> implements IParserObjectFac
     /** The pool of {@link Converter}s. */
     private final ConverterPool converterPool;
 
-    /**
-     * A <code>Map</code> of <code>PropertyDescriptor</code>s for typed <code>Object</code>, keyed by their name ({@link PropertyDescriptor#getName()}).
-     */
-    private final Map<String, PropertyDescriptor> propertyDescriptors;
-
     /** The class of object bean we are going to create here. */
     private final Class<E> beanClass;
 
@@ -57,7 +50,6 @@ public abstract class AbstractParserObjectFactory<E> implements IParserObjectFac
     {
         assert beanClass != null : "Given bean class can not be null.";
         assert propertyMapper != null : "Given property mapper can not be null.";
-        propertyDescriptors = BeanUtils.getPropertyDescriptors(beanClass);
         beanAnalyzer = new BeanAnalyzer<E>(beanClass);
         checkPropertyMapper(beanClass, propertyMapper);
         this.propertyMapper = propertyMapper;
@@ -105,9 +97,9 @@ public abstract class AbstractParserObjectFactory<E> implements IParserObjectFac
     /**
      * Checks given <code>IPropertyMapper</code>.
      * <p>
-     * This method tries to find properties declared in given <code>IPropertyMapper</code> that are not in
-     * {@link #propertyDescriptors} (throws a <code>UnmatchedPropertiesException</code>) or mandatory fields that
-     * could not be found in {@link #propertyDescriptors} (throws a <code>MandatoryPropertyMissingException</code>).
+     * This method tries to find properties declared in given <code>IPropertyMapper</code> that are not in labels in
+     * annotated write methods (throws a <code>UnmatchedPropertiesException</code>) or mandatory fields that could
+     * not be found in the same annotated write methods (throws a <code>MandatoryPropertyMissingException</code>).
      * </p>
      */
     private final void checkPropertyMapper(final Class<E> clazz, final IAliasPropertyMapper propMapper)
@@ -116,7 +108,7 @@ public abstract class AbstractParserObjectFactory<E> implements IParserObjectFac
         final Set<String> allPropertyNames = propMapper.getAllPropertyNames();
         final Set<String> propertyNames = new LinkedHashSet<String>(allPropertyNames);
         final Set<String> missingProperties = new LinkedHashSet<String>();
-        final Set<String> fieldNames = propertyDescriptors.keySet();
+        final Set<String> fieldNames = beanAnalyzer.getLabelToWriteMethods().keySet();
         for (final String fieldName : fieldNames)
         {
             if (propertyNames.contains(fieldName))
@@ -175,10 +167,10 @@ public abstract class AbstractParserObjectFactory<E> implements IParserObjectFac
     public E createObject(final String[] lineTokens) throws ParserException
     {
         final E object = ClassUtils.createInstance(beanClass);
-        for (final PropertyDescriptor descriptor : propertyDescriptors.values())
+        for (final Map.Entry<String, Method> entry : beanAnalyzer.getLabelToWriteMethods().entrySet())
         {
-            final Method writeMethod = descriptor.getWriteMethod();
-            final IPropertyModel propertyModel = tryGetPropertyModel(descriptor.getName());
+            final Method writeMethod = entry.getValue();
+            final IPropertyModel propertyModel = tryGetPropertyModel(entry.getKey());
             // They could have some optional descriptors that are not found in the file header.
             // Just ignore them.
             if (propertyModel != null)
diff --git a/common/source/java/ch/systemsx/cisd/common/parser/BeanAnalyzer.java b/common/source/java/ch/systemsx/cisd/common/parser/BeanAnalyzer.java
index 239b50a1cc3..ad4a0ff238d 100644
--- a/common/source/java/ch/systemsx/cisd/common/parser/BeanAnalyzer.java
+++ b/common/source/java/ch/systemsx/cisd/common/parser/BeanAnalyzer.java
@@ -16,14 +16,18 @@
 
 package ch.systemsx.cisd.common.parser;
 
-import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
 
+import org.apache.commons.lang.StringUtils;
+
 import ch.systemsx.cisd.common.annotation.BeanProperty;
-import ch.systemsx.cisd.common.utilities.ClassUtils;
+import ch.systemsx.cisd.common.utilities.AnnotationUtils;
 
 /**
  * A <i>Bean</i> class analyzer.
@@ -42,6 +46,8 @@ final class BeanAnalyzer<T>
 
     private final Set<String> optionalProperties = new TreeSet<String>();
 
+    private final Map<String, Method> labelToWriteMethods = new HashMap<String, Method>();
+
     BeanAnalyzer(final Class<T> beanClass)
     {
         this.beanClass = beanClass;
@@ -50,23 +56,37 @@ final class BeanAnalyzer<T>
 
     private final void fillProperties()
     {
-        final List<Field> annotatedFields = ClassUtils.getAnnotatedFieldList(beanClass, BeanProperty.class);
-        for (final Field field : annotatedFields)
+        final List<Method> annotatedMethods = AnnotationUtils.getAnnotatedMethodList(beanClass, BeanProperty.class);
+        for (final Method method : annotatedMethods)
         {
-            final BeanProperty annotation = field.getAnnotation(BeanProperty.class);
-            final String fieldName = field.getName();
+            checkMethod(method);
+            final BeanProperty annotation = method.getAnnotation(BeanProperty.class);
+            final String label = annotation.label();
+            assert StringUtils.isNotEmpty(label) : String.format(
+                    "BeanProperty annotation's label is not specified for method '%s'", method.getName());
+            labelToWriteMethods.put(label, method);
             final boolean optional = annotation.optional();
-            checkUnique(fieldName, optional);
+            checkUnique(label, optional);
             if (optional)
             {
-                optionalProperties.add(fieldName);
+                optionalProperties.add(label);
             } else
             {
-                mandatoryProperties.add(fieldName);
+                mandatoryProperties.add(label);
             }
         }
     }
 
+    private final static void checkMethod(final Method method)
+    {
+        final Class<?> returnType = method.getReturnType();
+        assert returnType.equals(Void.TYPE) : String.format("Return value of method '%s' must be void.", method
+                .getName());
+        final Class<?>[] parameterTypes = method.getParameterTypes();
+        assert parameterTypes.length == 1 : String.format("Annotated method '%s' must only accept one parameter.",
+                method.getName());
+    }
+
     private final void checkUnique(final String fieldName, final boolean optional)
     {
         assert optionalProperties.contains(fieldName) == false && mandatoryProperties.contains(fieldName) == false : String
@@ -99,4 +119,14 @@ final class BeanAnalyzer<T>
     {
         return Collections.unmodifiableSet(optionalProperties);
     }
+
+    /**
+     * Returns the mapping between static labels and methods.
+     * 
+     * @return never <code>null</code> but could return an empty unmodifiable <code>Map</code>.
+     */
+    final Map<String, Method> getLabelToWriteMethods()
+    {
+        return Collections.unmodifiableMap(labelToWriteMethods);
+    }
 }
\ No newline at end of file
diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/AnnotationUtils.java b/common/source/java/ch/systemsx/cisd/common/utilities/AnnotationUtils.java
new file mode 100644
index 00000000000..43bb0c8766c
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/AnnotationUtils.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.common.utilities;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * General utility methods for working with annotations.
+ * 
+ * @author Christian Ribeaud
+ */
+public final class AnnotationUtils
+{
+
+    private AnnotationUtils()
+    {
+        // Can not be instantiated.
+    }
+
+    /**
+     * For given <code>Class</code> returns a list of methods that are annotated with given <var>annotationClass</var>.
+     */
+    public final static List<Method> getAnnotatedMethodList(final Class<?> clazz,
+            final Class<? extends Annotation> annotationClass)
+    {
+        return AnnotationUtils.getAnnotatedMethodList(clazz, annotationClass, null);
+    }
+
+    /**
+     * For given <code>Class</code> returns a list of methods that are annotated with given <var>annotationClass</var>.
+     * 
+     * @param methods if <code>null</code>, then a new <code>List</code> is created.
+     */
+    private final static List<Method> getAnnotatedMethodList(final Class<?> clazz,
+            final Class<? extends Annotation> annotationClass, final List<Method> methods)
+    {
+        assert clazz != null : "Unspecified class.";
+        assert annotationClass != null : "Unspecified annotation class.";
+        List<Method> list = methods;
+        if (list == null)
+        {
+            list = new ArrayList<Method>();
+        }
+        for (final Method method : clazz.getDeclaredMethods())
+        {
+            if (method.getAnnotation(annotationClass) != null)
+            {
+                list.add(method);
+            }
+        }
+        final Class<?> superclass = clazz.getSuperclass();
+        if (superclass != null)
+        {
+            return getAnnotatedMethodList(superclass, annotationClass, list);
+        }
+        return list;
+    }
+
+    /**
+     * For given <code>Class</code> returns a list of fields that are annotated with given <var>annotationClass</var>.
+     */
+    public final static List<Field> getAnnotatedFieldList(final Class<?> clazz,
+            final Class<? extends Annotation> annotationClass)
+    {
+        return AnnotationUtils.getAnnotatedFieldList(clazz, annotationClass, null);
+    }
+
+    /**
+     * For given <code>Class</code> returns a list of fields that are annotated with given <var>annotationClass</var>.
+     * 
+     * @param fields if <code>null</code>, then a new <code>List</code> is created.
+     */
+    private final static List<Field> getAnnotatedFieldList(final Class<?> clazz,
+            final Class<? extends Annotation> annotationClass, final List<Field> fields)
+    {
+        assert clazz != null : "Unspecified class.";
+        assert annotationClass != null : "Unspecified annotation class.";
+        List<Field> list = fields;
+        if (list == null)
+        {
+            list = new ArrayList<Field>();
+        }
+        for (final Field field : clazz.getDeclaredFields())
+        {
+            if (field.getAnnotation(annotationClass) != null)
+            {
+                list.add(field);
+            }
+        }
+        final Class<?> superclass = clazz.getSuperclass();
+        if (superclass != null)
+        {
+            return getAnnotatedFieldList(superclass, annotationClass, list);
+        }
+        return list;
+    }
+}
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 e8ca3f8fe1b..e8ea6f609bb 100644
--- a/common/source/java/ch/systemsx/cisd/common/utilities/ClassUtils.java
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/ClassUtils.java
@@ -16,18 +16,14 @@
 
 package ch.systemsx.cisd.common.utilities;
 
-import java.lang.annotation.Annotation;
 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.Arrays;
-import java.util.List;
 
 import org.apache.commons.lang.StringUtils;
 
-import ch.systemsx.cisd.common.annotation.BeanProperty;
 import ch.systemsx.cisd.common.exceptions.CheckedExceptionTunnel;
 
 /**
@@ -42,45 +38,6 @@ public final class ClassUtils
         // Can not be instantiated.
     }
 
-    /**
-     * For given <code>Class</code> returns a list of fields that are annotated with given <var>annotationClass</var>.
-     */
-    public final static List<Field> getAnnotatedFieldList(final Class<?> clazz,
-            final Class<? extends Annotation> annotationClass)
-    {
-        return getAnnotatedFieldList(clazz, annotationClass, null);
-    }
-
-    /**
-     * For given <code>Class</code> returns a list of fields that are annotated with {@link BeanProperty}.
-     * 
-     * @param fields if <code>null</code>, then a new <code>List</code> is created.
-     */
-    private final static List<Field> getAnnotatedFieldList(final Class<?> clazz,
-            final Class<? extends Annotation> annotationClass, final List<Field> fields)
-    {
-        assert clazz != null : "Unspecified class.";
-        assert annotationClass != null : "Unspecified or not an annotation class.";
-        List<Field> list = fields;
-        if (list == null)
-        {
-            list = new ArrayList<Field>();
-        }
-        for (final Field field : clazz.getDeclaredFields())
-        {
-            if (field.getAnnotation(annotationClass) != null)
-            {
-                list.add(field);
-            }
-        }
-        final Class<?> superclass = clazz.getSuperclass();
-        if (superclass != null)
-        {
-            return getAnnotatedFieldList(superclass, annotationClass, list);
-        }
-        return list;
-    }
-
     /**
      * Returns the currently called <code>Method</code>.
      * <p>
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactoryTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactoryTest.java
index 3b29c1c1857..06a646f6402 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactoryTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactoryTest.java
@@ -44,7 +44,7 @@ public final class AbstractParserObjectFactoryTest
             { "Bean Name", "Bean Description", "1" };
     }
 
-    private final void checkBean(Bean bean)
+    private final void checkBean(final Bean bean)
     {
         assertEquals("Bean Name", bean.name);
         assertEquals("Bean Description", bean.description);
@@ -66,7 +66,7 @@ public final class AbstractParserObjectFactoryTest
         {
             new BeanFactory(Bean.class, propertyMapper);
             fail("Following properties '[isnotin]' are not part of 'Bean'.");
-        } catch (UnmatchedPropertiesException ex)
+        } catch (final UnmatchedPropertiesException ex)
         {
             assertEquals("Following header columns are not part of 'Bean': IsNotIn", ex.getMessage());
         }
@@ -75,16 +75,16 @@ public final class AbstractParserObjectFactoryTest
     @Test
     public final void testMandatoryFields()
     {
-        DefaultAliasPropertyMapper propertyMapper = new DefaultAliasPropertyMapper(new String[]
+        final DefaultAliasPropertyMapper propertyMapper = new DefaultAliasPropertyMapper(new String[]
             { "description" });
         try
         {
-            BeanFactory beanFactory = new BeanFactory(Bean.class, propertyMapper);
-            String[] lineTokens = new String[]
+            final BeanFactory beanFactory = new BeanFactory(Bean.class, propertyMapper);
+            final String[] lineTokens = new String[]
                 { "1. experiment" };
             beanFactory.createObject(lineTokens);
             fail("Field/Property name 'name' is mandatory.");
-        } catch (MandatoryPropertyMissingException ex)
+        } catch (final MandatoryPropertyMissingException ex)
         {
             assertEquals(String.format(MandatoryPropertyMissingException.MESSAGE_FORMAT, "name"), ex.getMessage());
         }
@@ -94,9 +94,9 @@ public final class AbstractParserObjectFactoryTest
     public final void testTooManyDataColumns()
     {
         final IAliasPropertyMapper propertyMapper = createPropertyMapper();
-        BeanFactory beanFactory = new BeanFactory(Bean.class, propertyMapper);
-        String[] lineTokens = (String[]) ArrayUtils.add(createDefaultLineTokens(), "notUsed");
-        Bean bean = beanFactory.createObject(lineTokens);
+        final BeanFactory beanFactory = new BeanFactory(Bean.class, propertyMapper);
+        final String[] lineTokens = (String[]) ArrayUtils.add(createDefaultLineTokens(), "notUsed");
+        final Bean bean = beanFactory.createObject(lineTokens);
         checkBean(bean);
     }
 
@@ -104,15 +104,15 @@ public final class AbstractParserObjectFactoryTest
     public final void testNotEnoughDataColumns()
     {
         final IAliasPropertyMapper propertyMapper = createPropertyMapper();
-        BeanFactory beanFactory = new BeanFactory(Bean.class, propertyMapper);
-        String[] defaultTokens = createDefaultLineTokens();
-        String[] lineTokens = (String[]) ArrayUtils.remove(defaultTokens, defaultTokens.length - 1);
-        String msg = String.format(IndexOutOfBoundsException.MESSAGE_FORMAT, 2, lineTokens.length);
+        final BeanFactory beanFactory = new BeanFactory(Bean.class, propertyMapper);
+        final String[] defaultTokens = createDefaultLineTokens();
+        final String[] lineTokens = (String[]) ArrayUtils.remove(defaultTokens, defaultTokens.length - 1);
+        final String msg = String.format(IndexOutOfBoundsException.MESSAGE_FORMAT, 2, lineTokens.length);
         try
         {
             beanFactory.createObject(lineTokens);
             fail(msg);
-        } catch (IndexOutOfBoundsException ex)
+        } catch (final IndexOutOfBoundsException ex)
         {
             assertEquals(msg, ex.getMessage());
         }
@@ -122,12 +122,12 @@ public final class AbstractParserObjectFactoryTest
     public final void testRegisterConverterWithNull()
     {
         final IAliasPropertyMapper propertyMapper = createPropertyMapper();
-        BeanFactory beanFactory = new BeanFactory(Bean.class, propertyMapper);
+        final BeanFactory beanFactory = new BeanFactory(Bean.class, propertyMapper);
         try
         {
             beanFactory.registerConverter(null, null);
             fail("Null type is not allowed.");
-        } catch (AssertionError ex)
+        } catch (final AssertionError ex)
         {
             // Nothing to do here.
         }
@@ -150,7 +150,6 @@ public final class AbstractParserObjectFactoryTest
 
     public final static class Bean
     {
-        @BeanProperty
         private String name;
 
         private String description;
@@ -162,7 +161,8 @@ public final class AbstractParserObjectFactoryTest
             return name;
         }
 
-        public final void setName(String name)
+        @BeanProperty(label = "name")
+        public final void setName(final String name)
         {
             this.name = name;
         }
@@ -172,7 +172,8 @@ public final class AbstractParserObjectFactoryTest
             return number;
         }
 
-        public final void setNumber(int number)
+        @BeanProperty(label = "number", optional = true)
+        public final void setNumber(final int number)
         {
             this.number = number;
         }
@@ -182,7 +183,8 @@ public final class AbstractParserObjectFactoryTest
             return description;
         }
 
-        public final void setDescription(String description)
+        @BeanProperty(label = "description", optional = true)
+        public final void setDescription(final String description)
         {
             this.description = description;
         }
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/AnnotationUtilsTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/AnnotationUtilsTest.java
new file mode 100644
index 00000000000..3c92e51ba37
--- /dev/null
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/AnnotationUtilsTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.common.utilities;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.fail;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.common.annotation.BeanProperty;
+
+/**
+ * Test cases for the {@link AnnotationUtils} class.
+ * 
+ * @author Christian Ribeaud
+ */
+public final class AnnotationUtilsTest
+{
+
+    @Test
+    public final void testGetAnnotatedFieldList()
+    {
+        try
+        {
+            AnnotationUtils.getAnnotatedFieldList(null, null);
+            fail("Null value not accepted.");
+        } catch (final AssertionError e)
+        {
+            // Nothing to do here.
+        }
+        List<Field> fields = AnnotationUtils.getAnnotatedFieldList(A.class, Deprecated.class);
+        assertEquals(1, fields.size());
+        fields = AnnotationUtils.getAnnotatedFieldList(B.class, Deprecated.class);
+        assertEquals(2, fields.size());
+    }
+
+    @Test
+    public final void testGetAnnotatedMethodList()
+    {
+        try
+        {
+            AnnotationUtils.getAnnotatedMethodList(null, null);
+            fail("Null value not accepted.");
+        } catch (final AssertionError e)
+        {
+            // Nothing to do here.
+        }
+        List<Method> methods = AnnotationUtils.getAnnotatedMethodList(A.class, BeanProperty.class);
+        assertEquals(1, methods.size());
+        methods = AnnotationUtils.getAnnotatedMethodList(B.class, BeanProperty.class);
+        assertEquals(2, methods.size());
+        for (final Method method : methods)
+        {
+            assertEquals(method.getName(), "setA");
+        }
+    }
+
+    //
+    // Helper classes
+    //
+
+    private static class A
+    {
+
+        Object a;
+
+        @Deprecated
+        Object b;
+
+        @BeanProperty
+        void setA(final Object a)
+        {
+            this.a = a;
+        }
+
+    }
+
+    private final static class B extends A
+    {
+
+        @Deprecated
+        Object c;
+
+        //
+        // A
+        //
+
+        @Override
+        @BeanProperty
+        final void setA(final Object a)
+        {
+            this.a = a;
+        }
+    }
+}
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 47262b8d428..c53fafd749a 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ClassUtilsTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ClassUtilsTest.java
@@ -25,15 +25,12 @@ import static org.testng.AssertJUnit.assertTrue;
 import static org.testng.AssertJUnit.fail;
 
 import java.io.IOException;
-import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Properties;
 
 import org.testng.annotations.Test;
 
-import ch.systemsx.cisd.common.annotation.BeanProperty;
-
 /**
  * Test cases for the {@link ClassUtils} class.
  * 
@@ -180,15 +177,6 @@ public final class ClassUtilsTest
         assertSame(object, myExtendedClass.finalObject);
     }
 
-    @Test
-    public final void testGetAnnotatedFieldList()
-    {
-        List<Field> fields = ClassUtils.getAnnotatedFieldList(A.class, BeanProperty.class);
-        assertEquals(1, fields.size());
-        fields = ClassUtils.getAnnotatedFieldList(B.class, BeanProperty.class);
-        assertEquals(2, fields.size());
-    }
-
     //
     // Helper Classes
     //
@@ -246,24 +234,4 @@ public final class ClassUtilsTest
         }
 
     }
-
-    private static class A
-    {
-
-        @BeanProperty
-        Object a;
-
-        Object b;
-
-    }
-
-    private final static class B extends A
-    {
-
-        @SuppressWarnings("hiding")
-        @BeanProperty
-        Object a;
-
-        Object c;
-    }
 }
-- 
GitLab