From d3b408fe0fa9bb10776ebbe94ecac47572cad7d2 Mon Sep 17 00:00:00 2001
From: ribeaudc <ribeaudc>
Date: Sat, 1 Mar 2008 02:24:56 +0000
Subject: [PATCH] change: - Annotation 'Mandatory' renamed to 'BeanProperty'.

SVN: 4615
---
 .../{Mandatory.java => BeanProperty.java}     | 18 +++++--
 .../parser/AbstractParserObjectFactory.java   | 21 +++++++-
 .../cisd/common/utilities/ClassUtils.java     | 48 +++++--------------
 .../AbstractParserObjectFactoryTest.java      |  4 +-
 .../cisd/common/utilities/ClassUtilsTest.java | 39 +++++++++++++++
 5 files changed, 85 insertions(+), 45 deletions(-)
 rename common/source/java/ch/systemsx/cisd/common/annotation/{Mandatory.java => BeanProperty.java} (69%)

diff --git a/common/source/java/ch/systemsx/cisd/common/annotation/Mandatory.java b/common/source/java/ch/systemsx/cisd/common/annotation/BeanProperty.java
similarity index 69%
rename from common/source/java/ch/systemsx/cisd/common/annotation/Mandatory.java
rename to common/source/java/ch/systemsx/cisd/common/annotation/BeanProperty.java
index 0cbeaf0d3cd..fb33ba2cb22 100644
--- a/common/source/java/ch/systemsx/cisd/common/annotation/Mandatory.java
+++ b/common/source/java/ch/systemsx/cisd/common/annotation/BeanProperty.java
@@ -17,20 +17,28 @@
 package ch.systemsx.cisd.common.annotation;
 
 import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 /**
- * Marks a field (typically a JavaBean field) as being 'mandatory'.
+ * Marks a field that will be set via the parser.
+ * <p>
+ * By default, each property annotated with <code>BeanProperty</code> is mandatory.
+ * </p>
  * 
+ * @see ch.systemsx.cisd.common.parser
  * @author Christian Ribeaud
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.FIELD)
-@Inherited
-public @interface Mandatory
+public @interface BeanProperty
 {
-
+    /**
+     * Whether this bean property is optional or not.
+     * <p>
+     * Default is <code>false</code>.
+     * </p>
+     */
+    public boolean optional() default false;
 }
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 fbe1a80ba6c..ab3c52f09ff 100644
--- a/common/source/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactory.java
+++ b/common/source/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactory.java
@@ -17,12 +17,16 @@
 package ch.systemsx.cisd.common.parser;
 
 import java.beans.PropertyDescriptor;
+import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.util.HashSet;
 import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import ch.systemsx.cisd.common.annotation.BeanProperty;
 import ch.systemsx.cisd.common.converter.Converter;
 import ch.systemsx.cisd.common.converter.ConverterPool;
 import ch.systemsx.cisd.common.exceptions.CheckedExceptionTunnel;
@@ -59,13 +63,28 @@ 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);
-        mandatoryFields = ClassUtils.getMandatoryFields(beanClass, true);
+        mandatoryFields = createMandatoryFields(beanClass);
         checkPropertyMapper(beanClass, propertyMapper);
         this.propertyMapper = propertyMapper;
         converterPool = createConverterPool();
         this.beanClass = beanClass;
     }
 
