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/28 15:50:39 UTC

svn commit: r1642306 - in /sling/trunk/contrib/extensions/validation: api/src/main/java/org/apache/sling/validation/api/ core/src/main/java/org/apache/sling/validation/impl/ core/src/main/java/org/apache/sling/validation/impl/util/ core/src/test/java/o...

Author: kwin
Date: Fri Nov 28 14:50:39 2014
New Revision: 1642306

URL: http://svn.apache.org/r1642306
Log:
SLING-4013 allow optional properties/child resources within validation model

Modified:
    sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/ChildResource.java
    sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/ResourceProperty.java
    sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ChildResourceImpl.java
    sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/Constants.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/test/java/org/apache/sling/validation/impl/ValidationServiceImplTest.java

Modified: sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/ChildResource.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/ChildResource.java?rev=1642306&r1=1642305&r2=1642306&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/ChildResource.java (original)
+++ sling/trunk/contrib/extensions/validation/api/src/main/java/org/apache/sling/validation/api/ChildResource.java Fri Nov 28 14:50:39 2014
@@ -44,6 +44,13 @@ public interface ChildResource {
     Pattern getNamePattern();
 
     /**
+     * Returns {@code true} if at least one resource matching the name/namePattern is required.
+     * 
+     * @return {@code true} if the resource is required, {@code false} otherwise
+     */
+    boolean isRequired();
+
+    /**
      * Returns the properties this child resource is expected to have.
      *
      * @return the properties set

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=1642306&r1=1642305&r2=1642306&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 Fri Nov 28 14:50:39 2014
@@ -49,6 +49,13 @@ public interface ResourceProperty {
     boolean isMultiple();
 
     /**
+     * Returns {@code true} if at least one property matching the name/namePattern is required.
+     * 
+     * @return {@code true} if the property is required, {@code false} otherwise
+     */
+    boolean isRequired();
+
+    /**
      * Returns a list of {@link ParameterizedValidator}s which should be applied on this property.
      *
      * @return the list of validators

Modified: sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ChildResourceImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ChildResourceImpl.java?rev=1642306&r1=1642305&r2=1642306&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ChildResourceImpl.java (original)
+++ sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ChildResourceImpl.java Fri Nov 28 14:50:39 2014
@@ -8,6 +8,7 @@ import java.util.regex.PatternSyntaxExce
 
 import org.apache.sling.api.resource.Resource;
 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.ResourceProperty;
 import org.apache.sling.validation.api.Validator;
@@ -22,6 +23,7 @@ public class ChildResourceImpl implement
     private final Pattern namePattern;
     private final Set<ResourceProperty> properties;
     private final List<ChildResource> children;
+    private final boolean isRequired;
 
     public ChildResourceImpl(Resource modelResource, Resource childResource, Map<String, Validator<?>> validatorsMap, List<ChildResource> children) {
         String root = modelResource.getPath();
@@ -46,7 +48,7 @@ public class ChildResourceImpl implement
             name = childResource.getName();
             namePattern = null;
         }
-        
+        isRequired = !PropertiesUtil.toBoolean(childrenProperties.get(Constants.OPTIONAL), false);
         properties = JCRBuilder.buildProperties(validatorsMap, childResource.getChild(Constants.PROPERTIES));
         this.children = children;
     }
@@ -69,4 +71,9 @@ public class ChildResourceImpl implement
     public List<ChildResource> getChildren() {
         return children;
     }
+
+    @Override
+    public boolean isRequired() {
+        return isRequired;
+    }
 }

Modified: sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/Constants.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/Constants.java?rev=1642306&r1=1642305&r2=1642306&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/Constants.java (original)
+++ sling/trunk/contrib/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/Constants.java Fri Nov 28 14:50:39 2014
@@ -30,6 +30,7 @@ public final class Constants {
     public static final String PROPERTIES = "properties";
     public static final String PROPERTY_TYPE = "propertyType";
     public static final String PROPERTY_MULTIPLE = "propertyMultiple";
+    public static final String OPTIONAL = "optional";
     public static final String VALIDATORS = "validators";
     public static final String VALIDATOR_ARGUMENTS = "validatorArguments";
     public static final String CHILDREN = "children";

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=1642306&r1=1642305&r2=1642306&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 Fri Nov 28 14:50:39 2014
@@ -28,10 +28,11 @@ public class ResourcePropertyImpl implem
 
     private String name;
     private boolean isMultiple;
+    private boolean isRequired;
     private List<ParameterizedValidator> validators;
     private Pattern namePattern;
     
-    public ResourcePropertyImpl(String name, String nameRegex, boolean isMultiple, List<ParameterizedValidator> validators) {
+    public ResourcePropertyImpl(String name, String nameRegex, boolean isMultiple, boolean isRequired, List<ParameterizedValidator> validators) {
         if (nameRegex != null) {
             this.name = null;
             this.namePattern = Pattern.compile(nameRegex);
@@ -40,6 +41,7 @@ public class ResourcePropertyImpl implem
             this.namePattern = null;
         }
         this.isMultiple = isMultiple;
+        this.isRequired = isRequired;
         this.validators = validators;
     }
 
@@ -59,6 +61,11 @@ public class ResourcePropertyImpl implem
     }
 
     @Override
+    public boolean isRequired() {
+        return isRequired;
+    }
+
+    @Override
     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=1642306&r1=1642305&r2=1642306&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 Fri Nov 28 14:50:39 2014
@@ -147,14 +147,14 @@ public class ValidationServiceImpl imple
                        foundMatch = true;
                     }
                 }
-                if (!foundMatch) {
+                if (!foundMatch && childResource.isRequired()) {
                     result.addFailureMessage(relativePath + childResource.getNamePattern().pattern(), "Missing required child resource.");
                 }
             } else {
                 Resource expectedResource = resource.getChild(childResource.getName());
                 if (expectedResource != null) {
                     validateChildResource(expectedResource, relativePath, childResource, result);
-                } else {
+                } else if (childResource.isRequired()) {
                     result.addFailureMessage(relativePath + childResource.getName(), "Missing required child resource.");
                 }
             } 
@@ -249,7 +249,7 @@ public class ValidationServiceImpl imple
                         validateValueMap(key, valueMap, relativePath, resourceProperty, result);
                     }
                 }
-                if (!foundMatch) {
+                if (!foundMatch && resourceProperty.isRequired()) {
                     result.addFailureMessage(relativePath + resourceProperty.getNamePattern(), "Missing required property.");
                 }
             } else {
@@ -262,7 +262,9 @@ public class ValidationServiceImpl imple
     private void validateValueMap(String property, ValueMap valueMap, String relativePath, ResourceProperty resourceProperty, ValidationResultImpl result) {
         Object fieldValues = valueMap.get(property);
         if (fieldValues == null) {
-            result.addFailureMessage(relativePath + property, "Missing required property.");
+            if (resourceProperty.isRequired()) {
+                result.addFailureMessage(relativePath + property, "Missing required property.");
+            }
             return;
         }
         List<ParameterizedValidator> validators = resourceProperty.getValidators();

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=1642306&r1=1642305&r2=1642306&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 Fri Nov 28 14:50:39 2014
@@ -59,6 +59,7 @@ public class JCRBuilder {
                 String fieldName = property.getName();
                 ValueMap propertyValueMap = property.adaptTo(ValueMap.class);
                 Boolean propertyMultiple = PropertiesUtil.toBoolean(propertyValueMap.get(Constants.PROPERTY_MULTIPLE), false);
+                Boolean propertyRequired = !PropertiesUtil.toBoolean(propertyValueMap.get(Constants.OPTIONAL), false);
                 String nameRegex = PropertiesUtil.toString(propertyValueMap.get(Constants.NAME_REGEX), null);
                 Resource validators = property.getChild(Constants.VALIDATORS);
                 List<ParameterizedValidator> parameterizedValidators = new ArrayList<ParameterizedValidator>();
@@ -87,7 +88,7 @@ public class JCRBuilder {
                         parameterizedValidators.add(new ParameterizedValidatorImpl(v, new ValueMapDecorator(validatorArgumentsMap)));
                     }
                 }
-                ResourceProperty f = new ResourcePropertyImpl(fieldName, nameRegex, propertyMultiple, parameterizedValidators);
+                ResourceProperty f = new ResourcePropertyImpl(fieldName, nameRegex, propertyMultiple, propertyRequired, parameterizedValidators);
                 properties.add(f);
             }
         }

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=1642306&r1=1642305&r2=1642306&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 Fri Nov 28 14:50:39 2014
@@ -226,6 +226,76 @@ public class ValidationServiceImplTest {
             }
         }
     }
+    
+    @Test()
+    public void testValueMapWithMissingOptionalValue() throws Exception {
+        validationService.validators.put("org.apache.sling.validation.impl.validators.RegexValidator", new RegexValidator());
+
+        TestProperty property = new TestProperty("field1");
+        property.optional = true;
+        property.addValidator("org.apache.sling.validation.impl.validators.RegexValidator", "");
+        
+        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"}, property);
+            }
+            ValidationModel vm = validationService.getValidationModel("sling/validation/test", "/apps/validation/1/resource");
+            HashMap<String, Object> hashMap = new HashMap<String, Object>() {{
+                put("field2", "1");
+            }};
+            ValueMap map = new ValueMapDecorator(hashMap);
+            ValidationResult vr = validationService.validate(map, vm);
+            Assert.assertTrue(vr.isValid());
+        } finally {
+            if (model1 != null) {
+                rr.delete(model1);
+            }
+            if (rr != null) {
+                rr.commit();
+                rr.close();
+            }
+        }
+    }
+    
+    @Test()
+    public void testValueMapWithEmptyOptionalValue() throws Exception {
+        validationService.validators.put("org.apache.sling.validation.impl.validators.RegexValidator", new RegexValidator());
+
+        TestProperty property = new TestProperty("field1");
+        property.optional = true;
+        property.addValidator("org.apache.sling.validation.impl.validators.RegexValidator", "regex=abc");
+        
+        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"}, property);
+            }
+            ValidationModel vm = validationService.getValidationModel("sling/validation/test", "/apps/validation/1/resource");
+            HashMap<String, Object> hashMap = new HashMap<String, Object>() {{
+                put("field1", "");
+            }};
+            ValueMap map = new ValueMapDecorator(hashMap);
+            ValidationResult vr = validationService.validate(map, vm);
+            Assert.assertFalse(vr.isValid());
+            // check for correct error message
+            Map<String, List<String>> expectedFailureMessages = new HashMap<String, List<String>>();
+            expectedFailureMessages.put("field2", Arrays.asList("Property does not match the pattern abc"));
+            Assert.assertThat(vr.getFailureMessages().entrySet(), Matchers.equalTo(expectedFailureMessages.entrySet()));
+        } finally {
+            if (model1 != null) {
+                rr.delete(model1);
+            }
+            if (rr != null) {
+                rr.commit();
+                rr.close();
+            }
+        }
+    }
 
     @Test
     public void testValueMapWithCorrectDataType() throws Exception {
@@ -281,27 +351,23 @@ public class ValidationServiceImplTest {
                 model1 = createValidationModelResource(rr, libsValidatorsRoot.getPath(), "testValidationModel1", "sling/validation/test",
                         new String[]{"/apps/validation"}, property);
                 
-                Resource child = createValidationModelChildResource(model1, "child1", null, new TestProperty("hello"));
-                createValidationModelChildResource(child, "grandChild1", null, new TestProperty("hello"));
+                Resource child = createValidationModelChildResource(model1, "child1", null, false,  new TestProperty("hello"));
+                createValidationModelChildResource(child, "grandChild1", null, false, new TestProperty("hello"));
 
                 testResource = ResourceUtil.getOrCreateResource(rr, "/apps/validation/1/resource", JcrConstants.NT_UNSTRUCTURED,
                         JcrConstants.NT_UNSTRUCTURED, true);
                 ModifiableValueMap mvm = testResource.adaptTo(ModifiableValueMap.class);
                 mvm.put("field1", "1");
-                rr.commit();
                 
                 Resource childResource = rr.create(testResource, "child1", new HashMap<String, Object>(){{
                     put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
                 }});
-                rr.commit();
-               
                 
                 Resource resourceChild = rr.create(testResource, "child1", new HashMap<String, Object>(){{
                     put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
                 }});
                 mvm = resourceChild.adaptTo(ModifiableValueMap.class);
                 mvm.put("hello", "1");
-                rr.commit();
 
                 // /apps/validation/1/resource/child1/grandChild1 will miss its mandatory "hello" property
                 Resource resourceGrandChild = rr.create(resourceChild, "grandChild1", new HashMap<String, Object>(){{
@@ -320,15 +386,54 @@ public class ValidationServiceImplTest {
             assertThat(vr.getFailureMessages().keySet(), Matchers.hasSize(1));
         } finally {
             if (rr != null) {
-                if (model1 != null) {
-                    rr.delete(model1);
-                }
-                if (testResource != null) {
-                    rr.delete(testResource);
-                }
+                rr.delete(model1);
+            }
+            if (testResource != null) {
+                 rr.delete(testResource);
+            }
+            rr.commit();
+            rr.close();
+        }
+    }
+    
+    @Test
+    public void testResourceWithMissingOptionalChildProperty() throws Exception {
+        validationService.validators.put("org.apache.sling.validation.impl.validators.RegexValidator", new RegexValidator());
+
+        TestProperty property = new TestProperty("field1");
+        property.addValidator("org.apache.sling.validation.impl.validators.RegexValidator", RegexValidator.REGEX_PARAM + "=" + "\\d");
+        ResourceResolver rr = rrf.getAdministrativeResourceResolver(null);
+        Resource model1 = null;
+        Resource testResource = null;
+        try {
+            if (rr != null) {
+                model1 = createValidationModelResource(rr, libsValidatorsRoot.getPath(), "testValidationModel1", "sling/validation/test",
+                        new String[]{"/apps/validation"}, property);
+                
+                createValidationModelChildResource(model1, "child1", null, true, new TestProperty("hello"));
+
+                testResource = ResourceUtil.getOrCreateResource(rr, "/apps/validation/1/resource", JcrConstants.NT_UNSTRUCTURED,
+                        JcrConstants.NT_UNSTRUCTURED, true);
+                ModifiableValueMap mvm = testResource.adaptTo(ModifiableValueMap.class);
+                mvm.put("field1", "1");
+                
+                rr.create(testResource, "child2", new HashMap<String, Object>(){{
+                    put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
+                }});
                 rr.commit();
-                rr.close();
             }
+            ValidationModel vm = validationService.getValidationModel("sling/validation/test", "/apps/validation/1/resource");
+            ValidationResult vr = validationService.validate(testResource, vm);
+            assertTrue(vr.isValid());
+        } finally {
+            if (rr != null) {
+                rr.delete(model1);
+            }
+            if (testResource != null) {
+                 rr.delete(testResource);
+            }
+            rr.commit();
+            rr.close();
         }
     }
     
@@ -346,8 +451,8 @@ public class ValidationServiceImplTest {
                 model1 = createValidationModelResource(rr, libsValidatorsRoot.getPath(), "testValidationModel1", "sling/validation/test",
                         new String[]{"/apps/validation"}, property);
                 
-                Resource child = createValidationModelChildResource(model1, "child1", null, new TestProperty("hello"));
-                createValidationModelChildResource(child, "grandChild1", null, new TestProperty("hello"));
+                Resource child = createValidationModelChildResource(model1, "child1", null, false, new TestProperty("hello"));
+                createValidationModelChildResource(child, "grandChild1", null, false, new TestProperty("hello"));
 
                 testResource = ResourceUtil.getOrCreateResource(rr, "/apps/validation/1/resource", JcrConstants.NT_UNSTRUCTURED,
                         JcrConstants.NT_UNSTRUCTURED, true);
@@ -401,8 +506,8 @@ public class ValidationServiceImplTest {
             if (rr != null) {
                 model1 = createValidationModelResource(rr, libsValidatorsRoot.getPath(), "testValidationModel1", "sling/validation/test",
                         new String[]{"/apps/validation"}, property);
-                Resource child = createValidationModelChildResource(model1, "child1", "child.*", new TestProperty("hello"));
-                createValidationModelChildResource(child, "grandChild", "grandChild.*", new TestProperty("hello"));
+                Resource child = createValidationModelChildResource(model1, "child1", "child.*", false, new TestProperty("hello"));
+                createValidationModelChildResource(child, "grandChild", "grandChild.*", false, new TestProperty("hello"));
                 rr.commit();
                 
                 testResource = ResourceUtil.getOrCreateResource(rr, "/apps/validation/1/resource", JcrConstants.NT_UNSTRUCTURED,
@@ -560,10 +665,12 @@ public class ValidationServiceImplTest {
                 Resource propertyResource = ResourceUtil.getOrCreateResource(rr, propertiesResource.getPath() + "/" + property.name,
                         modelPropertyJCRProperties, null, true);
                 if (propertyResource != null) {
+                    ModifiableValueMap values = propertyResource.adaptTo(ModifiableValueMap.class);
                     if (property.nameRegex != null) {
-                        ModifiableValueMap values = propertyResource.adaptTo(ModifiableValueMap.class);
                         values.put(Constants.NAME_REGEX, property.nameRegex);
                     }
+                    values.put(Constants.PROPERTY_MULTIPLE, property.multiple);
+                    values.put(Constants.OPTIONAL, property.optional);
                     Resource validators = ResourceUtil.getOrCreateResource(rr,
                             propertyResource.getPath() + "/" + Constants.VALIDATORS,
                             JcrConstants.NT_UNSTRUCTURED, null, true);
@@ -583,7 +690,7 @@ public class ValidationServiceImplTest {
         }
     }
     
-    private Resource createValidationModelChildResource(Resource parentResource, String name, String nameRegex, TestProperty... properties) throws PersistenceException {
+    private Resource createValidationModelChildResource(Resource parentResource, String name, String nameRegex, boolean isOptional, TestProperty... properties) throws PersistenceException {
         ResourceResolver rr = parentResource.getResourceResolver();
         Resource modelChildren = rr.create(parentResource, Constants.CHILDREN, new HashMap<String, Object>(){{
             put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
@@ -591,10 +698,11 @@ public class ValidationServiceImplTest {
         Resource child = rr.create(modelChildren, name, new HashMap<String, Object>(){{
             put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
         }});
+        ModifiableValueMap mvm = child.adaptTo(ModifiableValueMap.class);
         if (nameRegex != null) {
-            ModifiableValueMap mvm = child.adaptTo(ModifiableValueMap.class);
             mvm.put(Constants.NAME_REGEX, nameRegex);
         }
+        mvm.put(Constants.OPTIONAL, isOptional);
         createValidationModelProperties(child, properties);
         return child;
     }
@@ -613,6 +721,8 @@ public class ValidationServiceImplTest {
     }
 
     private class TestProperty {
+        public boolean optional;
+        public boolean multiple;
         final String name;
         String nameRegex;
         final Map<String, String[]> validators;
@@ -621,6 +731,8 @@ public class ValidationServiceImplTest {
             validators = new HashMap<String, String[]>();
             this.name = name;
             this.nameRegex = null;
+            this.optional = false;
+            this.multiple = false;
         }
         
         TestProperty setNameRegex(String nameRegex) {