Skip to content

Commit

Permalink
Tested and reworked some validators (Max/MinLength are just usable fo…
Browse files Browse the repository at this point in the history
…r Strings now)
  • Loading branch information
tobiasstamann committed Feb 5, 2024
1 parent ecd471f commit a88ba41
Show file tree
Hide file tree
Showing 18 changed files with 491 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,16 @@

/**
* Used to map parameters to validator constructor.
* Defaults to empty array for no-arg constructor.
* @return the parameter names
*/
String[] attributeNamesToConstructorParameterMapping() default {};

/**
* Must reference annotation types annotated with this meta annotation.
* Defaults to empty array.
* @return the annotations overwritten with this annotation
*/
Class<?>[] overwrites() default {};

}
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package io.toolisticon.fluapigen.validation.api;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

/**
* Meta annotation to declare validators via annotation.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@FluentApiValidator(value = HasNoArgConstructor.ValidatorImpl.class, attributeNamesToConstructorParameterMapping = {"modifier"})
public @interface HasNoArgConstructor {

Expand All @@ -27,7 +33,7 @@ public boolean validate(Class obj) {

try {
// need to get constructor method
Constructor<?> constructor = obj.getConstructor();
Constructor<?> constructor = obj.getDeclaredConstructor();

for (int modifier : modifiers) {
if ((modifier & obj.getModifiers()) == 0) {
Expand All @@ -36,12 +42,24 @@ public boolean validate(Class obj) {
}

} catch (NoSuchMethodException e) {
return false;

// must check if there are any explicit constructors, if not then there is just the default public one.
return obj.getDeclaredConstructors().length == 0 && hasPublicModifier();

}
}

return true;
}

boolean hasPublicModifier () {
for (int modifier : modifiers){
if (modifier == Modifier.PUBLIC) {
return true;
}
}
return false;
}
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
package io.toolisticon.fluapigen.validation.api;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.regex.Pattern;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@FluentApiValidator(value = Matches.ValidatorImpl.class, attributeNamesToConstructorParameterMapping = {"value"})
public @interface Matches {

Expand All @@ -18,7 +24,7 @@ public ValidatorImpl(String regularExpression) {

@Override
public boolean validate(String obj) {
return Pattern.compile(regularExpression).matcher(obj).matches();
return obj == null || Pattern.compile(regularExpression).matcher(obj).matches();
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,36 @@
package io.toolisticon.fluapigen.validation.api;

import java.lang.reflect.Array;
import java.util.Collection;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Checks if string has maximal length.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@FluentApiValidator(value = MaxLength.ValidatorImpl.class, attributeNamesToConstructorParameterMapping = {"value"})
public @interface MaxLength {

int value();

class ValidatorImpl implements Validator<Object> {
class ValidatorImpl implements Validator<String> {

private final int maxLength;


public ValidatorImpl(int maxLength) {

this.maxLength = maxLength;

}

@Override
public boolean validate(Object obj) {

if (obj.getClass().isArray()) {
return Array.getLength(obj) <= maxLength;
} else if (obj instanceof Collection) {
return ((Collection) obj).size() <= maxLength;
} else if (obj instanceof String) {
return ((String) obj).length() <= maxLength;
}
return obj != null;
public boolean validate(String obj) {
return obj == null || obj.length() <= maxLength;
}

}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
package io.toolisticon.fluapigen.validation.api;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Array;
import java.util.Collection;


/**
* Checks if string has mininmal length.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@FluentApiValidator(value = MinLength.ValidatorImpl.class, attributeNamesToConstructorParameterMapping = {"value"})
public @interface MinLength {

int value();

class ValidatorImpl implements Validator<Object> {
class ValidatorImpl implements Validator<String> {

private final int minLength;

Expand All @@ -18,16 +26,10 @@ public ValidatorImpl(int minLength) {
}

@Override
public boolean validate(Object obj) {

if (obj.getClass().isArray()) {
return Array.getLength(obj) >= minLength;
} else if (obj instanceof Collection) {
return ((Collection) obj).size() >= minLength;
} else if (obj instanceof String) {
return ((String) obj).length() >= minLength;
}
return obj != null;
public boolean validate(String obj) {

return obj == null || obj.length() >= minLength;

}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
package io.toolisticon.fluapigen.validation.api;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Array;
import java.util.Collection;

/**
* Validates String to be not empty.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@FluentApiValidator(NotEmpty.ValidatorImpl.class)
public @interface NotEmpty {

class ValidatorImpl implements Validator<Object> {
class ValidatorImpl implements Validator<String> {
@Override
public boolean validate(Object obj) {

if (obj.getClass().isArray()) {
return Array.getLength(obj) > 0;
} else if (obj instanceof Collection) {
return !((Collection) obj).isEmpty();
} else if (obj instanceof String) {
return !((String) obj).isEmpty();
}
return obj != null;
public boolean validate(String obj) {
return obj == null || !obj.isEmpty();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
package io.toolisticon.fluapigen.validation.api;

@FluentApiValidator(NotNull.ValidatorImpl.class)
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Validates if values isn't null.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.TYPE})
@FluentApiValidator(value = NotNull.ValidatorImpl.class, overwrites = {Nullable.class})
public @interface NotNull {

class ValidatorImpl implements Validator<Object> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.toolisticon.fluapigen.validation.api;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Needed to overrule {@link NotNull} annotations on method or enclosing interfaces/types.
* All parameters are by default nullable.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.TYPE})
@FluentApiValidator(value = Nullable.ValidatorImpl.class, overwrites = NotNull.class)
public @interface Nullable {

class ValidatorImpl implements Validator<Object> {
@Override
public boolean validate(Object obj) {
return true;
}

@Override
public boolean validate(Object[] obj) {
return true;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.toolisticon.fluapigen.validation.api;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Checks if string has specific length.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@FluentApiValidator(value = OfLength.ValidatorImpl.class, attributeNamesToConstructorParameterMapping = {"value", "target"})
public @interface OfLength {

int value();

class ValidatorImpl implements Validator<String> {

private final int ofLength;


public ValidatorImpl(int ofLength) {

this.ofLength = ofLength;

}

@Override
public boolean validate(String obj) {
return obj == null || obj.length() == ofLength;
}

}

}


Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
/**
* The Validator interface.
*
* One hint validators should always return true for null values!
* To prevent null values you should use {@link NotNull} validator in combination.
*
* @param <TYPE> The type which can be validated
*/
public interface Validator<TYPE> {
/**
* Validates passed in instance
* Validates passed in instance.
*
* @param obj the object to validate
* @return true if obj is valid otherwise false
Expand All @@ -21,6 +24,7 @@ default boolean validate(TYPE[] obj) {
return false;
}
}

}
return true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* This package contains all kind of predefined validators.
* Some validators like {@link io.toolisticon.fluapigen.validation.api.Nullable} and {@link io.toolisticon.fluapigen.validation.api.NotNull} can also be used on method or type level to define a default behavior.
*/
package io.toolisticon.fluapigen.validation.api;

Loading

0 comments on commit a88ba41

Please sign in to comment.