+    private final static Set<String> createMandatoryFields(final Class<?> beanClass)
+    {
+        final List<Field> annotatedFields = ClassUtils.getAnnotatedFieldList(beanClass, BeanProperty.class);
+        final Set<String> mandatoryFields = new HashSet<String>();
+        for (final Field field : annotatedFields)
+        {
+            final BeanProperty annotation = field.getAnnotation(BeanProperty.class);
+            if (annotation.optional() == false)
+            {
+                mandatoryFields.add(field.getName().toLowerCase());
+            }
+        }
+        return mandatoryFields;
+    }
+
     private final static ConverterPool createConverterPool()
     {
         return new ConverterPool();
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 df1facee4ed..a79a5bdaf4e 100644
--- a/common/source/java/ch/systemsx/cisd/common/utilities/ClassUtils.java
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/ClassUtils.java
@@ -22,13 +22,11 @@ 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 org.apache.commons.lang.StringUtils;
 
-import ch.systemsx.cisd.common.annotation.Mandatory;
+import ch.systemsx.cisd.common.annotation.BeanProperty;
 import ch.systemsx.cisd.common.exceptions.CheckedExceptionTunnel;
 
 /**
@@ -44,47 +42,23 @@ public final class ClassUtils
     }
 
     /**
-     * For given <code>Class</code> returns a set of field names that are annotated with {@link Mandatory}.
-     * <p>
-     * Never returns <code>null</code> but could return an empty set.
-     * </p>
-     * 
-     * @param clazz The class to return the mandatory fields for.
-     * @param convertToLowerCase If <code>true</code>, all field names are converted to lower case in the set
-     *            returned.
-     */
-    public final static Set<String> getMandatoryFields(final Class<?> clazz, final boolean convertToLowerCase)
-    {
-        final Set<String> set = new HashSet<String>();
-        final List<Field> fields = ClassUtils.getMandatoryFieldsList(clazz);
-        for (final Field field : fields)
-        {
-            if (convertToLowerCase)
-            {
-                set.add(field.getName().toLowerCase());
-            } else
-            {
-                set.add(field.getName());
-            }
-        }
-        return set;
-    }
-
-    /**
-     * For given <code>Class</code> returns a list of fields that are annotated with {@link Mandatory}.
+     * For given <code>Class</code> returns a list of fields that are annotated with given <var>annotationClass</var>.
      */
-    private final static List<Field> getMandatoryFieldsList(final Class<?> clazz)
+    public final static List<Field> getAnnotatedFieldList(final Class<?> clazz, final Class<?> annotationClass)
     {
-        return getMandatoryFields(clazz, null);
+        return getAnnotatedFieldList(clazz, annotationClass, null);
     }
 
     /**
-     * For given <code>Class</code> returns a list of fields that are annotated with {@link Mandatory}.
+     * 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> getMandatoryFields(final Class<?> clazz, final List<Field> fields)
+    private final static List<Field> getAnnotatedFieldList(final Class<?> clazz, final Class<?> annotationClass,
+            final List<Field> fields)
     {
+        assert clazz != null : "Unspecified class.";
+        assert annotationClass != null && annotationClass.isAnnotation() : "Unspecified or not an annotation class.";
         List<Field> list = fields;
         if (list == null)
         {
@@ -92,7 +66,7 @@ public final class ClassUtils
         }
         for (final Field field : clazz.getDeclaredFields())
         {
-            if (field.getAnnotation(Mandatory.class) != null)
+            if (field.getAnnotation(BeanProperty.class) != null)
             {
                 list.add(field);
             }
@@ -100,7 +74,7 @@ public final class ClassUtils
         final Class<?> superclass = clazz.getSuperclass();
         if (superclass != null)
         {
-            return getMandatoryFields(superclass, list);
+            return getAnnotatedFieldList(superclass, annotationClass, list);
         }
         return list;
     }
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 d0196406ce4..f2e139487fd 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactoryTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactoryTest.java
@@ -22,7 +22,7 @@ import static org.testng.AssertJUnit.fail;
 import org.apache.commons.lang.ArrayUtils;
 import org.testng.annotations.Test;
 
-import ch.systemsx.cisd.common.annotation.Mandatory;
+import ch.systemsx.cisd.common.annotation.BeanProperty;
 
 /**
  * Test cases for corresponding {@link AbstractParserObjectFactory} class.
@@ -150,7 +150,7 @@ public final class AbstractParserObjectFactoryTest
 
     public final static class Bean
     {
-        @Mandatory
+        @BeanProperty
         private String nAme;
 
         private String description;
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 44ca0f90ef5..6caf2b14dd1 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ClassUtilsTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ClassUtilsTest.java
@@ -25,12 +25,15 @@ 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.
  * 
@@ -177,6 +180,22 @@ public final class ClassUtilsTest
         assertSame(object, myExtendedClass.finalObject);
     }
 
+    @Test
+    public final void testGetAnnotatedFieldList()
+    {
+        try
+        {
+            ClassUtils.getAnnotatedFieldList(A.class, String.class);
+            fail("Not an annotation class.");
+        } catch (final AssertionError e)
+        {
+        }
+        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
     //
@@ -234,4 +253,24 @@ 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