protected ConstraintDescriptorImpl(final T annotation, final Set<Class<?>> groups, final Set<Class<? extends Payload>> payload, final List<Class<? extends ConstraintValidator<T, ?>>> constraintValidatorClasses, final Map<String, Object> attributes, final Set<ConstraintDescriptor<?>> composingConstraints, final boolean reportAsSingleViolation, final ElementType elementType, final ConstraintOrigin definedOn) { super(); this.annotation = annotation; this.groups = groups; this.payload = payload; this.constraintValidatorClasses = constraintValidatorClasses; this.attributes = attributes; this.composingConstraints = composingConstraints; this.reportAsSingleViolation = reportAsSingleViolation; this.elementType = elementType; this.definedOn = definedOn; }
/** * Finds the type that a constraint validator will check. * * <p> * This type comes from the first parameter of the isValid() method on the constraint validator. * However, this is a bit tricky because ConstraintValidator has a parameterized type. When using * Java reflection, we will see multiple isValid() methods, including one that checks * java.lang.Object. * </p> * * <p> * Strategy: for now, assume there are at most two isValid() methods. If there are two, assume one * of them has a type that is assignable from the other. (Most likely, one of them will be * java.lang.Object.) * </p> * * @throws IllegalStateException if there isn't any isValid() method or there are more than two. */ static <T extends Annotation> Class<?> getTypeOfConstraintValidator( final Class<? extends ConstraintValidator<T, ?>> constraintClass) { int candidateCount = 0; Class<?> result = null; for (final Method method : constraintClass.getMethods()) { if (method.getName().equals("isValid") && method.getParameterTypes().length == 2 && method.getReturnType().isAssignableFrom(Boolean.TYPE)) { final Class<?> firstArgType = method.getParameterTypes()[0]; if (result == null || result.isAssignableFrom(firstArgType)) { result = firstArgType; } candidateCount++; } } if (candidateCount == 0) { throw new IllegalStateException("ConstraintValidators must have a isValid method"); } else if (candidateCount > 2) { throw new IllegalStateException( "ConstraintValidators must have no more than two isValid methods"); } return result; }
static <A extends Annotation> ImmutableSet<Class<? extends ConstraintValidator<A, ?>>> // getValidatorForType(final Class<?> ptype, final List<Class<? extends ConstraintValidator<A, ?>>> constraintValidatorClasses) { final Class<?> type = Primitives.wrap(ptype); final Map<Class<?>, Class<? extends ConstraintValidator<A, ?>>> map = Maps.newHashMap(); for (final Class<? extends ConstraintValidator<A, ?>> conClass : constraintValidatorClasses) { final Class<?> aType = Primitives.wrap(getTypeOfConstraintValidator(conClass)); if (aType.isAssignableFrom(type)) { map.put(aType, conClass); } } // TODO(nchalko) implement per spec // Handle Arrays and Generics final Set<Class<?>> best = Util.findBestMatches(type, map.keySet()); final Predicate<Class<?>> inBest = key -> best.contains(key); return ImmutableSet.copyOf(Maps.filterKeys(map, inBest).values()); }
/** * Gets the best {@link ConstraintValidator}. * * <p> * The ConstraintValidator chosen to validate a declared type {@code targetType} is the one where * the type supported by the ConstraintValidator is a supertype of {@code targetType} and where * there is no other ConstraintValidator whose supported type is a supertype of {@code type} and * not a supertype of the chosen ConstraintValidator supported type. * </p> * * @param constraint the constraint to find ConstraintValidators for. * @param targetType The type to find a ConstraintValidator for. * @return ConstraintValidator * * @throws UnexpectedTypeException if there is not exactly one maximally specific constraint * validator for targetType. */ private static <A extends Annotation> Class<? extends ConstraintValidator<A, ?>> // getValidatorForType(final ConstraintDescriptor<A> constraint, final Class<?> targetType) throws UnexpectedTypeException { final List<Class<? extends ConstraintValidator<A, ?>>> constraintValidatorClasses = constraint.getConstraintValidatorClasses(); if (constraintValidatorClasses.isEmpty()) { throw new UnexpectedTypeException( "No ConstraintValidator found for " + constraint.getAnnotation()); } final ImmutableSet<Class<? extends ConstraintValidator<A, ?>>> best = getValidatorForType(targetType, constraintValidatorClasses); if (best.isEmpty()) { throw new UnexpectedTypeException( "No " + constraint.getAnnotation() + " ConstraintValidator for type " + targetType); } if (best.size() > 1) { throw new UnexpectedTypeException("More than one maximally specific " + constraint.getAnnotation() + " ConstraintValidator for type " + targetType + ", found " + Ordering.usingToString().sortedCopy(best)); } return Iterables.get(best, 0); }
@Bean public LocalValidatorFactoryBean localValidatorFactoryBean() { HibernateValidatorConfigurationStrategy strategy = Optional.ofNullable(hibernateValidatorConfigurationStrategy) .orElseGet(() -> configuration -> { }); List<? extends ConstraintValidator> validators = Optional.ofNullable(this.validators) .orElseGet(Collections::emptyList); return new CustomLocalValidatorFactoryBean(strategy, validators); }
private void addConstraint(ConstraintMapping mapping, ConstraintValidator validator) { Stream.of(validator.getClass().getGenericInterfaces()) .filter(genericInterface -> genericInterface instanceof ParameterizedType) .map(genericInterface -> (ParameterizedType) genericInterface) .filter(genericInterface -> isConstraintValidator(genericInterface.getRawType())) .forEach(constraintValidatorInterface -> { @SuppressWarnings("unchecked") Class<? extends Annotation> a = (Class<? extends Annotation>) constraintValidatorInterface.getActualTypeArguments()[0]; mapping.constraintDefinition(a).validatedBy(getValidatorClass(validator)); }); }
private JDefinedClass buildTemplateConstraintValidator(String name, JDefinedClass constraint, Class<?> param) { try { JClass cv = (JClass) codeModel._ref(ConstraintValidator.class); cv = cv.narrow(constraint, (JClass) codeModel._ref(param)); JDefinedClass validator = constraint._class(JMod.STATIC | JMod.PUBLIC, name); validator._implements(cv); validator.method(JMod.PUBLIC, void.class, "initialize").param(constraint, "parameters"); JMethod isValid = validator.method(JMod.PUBLIC, boolean.class, "isValid"); isValid.param(Object.class, "value"); isValid.param(ConstraintValidatorContext.class, "context"); return validator; } catch (JClassAlreadyExistsException e) { throw new RuntimeException("Tried to create an already existing class: " + name, e); } }
@SuppressWarnings({ "rawtypes", "unchecked" }) private <T> void validatePropertyConstraints( final MinijaxConstraintValidatorContext<T> context, final PropertyDescriptor property, final Object value) { for (final ConstraintDescriptor constraint : property.getConstraintDescriptors()) { final ConstraintValidator validator = ((MinijaxConstraintDescriptor) constraint).getValidator(); if (!validator.isValid(value, context)) { context.buildViolation(constraint, value); } } }
@SuppressWarnings("rawtypes") private <T> void validatePropertyElementConstraints( final MinijaxConstraintValidatorContext<T> context, final PropertyDescriptor property, final Object value) { for (final ContainerElementTypeDescriptor descriptor : property.getConstrainedContainerElementTypes()) { for (final ConstraintDescriptor constraint : descriptor.getConstraintDescriptors()) { final ConstraintValidator validator = ((MinijaxConstraintDescriptor) constraint).getValidator(); if (value instanceof List) { validateList(context, constraint, validator, (List) value); } else if (value instanceof Iterable) { validateIterable(context, constraint, validator, (Iterable) value); } else if (value instanceof Map && descriptor.getTypeArgumentIndex() == 0) { validateMapKeys(context, constraint, validator, (Map<?, ?>) value); } else if (value instanceof Map) { validateMapValues(context, constraint, validator, (Map<?, ?>) value); } else if (value instanceof Optional) { validateOptional(context, constraint, validator, (Optional) value); } } } }
@SuppressWarnings({ "rawtypes", "unchecked" }) private <T> void validateList( final MinijaxConstraintValidatorContext<T> context, final ConstraintDescriptor constraint, final ConstraintValidator validator, final List list) { for (int i = 0; i < list.size(); i++) { if (!validator.isValid(list.get(i), context)) { context.buildViolation(constraint, list.get(i), "[" + i + "].<list element>"); } } }
@SuppressWarnings({ "rawtypes", "unchecked" }) private <T> void validateIterable( final MinijaxConstraintValidatorContext<T> context, final ConstraintDescriptor constraint, final ConstraintValidator validator, final Iterable iterable) { for (final Object element : iterable) { if (!validator.isValid(element, context)) { context.buildViolation(constraint, element, "[].<iterable element>"); } } }
@SuppressWarnings({ "rawtypes", "unchecked" }) private <T> void validateMapKeys( final MinijaxConstraintValidatorContext<T> context, final ConstraintDescriptor constraint, final ConstraintValidator validator, final Map<?, ?> map) { for (final Object element : map.keySet()) { if (!validator.isValid(element, context)) { context.buildViolation(constraint, element, "<K>[].<map key>"); } } }
@SuppressWarnings({ "rawtypes", "unchecked" }) private <T> void validateMapValues( final MinijaxConstraintValidatorContext<T> context, final ConstraintDescriptor constraint, final ConstraintValidator validator, final Map<?, ?> map) { for (final Entry<?, ?> entry : map.entrySet()) { if (!validator.isValid(entry.getValue(), context)) { context.buildViolation(constraint, entry.getValue(), "[" + entry.getKey() + "].<map value>"); } } }
@SuppressWarnings({ "rawtypes", "unchecked" }) private <T> void validateOptional( final MinijaxConstraintValidatorContext<T> context, final ConstraintDescriptor constraint, final ConstraintValidator validator, final Optional optional) { if (optional.isPresent() && !validator.isValid(optional.get(), context)) { context.buildViolation(constraint, optional.get()); } }
@SuppressWarnings({ "unchecked", "rawtypes" }) private static <T extends Annotation> MinijaxConstraintDescriptor<T> buildDeclaredValidator(final T annotation, final Class validatedBy) { final Class<? extends ConstraintValidator<T, ?>> c = validatedBy; try { return new MinijaxConstraintDescriptor<>(annotation, c.getConstructor().newInstance()); } catch (final ReflectiveOperationException ex) { throw new ValidationException(ex); } }
@Override public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> type) { T result = null; try { result = this.beanFactory.getBean(type); } catch(BeansException e) { // ignore, as we initialize the validator below } if( result == null ) { result = this.delegate.getInstance(type); this.beanFactory.initializeBean(result, result.getClass() + "#" + result.hashCode()); } return result; }
@Test public void test() { final ConstraintValidatorContext context = mock(ConstraintValidatorContext.class); final ConstraintViolationBuilder builder = mock(ConstraintViolationBuilder.class); final NodeBuilderCustomizableContext node = mock(NodeBuilderCustomizableContext.class); when(context.buildConstraintViolationWithTemplate(anyString())).thenReturn(builder); when(builder.addPropertyNode(anyString())).thenReturn(node); mockCountToReturn(2l); final ConstraintValidator<Unique, Object> validator = new UniqueValidator(); final Unique annotation = Model2.class.getAnnotation(Unique.class); validator.initialize(annotation); assertFalse(validator.isValid("somevalue", context)); }
/** * setter for constraint validator class. * * @param constraintValidatorClasses value to set * @return this class */ public Builder<T> setConstraintValidatorClasses( final Class<? extends ConstraintValidator<T, ?>>[] constraintValidatorClasses) { final List<Class<? extends ConstraintValidator<T, ?>>> list = Arrays.asList(constraintValidatorClasses); this.setConstraintValidatorClasses(list); return this; }
/** * Perform the actual validation of a single {@link ConstraintValidator}. * <p> * As a side effect {@link ConstraintViolation}s may be added to {@code violations}. * </p> * * @return true if there was any constraint violations */ protected <A extends Annotation, T, V> boolean validate(final GwtValidationContext<T> context, final Set<ConstraintViolation<T>> violations, final G object, final V value, final ConstraintValidator<A, ? super V> validator, final ConstraintDescriptorImpl<A> constraintDescriptor, final Class<?>... groups) { validator.initialize(constraintDescriptor.getAnnotation()); final ConstraintValidatorContextImpl<A, V> constraintValidatorContext = context.createConstraintValidatorContext(constraintDescriptor); final List<Class<?>> groupsList = Arrays.asList(groups); final ValidationGroupsMetadata validationGroupsMetadata = context.getValidator().getValidationGroupsMetadata(); final Set<Class<?>> constraintGroups = constraintDescriptor.getGroups(); // check groups requested are in the set of constraint groups (including the implicit group) if (!this.containsAny(groupsList, constraintGroups) && !groupsList.contains(this.getConstraints(validationGroupsMetadata).getElementClass())) { return false; } if (!validator.isValid(value, constraintValidatorContext)) { this.addViolations(// context, // violations, // object, // value, // constraintDescriptor, // constraintValidatorContext); return true; } return false; }
private void writeClassLevelConstraintsValidation(final SourceWriter sw, final String groupsVarName) throws UnableToCompleteException { // all class level constraints int count = 0; final Class<?> clazz = this.beanHelper.getClazz(); for (final ConstraintDescriptor<?> constraint : this.beanHelper.getBeanDescriptor() .getConstraintDescriptors()) { if (this.areConstraintDescriptorGroupsValid(constraint)) { if (this.hasMatchingAnnotation(constraint)) { if (!constraint.getConstraintValidatorClasses().isEmpty()) { // NOPMD final Class<? extends ConstraintValidator<? extends Annotation, ?>> validatorClass = getValidatorForType(constraint, clazz); // validate(context, violations, null, object, sw.print("validate(context, violations, null, object, "); // new MyValidtor(), sw.print("new "); sw.print(validatorClass.getCanonicalName()); sw.print("(), "); // TODO(nchalko) use ConstraintValidatorFactory // this.aConstraintDescriptor, groups); sw.print(this.constraintDescriptorVar("this", count)); sw.print(", "); sw.print(groupsVarName); sw.println(");"); } else if (constraint.getComposingConstraints().isEmpty()) { // TODO(nchalko) What does the spec say to do here. this.logger.log(TreeLogger.WARN, "No ConstraintValidator of " + constraint + " for type " + clazz); } // TODO(nchalko) handle constraint.isReportAsSingleViolation() and // hasComposingConstraints } count++; } } }
protected ConstraintDescriptorImpl(final T pannotation, final Set<Class<?>> pgroups, final Set<Class<? extends Payload>> ppayload, final List<Class<? extends ConstraintValidator<T, ?>>> pconstraintValidatorClasses, final Map<String, Object> pattributes, final Set<ConstraintDescriptor<?>> pcomposingConstraints, final boolean preportAsSingleViolation, final ElementType pelementType, final ConstraintOrigin pdefinedOn) { super(pannotation, pgroups, ppayload, pconstraintValidatorClasses, pattributes, pcomposingConstraints, preportAsSingleViolation, pelementType, pdefinedOn); }
private boolean processViolations(Set<ConstraintViolation<Object>> violations, Class<? extends ConstraintValidator> validator) { boolean result = false; for (ConstraintViolation<Object> violation : violations) { List<?> validatorClasses = violation.getConstraintDescriptor().getConstraintValidatorClasses(); if (validatorClasses.contains(validator)) { showMessage(violation.getMessage()); result = true; } } return result; }
public static List<Class<? extends ConstraintValidator<?, ?>>> getBeanConstraintValidator(String annotationName) { List<Class<? extends ConstraintValidator<?, ?>>> result = new ArrayList<>(); try { Class<?> annotationClass = Class.forName(annotationName); result = getBeanConstraintValidator(annotationClass); } catch (ClassNotFoundException e) { ; // TODO At least log this, probably some class loading issue that we have to solve } return result; }
private static List<Class<? extends ConstraintValidator<?, ?>>> getBeanConstraintValidator(Class annotationClass) { Constraint annotation = (Constraint) annotationClass.getAnnotation(Constraint.class); List<Class<? extends ConstraintValidator<?, ?>>> result = new ArrayList<>(); if (annotation != null) { result = Arrays.asList(annotation.validatedBy()); } return result; }
public static List<RecordValueInfo> getClassLevelBeanValidationInfo(Class clazz) { List<RecordValueInfo> result = new ArrayList<>(); for (Annotation annotation : clazz.getDeclaredAnnotations()) { List<Class<? extends ConstraintValidator<?, ?>>> beanValidationConstraints = getBeanConstraintValidator(annotation.annotationType()); for (Class<? extends ConstraintValidator<?, ?>> validationConstraint : beanValidationConstraints) { result.add(new RecordValueInfo(clazz, validationConstraint)); } } if (!Object.class.equals(clazz.getSuperclass())) { result.addAll(getClassLevelBeanValidationInfo(clazz.getSuperclass())); } return result; }
@Override public boolean isValid(List<?> entries, ConstraintValidatorContext context) { boolean valid = true; if(entries == null){ return valid; } if(ArrayUtils.getLength(constraints) != ArrayUtils.getLength(messages)){ throw new ConstraintDeclarationException("Number of messages must be the same as number of constraints"); } ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); ConstraintValidatorFactory constraintValidatorFactory = validatorFactory.getConstraintValidatorFactory(); for(Object element : entries) { for(Class<?> constraint : constraints) { Constraint constraintAnnotation = constraint.getAnnotation(Constraint.class); Class<? extends ConstraintValidator<?, ?>>[] constraintValidators = constraintAnnotation.validatedBy(); for (int i = 0; i < constraintValidators.length; i++) { ConstraintValidator constraintValidator = constraintValidatorFactory.getInstance(constraintValidators[i]); if(!constraintValidator.isValid(element, context)){ context.buildConstraintViolationWithTemplate(messages[i]).addConstraintViolation().disableDefaultConstraintViolation(); valid = false; } } } } return valid; }
@Override public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) { try { String beanName = getBeanName(key); if (!beanFactory.isPrototype(beanName)) { String msg = "Bean [%s] must be of prototype scope."; throw new IllegalArgumentException(String.format(msg, beanName)); } return beanFactory.getBean(beanName, key); } catch (NoSuchElementException e) { // The factory does not know about the bean it creates it. return beanFactory.createBean(key); } }
@Override public <T extends ConstraintValidator<?, ?>> T getInstance(final Class<T> key) { /* By default, all beans are in prototype scope, so new instance will be obtained each time. Validator implementer may declare it as singleton and manually maintain internal state (to re-use validators and simplify life for GC) */ return injector.getInstance(key); }
@Override public void releaseInstance(final ConstraintValidator<?, ?> instance) { if (instance instanceof Closeable) { try { ((Closeable) instance).close(); } catch (IOException ex) { log.debug("Can't close constraint validator", ex); } } }
@Test public void getInstance() throws Exception { new MockUnit(Injector.class, ConstraintValidator.class) .expect(unit -> { Injector injector = unit.get(Injector.class); expect(injector.getInstance(ConstraintValidator.class)).andReturn( unit.get(ConstraintValidator.class)); }) .run(unit -> { assertEquals(unit.get(ConstraintValidator.class), new HbvConstraintValidatorFactory(unit.get(Injector.class)) .getInstance(ConstraintValidator.class)); }); }
@Test public void releaseInstance() throws Exception { new MockUnit(Injector.class, ConstraintValidator.class) .run(unit -> { new HbvConstraintValidatorFactory(unit.get(Injector.class)) .releaseInstance(unit.get(ConstraintValidator.class)); }); }
@SuppressWarnings({ "unchecked", "rawtypes" }) public static Validator getValidator(String validatorSpec, BeneratorContext context) { try { if (StringUtil.isEmpty(validatorSpec)) return null; Validator result = null; Expression[] beanExpressions = DatabeneScriptParser.parseBeanSpecList(validatorSpec); Object[] beans = ExpressionUtil.evaluateAll(beanExpressions, context); for (Object bean : beans) { // check validator type Validator validator; if (bean instanceof Validator) validator = (Validator<?>) bean; else if (bean instanceof ConstraintValidator) validator = new BeanConstraintValidator((ConstraintValidator) bean); else throw new ConfigurationError("Unknown validator type: " + BeanUtil.simpleClassName(bean)); // compose one or more validators if (result == null) // if it is the first or even only validator, simply use it result = validator; else if (result instanceof AndValidator) // else compose all validators to an AndValidator ((AndValidator) result).add(validator); else result = new AndValidator(result, validator); } result = BeneratorFactory.getInstance().configureValidator(result, context); return result; } catch (ParseException e) { throw new ConfigurationError("Invalid validator definition", e); } }
@Override public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> validatorClass) { T resolvedInst = BeanProvider.getContextualReference(validatorClass, true); if (resolvedInst == null) { if (log.isLoggable(Level.CONFIG)) { log.config("No contextual instances found for class " + validatorClass.getCanonicalName() + " delegating to DefaultProvider behavior."); } resolvedInst = this.delegate.getInstance(validatorClass); } return resolvedInst; }
public void releaseInstance(ConstraintValidator<?, ?> constraintValidator) { if (releaseInstanceMethodFound == null) { lazyInit(); } if (Boolean.TRUE.equals(releaseInstanceMethodFound)) { ReflectionUtils.invokeMethod(this.delegate, releaseInstanceMethod, Void.class, true, constraintValidator); } }
private synchronized void lazyInit() { if (releaseInstanceMethodFound != null) { return; } Class<?> currentClass = delegate.getClass(); while (currentClass != null && !Object.class.getName().equals(currentClass.getName())) { for (Method currentMethod : currentClass.getDeclaredMethods()) { if (RELEASE_INSTANCE_METHOD_NAME.equals(currentMethod.getName()) && currentMethod.getParameterTypes().length == 1 && currentMethod.getParameterTypes()[0].equals(ConstraintValidator.class)) { releaseInstanceMethod = currentMethod; releaseInstanceMethodFound = true; return; } } currentClass = currentClass.getSuperclass(); } releaseInstanceMethodFound = false; }
CustomLocalValidatorFactoryBean(HibernateValidatorConfigurationStrategy hibernateValidatorConfigurationStrategy, List<? extends ConstraintValidator> validators) { this.hibernateValidatorConfigurationStrategy = hibernateValidatorConfigurationStrategy; this.validators = validators; }
private boolean isConstraintValidator(Type type) { return type.equals(ConstraintValidator.class) || type.equals(SimpleConstraintValidator.class); }
@SuppressWarnings("unchecked") private <A extends Annotation> Class<? extends ConstraintValidator<A, ?>> getValidatorClass(ConstraintValidator validator) { return (Class<? extends ConstraintValidator<A, ?>>) validator.getClass(); }
@Override public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) { return this.beanFactory.createBean(key); }
public void releaseInstance(ConstraintValidator<?, ?> instance) { this.beanFactory.destroyBean(instance); }