/** * Copyright (C) 2016 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.errai.validation.client.dynamic; import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.Set; import javax.enterprise.inject.Alternative; import javax.validation.Constraint; import javax.validation.ConstraintViolation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Validates values with for any {@link Constraint Constraints} that were available at compile-time. * * @author Christian Sadilek <csadilek@redhat.com> * @author Max Barkley <mbarkley@redhat.com> */ @SuppressWarnings("unchecked") @Alternative public class DynamicValidator { private static final Logger logger = LoggerFactory.getLogger(DynamicValidator.class); private final Map<DynamicValidatorKey, GeneratedDynamicValidator<?>> validators = new HashMap<>(); /** * Used by generated code to add {@link GeneratedDynamicValidator GeneratedDynamicValidators}. Allows overriding of * validators (logged at warning level). */ public void addValidator(final String constraint, final String valueType, final GeneratedDynamicValidator<?> validator) { final DynamicValidatorKey key = new DynamicValidatorKey(constraint, valueType); if (validators.containsKey(key)) { logger.warn("Validator for " + key + " is being overridden.\n\tPrevious: " + validators.get(key).getClass().getSimpleName() + "\n\tNew: " + validator.getClass().getSimpleName()); } validators.put(key, validator); } /** * @param constraint * The {@link Constraint} annotation type. * @param parameters * A map of parameter values for the given {@link Constraint}. Keys are names of the parameters in the * {@link Constraint} annotation source. * @param value * The value being validated. * @return An empty set if the given value is valid, or a set with one or more {@link ConstraintViolation * ConstraintViolations} if the given value is invalid. * @throws IllegalArgumentException * If a validator can not be found for the given {@link Constraint} and value type. */ public <T> Set<ConstraintViolation<T>> validate(final Class<? extends Annotation> constraint, final Map<String, Object> parameters, final T value) { return validate(constraint.getName(), parameters, value); } /** * @param constraint * The fully-qualified class name of a {@link Constraint}. * @param parameters * A map of parameter values for the given {@link Constraint}. Keys are names of the parameters in the * {@link Constraint} annotation source. * @param value * The value being validated. * @return An empty set if the given value is valid, or a set with one or more {@link ConstraintViolation * ConstraintViolations} if the given value is invalid. * @throws IllegalArgumentException * If a validator can not be found for the given {@link Constraint} and value type. */ public <T> Set<ConstraintViolation<T>> validate(final String constraint, final Map<String, Object> parameters, final T value) { final GeneratedDynamicValidator<T> dynamicValidator = getValidatorOrThrow(constraint, value); return dynamicValidator.validate(parameters, value); } private <T> GeneratedDynamicValidator<T> getValidatorOrThrow(final String constraint, final T value) { final DynamicValidatorKey originalKey = new DynamicValidatorKey(constraint, getValueClassName(value)); DynamicValidatorKey key = originalKey; GeneratedDynamicValidator<T> dynamicValidator = (GeneratedDynamicValidator<T>) validators.get(key); while (dynamicValidator == null && key.hasAlias()) { key = key.getAlias().get(); dynamicValidator = (GeneratedDynamicValidator<T>) validators.get(key); } if (dynamicValidator == null) { throw new IllegalArgumentException("There is no validator for " + originalKey); } else { return dynamicValidator; } } private <T> String getValueClassName(final T value) { return Optional .ofNullable(value) .map(v -> v.getClass().getName()) .orElseGet(() -> Object.class.getName()); } }