package nl.fontys.sofa.limo.validation; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; import nl.fontys.sofa.limo.validation.annotations.AssertFalse; import nl.fontys.sofa.limo.validation.annotations.AssertTrue; import nl.fontys.sofa.limo.validation.annotations.DecimalMax; import nl.fontys.sofa.limo.validation.annotations.DecimalMin; import nl.fontys.sofa.limo.validation.annotations.Future; import nl.fontys.sofa.limo.validation.annotations.Max; import nl.fontys.sofa.limo.validation.annotations.Min; import nl.fontys.sofa.limo.validation.annotations.NotNull; import nl.fontys.sofa.limo.validation.annotations.Null; import nl.fontys.sofa.limo.validation.annotations.Past; import nl.fontys.sofa.limo.validation.annotations.Pattern; import nl.fontys.sofa.limo.validation.annotations.Size; import nl.fontys.sofa.limo.validation.utils.AssertFalseValidator; import nl.fontys.sofa.limo.validation.utils.AssertTrueValidator; import nl.fontys.sofa.limo.validation.utils.DecimalMaxValidator; import nl.fontys.sofa.limo.validation.utils.DecimalMinValidator; import nl.fontys.sofa.limo.validation.utils.FieldValidator; import nl.fontys.sofa.limo.validation.utils.FutureValidator; import nl.fontys.sofa.limo.validation.utils.MaxValidator; import nl.fontys.sofa.limo.validation.utils.MinValidator; import nl.fontys.sofa.limo.validation.utils.NotNullValidator; import nl.fontys.sofa.limo.validation.utils.NullValidator; import nl.fontys.sofa.limo.validation.utils.PastValidator; import nl.fontys.sofa.limo.validation.utils.PatternValidator; import nl.fontys.sofa.limo.validation.utils.SizeValidator; /** * Validates beans according to their annotations and state. * * @author Miguel Gonzalez <m.gonzalez@student.fontys.nl> */ public class BeanValidator { private static final BeanValidator instance = new BeanValidator(); private static final Map<Class<? extends Annotation>, FieldValidator<?>> validators = new HashMap<>(); static { validators.put(Min.class, new MinValidator()); validators.put(Max.class, new MaxValidator()); validators.put(AssertTrue.class, new AssertTrueValidator()); validators.put(AssertFalse.class, new AssertFalseValidator()); validators.put(DecimalMin.class, new DecimalMinValidator()); validators.put(DecimalMax.class, new DecimalMaxValidator()); validators.put(Pattern.class, new PatternValidator()); validators.put(Null.class, new NullValidator()); validators.put(NotNull.class, new NotNullValidator()); validators.put(Past.class, new PastValidator()); validators.put(Future.class, new FutureValidator()); validators.put(Size.class, new SizeValidator()); } private BeanValidator() { } public static BeanValidator getInstance() { return instance; } /** * Validates beans and throws exception on bad result. * * @param bean bean to validate * @throws ValidationException is thrown on bad validation */ public <T> void validate(T bean) throws ValidationException { validateOnly(bean); } /** * Validates beans depending on the given fields and throws exception on bad result. * * @param bean bean to validate * @param fieldNames field names to consider only * @throws ValidationException is thrown on bad validation */ public <T> void validateOnly(T bean, String ... fieldNames) throws ValidationException { validateInternally(bean, false, fieldNames); } /** * Validates beans by ignoring the given fields and throws exception on bad result. * * @param bean bean to validate * @param fieldNames field names to ignore * @throws ValidationException is thrown on bad validation */ public <T> void validateWithout(T bean, String ... fieldNames) throws ValidationException { validateInternally(bean, true, fieldNames); } private <T> void validateInternally(T bean, boolean exclude, String ... fieldNames) throws ValidationException{ Class<?> clazz = bean.getClass(); do { Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { boolean accessible = field.isAccessible(); field.setAccessible(true); boolean valid = exclude ? isFieldExcluded(field, fieldNames) : isFieldValid(field, fieldNames); if (valid) { for (Annotation annotation : field.getAnnotations()) { try { FieldValidator validator = validators.get(annotation.annotationType()); if (validator != null) { validator.validate(annotation, field, field.get(bean)); } } catch (IllegalAccessException ex) { } } } field.setAccessible(accessible); } clazz = clazz.getSuperclass(); } while (clazz != null); } private boolean isFieldValid(Field field, String ... fieldNames) { if (fieldNames.length == 0) { return true; } for (String name : fieldNames) { if (name.equals(field.getName())) { return true; } } return false; } private boolean isFieldExcluded(Field field, String ... fieldNames) { if (fieldNames.length == 0) { return false; } for (String name : fieldNames) { if (name.equals(field.getName())) { return false; } } return true; } }