Skip to content

Commit

Permalink
Sources are now also generated from templates
Browse files Browse the repository at this point in the history
  • Loading branch information
dabico committed Dec 21, 2023
1 parent 067d4c5 commit 0e04a08
Show file tree
Hide file tree
Showing 12 changed files with 446 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package ch.usi.si.seart.validation.constraints;

import ${jakarta.validation.basePackage}.Constraint;
import ${jakarta.validation.basePackage}.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

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;

/**
* The string has to be comprised of ASCII characters. Accepts {@code CharSequence}.
* <p>
* {@code null} and blank elements are considered valid.
*
* @author Ozren Dabić
* @since 0.2.0
*/
@Documented
@Constraint(validatedBy = {})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ASCII {

String message() default "{ch.usi.si.seart.validation.constraints.ASCII.message}";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package ch.usi.si.seart.validation.constraints;

import ${jakarta.validation.basePackage}.Constraint;
import ${jakarta.validation.basePackage}.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

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;

/**
* The string has to be comprised of alphanumeric characters. Accepts {@code CharSequence}.
* <p>
* {@code null} and blank elements are considered valid.
*
* @author Ozren Dabić
* @since 0.2.0
*/
@Documented
@Constraint(validatedBy = {})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface Alphanumeric {

String message() default "{ch.usi.si.seart.validation.constraints.Alphanumeric.message}";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package ch.usi.si.seart.validation.constraints;

import ${jakarta.validation.basePackage}.Constraint;
import ${jakarta.validation.basePackage}.Payload;
import ${jakarta.validation.basePackage}.constraints.Pattern;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

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;

/**
* The string has to be a valid bcrypt hash value. Accepts {@code CharSequence}.
* <p>
* {@code null} elements are considered valid.
*
* @see <a href="https://en.wikipedia.org/wiki/Bcrypt">bcrypt</a>
* @see <a href="https://www.debuggex.com/r/DLxkWMzmmeSbC3QH">Regex Definition</a>
* @author Ozren Dabić
* @since 0.1.0
*/
@Documented
@Pattern(regexp = "^\\$2[aby]?\\$\\d{1,2}\\$[./A-Za-z0-9]{53}$")
@Constraint(validatedBy = {})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface BCryptHash {

String message() default "{ch.usi.si.seart.validation.constraints.BCryptHash.message}";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package ch.usi.si.seart.validation.constraints;

import ${jakarta.validation.basePackage}.Constraint;
import ${jakarta.validation.basePackage}.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

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;

/**
* The string must either be null, or have a non-empty value.
* This is a disjunction between {@link ${jakarta.validation.basePackage}.constraints.Null Null}
* and {@link ${jakarta.validation.basePackage}.constraints.NotBlank NotBlank}.
* Accepts {@code CharSequence}.
*
* @author Ozren Dabić
* @since 0.1.0
*/
@Documented
@Constraint(validatedBy = {})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface NullOrNotBlank {

String message() default "{ch.usi.si.seart.validation.constraints.NullOrNotBlank.message}";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package ch.usi.si.seart.validation.constraints;

import ${jakarta.validation.basePackage}.Constraint;
import ${jakarta.validation.basePackage}.Payload;
import ${jakarta.validation.basePackage}.ReportAsSingleViolation;
import ${jakarta.validation.basePackage}.constraints.Email;
import ${jakarta.validation.basePackage}.constraints.Size;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

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;

/**
* The string has to be an email address compliant with OWASP's recommended practices. Accepts {@code CharSequence}.
* <p>
* {@code null} elements are considered valid.
*
* @see <a href="https://owasp.org/www-community/OWASP_Validation_Regex_Repository">OWASP Validation Regex Repository</a>
* @see <a href="https://www.debuggex.com/r/hqu5CxrBMdxdwifC">Regex Definition</a>
* @author Ozren Dabić
* @since 0.1.0
*/
@Documented
@Size(min = 7, max = 256)
@Email(regexp = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,}$")
@Constraint(validatedBy = {})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@ReportAsSingleViolation
public @interface OWASPEmail {

String message() default "{ch.usi.si.seart.validation.constraints.OWASPEmail.message}";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}
101 changes: 101 additions & 0 deletions jakarta-validation-utils-template/validation/constraints/Password.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package ch.usi.si.seart.validation.constraints;

import ${jakarta.validation.basePackage}.Constraint;
import ${jakarta.validation.basePackage}.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

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;

/**
* The string has to be a well-formed password.
* Exact semantics of what makes up a valid password are left to Jakarta Bean Validation providers.
* By default, all passwords must consist of at least 6 of the following:
*
* <ul>
* <li>number</li>
* <li>lower-case character</li>
* <li>upper-case character</li>
* </ul>
*
* We additionally provide an upper bound for the length, and a requirement of special symbols.
* Accepts {@code CharSequence}.
*
* @author Ozren Dabić
* @since 0.1.0
*/
@Documented
@Constraint(validatedBy = {})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface Password {

/**
* @return The array of {@code Requirement} for the annotated element.
*/
Requirement[] requirements() default {
Requirement.NUMBER,
Requirement.LOWERCASE_LETTER,
Requirement.UPPERCASE_LETTER,
};

/**
* Represents a password requirement.
*/
enum Requirement {

/**
* Number requirement. Corresponds to the regular expression character class {@code [0-9]}.
*/
NUMBER("\\d"),

/**
* Special symbol requirement. Includes the whitespace character, as well as the following:
* {@code !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~}
*/
SYMBOL("[ !\"#$%&'()*+,-./:;<=>?@\\[\\]^_`{|}~]"),

/**
* Lower case letter requirement. Corresponds to the regular expression character class {@code [a-z]}.
*/
LOWERCASE_LETTER("[a-z]"),

/**
* Upper case letter requirement. Corresponds to the regular expression character class {@code [A-Z]}.
*/
UPPERCASE_LETTER("[A-Z]");

private final String charClass;

Requirement(String charClass) {
this.charClass = charClass;
}

public String getRegexp() {
return "(?=.*?" + charClass + ")";
}
}

/**
* @return The minimum password length. Can not be negative or zero.
*/
int minLength() default 6;

/**
* @return The maximum password length. Can not be negative or zero.
*/
int maxLength() default Integer.MAX_VALUE;

String message() default "{ch.usi.si.seart.validation.constraints.Password.message}";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package ch.usi.si.seart.validation.constraints;

import ${jakarta.validation.basePackage}.Constraint;
import ${jakarta.validation.basePackage}.Payload;
import ${jakarta.validation.basePackage}.constraints.Pattern;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

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;

/**
* The string has to be a valid SHA hash value. Accepts {@code CharSequence}.
* <p>
* {@code null} elements are considered valid.
*
* @see <a href="https://www.debuggex.com/r/7QTTG9mm4UhyZ2_i">Regex Definition</a>
* @author Ozren Dabić
* @since 0.1.0
*/
@Documented
@Pattern(regexp = "^[0-9a-fA-F]{32,128}$")
@Constraint(validatedBy = {})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface SHAHash {

String message() default "{ch.usi.si.seart.validation.constraints.SHAHash.message}";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package ch.usi.si.seart.validation.validator;

import ch.usi.si.seart.validation.constraints.ASCII;

import ${jakarta.validation.basePackage}.ConstraintValidator;
import ${jakarta.validation.basePackage}.ConstraintValidatorContext;
import java.nio.charset.StandardCharsets;

public class ASCIIValidator implements ConstraintValidator<ASCII, CharSequence> {

@Override
public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
return value == null || StandardCharsets.US_ASCII.newEncoder().canEncode(value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package ch.usi.si.seart.validation.validator;

import ch.usi.si.seart.validation.constraints.Alphanumeric;

import ${jakarta.validation.basePackage}.ConstraintValidator;
import ${jakarta.validation.basePackage}.ConstraintValidatorContext;

public class AlphanumericValidator implements ConstraintValidator<Alphanumeric, CharSequence> {

@Override
public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
return value == null || value.toString().chars().allMatch(Character::isLetterOrDigit);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package ch.usi.si.seart.validation.validator;

import ch.usi.si.seart.validation.constraints.NullOrNotBlank;

import ${jakarta.validation.basePackage}.ConstraintValidator;
import ${jakarta.validation.basePackage}.ConstraintValidatorContext;

public class NullOrNotBlankValidator implements ConstraintValidator<NullOrNotBlank, CharSequence> {

@Override
public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
return value == null || !value.toString().trim().isEmpty();
}
}
Loading

0 comments on commit 0e04a08

Please sign in to comment.