Revision: 790
          http://stripes.svn.sourceforge.net/stripes/?rev=790&view=rev
Author:   bengunter
Date:     2008-01-21 10:44:14 -0800 (Mon, 21 Jan 2008)

Log Message:
-----------
Fixed STS-78 (at long last!). When validation info is loaded for a class, 
Stripes climbs the class hierarchy checking each class for conflicts in the 
annotations. The @Validate and @ValidateNestedProperties for a single property 
must be present on only one element (getter, setter or field) in a single class.

Modified Paths:
--------------
    
trunk/stripes/src/net/sourceforge/stripes/validation/DefaultValidationMetadataProvider.java

Modified: 
trunk/stripes/src/net/sourceforge/stripes/validation/DefaultValidationMetadataProvider.java
===================================================================
--- 
trunk/stripes/src/net/sourceforge/stripes/validation/DefaultValidationMetadataProvider.java
 2008-01-21 17:00:29 UTC (rev 789)
+++ 
trunk/stripes/src/net/sourceforge/stripes/validation/DefaultValidationMetadataProvider.java
 2008-01-21 18:44:14 UTC (rev 790)
@@ -79,8 +79,11 @@
      * @param clazz a class
      * @return A map of (possibly nested) property names to [EMAIL PROTECTED] 
ValidationMetadata} for the
      *         property.
+     * @throws StripesRuntimeException if conflicts are found in the 
validation annotations, as
+     *             determined by [EMAIL PROTECTED] 
#checkForValidationAnnotationConflicts(Class)}
      */
     protected Map<String, ValidationMetadata> loadForClass(Class<?> clazz) {
+        checkForValidationAnnotationConflicts(clazz);
         Map<String, ValidationMetadata> meta = new HashMap<String, 
ValidationMetadata>();
         try {
             PropertyDescriptor[] pds = 
Introspector.getBeanInfo(clazz).getPropertyDescriptors();
@@ -177,4 +180,117 @@
 
         return Collections.unmodifiableMap(meta);
     }
+
+    /**
+     * Checks the given class and all its superclasses to ensure there are no 
conflicts in the
+     * [EMAIL PROTECTED] Validate} and [EMAIL PROTECTED] 
ValidateNestedProperties} annotations. These annotations may be
+     * applied to exactly one of the getter method, setter method, or field to 
which they apply.
+     * They must be applied together on the same element. If any conflicts are 
found in the class
+     * hierarchy, a [EMAIL PROTECTED] StripesRuntimeException} is thrown 
explaining what went wrong.
+     * 
+     * @param clazz the class to check
+     * @throws StripesRuntimeException if any conflicts are found
+     */
+    protected void checkForValidationAnnotationConflicts(Class<?> clazz) {
+        try {
+            do {
+                PropertyDescriptor[] pds = 
Introspector.getBeanInfo(clazz).getPropertyDescriptors();
+                for (PropertyDescriptor pd : pds) {
+                    String propertyName = pd.getName();
+                    Method accessor = pd.getReadMethod();
+                    Method mutator = pd.getWriteMethod();
+                    Field field = null;
+                    try {
+                        field = clazz.getDeclaredField(propertyName);
+                    }
+                    catch (NoSuchFieldException e) {
+                    }
+
+                    boolean onAccessor = accessor != null
+                            && Modifier.isPublic(accessor.getModifiers())
+                            && accessor.getDeclaringClass().equals(clazz)
+                            && (accessor.isAnnotationPresent(Validate.class) 
|| accessor
+                                    
.isAnnotationPresent(ValidateNestedProperties.class));
+                    boolean onMutator = mutator != null
+                            && Modifier.isPublic(mutator.getModifiers())
+                            && mutator.getDeclaringClass().equals(clazz)
+                            && (mutator.isAnnotationPresent(Validate.class) || 
mutator
+                                    
.isAnnotationPresent(ValidateNestedProperties.class));
+                    boolean onField = field != null
+                            && !Modifier.isStatic(field.getModifiers())
+                            && field.getDeclaringClass().equals(clazz)
+                            && (field.isAnnotationPresent(Validate.class) || 
field
+                                    
.isAnnotationPresent(ValidateNestedProperties.class));
+
+                    // I don't think George Boole would like this ...
+                    int count = 0;
+                    if (onAccessor) ++count;
+                    if (onMutator) ++count;
+                    if (onField) ++count;
+
+                    // must be 0 or 1
+                    if (count > 1) {
+                        StringBuilder buf = new StringBuilder(
+                                "There are conflicting @Validate and/or 
@ValidateNestedProperties annotations in ")
+                                .append(clazz)
+                                .append(". The following elements are 
improperly annotated for the '")
+                                .append(propertyName).append("' property:\n");
+                        if (onAccessor) {
+                            boolean hasSimple = 
accessor.isAnnotationPresent(Validate.class);
+                            boolean hasNested = accessor
+                                    
.isAnnotationPresent(ValidateNestedProperties.class);
+                            buf.append("--> Getter method 
").append(accessor.getName()).append(
+                                    " is annotated with ");
+                            if (hasSimple)
+                                buf.append("@Validate");
+                            if (hasSimple && hasNested)
+                                buf.append(" and ");
+                            if (hasNested)
+                                buf.append("@ValidateNestedProperties");
+                            buf.append('\n');
+                        }
+                        if (onMutator) {
+                            boolean hasSimple = 
mutator.isAnnotationPresent(Validate.class);
+                            boolean hasNested = mutator
+                                    
.isAnnotationPresent(ValidateNestedProperties.class);
+                            buf.append("--> Setter method 
").append(mutator.getName()).append(
+                                    " is annotated with ");
+                            if (hasSimple)
+                                buf.append("@Validate");
+                            if (hasSimple && hasNested)
+                                buf.append(" and ");
+                            if (hasNested)
+                                buf.append("@ValidateNestedProperties");
+                            buf.append('\n');
+                        }
+                        if (onField) {
+                            boolean hasSimple = 
field.isAnnotationPresent(Validate.class);
+                            boolean hasNested = field
+                                    
.isAnnotationPresent(ValidateNestedProperties.class);
+                            buf.append("--> Field 
").append(field.getName()).append(
+                                    " is annotated with ");
+                            if (hasSimple)
+                                buf.append("@Validate");
+                            if (hasSimple && hasNested)
+                                buf.append(" and ");
+                            if (hasNested)
+                                buf.append("@ValidateNestedProperties");
+                            buf.append('\n');
+                        }
+                        throw new StripesRuntimeException(buf.toString());
+                    }
+                }
+            } while ((clazz = clazz.getSuperclass()) != null);
+        }
+        catch (RuntimeException e) {
+            log.error(e, "Failure checking @Validate annotations ", 
getClass().getName());
+            throw e;
+        }
+        catch (Exception e) {
+            log.error(e, "Failure checking @Validate annotations ", 
getClass().getName());
+            StripesRuntimeException sre = new 
StripesRuntimeException(e.getMessage(), e);
+            sre.setStackTrace(e.getStackTrace());
+            throw sre;
+        }
+    }
 }


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development

Reply via email to