diff --git a/pom.xml b/pom.xml
index 8e4b926e4..d5c5c1f2a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -168,6 +168,11 @@
+
+ javax.validation
+ validation-api
+ 2.0.1.Final
+
xom
xom
@@ -398,6 +403,19 @@
${version.jmh}
test
+
+ org.hibernate.validator
+ hibernate-validator
+ 6.2.5.Final
+ test
+
+
+ org.glassfish
+ javax.el
+ 3.0.0
+ test
+
+
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidCreditCard.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidCreditCard.java
new file mode 100644
index 000000000..00ccb793b
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidCreditCard.java
@@ -0,0 +1,35 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+@Retention(RUNTIME)
+@Constraint(validatedBy = ValidCreditCardValidator.class)
+@Documented
+public @interface ValidCreditCard {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ String context();
+
+ boolean allowNull();
+
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidCreditCardValidator.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidCreditCardValidator.java
new file mode 100644
index 000000000..ec1105fd2
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidCreditCardValidator.java
@@ -0,0 +1,35 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ValidationErrorList;
+import org.owasp.esapi.ESAPI;
+
+
+public class ValidCreditCardValidator implements ConstraintValidator{
+
+ private String context;
+ private boolean allowNull;
+
+ @Override
+ public void initialize(ValidCreditCard validCreditCard) {
+ context = validCreditCard.context();
+ allowNull = validCreditCard.allowNull();
+ }
+
+ @Override
+ public boolean isValid(String input, ConstraintValidatorContext constraintValidatorContext) {
+ if (input == null) {
+ return true;
+ }
+ ValidationErrorList errorList = new ValidationErrorList();
+ boolean valid = ESAPI.validator().isValidCreditCard(context, input, allowNull, errorList);
+
+ if(!valid){
+ ValidationUtil.addViolations(errorList, constraintValidatorContext);
+ }
+
+ return valid;
+ }
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDate.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDate.java
new file mode 100644
index 000000000..7ccae19c3
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDate.java
@@ -0,0 +1,42 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+@Retention(RUNTIME)
+@Constraint(validatedBy = ValidDateValidator.class)
+@Documented
+public @interface ValidDate {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ String context();
+
+ //Invalid type DateFormat for the annotation attribute ValidDate.format;
+ //only primitive type, String, Class, annotation, enumeration are permitted or 1-dimensional arrays thereof
+ //DateFormat format();
+
+ int dateStyle();
+
+ String locale();
+
+ boolean allowNull();
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDateValidator.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDateValidator.java
new file mode 100644
index 000000000..1e09df5b6
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDateValidator.java
@@ -0,0 +1,57 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import java.text.DateFormat;
+import java.util.Locale;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ValidationErrorList;
+import org.owasp.esapi.ESAPI;
+
+
+public class ValidDateValidator implements ConstraintValidator{
+
+ private String context;
+ private int dateStyle;
+ private String localeString;
+ private boolean allowNull;
+
+ @Override
+ public void initialize(ValidDate validDate) {
+ context = validDate.context();
+ dateStyle = validDate.dateStyle();
+ localeString = validDate.locale();
+ allowNull = validDate.allowNull();
+ }
+
+ @Override
+ public boolean isValid(String input, ConstraintValidatorContext constraintValidatorContext) {
+ if (input == null) {
+ return true;
+ }
+ Locale locale = toLocale(localeString);
+ DateFormat dateFormat = DateFormat.getDateInstance(dateStyle, locale);
+
+ ValidationErrorList errorList = new ValidationErrorList();
+ boolean valid = ESAPI.validator().isValidDate(context, input, dateFormat, allowNull, errorList);
+
+ if(!valid){
+ ValidationUtil.addViolations(errorList, constraintValidatorContext);
+ }
+
+ return valid;
+ }
+
+ private static Locale toLocale(String localeValue) {
+ if (localeValue == null) {
+ return Locale.getDefault();
+ }
+ String normalized = localeValue.trim();
+ if (normalized.isEmpty()) {
+ return Locale.getDefault();
+ }
+ Locale locale = Locale.forLanguageTag(normalized.replace('_', '-'));
+ return Locale.ROOT.equals(locale) ? Locale.getDefault() : locale;
+ }
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDirectoryPath.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDirectoryPath.java
new file mode 100644
index 000000000..c5e199c7d
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDirectoryPath.java
@@ -0,0 +1,37 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+@Retention(RUNTIME)
+@Constraint(validatedBy = ValidDirectoryPathValidator.class)
+@Documented
+public @interface ValidDirectoryPath {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ String context();
+
+ String parent();
+
+ boolean allowNull();
+
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDirectoryPathValidator.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDirectoryPathValidator.java
new file mode 100644
index 000000000..c6990c678
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDirectoryPathValidator.java
@@ -0,0 +1,40 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import java.io.File;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ValidationErrorList;
+import org.owasp.esapi.ESAPI;
+
+
+public class ValidDirectoryPathValidator implements ConstraintValidator{
+
+ private String context;
+ private String parentString;
+ private boolean allowNull;
+
+ @Override
+ public void initialize(ValidDirectoryPath validDirectoryPath) {
+ context = validDirectoryPath.context();
+ parentString = validDirectoryPath.parent();
+ allowNull = validDirectoryPath.allowNull();
+ }
+
+ @Override
+ public boolean isValid(String input, ConstraintValidatorContext constraintValidatorContext) {
+ if (input == null) {
+ return true;
+ }
+ ValidationErrorList errorList = new ValidationErrorList();
+ File parent = new File(parentString);
+ boolean valid = ESAPI.validator().isValidDirectoryPath(context, input, parent, allowNull, errorList);
+
+ if(!valid){
+ ValidationUtil.addViolations(errorList, constraintValidatorContext);
+ }
+
+ return valid;
+ }
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDouble.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDouble.java
new file mode 100644
index 000000000..c141e87f9
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDouble.java
@@ -0,0 +1,39 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+@Retention(RUNTIME)
+@Constraint(validatedBy = ValidDoubleValidator.class)
+@Documented
+public @interface ValidDouble {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ String context();
+
+ double minValue();
+
+ double maxValue();
+
+ boolean allowNull();
+
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDoubleValidator.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDoubleValidator.java
new file mode 100644
index 000000000..ee81211bf
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidDoubleValidator.java
@@ -0,0 +1,39 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ValidationErrorList;
+import org.owasp.esapi.ESAPI;
+
+
+public class ValidDoubleValidator implements ConstraintValidator{
+
+ private String context;
+ private double minValue;
+ private double maxValue;
+ private boolean allowNull;
+
+ @Override
+ public void initialize(ValidDouble validDouble) {
+ context = validDouble.context();
+ minValue = validDouble.minValue();
+ maxValue = validDouble.maxValue();
+ allowNull = validDouble.allowNull();
+ }
+
+ @Override
+ public boolean isValid(String input, ConstraintValidatorContext constraintValidatorContext) {
+ if (input == null) {
+ return true;
+ }
+ ValidationErrorList errorList = new ValidationErrorList();
+ boolean valid = ESAPI.validator().isValidDouble(context, input, minValue, maxValue, allowNull, errorList);
+
+ if(!valid){
+ ValidationUtil.addViolations(errorList, constraintValidatorContext);
+ }
+
+ return valid;
+ }
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileContent.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileContent.java
new file mode 100644
index 000000000..39cb2242f
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileContent.java
@@ -0,0 +1,37 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+@Retention(RUNTIME)
+@Constraint(validatedBy = ValidFileContentValidator.class)
+@Documented
+public @interface ValidFileContent {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ String context();
+
+ int maxBytes();
+
+ boolean allowNull();
+
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileContentValidator.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileContentValidator.java
new file mode 100644
index 000000000..bf7dd966b
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileContentValidator.java
@@ -0,0 +1,37 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ValidationErrorList;
+import org.owasp.esapi.ESAPI;
+
+
+public class ValidFileContentValidator implements ConstraintValidator{
+
+ private String context;
+ private int maxBytes;
+ private boolean allowNull;
+
+ @Override
+ public void initialize(ValidFileContent validFileContent) {
+ context = validFileContent.context();
+ maxBytes = validFileContent.maxBytes();
+ allowNull = validFileContent.allowNull();
+ }
+
+ @Override
+ public boolean isValid(byte[] input, ConstraintValidatorContext constraintValidatorContext) {
+ if (input == null) {
+ return true;
+ }
+ ValidationErrorList errorList = new ValidationErrorList();
+ boolean valid = ESAPI.validator().isValidFileContent(context, input, maxBytes, allowNull, errorList);
+
+ if(!valid){
+ ValidationUtil.addViolations(errorList, constraintValidatorContext);
+ }
+
+ return valid;
+ }
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileName.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileName.java
new file mode 100644
index 000000000..365926335
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileName.java
@@ -0,0 +1,37 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+@Retention(RUNTIME)
+@Constraint(validatedBy = ValidFileNameValidator.class)
+@Documented
+public @interface ValidFileName {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ String context();
+
+ String[] allowedExtensions() default {};
+
+ boolean allowNull();
+
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileNameValidator.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileNameValidator.java
new file mode 100644
index 000000000..5bcbe4278
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileNameValidator.java
@@ -0,0 +1,47 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ValidationErrorList;
+import org.owasp.esapi.ESAPI;
+
+
+public class ValidFileNameValidator implements ConstraintValidator{
+
+ private String context;
+ private String[] allowedExtensions;
+ private boolean allowNull;
+
+ @Override
+ public void initialize(ValidFileName validFileName) {
+ context = validFileName.context();
+ allowedExtensions = validFileName.allowedExtensions();
+ allowNull = validFileName.allowNull();
+ }
+
+ @Override
+ public boolean isValid(String input, ConstraintValidatorContext constraintValidatorContext) {
+ if (input == null) {
+ return true;
+ }
+ ValidationErrorList errorList = new ValidationErrorList();
+ boolean valid;
+ if(allowedExtensions.length == 0){
+ valid = ESAPI.validator().isValidFileName(context, input, allowNull, errorList);
+ } else {
+ List allowedExtensionsList = new ArrayList<>(Arrays.asList(allowedExtensions));
+ valid = ESAPI.validator().isValidFileName(context, input, allowedExtensionsList, allowNull, errorList);
+ }
+
+ if(!valid){
+ ValidationUtil.addViolations(errorList, constraintValidatorContext);
+ }
+
+ return valid;
+ }
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileUpload.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileUpload.java
new file mode 100644
index 000000000..3edf41381
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileUpload.java
@@ -0,0 +1,43 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+@Retention(RUNTIME)
+@Constraint(validatedBy = ValidFileUploadValidator.class)
+@Documented
+public @interface ValidFileUpload {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ String context();
+
+ String directoryPath();
+
+ String fileName();
+
+ String parent();
+
+ int maxBytes();
+
+ boolean allowNull();
+
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileUploadValidator.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileUploadValidator.java
new file mode 100644
index 000000000..757206eca
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidFileUploadValidator.java
@@ -0,0 +1,46 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import java.io.File;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ValidationErrorList;
+import org.owasp.esapi.ESAPI;
+
+
+public class ValidFileUploadValidator implements ConstraintValidator{
+
+ private String context;
+ private String directoryPath;
+ private String fileName;
+ private String parentString;
+ private int maxBytes;
+ private boolean allowNull;
+
+ @Override
+ public void initialize(ValidFileUpload validFileUpload) {
+ context = validFileUpload.context();
+ directoryPath = validFileUpload.directoryPath();
+ fileName = validFileUpload.fileName();
+ parentString = validFileUpload.parent();
+ maxBytes = validFileUpload.maxBytes();
+ allowNull = validFileUpload.allowNull();
+ }
+
+ @Override
+ public boolean isValid(byte[] input, ConstraintValidatorContext constraintValidatorContext) {
+ if (input == null) {
+ return true;
+ }
+ ValidationErrorList errorList = new ValidationErrorList();
+ File parent = new File(parentString);
+ boolean valid = ESAPI.validator().isValidFileUpload(context, directoryPath, fileName, parent, input, maxBytes, allowNull, errorList);
+
+ if(!valid){
+ ValidationUtil.addViolations(errorList, constraintValidatorContext);
+ }
+
+ return valid;
+ }
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidHTTPRequestParameterSet.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidHTTPRequestParameterSet.java
new file mode 100644
index 000000000..a2cb9e911
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidHTTPRequestParameterSet.java
@@ -0,0 +1,43 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+@Retention(RUNTIME)
+@Constraint(validatedBy = ValidHTTPRequestParameterSetValidator.class)
+@Documented
+public @interface ValidHTTPRequestParameterSet {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ String context();
+
+ //Invalid type Set for the annotation attribute ValidHTTPRequestParameters.requiredNames;
+ //only primitive type, String, Class, annotation, enumeration are permitted or 1-dimensional arrays thereof
+ //Set requiredNames();
+
+ String[] requiredNames();
+
+ String[] optionalNames();
+
+ boolean allowNull();
+
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidHTTPRequestParameterSetValidator.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidHTTPRequestParameterSetValidator.java
new file mode 100644
index 000000000..100f2213f
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidHTTPRequestParameterSetValidator.java
@@ -0,0 +1,49 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ValidationErrorList;
+import org.owasp.esapi.ESAPI;
+
+
+public class ValidHTTPRequestParameterSetValidator implements ConstraintValidator{
+
+ private String context;
+ private String[] requiredNames;
+ private String[] optionalNames;
+ private boolean allowNull;
+
+ @Override
+ public void initialize(ValidHTTPRequestParameterSet validHTTPRequestParameters) {
+ context = validHTTPRequestParameters.context();
+ requiredNames = validHTTPRequestParameters.requiredNames();
+ optionalNames = validHTTPRequestParameters.optionalNames();
+ allowNull = validHTTPRequestParameters.allowNull();
+ }
+
+ @Override
+ public boolean isValid(HttpServletRequest input, ConstraintValidatorContext constraintValidatorContext) {
+ if (input == null) {
+ return true;
+ }
+ if (allowNull && input.getParameterMap().isEmpty()) {
+ return true;
+ }
+ ValidationErrorList errorList = new ValidationErrorList();
+ Set requiredNamesSet = new HashSet<>(Arrays.asList(requiredNames));
+ Set optionalNamesSet = new HashSet<>(Arrays.asList(optionalNames));
+ boolean valid = ESAPI.validator().isValidHTTPRequestParameterSet(context, input, requiredNamesSet, optionalNamesSet, errorList);
+
+ if(!valid){
+ ValidationUtil.addViolations(errorList, constraintValidatorContext);
+ }
+
+ return valid;
+ }
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidInteger.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidInteger.java
new file mode 100644
index 000000000..7754e2dde
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidInteger.java
@@ -0,0 +1,39 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+@Retention(RUNTIME)
+@Constraint(validatedBy = ValidIntegerValidator.class)
+@Documented
+public @interface ValidInteger {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ String context();
+
+ int minValue();
+
+ int maxValue();
+
+ boolean allowNull();
+
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidIntegerValidator.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidIntegerValidator.java
new file mode 100644
index 000000000..c669c8dc0
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidIntegerValidator.java
@@ -0,0 +1,39 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ValidationErrorList;
+import org.owasp.esapi.ESAPI;
+
+
+public class ValidIntegerValidator implements ConstraintValidator{
+
+ private String context;
+ private int minValue;
+ private int maxValue;
+ private boolean allowNull;
+
+ @Override
+ public void initialize(ValidInteger validInteger) {
+ context = validInteger.context();
+ minValue = validInteger.minValue();
+ maxValue = validInteger.maxValue();
+ allowNull = validInteger.allowNull();
+ }
+
+ @Override
+ public boolean isValid(String input, ConstraintValidatorContext constraintValidatorContext) {
+ if (input == null) {
+ return true;
+ }
+ ValidationErrorList errorList = new ValidationErrorList();
+ boolean valid = ESAPI.validator().isValidInteger(context, input, minValue, maxValue, allowNull, errorList);
+
+ if(!valid){
+ ValidationUtil.addViolations(errorList, constraintValidatorContext);
+ }
+
+ return valid;
+ }
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidListItem.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidListItem.java
new file mode 100644
index 000000000..8ddd81850
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidListItem.java
@@ -0,0 +1,41 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+@Retention(RUNTIME)
+@Constraint(validatedBy = ValidListItemValidator.class)
+@Documented
+public @interface ValidListItem {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ String context();
+
+ // Invalid type List for the annotation attribute ValidListItem.list;
+ // only primitive type, String, Class, annotation, enumeration are permitted or 1-dimensional arrays thereof
+ //List list();
+
+ String[] list();
+
+ boolean allowNull();
+
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidListItemValidator.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidListItemValidator.java
new file mode 100644
index 000000000..2a3aa0fbe
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidListItemValidator.java
@@ -0,0 +1,44 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ValidationErrorList;
+import org.owasp.esapi.ESAPI;
+
+
+public class ValidListItemValidator implements ConstraintValidator{
+
+ private String context;
+ private String[] listArray;
+ private boolean allowNull;
+
+ @Override
+ public void initialize(ValidListItem validListItem) {
+ context = validListItem.context();
+ listArray = validListItem.list();
+ allowNull = validListItem.allowNull();
+ }
+
+ @Override
+ public boolean isValid(String input, ConstraintValidatorContext constraintValidatorContext) {
+ if (input == null) {
+ return true;
+ }
+ if (allowNull && input.isEmpty()) {
+ return true;
+ }
+ ValidationErrorList errorList = new ValidationErrorList();
+ List list = Arrays.asList(listArray);
+ boolean valid = ESAPI.validator().isValidListItem(context, input, list, errorList);
+
+ if(!valid){
+ ValidationUtil.addViolations(errorList, constraintValidatorContext);
+ }
+
+ return valid;
+ }
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidNumber.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidNumber.java
new file mode 100644
index 000000000..5d6298d9a
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidNumber.java
@@ -0,0 +1,39 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+@Retention(RUNTIME)
+@Constraint(validatedBy = ValidNumberValidator.class)
+@Documented
+public @interface ValidNumber {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ String context();
+
+ long minValue();
+
+ long maxValue();
+
+ boolean allowNull();
+
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidNumberValidator.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidNumberValidator.java
new file mode 100644
index 000000000..eac3a973d
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidNumberValidator.java
@@ -0,0 +1,39 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ValidationErrorList;
+import org.owasp.esapi.ESAPI;
+
+
+public class ValidNumberValidator implements ConstraintValidator{
+
+ private String context;
+ private long minValue;
+ private long maxValue;
+ private boolean allowNull;
+
+ @Override
+ public void initialize(ValidNumber validNumber) {
+ context = validNumber.context();
+ minValue = validNumber.minValue();
+ maxValue = validNumber.maxValue();
+ allowNull = validNumber.allowNull();
+ }
+
+ @Override
+ public boolean isValid(String input, ConstraintValidatorContext constraintValidatorContext) {
+ if (input == null) {
+ return true;
+ }
+ ValidationErrorList errorList = new ValidationErrorList();
+ boolean valid = ESAPI.validator().isValidNumber(context, input, minValue, maxValue, allowNull, errorList);
+
+ if(!valid){
+ ValidationUtil.addViolations(errorList, constraintValidatorContext);
+ }
+
+ return valid;
+ }
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidPrintable.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidPrintable.java
new file mode 100644
index 000000000..8a4923d18
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidPrintable.java
@@ -0,0 +1,37 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+@Retention(RUNTIME)
+@Constraint(validatedBy = {ValidPrintableValidator.class, ValidPrintableStringValidator.class})
+@Documented
+public @interface ValidPrintable {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ String context();
+
+ int maxLength();
+
+ boolean allowNull();
+
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidPrintableStringValidator.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidPrintableStringValidator.java
new file mode 100644
index 000000000..631d52a9e
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidPrintableStringValidator.java
@@ -0,0 +1,37 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ESAPI;
+import org.owasp.esapi.ValidationErrorList;
+
+
+public class ValidPrintableStringValidator implements ConstraintValidator{
+
+ private String context;
+ private int maxLength;
+ private boolean allowNull;
+
+ @Override
+ public void initialize(ValidPrintable validPrintable) {
+ context = validPrintable.context();
+ maxLength = validPrintable.maxLength();
+ allowNull = validPrintable.allowNull();
+ }
+
+ @Override
+ public boolean isValid(String input, ConstraintValidatorContext constraintValidatorContext) {
+ if (input == null) {
+ return true;
+ }
+ ValidationErrorList errorList = new ValidationErrorList();
+ boolean valid = ESAPI.validator().isValidPrintable(context, input, maxLength, allowNull, errorList);
+
+ if(!valid){
+ ValidationUtil.addViolations(errorList, constraintValidatorContext);
+ }
+
+ return valid;
+ }
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidPrintableValidator.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidPrintableValidator.java
new file mode 100644
index 000000000..355a9fb84
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidPrintableValidator.java
@@ -0,0 +1,37 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ValidationErrorList;
+import org.owasp.esapi.ESAPI;
+
+
+public class ValidPrintableValidator implements ConstraintValidator{
+
+ private String context;
+ private int maxLength;
+ private boolean allowNull;
+
+ @Override
+ public void initialize(ValidPrintable validPrintable) {
+ context = validPrintable.context();
+ maxLength = validPrintable.maxLength();
+ allowNull = validPrintable.allowNull();
+ }
+
+ @Override
+ public boolean isValid(char[] input, ConstraintValidatorContext constraintValidatorContext) {
+ if (input == null) {
+ return true;
+ }
+ ValidationErrorList errorList = new ValidationErrorList();
+ boolean valid = ESAPI.validator().isValidPrintable(context, input, maxLength, allowNull, errorList);
+
+ if(!valid){
+ ValidationUtil.addViolations(errorList, constraintValidatorContext);
+ }
+
+ return valid;
+ }
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidRedirectLocation.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidRedirectLocation.java
new file mode 100644
index 000000000..2869ecbeb
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidRedirectLocation.java
@@ -0,0 +1,35 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+@Retention(RUNTIME)
+@Constraint(validatedBy = ValidRedirectLocationValidator.class)
+@Documented
+public @interface ValidRedirectLocation {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ String context();
+
+ boolean allowNull();
+
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidRedirectLocationValidator.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidRedirectLocationValidator.java
new file mode 100644
index 000000000..c1b0693fc
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidRedirectLocationValidator.java
@@ -0,0 +1,35 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ValidationErrorList;
+import org.owasp.esapi.ESAPI;
+
+
+public class ValidRedirectLocationValidator implements ConstraintValidator{
+
+ private String context;
+ private boolean allowNull;
+
+ @Override
+ public void initialize(ValidRedirectLocation validRedirectLocation) {
+ context = validRedirectLocation.context();
+ allowNull = validRedirectLocation.allowNull();
+ }
+
+ @Override
+ public boolean isValid(String input, ConstraintValidatorContext constraintValidatorContext) {
+ if (input == null) {
+ return true;
+ }
+ ValidationErrorList errorList = new ValidationErrorList();
+ boolean valid = ESAPI.validator().isValidRedirectLocation(context, input, allowNull, errorList);
+
+ if(!valid){
+ ValidationUtil.addViolations(errorList, constraintValidatorContext);
+ }
+
+ return valid;
+ }
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidSafeHTML.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidSafeHTML.java
new file mode 100644
index 000000000..221ff4853
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidSafeHTML.java
@@ -0,0 +1,37 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+@Retention(RUNTIME)
+@Constraint(validatedBy = ValidSafeHTMLValidator.class)
+@Documented
+public @interface ValidSafeHTML {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ String context();
+
+ int maxLength();
+
+ boolean allowNull();
+
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidSafeHTMLValidator.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidSafeHTMLValidator.java
new file mode 100644
index 000000000..6e5fb9756
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidSafeHTMLValidator.java
@@ -0,0 +1,38 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ValidationErrorList;
+import org.owasp.esapi.ESAPI;
+
+
+public class ValidSafeHTMLValidator implements ConstraintValidator{
+
+ private String context;
+ private int maxLength;
+ private boolean allowNull;
+
+ @Override
+ public void initialize(ValidSafeHTML validSafeHTML) {
+ context = validSafeHTML.context();
+ maxLength = validSafeHTML.maxLength();
+ allowNull = validSafeHTML.allowNull();
+ }
+
+ @Override
+ public boolean isValid(String input, ConstraintValidatorContext constraintValidatorContext) {
+ if (input == null) {
+ return true;
+ }
+ ValidationErrorList errorList = new ValidationErrorList();
+ ESAPI.validator().getValidSafeHTML(context, input, maxLength, allowNull, errorList);
+ boolean valid = errorList.isEmpty();
+
+ if(!valid){
+ ValidationUtil.addViolations(errorList, constraintValidatorContext);
+ }
+
+ return valid;
+ }
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidString.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidString.java
new file mode 100644
index 000000000..9a91ff7a2
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidString.java
@@ -0,0 +1,43 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+@Retention(RUNTIME)
+@Constraint(validatedBy = ValidStringValidator.class)
+@Documented
+public @interface ValidString {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ String context();
+
+ String type() default "SafeString";
+
+ int maxLength();
+
+ boolean allowNull();
+
+ boolean canonicalize() default true;
+
+}
+
+
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidStringValidator.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidStringValidator.java
new file mode 100644
index 000000000..9d2c96aa5
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidStringValidator.java
@@ -0,0 +1,41 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ValidationErrorList;
+import org.owasp.esapi.ESAPI;
+
+
+public class ValidStringValidator implements ConstraintValidator{
+
+ private String context;
+ private String type;
+ private int maxLength;
+ private boolean allowNull;
+ private boolean canonicalize;
+
+ @Override
+ public void initialize(ValidString validString) {
+ context = validString.context();
+ type = validString.type();
+ maxLength = validString.maxLength();
+ allowNull = validString.allowNull();
+ canonicalize = validString.canonicalize();
+ }
+
+ @Override
+ public boolean isValid(String input, ConstraintValidatorContext constraintValidatorContext) {
+ if (input == null) {
+ return true;
+ }
+ ValidationErrorList errorList = new ValidationErrorList();
+ boolean valid = ESAPI.validator().isValidInput(context, input, type, maxLength, allowNull, canonicalize, errorList);
+
+ if(!valid){
+ ValidationUtil.addViolations(errorList, constraintValidatorContext);
+ }
+
+ return valid;
+ }
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidURI.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidURI.java
new file mode 100644
index 000000000..2041210f7
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidURI.java
@@ -0,0 +1,35 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+@Retention(RUNTIME)
+@Constraint(validatedBy = ValidURIValidator.class)
+@Documented
+public @interface ValidURI {
+
+ String message() default "Invalid URI";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ String context();
+
+ boolean allowNull();
+
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidURIValidator.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidURIValidator.java
new file mode 100644
index 000000000..f7c842ee6
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidURIValidator.java
@@ -0,0 +1,41 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ValidationErrorList;
+import org.owasp.esapi.ESAPI;
+
+
+public class ValidURIValidator implements ConstraintValidator{
+
+ private String context;
+ private boolean allowNull;
+
+ @Override
+ public void initialize(ValidURI validURI) {
+ context = validURI.context();
+ allowNull = validURI.allowNull();
+ }
+
+ @Override
+ public boolean isValid(String input, ConstraintValidatorContext constraintValidatorContext) {
+ if (input == null) {
+ return true;
+ }
+ //isValidURI has no method signature that accepts a ValidationErrorList
+ //ValidationErrorList errorList = new ValidationErrorList();
+ boolean valid = ESAPI.validator().isValidURI(context, input, allowNull);
+
+ if (!valid) {
+ constraintValidatorContext.disableDefaultConstraintViolation();
+ String message = constraintValidatorContext.getDefaultConstraintMessageTemplate();
+ if (message == null || message.isEmpty()) {
+ message = "Invalid URI";
+ }
+ constraintValidatorContext.buildConstraintViolationWithTemplate(message).addConstraintViolation();
+ }
+
+ return valid;
+ }
+}
diff --git a/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidationUtil.java b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidationUtil.java
new file mode 100644
index 000000000..20bd35950
--- /dev/null
+++ b/src/main/java/org/owasp/esapi/reference/validation/annotations/ValidationUtil.java
@@ -0,0 +1,23 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import javax.validation.ConstraintValidatorContext;
+
+import org.owasp.esapi.ValidationErrorList;
+import org.owasp.esapi.errors.ValidationException;
+
+public class ValidationUtil {
+
+ private ValidationUtil(){}
+
+ public static void addViolations(ValidationErrorList errorList, ConstraintValidatorContext constraintValidatorContext){
+ constraintValidatorContext.disableDefaultConstraintViolation();
+ for (ValidationException vex : errorList.errors()) {
+ String errorMessage = vex.getUserMessage();
+ if (errorMessage == null || errorMessage.isEmpty()) {
+ errorMessage = constraintValidatorContext.getDefaultConstraintMessageTemplate();
+ }
+ constraintValidatorContext.buildConstraintViolationWithTemplate(errorMessage).addConstraintViolation();
+ }
+ }
+
+}
diff --git a/src/test/java/org/owasp/esapi/reference/validation/annotations/ValidationAnnotationsTest.java b/src/test/java/org/owasp/esapi/reference/validation/annotations/ValidationAnnotationsTest.java
new file mode 100644
index 000000000..4f653c7c0
--- /dev/null
+++ b/src/test/java/org/owasp/esapi/reference/validation/annotations/ValidationAnnotationsTest.java
@@ -0,0 +1,446 @@
+package org.owasp.esapi.reference.validation.annotations;
+
+import static org.junit.Assert.assertEquals;
+import static org.owasp.esapi.PropNames.DISABLE_INTRUSION_DETECTION;
+
+import java.nio.charset.StandardCharsets;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.validation.ConstraintViolation;
+import javax.validation.Valid;
+import javax.validation.Validation;
+import javax.validation.Validator;
+
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+import org.owasp.esapi.ESAPI;
+import org.owasp.esapi.SecurityConfiguration;
+import org.owasp.esapi.SecurityConfigurationWrapper;
+import org.owasp.esapi.http.MockHttpServletRequest;
+
+public class ValidationAnnotationsTest {
+ private static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase(Locale.ROOT).contains("win");
+ private static final String WINDOWS_ROOT = "C:\\";
+ private static final String UNIX_ROOT = "/";
+
+ private static class ConfOverride extends SecurityConfigurationWrapper {
+ ConfOverride(SecurityConfiguration orig) {
+ super(orig);
+ }
+
+ @Override
+ public Boolean getBooleanProp(String propName) {
+ if (DISABLE_INTRUSION_DETECTION.equals(propName)) {
+ return Boolean.TRUE;
+ }
+ return super.getBooleanProp(propName);
+ }
+ }
+
+ private Validator validator;
+
+ @Before
+ public void setUp() {
+ ESAPI.override(new ConfOverride(ESAPI.securityConfiguration()));
+ validator = Validation.buildDefaultValidatorFactory().getValidator();
+ }
+
+ @After
+ public void tearDown() {
+ ESAPI.override(null);
+ }
+
+ @Test
+ public void testValidCreditCard() {
+ CreditCardBean bean = new CreditCardBean("1234 9876 0000 0008");
+ assertViolations(bean, 0);
+ bean.number = "4417 1234 5678 9112";
+ assertViolations(bean, 1);
+ }
+
+ @Test
+ public void testValidDate() {
+ String validDate = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US).format(new Date(0));
+ DateBean bean = new DateBean(validDate);
+ assertViolations(bean, 0);
+ bean.value = "not-a-date";
+ assertViolations(bean, 1);
+ }
+
+ @Test
+ public void testValidDirectoryPath() {
+ if (IS_WINDOWS) {
+ Assume.assumeTrue(isSystemDriveC());
+ DirectoryPathWindowsBean bean = new DirectoryPathWindowsBean(WINDOWS_ROOT);
+ assertViolations(bean, 0);
+ bean.path = WINDOWS_ROOT + "does-not-exist";
+ assertViolations(bean, 1);
+ } else {
+ DirectoryPathUnixBean bean = new DirectoryPathUnixBean(UNIX_ROOT);
+ assertViolations(bean, 0);
+ bean.path = UNIX_ROOT + "does-not-exist";
+ assertViolations(bean, 1);
+ }
+ }
+
+ @Test
+ public void testValidDouble() {
+ DoubleBean bean = new DoubleBean("1.0");
+ assertViolations(bean, 0);
+ bean.value = "ridiculous";
+ assertViolations(bean, 1);
+ }
+
+ @Test
+ public void testValidFileContent() {
+ FileContentBean bean = new FileContentBean("12345".getBytes(StandardCharsets.UTF_8));
+ assertViolations(bean, 0);
+ bean.content = "123456".getBytes(StandardCharsets.UTF_8);
+ assertViolations(bean, 1);
+ }
+
+ @Test
+ public void testValidFileName() {
+ FileNameBean bean = new FileNameBean("test.txt");
+ assertViolations(bean, 0);
+ bean.name = "test.exe";
+ assertViolations(bean, 1);
+ }
+
+ @Test
+ public void testValidFileUpload() {
+ if (IS_WINDOWS) {
+ Assume.assumeTrue(isSystemDriveC());
+ FileUploadWindowsBean bean = new FileUploadWindowsBean("12345".getBytes(StandardCharsets.UTF_8));
+ assertViolations(bean, 0);
+ bean.content = "123456".getBytes(StandardCharsets.UTF_8);
+ assertViolations(bean, 1);
+ } else {
+ FileUploadUnixBean bean = new FileUploadUnixBean("12345".getBytes(StandardCharsets.UTF_8));
+ assertViolations(bean, 0);
+ bean.content = "123456".getBytes(StandardCharsets.UTF_8);
+ assertViolations(bean, 1);
+ }
+ }
+
+ @Test
+ public void testValidInteger() {
+ IntegerBean bean = new IntegerBean("5");
+ assertViolations(bean, 0);
+ bean.value = "20";
+ assertViolations(bean, 1);
+ }
+
+ @Test
+ public void testValidListItem() {
+ ListItemBean bean = new ListItemBean("red");
+ assertViolations(bean, 0);
+ bean.value = "blue";
+ assertViolations(bean, 1);
+ }
+
+ @Test
+ public void testValidNumber() {
+ NumberBean bean = new NumberBean("10");
+ assertViolations(bean, 0);
+ bean.value = "1000";
+ assertViolations(bean, 1);
+ }
+
+ @Test
+ public void testValidPrintableChars() {
+ PrintableCharsBean bean = new PrintableCharsBean("Hello".toCharArray());
+ assertViolations(bean, 0);
+ bean.value = "Hi\n".toCharArray();
+ assertViolations(bean, 1);
+ }
+
+ @Test
+ public void testValidPrintableString() {
+ PrintableStringBean bean = new PrintableStringBean("Hello");
+ assertViolations(bean, 0);
+ bean.value = "Hi\n";
+ assertViolations(bean, 1);
+ }
+
+ @Test
+ public void testValidRedirectLocation() {
+ RedirectBean bean = new RedirectBean("/test/ok");
+ assertViolations(bean, 0);
+ bean.value = "http://example.com";
+ assertViolations(bean, 1);
+ }
+
+ @Test
+ public void testValidSafeHTML() {
+ SafeHtmlBean bean = new SafeHtmlBean("Jeff");
+ assertViolations(bean, 0);
+ bean.value = "Test. ";
+ assertViolations(bean, 1);
+ }
+
+ @Test
+ public void testValidURI() {
+ UriBean bean = new UriBean("http://example.com");
+ assertViolations(bean, 0);
+ bean.value = "javascript:alert(1)";
+ assertViolations(bean, 1);
+ }
+
+ @Test
+ public void testValidString() {
+ Person person = new Person("John");
+ assertViolations(person, 0);
+ }
+
+ @Test
+ public void testInvalidStringType() {
+ Person person = new Person("John