You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by kw...@apache.org on 2014/11/19 16:23:06 UTC

svn commit: r1640572 - in /sling/trunk/contrib/extensions/validation: api/src/main/java/org/apache/sling/validation/api/ api/src/main/java/org/apache/sling/validation/api/exceptions/ core/ core/src/main/java/org/apache/sling/validation/impl/ core/src/m...

Author: kwin
Date: Wed Nov 19 15:23:05 2014
New Revision: 1640572

URL: http://svn.apache.org/r1640572
Log:
SLING-4138, refactored Validator interface to support arbitrary types, arrays and cross-field validation

Added:
    sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/ParameterizedValidator.java
    sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ParameterizedValidatorImpl.java
    sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/util/ValidatorTypeUtil.java
    sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/ValidatorTypeUtilTest.java
    sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/
    sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/AbstractValidatorWithAdditionalType.java
    sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/DateValidator.java
    sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/DerivedStringValidator.java
    sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/ExtendedStringValidator.java
    sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/GenericTypeParameterBaseClass.java
    sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/IntegerValidator.java
    sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/StringArrayValidator.java
    sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/StringValidator.java
Removed:
    sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/Type.java
    sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/exceptions/NonExistingTypeException.java
Modified:
    sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/ResourceProperty.java
    sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/Validator.java
    sling/trunk/contrib/extensions/validation/core/pom.xml
    sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/JCRValidationModel.java
    sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ResourcePropertyImpl.java
    sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationServiceImpl.java
    sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/util/JCRBuilder.java
    sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/validators/RegexValidator.java
    sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/ValidationServiceImplTest.java

Added: sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/ParameterizedValidator.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/ParameterizedValidator.java?rev=1640572&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/ParameterizedValidator.java (added)
+++ sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/ParameterizedValidator.java Wed Nov 19 15:23:05 2014
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.validation.api;
+
+import java.util.Map;
+
+/**
+ * Defines a validator instance with information about the type and the parameterization of the validator.
+ *
+ */
+public interface ParameterizedValidator {
+
+    public abstract Validator<?> getValidator();
+
+    public abstract Map<String, String> getParameters();
+
+    public abstract Class<?> getType();
+
+}
\ No newline at end of file

Modified: sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/ResourceProperty.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/ResourceProperty.java?rev=1640572&r1=1640571&r2=1640572&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/ResourceProperty.java (original)
+++ sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/ResourceProperty.java Wed Nov 19 15:23:05 2014
@@ -18,7 +18,7 @@
  */
 package org.apache.sling.validation.api;
 
-import java.util.Map;
+import java.util.List;
 
 /**
  * Describes a {@link org.apache.sling.api.resource.Resource} property.
@@ -33,13 +33,6 @@ public interface ResourceProperty {
     String getName();
 
     /**
-     * Returns the type of data this property should contain.
-     *
-     * @return the type
-     */
-    Type getType();
-
-    /**
      * Returns {@code true} if this property is expected to be a multiple property (e.g. array of values).
      *
      * @return {@code true} if the  property is multiple, {@code false} otherwise
@@ -47,10 +40,9 @@ public interface ResourceProperty {
     boolean isMultiple();
 
     /**
-     * Returns a map containing the validators that should be applied to this property together with the arguments for each validator, also
-     * stored in a key-value map.
+     * Returns a list of {@link ParameterizedValidator}s which should be applied on this property.
      *
-     * @return the validators
+     * @return the list of validators
      */
-    Map<Validator, Map<String, String>> getValidators();
+    List<ParameterizedValidator> getValidators();
 }

Modified: sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/Validator.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/Validator.java?rev=1640572&r1=1640571&r2=1640572&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/Validator.java (original)
+++ sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/Validator.java Wed Nov 19 15:23:05 2014
@@ -20,20 +20,53 @@ package org.apache.sling.validation.api;
 
 import java.util.Map;
 
+import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.validation.api.exceptions.SlingValidationException;
 
 /**
  * A {@code Validator} is responsible for validating a single piece of information according to an internal constraint.
  */
-public interface Validator {
+public interface Validator <T> {
 
     /**
-     * Validates the {@code data} according to the internal constraints of this validator.
+     * Validates the {@code data} and/or the {@code valueMap} according to the internal constraints of this validator.
+     * 
+     * The validator can enforce the type of the given data just by setting the appropriate parameter type which can be any non-primitive class. 
+     * Depending on whether this type is an array or not the {@code validate} method is called differently:
+     * <table> 
+     *  <tr>
+     *    <th>T is array type</th>
+     *    <th>Valuemap contains array value</th>
+     *    <th>{@code validate} is called...</th>
+     *  </tr>
+     *  <tr>
+     *    <td>yes</td>
+     *    <td>yes</td>
+     *    <td>once per property with {@code data} containing the full array</td>
+     *  </tr>
+     *  <tr>
+     *    <td>yes</td>
+     *    <td>no</td>
+     *    <td>once per property with {@code data} containing a single element array</td>
+     *  </tr>
+     *  <tr>
+     *    <td>no</td>
+     *    <td>yes</td>
+     *    <td>once per element in the property array with {@code data} containing one array element</td>
+     *  </tr>
+     *  <tr>
+     *    <td>no</td>
+     *    <td>no</td>
+     *    <td>once per property with {@code data} containing the value of the property</td>
+     *  </tr>
+     * </table>
+     * If the data cannot be converted into the type {@code T} the validator is not called, but validation fails.
      *
-     * @param data the data to validate
-     * @return validation error message if validation was not successfull, {@code null} otherwise. In case an empty string is returned a generic validation error message is used.
-     * @throws org.apache.sling.validation.api.exceptions.SlingValidationException if the method is called with {@code null} arguments or
-     * some expected arguments are missing from the arguments map
+     * @param data the data to validate (primary property), never {@code null}.
+     * @param valueMap all properties (only used for validations considering multiple properties), never {@code null}.
+     * @param arguments the parameterization of the validator. Might be {@code null} in case no arguments were given.
+     * @return validation error message if validation was not successful, {@code null} otherwise. In case an empty string is returned a generic validation error message is used.
+     * @throws org.apache.sling.validation.api.exceptions.SlingValidationException if some expected arguments are missing from the arguments map
      */
-    String validate(String data, Map<String, String> arguments) throws SlingValidationException;
+    String validate(T data, ValueMap valueMap, Map<String, String> arguments) throws SlingValidationException;
 }

Modified: sling/trunk/contrib/extensions/validation/core/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/pom.xml?rev=1640572&r1=1640571&r2=1640572&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/pom.xml (original)
+++ sling/trunk/contrib/extensions/validation/core/pom.xml Wed Nov 19 15:23:05 2014
@@ -68,6 +68,7 @@
                         <Private-Package>
                             org.apache.sling.validation.impl*
                         </Private-Package>
+                        <Embed-Dependency>commons-lang3</Embed-Dependency>
                     </instructions>
                 </configuration>
             </plugin>
@@ -142,10 +143,11 @@
             <version>2.7.1</version>
             <scope>provided</scope>
         </dependency>
+        <!-- used for getting type information of validators -->
         <dependency>
-            <groupId>commons-lang</groupId>
-            <artifactId>commons-lang</artifactId>
-            <version>2.5</version>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.3.2</version>
             <scope>provided</scope>
         </dependency>
         <dependency>

Modified: sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/JCRValidationModel.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/JCRValidationModel.java?rev=1640572&r1=1640571&r2=1640572&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/JCRValidationModel.java (original)
+++ sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/JCRValidationModel.java Wed Nov 19 15:23:05 2014
@@ -21,7 +21,7 @@ package org.apache.sling.validation.impl
 import java.util.List;
 import java.util.Set;
 
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.sling.validation.api.ChildResource;
 import org.apache.sling.validation.api.ResourceProperty;
 import org.apache.sling.validation.api.ValidationModel;

Added: sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ParameterizedValidatorImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ParameterizedValidatorImpl.java?rev=1640572&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ParameterizedValidatorImpl.java (added)
+++ sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ParameterizedValidatorImpl.java Wed Nov 19 15:23:05 2014
@@ -0,0 +1,45 @@
+package org.apache.sling.validation.impl;
+
+import java.util.Map;
+
+import org.apache.sling.validation.api.ParameterizedValidator;
+import org.apache.sling.validation.api.Validator;
+import org.apache.sling.validation.impl.util.ValidatorTypeUtil;
+
+public class ParameterizedValidatorImpl implements ParameterizedValidator {
+    private final Validator<?> validator;
+    private final Map<String, String> parameters;
+    private final Class<?> type;
+    
+    public ParameterizedValidatorImpl(Validator<?> validator, Map<String, String> parameters) {
+        super();
+        this.validator = validator;
+        this.parameters = parameters;
+        // cache type information as this is using reflection
+        this.type = ValidatorTypeUtil.getValidatorType(validator);
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.sling.validation.impl.ParameterizedValidator#getValidator()
+     */
+    @Override
+    public Validator<?> getValidator() {
+        return validator;
+    }
+    
+    /* (non-Javadoc)
+     * @see org.apache.sling.validation.impl.ParameterizedValidator#getParameters()
+     */
+    @Override
+    public Map<String, String> getParameters() {
+        return parameters;
+    }
+    
+    /* (non-Javadoc)
+     * @see org.apache.sling.validation.impl.ParameterizedValidator#getType()
+     */
+    @Override
+    public Class<?> getType() {
+        return type;
+    }
+}

Modified: sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ResourcePropertyImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ResourcePropertyImpl.java?rev=1640572&r1=1640571&r2=1640572&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ResourcePropertyImpl.java (original)
+++ sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ResourcePropertyImpl.java Wed Nov 19 15:23:05 2014
@@ -18,26 +18,23 @@
  */
 package org.apache.sling.validation.impl;
 
-import org.apache.sling.validation.api.ResourceProperty;
-import org.apache.sling.validation.api.Type;
-import org.apache.sling.validation.api.Validator;
+import java.util.List;
 
-import java.util.Map;
+import org.apache.sling.validation.api.ParameterizedValidator;
+import org.apache.sling.validation.api.ResourceProperty;
 
 public class ResourcePropertyImpl implements ResourceProperty {
 
     private String name;
-    private Type type;
     private boolean isMultiple;
-    private Map<Validator, Map<String, String>> validators;
+    private List<ParameterizedValidator> validators;
 
-    public ResourcePropertyImpl(String name, Type type, Map<Validator, Map<String, String>> validators) {
-        this(name, type, false, validators);
+    public ResourcePropertyImpl(String name, List<ParameterizedValidator> validators) {
+        this(name, false, validators);
     }
 
-    public ResourcePropertyImpl(String name, Type type, boolean isMultiple, Map<Validator, Map<String, String>> validators) {
+    public ResourcePropertyImpl(String name, boolean isMultiple, List<ParameterizedValidator> validators) {
         this.name = name;
-        this.type = type;
         this.isMultiple = isMultiple;
         this.validators = validators;
     }
@@ -48,17 +45,12 @@ public class ResourcePropertyImpl implem
     }
 
     @Override
-    public Type getType() {
-        return type;
-    }
-
-    @Override
     public boolean isMultiple() {
         return isMultiple;
     }
 
     @Override
-    public Map<Validator, Map<String, String>> getValidators() {
+    public List<ParameterizedValidator> getValidators() {
         return validators;
     }
 }

Modified: sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationServiceImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationServiceImpl.java?rev=1640572&r1=1640571&r2=1640572&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationServiceImpl.java (original)
+++ sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationServiceImpl.java Wed Nov 19 15:23:05 2014
@@ -18,7 +18,23 @@
  */
 package org.apache.sling.validation.impl;
 
-import org.apache.commons.lang.StringUtils;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.jcr.query.Query;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.reflect.TypeUtils;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
@@ -32,8 +48,8 @@ import org.apache.sling.commons.osgi.Pro
 import org.apache.sling.commons.threads.ThreadPool;
 import org.apache.sling.commons.threads.ThreadPoolManager;
 import org.apache.sling.validation.api.ChildResource;
+import org.apache.sling.validation.api.ParameterizedValidator;
 import org.apache.sling.validation.api.ResourceProperty;
-import org.apache.sling.validation.api.Type;
 import org.apache.sling.validation.api.ValidationModel;
 import org.apache.sling.validation.api.ValidationResult;
 import org.apache.sling.validation.api.ValidationService;
@@ -50,15 +66,8 @@ import org.osgi.service.event.EventHandl
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.jcr.query.Query;
 
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+
 
 @Component()
 @Service(ValidationService.class)
@@ -113,13 +122,13 @@ public class ValidationServiceImpl imple
         ValidationResultImpl result = new ValidationResultImpl();
 
         // validate direct properties of the resource
-        validateResourceProperties(resource, resource, model.getResourceProperties(), result);
+        validateValueMap(resource.adaptTo(ValueMap.class), model.getResourceProperties(), result, "");
 
         // validate children resources, if any
         for (ChildResource childResource : model.getChildren()) {
             Resource expectedResource = resource.getChild(childResource.getName());
             if (expectedResource != null) {
-                validateResourceProperties(resource, expectedResource, childResource.getProperties(), result);
+                validateValueMap(expectedResource.adaptTo(ValueMap.class), childResource.getProperties(), result, childResource.getName() + "/");
             } else {
                 result.addFailureMessage(childResource.getName(), "Missing required child resource.");
             }
@@ -133,36 +142,7 @@ public class ValidationServiceImpl imple
             throw new IllegalArgumentException("ValidationResult.validate - cannot accept null parameters");
         }
         ValidationResultImpl result = new ValidationResultImpl();
-        for (ResourceProperty resourceProperty : model.getResourceProperties()) {
-            String property = resourceProperty.getName();
-            Object valuesObject = valueMap.get(property);
-            if (valuesObject == null) {
-                result.addFailureMessage(property, "Missing required property.");
-            }
-            Type propertyType = resourceProperty.getType();
-            Map<Validator, Map<String, String>> validators = resourceProperty.getValidators();
-            if (resourceProperty.isMultiple()) {
-                if (valuesObject instanceof String[]) {
-                    for (String fieldValue : (String[]) valuesObject) {
-                        validatePropertyValue(result, property, fieldValue, propertyType, validators);
-                    }
-                } else {
-                    result.addFailureMessage(property, "Expected multiple-valued property.");
-                }
-            } else {
-                if (valuesObject instanceof String[]) {
-                    // treat request attributes which are arrays
-                    String[] fieldValues = (String[]) valuesObject;
-                    if (fieldValues.length == 1) {
-                        validatePropertyValue(result, property, fieldValues[0], propertyType, validators);
-                    } else {
-                        result.addFailureMessage(property, "Expected single-valued property.");
-                    }
-                } else if (valuesObject instanceof String) {
-                    validatePropertyValue(result, property, (String) valuesObject, propertyType, validators);
-                }
-            }
-        }
+        validateValueMap(valueMap, model.getResourceProperties(), result, "");
         return result;
     }
 
@@ -225,31 +205,26 @@ public class ValidationServiceImpl imple
         }
     }
 
-    private void validateResourceProperties(Resource rootResource, Resource resource, Set<ResourceProperty> resourceProperties,
-                                            ValidationResultImpl result) {
+    private void validateValueMap(ValueMap valueMap, Set<ResourceProperty> resourceProperties,
+                                            ValidationResultImpl result, String relativePathName) {
+        if (valueMap == null) {
+            throw new IllegalArgumentException("ValueMap may not be null");
+        }
         for (ResourceProperty resourceProperty : resourceProperties) {
             String property = resourceProperty.getName();
-            ValueMap valueMap = resource.adaptTo(ValueMap.class);
             Object fieldValues = valueMap.get(property);
-            String relativePath = resource.getPath().replace(rootResource.getPath(), "");
-            if (relativePath.length() > 0) {
-                if (relativePath.startsWith("/")) {
-                    relativePath = relativePath.substring(1);
-                }
-                property = relativePath + "/" + property;
-            }
             if (fieldValues == null) {
-                result.addFailureMessage(property, "Missing required property.");
+                result.addFailureMessage(relativePathName + property, "Missing required property.");
+                return;
             }
-            Type propertyType = resourceProperty.getType();
-            Map<Validator, Map<String, String>> validators = resourceProperty.getValidators();
-            if (fieldValues instanceof String[]) {
-                for (String fieldValue : (String[]) fieldValues) {
-                    validatePropertyValue(result, property, fieldValue, propertyType, validators);
+            List<ParameterizedValidator> validators = resourceProperty.getValidators();
+            if (resourceProperty.isMultiple()) {
+                if (!fieldValues.getClass().isArray()) {
+                    result.addFailureMessage(relativePathName + property, "Expected multiple-valued property.");
+                    return;
                 }
-            } else if (fieldValues instanceof String) {
-                validatePropertyValue(result, property, (String) fieldValues, propertyType, validators);
             }
+            validatePropertyValue(result, property, relativePathName, valueMap, validators);
         }
     }
 
@@ -375,29 +350,67 @@ public class ValidationServiceImpl imple
         }
         return true;
     }
-
-    private void validatePropertyValue(ValidationResultImpl result, String property, String value, Type propertyType, Map<Validator,
-            Map<String, String>> validators) {
-        if (!propertyType.isValid(value)) {
-            result.addFailureMessage(property, "Property was expected to be of type " + propertyType.getName());
-        }
-        for (Map.Entry<Validator, Map<String, String>> validatorEntry : validators.entrySet()) {
-            Validator validator = validatorEntry.getKey();
-            Map<String, String> arguments = validatorEntry.getValue();
-            try {
-                String validatorMessage = validator.validate(value, arguments);
-                if (validatorMessage != null) {
-                    if (validatorMessage.isEmpty()) {
-                        validatorMessage = "Property does not contain a valid value for the " + validator
-                                .getClass().getName() + " validator";
-                    } 
-                    result.addFailureMessage(property, validatorMessage);
+    
+   
+    
+    private void validatePropertyValue(ValidationResultImpl result, String property, String relativePath, ValueMap valueMap, List<ParameterizedValidator> validators) {
+        for (ParameterizedValidator validator : validators) {
+            // convert the type always to an array
+            Class<?> type = validator.getType();
+            if (!type.isArray()) {
+                try {
+                    // https://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#getName%28%29 has some hints on class names
+                    type = Class.forName("[L"+type.getName()+";", false, type.getClassLoader());
+                } catch (ClassNotFoundException e) {
+                    throw new SlingValidationException("Could not generate array class for type " + type, e);
                 }
-            } catch (SlingValidationException e) {
-                // wrap in another SlingValidationException to include information about the property
-                throw new SlingValidationException("Could not call validator " + validator
-                        .getClass().getName() + " for resourceProperty " + property, e);
             }
+            
+            Object[] typedValue = (Object[])valueMap.get(property, type);
+            // see https://issues.apache.org/jira/browse/SLING-4178 for why the second check is necessary
+            if (typedValue == null || typedValue[0] == null) {
+                // here the missing required property case was already treated in validateValueMap
+                result.addFailureMessage(property, "Property was expected to be of type '" + validator.getType() + "' but cannot be converted to that type." );
+                return;
+            }
+            
+            // see https://issues.apache.org/jira/browse/SLING-662 for a description on how multivalue properties are treated with ValueMap
+            if (validator.getType().isArray()) {
+                // ValueMap already returns an array in both cases (property is single value or multivalue)
+                validateValue(result, typedValue, property, relativePath, valueMap, validator);
+            } else {
+                // call validate for each entry in the array (supports both singlevalue and multivalue)
+                if (typedValue.getClass().isArray()) {
+                    Object[] array = (Object[])typedValue;
+                    if (array.length == 1) {
+                        validateValue(result, array[0], property, relativePath, valueMap, validator);
+                    } else {
+                        int n = 0;
+                        for (Object item : array) {
+                            validateValue(result, item, property + "[" + n++ + "]", relativePath, valueMap, validator);
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    @SuppressWarnings("rawtypes")
+    private void validateValue(ValidationResultImpl result, Object value, String property, String relativePath, ValueMap valueMap, ParameterizedValidator validator) {
+        try {
+            @SuppressWarnings("unchecked")
+            String validatorMessage = ((Validator)validator.getValidator()).validate(value, valueMap, validator.getParameters());
+            if (validatorMessage != null) {
+                if (validatorMessage.isEmpty()) {
+                    validatorMessage = "Property does not contain a valid value for the " + validator
+                            .getClass().getName() + " validator";
+                } 
+                result.addFailureMessage(relativePath + property, validatorMessage);
+            }
+        } catch (SlingValidationException e) {
+            // wrap in another SlingValidationException to include information about the property
+            throw new SlingValidationException("Could not call validator " + validator
+                    .getClass().getName() + " for resourceProperty " + relativePath + property, e);
         }
     }
-}
\ No newline at end of file
+}

Modified: sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/util/JCRBuilder.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/util/JCRBuilder.java?rev=1640572&r1=1640571&r2=1640572&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/util/JCRBuilder.java (original)
+++ sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/util/JCRBuilder.java Wed Nov 19 15:23:05 2014
@@ -30,12 +30,13 @@ import org.apache.sling.api.resource.Res
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.commons.osgi.PropertiesUtil;
 import org.apache.sling.validation.api.ChildResource;
+import org.apache.sling.validation.api.ParameterizedValidator;
 import org.apache.sling.validation.api.ResourceProperty;
-import org.apache.sling.validation.api.Type;
 import org.apache.sling.validation.api.Validator;
 import org.apache.sling.validation.api.ValidatorLookupService;
 import org.apache.sling.validation.impl.ChildResourceImpl;
 import org.apache.sling.validation.impl.Constants;
+import org.apache.sling.validation.impl.ParameterizedValidatorImpl;
 import org.apache.sling.validation.impl.ResourcePropertyImpl;
 
 /**
@@ -57,10 +58,9 @@ public class JCRBuilder {
             for (Resource property : propertiesResource.getChildren()) {
                 String fieldName = property.getName();
                 ValueMap propertyValueMap = property.adaptTo(ValueMap.class);
-                Type type = Type.getType(propertyValueMap.get(Constants.PROPERTY_TYPE, String.class));
                 Boolean propertyMultiple = PropertiesUtil.toBoolean(propertyValueMap.get(Constants.PROPERTY_MULTIPLE), false);
                 Resource validators = property.getChild(Constants.VALIDATORS);
-                Map<Validator, Map<String, String>> validatorsMap = new HashMap<Validator, Map<String, String>>();
+                List<ParameterizedValidator> parameterizedValidators = new ArrayList<ParameterizedValidator>();
                 if (validators != null) {
                     Iterator<Resource> validatorsIterator = validators.listChildren();
                     while (validatorsIterator.hasNext()) {
@@ -71,6 +71,7 @@ public class JCRBuilder {
                         if (v == null) {
                             throw new IllegalArgumentException("Could not find validator with name '" + validatorName + "'");
                         }
+                        // get type of validator
                         String[] validatorArguments = validatorProperties.get(Constants.VALIDATOR_ARGUMENTS, String[].class);
                         Map<String, String> validatorArgumentsMap = new HashMap<String, String>();
                         if (validatorArguments != null) {
@@ -82,10 +83,10 @@ public class JCRBuilder {
                                 validatorArgumentsMap.put(keyValuePair[0], keyValuePair[1]);
                             }
                         }
-                        validatorsMap.put(v, validatorArgumentsMap);
+                        parameterizedValidators.add(new ParameterizedValidatorImpl(v, validatorArgumentsMap));
                     }
                 }
-                ResourceProperty f = new ResourcePropertyImpl(fieldName, type, propertyMultiple, validatorsMap);
+                ResourceProperty f = new ResourcePropertyImpl(fieldName, propertyMultiple, parameterizedValidators);
                 properties.add(f);
             }
         }

Added: sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/util/ValidatorTypeUtil.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/util/ValidatorTypeUtil.java?rev=1640572&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/util/ValidatorTypeUtil.java (added)
+++ sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/util/ValidatorTypeUtil.java Wed Nov 19 15:23:05 2014
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.validation.impl.util;
+
+import java.lang.reflect.TypeVariable;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.commons.lang3.reflect.TypeUtils;
+import org.apache.sling.validation.api.Validator;
+
+public class ValidatorTypeUtil {
+    
+    /**
+     * 
+     * @param validator
+     * @return the type parametrization value on the {@link Validator} interface
+     */
+    public static Class<?> getValidatorType(Validator<?> validator) {
+        // get all type arguments from the current validator class up to the Validator interface
+        Map<TypeVariable<?>, java.lang.reflect.Type> typeMap = TypeUtils.getTypeArguments(validator.getClass(), Validator.class);
+        java.lang.reflect.Type type = null;
+        for (Entry<TypeVariable<?>, java.lang.reflect.Type> entry : typeMap.entrySet()) {
+            type = entry.getValue();
+            // check if this is really the type argument defined on the interface {@link Validator}
+            if (entry.getKey().getGenericDeclaration() instanceof Class<?>) {
+                Class clazz = (Class)entry.getKey().getGenericDeclaration();
+                if (clazz.equals(Validator.class)) {
+                    if (type instanceof Class<?>) {
+                        return (Class)type;
+                    }
+                    // type may also be a parmeterized type (e.g. for Collection<String>), this is not allowed!
+                    else {
+                        throw new IllegalArgumentException("Validators may not use parameterized types as type parameter. Only simple class types and arrays of class types are allowed.");
+                    }
+                }
+            }
+           
+        }
+        throw new IllegalArgumentException("Validator '" + validator +"' has not valid type parameter!");
+}
+}

Modified: sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/validators/RegexValidator.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/validators/RegexValidator.java?rev=1640572&r1=1640571&r2=1640572&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/validators/RegexValidator.java (original)
+++ sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/validators/RegexValidator.java Wed Nov 19 15:23:05 2014
@@ -20,6 +20,7 @@ package org.apache.sling.validation.impl
 
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.validation.api.Validator;
 import org.apache.sling.validation.api.exceptions.SlingValidationException;
 
@@ -32,13 +33,14 @@ import java.util.regex.Pattern;
  */
 @Component()
 @Service(Validator.class)
-public class RegexValidator implements Validator {
+public class RegexValidator implements Validator<String> {
 
     public static final String REGEX_PARAM = "regex";
 
     @Override
-    public String validate(String data, Map<String, String> arguments) {
-        if (data == null || arguments == null) {
+    public String validate(String data, ValueMap valueMap, Map<String, String> arguments)
+            throws SlingValidationException {
+        if (arguments == null) {
             throw new SlingValidationException("Cannot perform data validation with null parameters");
         }
         String regex = arguments.get(REGEX_PARAM);
@@ -46,9 +48,12 @@ public class RegexValidator implements V
             throw new SlingValidationException("Mandatory " + REGEX_PARAM + " is missing from the arguments map.");
         }
         Pattern pattern = Pattern.compile(regex);
-        if (pattern.matcher(data).matches()) {
+        if (pattern.matcher((String)data).matches()) {
             return null;
         }
         return "Property does not match the pattern " + regex;
     }
+
+   
+    
 }

Modified: sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/ValidationServiceImplTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/ValidationServiceImplTest.java?rev=1640572&r1=1640571&r2=1640572&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/ValidationServiceImplTest.java (original)
+++ sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/ValidationServiceImplTest.java Wed Nov 19 15:23:05 2014
@@ -20,6 +20,7 @@ package org.apache.sling.validation.impl
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -38,13 +39,14 @@ import org.apache.sling.api.resource.Res
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.api.wrappers.ValueMapDecorator;
 import org.apache.sling.jcr.resource.JcrResourceConstants;
-import org.apache.sling.validation.api.Type;
 import org.apache.sling.validation.api.ValidationModel;
 import org.apache.sling.validation.api.ValidationResult;
 import org.apache.sling.validation.api.ValidationService;
+import org.apache.sling.validation.api.Validator;
 import org.apache.sling.validation.api.ValidatorLookupService;
 import org.apache.sling.validation.api.exceptions.SlingValidationException;
 import org.apache.sling.validation.impl.setup.MockedResourceResolver;
+import org.apache.sling.validation.impl.util.examplevalidators.DateValidator;
 import org.apache.sling.validation.impl.validators.RegexValidator;
 import org.hamcrest.Matchers;
 import org.junit.AfterClass;
@@ -109,7 +111,7 @@ public class ValidationServiceImplTest {
         Whitebox.setInternalState(validationService, "rrf", rrf);
         validatorLookupService = mock(ValidatorLookupService.class);
     }
-
+    
     @Test
     public void testGetValidationModel() throws Exception {
         when(validatorLookupService.getValidator("org.apache.sling.validation.impl.validators.RegexValidator")).thenReturn(new
@@ -119,7 +121,6 @@ public class ValidationServiceImplTest {
         List<TestProperty> properties = new ArrayList<TestProperty>();
         TestProperty property = new TestProperty();
         property.name = "field1";
-        property.type = Type.DATE;
         property.validators.put("org.apache.sling.validation.impl.validators.RegexValidator", null);
         properties.add(property);
         ResourceResolver rr = rrf.getAdministrativeResourceResolver(null);
@@ -164,7 +165,6 @@ public class ValidationServiceImplTest {
         List<TestProperty> fields = new ArrayList<TestProperty>();
         TestProperty field = new TestProperty();
         field.name = "field1";
-        field.type = Type.DATE;
         field.validators.put("org.apache.sling.validation.impl.validators.RegexValidator", null);
         fields.add(field);
         ResourceResolver rr = rrf.getAdministrativeResourceResolver(null);
@@ -204,7 +204,7 @@ public class ValidationServiceImplTest {
         }
     }
 
-    @Test(expected=SlingValidationException.class)
+    @Test()
     public void testValueMapWithWrongDataType() throws Exception {
         when(validatorLookupService.getValidator("org.apache.sling.validation.impl.validators.RegexValidator")).thenReturn(new
                 RegexValidator());
@@ -213,8 +213,9 @@ public class ValidationServiceImplTest {
         List<TestProperty> properties = new ArrayList<TestProperty>();
         TestProperty property = new TestProperty();
         property.name = "field1";
-        property.type = Type.DATE;
-        property.validators.put("org.apache.sling.validation.impl.validators.RegexValidator", null);
+        when(validatorLookupService.getValidator("org.apache.sling.validation.impl.util.examplevalidators.DateValidator")).thenReturn(new
+                DateValidator());
+        property.validators.put("org.apache.sling.validation.impl.util.examplevalidators.DateValidator", null);
         properties.add(property);
         ResourceResolver rr = rrf.getAdministrativeResourceResolver(null);
         Resource model1 = null;
@@ -229,6 +230,10 @@ public class ValidationServiceImplTest {
             }};
             ValueMap map = new ValueMapDecorator(hashMap);
             ValidationResult vr = validationService.validate(map, vm);
+            
+            Map<String, List<String>> expectedFailureMessages = new HashMap<String, List<String>>();
+            expectedFailureMessages.put("field1", Arrays.asList("Property was expected to be of type 'class java.util.Date' but cannot be converted to that type."));
+            Assert.assertThat(vr.getFailureMessages().entrySet(), Matchers.equalTo(expectedFailureMessages.entrySet()));
         } finally {
             if (model1 != null) {
                 rr.delete(model1);
@@ -249,11 +254,9 @@ public class ValidationServiceImplTest {
         List<TestProperty> fields = new ArrayList<TestProperty>();
         TestProperty field = new TestProperty();
         field.name = "field1";
-        field.type = Type.STRING;
         field.validators.put("org.apache.sling.validation.impl.validators.RegexValidator", new String[] {"regex=^\\p{L}+$"});
         fields.add(field);
         field.name = "field2";
-        field.type = Type.STRING;
         final String TEST_REGEX = "^test$";
         field.validators.put("org.apache.sling.validation.impl.validators.RegexValidator", new String[] {"regex="+TEST_REGEX});
         fields.add(field);
@@ -288,7 +291,7 @@ public class ValidationServiceImplTest {
     }
 
     @Test
-     public void testResourceWithMissingChildProperty() throws Exception {
+    public void testResourceWithMissingChildProperty() throws Exception {
         when(validatorLookupService.getValidator("org.apache.sling.validation.impl.validators.RegexValidator")).thenReturn(new
                 RegexValidator());
         Whitebox.setInternalState(validationService, "validatorLookupService", validatorLookupService);
@@ -296,7 +299,6 @@ public class ValidationServiceImplTest {
         List<TestProperty> fields = new ArrayList<TestProperty>();
         TestProperty property = new TestProperty();
         property.name = "field1";
-        property.type = Type.INT;
         property.validators.put("org.apache.sling.validation.impl.validators.RegexValidator", new String[] {RegexValidator.REGEX_PARAM + "=" + "\\d"});
         fields.add(property);
         ResourceResolver rr = rrf.getAdministrativeResourceResolver(null);
@@ -350,7 +352,7 @@ public class ValidationServiceImplTest {
             ValidationModel vm = validationService.getValidationModel("sling/validation/test", "/apps/validation/1/resource");
             ValidationResult vr = validationService.validate(testResource, vm);
             assertFalse(vr.isValid());
-            assertTrue(vr.getFailureMessages().containsKey("child1/hello"));
+            assertThat(vr.getFailureMessages(), Matchers.hasKey("child1/hello"));
         } finally {
             if (rr != null) {
                 if (model1 != null) {
@@ -364,6 +366,47 @@ public class ValidationServiceImplTest {
             }
         }
     }
+    
+    @Test
+    public void testResourceWithMultivalueProperties() throws Exception {
+        when(validatorLookupService.getValidator("org.apache.sling.validation.impl.validators.RegexValidator")).thenReturn(new
+                RegexValidator());
+        Whitebox.setInternalState(validationService, "validatorLookupService", validatorLookupService);
+
+        List<TestProperty> fields = new ArrayList<TestProperty>();
+        TestProperty property = new TestProperty();
+        property.name = "field1";
+        final String TEST_REGEX = "^testvalue.*$";
+        property.validators.put("org.apache.sling.validation.impl.validators.RegexValidator", new String[] {"regex="+TEST_REGEX});
+        fields.add(property);
+        ResourceResolver rr = rrf.getAdministrativeResourceResolver(null);
+        Resource model1 = null;
+        try {
+            if (rr != null) {
+                model1 = createValidationModelResource(rr, libsValidatorsRoot.getPath(), "testValidationModel1", "sling/validation/test",
+                        new String[]{"/apps/validation"}, fields);
+            }
+            ValidationModel vm = validationService.getValidationModel("sling/validation/test", "/apps/validation/1/resource");
+            HashMap<String, Object> hashMap = new HashMap<String, Object>() {{
+                put("field1", new String[] {"testvalue1", "test2value", "testvalue3"});
+            }};
+            ValueMap map = new ValueMapDecorator(hashMap);
+            ValidationResult vr = validationService.validate(map, vm);
+            assertFalse(vr.isValid());
+            // check for correct error message
+            Map<String, List<String>> expectedFailureMessages = new HashMap<String, List<String>>();
+            expectedFailureMessages.put("field1[1]", Arrays.asList("Property does not match the pattern " + TEST_REGEX));
+            Assert.assertThat(vr.getFailureMessages().entrySet(), Matchers.equalTo(expectedFailureMessages.entrySet()));
+        } finally {
+            if (model1 != null) {
+                rr.delete(model1);
+            }
+            if (rr != null) {
+                rr.commit();
+                rr.close();
+            }
+        }
+    }
 
     private Resource createValidationModelResource(ResourceResolver rr, String root, String name, String validatedResourceType,
                                                String[] applicableResourcePaths, List<TestProperty> properties) throws Exception {
@@ -379,7 +422,6 @@ public class ValidationServiceImplTest {
             if (propertiesResource != null) {
                 for (TestProperty property : properties) {
                     Map<String, Object> modelPropertyJCRProperties = new HashMap<String, Object>();
-                    modelPropertyJCRProperties.put(Constants.PROPERTY_TYPE, property.type.getName());
                     modelPropertyJCRProperties.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
                     Resource propertyResource = ResourceUtil.getOrCreateResource(rr, propertiesResource.getPath() + "/" + property.name,
                             modelPropertyJCRProperties, null, true);
@@ -394,7 +436,7 @@ public class ValidationServiceImplTest {
                                 if (v.getValue() != null) {
                                     validatorProperties.put(Constants.VALIDATOR_ARGUMENTS, v.getValue());
                                 }
-                                ResourceUtil.getOrCreateResource(rr, validators.getPath() + "/" + v.getKey(), validatorProperties, null,
+                                 ResourceUtil.getOrCreateResource(rr, validators.getPath() + "/" + v.getKey(), validatorProperties, null,
                                         true);
                             }
                         }
@@ -420,7 +462,6 @@ public class ValidationServiceImplTest {
 
     private class TestProperty {
         String name;
-        Type type;
         Map<String, String[]> validators;
 
         TestProperty() {

Added: sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/ValidatorTypeUtilTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/ValidatorTypeUtilTest.java?rev=1640572&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/ValidatorTypeUtilTest.java (added)
+++ sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/ValidatorTypeUtilTest.java Wed Nov 19 15:23:05 2014
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.validation.impl.util;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.validation.api.Validator;
+import org.apache.sling.validation.api.exceptions.SlingValidationException;
+import org.apache.sling.validation.impl.util.examplevalidators.DerivedStringValidator;
+import org.apache.sling.validation.impl.util.examplevalidators.ExtendedStringValidator;
+import org.apache.sling.validation.impl.util.examplevalidators.GenericTypeParameterBaseClass;
+import org.apache.sling.validation.impl.util.examplevalidators.IntegerValidator;
+import org.apache.sling.validation.impl.util.examplevalidators.StringArrayValidator;
+import org.apache.sling.validation.impl.util.examplevalidators.StringValidator;
+import org.apache.sling.validation.impl.validators.RegexValidator;
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ValidatorTypeUtilTest {
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testGetValidatorTypeOfDirectImplementations() {
+        Assert.assertThat((Class<String>)ValidatorTypeUtil.getValidatorType(new RegexValidator()), Matchers.equalTo(String.class));
+        Assert.assertThat((Class<String>)ValidatorTypeUtil.getValidatorType(new StringValidator()), Matchers.equalTo(String.class));
+        Assert.assertThat((Class<Integer>)ValidatorTypeUtil.getValidatorType(new IntegerValidator()), Matchers.equalTo(Integer.class));
+    }
+    
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testGetValidatorTypeOfDerivedImplementations() {
+        Assert.assertThat((Class<String>)ValidatorTypeUtil.getValidatorType(new DerivedStringValidator()), Matchers.equalTo(String.class));
+    }
+    
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testGetValidatorTypeWithAdditionalTypeParameters() {
+        Assert.assertThat((Class<String>)ValidatorTypeUtil.getValidatorType(new ExtendedStringValidator()), Matchers.equalTo(String.class));
+    }
+    
+    private class InnerStringValidator implements Validator<String> {
+
+        @Override
+        public String validate(String data, ValueMap valueMap, Map<String, String> arguments)
+                throws SlingValidationException {
+            return null;
+        }
+    }
+    
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testGetValidatorTypeWithInnerClass() {
+        Assert.assertThat((Class<String>)ValidatorTypeUtil.getValidatorType(new InnerStringValidator()), Matchers.equalTo(String.class));
+    }
+    
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testGetValidatorTypeWithAnonymousClass() {
+        Assert.assertThat((Class<String>)ValidatorTypeUtil.getValidatorType(new Validator<String>() {
+            @Override
+            public String validate(String data, ValueMap valueMap, Map<String, String> arguments)
+                    throws SlingValidationException {
+                return null;
+            }
+            
+        }), Matchers.equalTo(String.class));
+    }
+    
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testGetValidatorTypeWithArrayType() {
+        Assert.assertThat((Class<String[]>)ValidatorTypeUtil.getValidatorType(new StringArrayValidator()), Matchers.equalTo(String[].class));
+    }
+    
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetValidatorTypeWithCollectionType() {
+        ValidatorTypeUtil.getValidatorType(new Validator<Collection<String>>() {
+            @Override
+            public String validate(Collection<String> data, ValueMap valueMap, Map<String, String> arguments)
+                    throws SlingValidationException {
+                return null;
+            }
+        });
+    }
+    
+    private class InnerStringValidatorWithAdditionalBaseClass extends GenericTypeParameterBaseClass<Integer> implements Validator<String> {
+        @Override
+        public String validate(String data, ValueMap valueMap, Map<String, String> arguments)
+                throws SlingValidationException {
+            return null;
+        }
+    }
+    
+    @Test
+    public void testGetValidatorTypeWithUnrelatedSuperClass() {
+        Assert.assertThat((Class<String>)ValidatorTypeUtil.getValidatorType(new InnerStringValidatorWithAdditionalBaseClass()), Matchers.equalTo(String.class));
+    }
+}

Added: sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/AbstractValidatorWithAdditionalType.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/AbstractValidatorWithAdditionalType.java?rev=1640572&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/AbstractValidatorWithAdditionalType.java (added)
+++ sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/AbstractValidatorWithAdditionalType.java Wed Nov 19 15:23:05 2014
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.validation.impl.util.examplevalidators;
+
+import org.apache.sling.validation.api.Validator;
+
+public abstract class AbstractValidatorWithAdditionalType<A,T,B> implements Validator<T>{
+    public abstract A getA();
+    public abstract B getB();
+}

Added: sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/DateValidator.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/DateValidator.java?rev=1640572&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/DateValidator.java (added)
+++ sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/DateValidator.java Wed Nov 19 15:23:05 2014
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.validation.impl.util.examplevalidators;
+
+import java.util.Date;
+import java.util.Map;
+
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.validation.api.Validator;
+import org.apache.sling.validation.api.exceptions.SlingValidationException;
+
+public class DateValidator implements Validator<Date> {
+
+    @Override
+    public String validate(Date data, ValueMap valueMap, Map<String, String> arguments) throws SlingValidationException {
+        return null;
+    }
+
+}

Added: sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/DerivedStringValidator.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/DerivedStringValidator.java?rev=1640572&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/DerivedStringValidator.java (added)
+++ sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/DerivedStringValidator.java Wed Nov 19 15:23:05 2014
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.validation.impl.util.examplevalidators;
+
+public class DerivedStringValidator extends StringValidator {
+
+}

Added: sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/ExtendedStringValidator.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/ExtendedStringValidator.java?rev=1640572&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/ExtendedStringValidator.java (added)
+++ sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/ExtendedStringValidator.java Wed Nov 19 15:23:05 2014
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.validation.impl.util.examplevalidators;
+
+import java.util.Map;
+
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.validation.api.exceptions.SlingValidationException;
+
+public class ExtendedStringValidator extends AbstractValidatorWithAdditionalType<Boolean, String, Integer> {
+
+    @Override
+    public String validate(String data, ValueMap valueMap, Map<String, String> arguments)
+            throws SlingValidationException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Boolean getA() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Integer getB() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+}

Added: sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/GenericTypeParameterBaseClass.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/GenericTypeParameterBaseClass.java?rev=1640572&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/GenericTypeParameterBaseClass.java (added)
+++ sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/GenericTypeParameterBaseClass.java Wed Nov 19 15:23:05 2014
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.validation.impl.util.examplevalidators;
+
+public class GenericTypeParameterBaseClass <T> {
+    public void test(T param) {
+        
+    }
+}

Added: sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/IntegerValidator.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/IntegerValidator.java?rev=1640572&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/IntegerValidator.java (added)
+++ sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/IntegerValidator.java Wed Nov 19 15:23:05 2014
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.validation.impl.util.examplevalidators;
+
+import java.util.Map;
+
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.validation.api.Validator;
+import org.apache.sling.validation.api.exceptions.SlingValidationException;
+
+public class IntegerValidator implements Validator<Integer> {
+
+    @Override
+    public String validate(Integer data, ValueMap valueMap, Map<String, String> arguments)
+            throws SlingValidationException {
+        return null;
+    }
+
+}

Added: sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/StringArrayValidator.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/StringArrayValidator.java?rev=1640572&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/StringArrayValidator.java (added)
+++ sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/StringArrayValidator.java Wed Nov 19 15:23:05 2014
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.validation.impl.util.examplevalidators;
+
+import java.util.Map;
+
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.validation.api.Validator;
+import org.apache.sling.validation.api.exceptions.SlingValidationException;
+
+public class StringArrayValidator implements Validator<String[]> {
+
+    @Override
+    public String validate(String[] data, ValueMap valueMap, Map<String, String> arguments)
+            throws SlingValidationException {
+        return null;
+    }
+
+}

Added: sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/StringValidator.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/StringValidator.java?rev=1640572&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/StringValidator.java (added)
+++ sling/trunk/contrib/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/StringValidator.java Wed Nov 19 15:23:05 2014
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.validation.impl.util.examplevalidators;
+
+import java.util.Map;
+
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.validation.api.Validator;
+import org.apache.sling.validation.api.exceptions.SlingValidationException;
+
+public class StringValidator implements Validator<String> {
+
+    @Override
+    public String validate(String data, ValueMap valueMap, Map<String, String> arguments)
+            throws SlingValidationException {
+        return null;
+    }
+
+}