Giter Site home page Giter Site logo

validator-collection's Introduction

Bean Validation / Collection Validators

Build Status Coverage Status Code quality Maven Central

Neither Bean Validation 1.1 (JSR 303/349) nor Hibernate Validator, the reference (and the only one…) implementation of it, provide simple way to validate a collection of basic types like String, Integer, Date… (i.e. validate each element of the collection).

This library allows you to easily create a “pseudo constraint” (typically named as @EachX) for any validation constraint to annotate a collection of simple types, without writing an extra validator or unnecessary wrapper classes for every collection. EachX constraint is supported for all standard Bean Validation constraints and Hibernate specific constraints. For example:

@EachSize(min = 5, max = 255)
Collection<String> values;

@EachFuture
List<Date> dates;

@EachEmail
Set<String> emails;

How to create a custom constraint

Every @EachX pseudo constraint uses the same validator, CommonEachValidator. To create an @EachAwesome for your own @Awesome constraint, just copy & paste the annotation class (i.e. all the attributes and boilerplate meta annotations), replace @Constraint annotation with @Constraint(validatedBy = CommonEachValidator.class) and add the annotation @EachConstraint(validateAs = Awesome.class). That’s all!

// common boilerplate
@Documented
@Retention(RUNTIME)
@Target({METHOD, FIELD, ANNOTATION_TYPE})
// this is important!
@EachConstraint(validateAs = Awesome.class)
@Constraint(validatedBy = CommonEachValidator.class)
public @interface EachAwesome {

    // copy&paste all attributes from Awesome annotation here
    String message() default "";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    String someAttribute();
}

The old way

The previous versions (before 2.1.0) used a different approach to write @EachX annotations (see here). It is still supported for custom constraints, but all the built-in annotations has been already updated to the new style.

If you’re upgrading from an older version of Collection Validators, then you must update all built-in annotations to the new style. For example:

@EachSize(@Size(min = 5, max = 255)) -> @EachSize(min = 5, max = 255)

You should also update custom annotations. The old style is still supported, but may be deprecated in the future.

Maven

Released versions are available in The Central Repository. Just add this artifact to your project:

<dependency>
    <groupId>cz.jirutka.validator</groupId>
    <artifactId>validator-collection</artifactId>
    <version>2.2.0</version>
</dependency>

However if you want to use the last snapshot version, you have to add the JFrog OSS repository:

<repository>
    <id>jfrog-oss-snapshot-local</id>
    <name>JFrog OSS repository for snapshots</name>
    <url>https://oss.jfrog.org/oss-snapshot-local</url>
    <snapshots>
        <enabled>true</enabled>
    </snapshots>
</repository>

Requirements

Hibernate Validator 4.3.1.Final and newer is supported, but 5.× is recommended.

Please note that on older versions some Hibernate specific constraints doesn’t exist, so their @EachX annotations will not work (e.g. @EachEAN, @EachMod10Check, …). It’s described in JavaDoc.

Version detection

In order to support multiple versions of Hibernate Validator at a time, we attempt to determine what version is being used at runtime using the package metadata for the HibernateValidator class. This can sometimes fail, particularly if your project creates an “uber JAR.” If the version cannot be detected, then it fallbacks to ≥ 5.1.0.

License

This project is licensed under MIT license.

validator-collection's People

Contributors

jirutka avatar jnv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

validator-collection's Issues

Not compatible with hibernate-validator 6.x

I want to use your library in my Spring Boot 2.0 project which includes hibernate-validator 6.0.7.Final.

Unfortunately, version 2.2.0 of validator-collection seems not to be compatible:

Caused by: java.lang.NoSuchMethodException: org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl.<init>(org.hibernate.validator.internal.metadata.core.ConstraintHelper, java.lang.reflect.Member, java.lang.annotation.Annotation, java.lang.annotation.ElementType)
	at java.lang.Class.getConstructor0(Class.java:3082) ~[na:1.8.0_121]
	at java.lang.Class.getConstructor(Class.java:1825) ~[na:1.8.0_121]
	at cz.jirutka.validator.collection.internal.ConstraintDescriptorFactory.<init>(ConstraintDescriptorFactory.java:56) ~[validator-collection-2.2.0.jar:2.2.0]

hibernate-validator 5.1.0

Hi,

I've tried to use your collection annotations with hibernate-validator 5.1.0 and you are using some internal API which no long exists!!

Regards,
Ced.

Spring custom method annotation not working

I have a custom SecurityAnnotation annotation class

@Constraint(validatedBy = SecurityAnnotationValidator.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface SecurityAnnotation {

    EmployeeRoles[] employeeRoles();

    String message();

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

    Class<? extends Payload>[] payload() default {};
}

And i have a Constraint validator class

public class SecurityAnnotationValidator implements ConstraintValidator<SecurityAnnotation, String> {

private EmployeeRoles[] employeeRoles;

@Autowired
EmployeeService employeeService;

@Override
public void initialize(SecurityAnnotation securityAnnotation) {
    employeeRoles = securityAnnotation.employeeRoles();
}

@Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
    //logic goes here
    return false;
}
}

In my controller, i have annotated a method

@RequestMapping( method = RequestMethod.POST)
@SecurityAnnotation(employeeRoles = {EmployeeRoles.HR}, message = "Invalid User")
public HrmsResponse create(@Valid @RequestBody CreateEmployee createEmployee){
    Employee employee = employeeService.createEmployee(createEmployee);
    return HrmsResponse.buildSuccessResponse(employee);
}

But my annotation's isValid function is not getting called, googled and not finding any results.
Any help would be appreciated. Thanks in advance.

[CommonEachValidator]NoUniqueBeanDefinitionException:expected single matching bean but found 2: validator,mvcValidator

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cz.jirutka.validator.collection.CommonEachValidator': Unsatisfied dependency expressed through field 'factory'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.validation.ValidatorFactory' available: expected single matching bean but found 2: validator,mvcValidator

spring mvc config

  <mvc:annotation-driven validator="validator"/>
  <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
    <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
    <property name="validationMessageSource" ref="messageSource"/>
  </bean>
<spring.version>4.3.6.RELEASE</spring.version>

<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-validator</artifactId>
  <version>5.4.1.Final</version>
</dependency>
<dependency>
  <groupId>cz.jirutka.validator</groupId>
  <artifactId>validator-collection</artifactId>
  <version>2.2.0</version>
</dependency>

@EachNotEmpty field does not indicate element that has failed

Firstly thank you for your library and thank you for fixing issue 12.

Given I have a class

public class MyClass { @EachNotNull private Set<String> myCollection; }

When I use @EachNotNull and the first entry of the collection is a null value, then the field error correctly indicates that it's the first item that has an error: myCollection[0]

When I use @EachNotEmpty then the field reported as having the error is the collection field and not the entry: myCollection

For a collection with only one element it's trivial, but when you have multiple entries it's nice to be able to report which element had the problem.

Unable to override system locale

Currently hibernate validators use LocaleContextHolder's locale for the constraint violation message. However, when using @each... anotations the message is always in system's locale and I can't find a way to override it.

Hibernate version detection fails when library is used in uber jars

This may be something of a niche issue, but I thought I'd report it since it affects our usage of the library, and may affect others as well.

Version detection fails when this library is included in an uber jar (as created by the maven assembly plugin, jar-with-dependencies descriptor). The reason for this comes down to this snippet:

 Package pkg = HibernateValidator.class.getPackage();

    if (pkg != null) {
        String version = pkg.getImplementationVersion();

The package object has its version set by MANIFEST.mf in the jar. In the regular, non-uber jar case, HibernateValidator is provided by hibernate-validator-5.1.3.Final.jar (for instance), and the version is set correctly. In the uber jar case however, the version is set to that of the project building the uber jar, causing the hibernate version to be incorrectly detected.

The library should ideally provide a way to work around this, possibly by inclusion of a metadata file on the classpath indicating the desired hibernate version.

EachXXX with custom annotation gives error

Here is my code and error:

import cz.jirutka.validator.collection.CommonEachValidator;
import cz.jirutka.validator.collection.constraints.EachConstraint;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

// common boilerplate
@Documented
@Retention(RUNTIME)
@Target({METHOD, FIELD, ANNOTATION_TYPE})
// this is important!
@EachConstraint(validateAs = UUID.class)
@Constraint(validatedBy = CommonEachValidator.class)
public @interface EachUUID {

    String message() default "{com.mz.UUID}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.Pattern;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target(ElementType.FIELD)
@Constraint(validatedBy={})
@Retention(RUNTIME)
@Pattern(regexp="^\\p{XDigit}{8}-\\p{XDigit}{4}-[1-5]\\p{XDigit}{3}-[89ab]\\p{XDigit}{3}-\\p{XDigit}{12}$")
public @interface UUID {
    String message() default "{com.mz.UUID}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Caused by: java.lang.IllegalArgumentException: No validator found for constraint: interface com.mz.UUID

Your examples didn't list using a custom annotation -- this UUID annotation works fine for validation on it's own but not with this library. Maybe just some documentation to explain how?

@EachNotEmpty cannot find validator with hibernate-validator 5.1.3

Using hibernate-validator 5.1.3 (version packaged with latest spring-boot 1.2.3) and version 2.1.3 of this library whenever I use the @EachNotEmpty validator I get the following exception ...

java.lang.IllegalArgumentException: No validator found for constraint: interface org.hibernate.validator.constraints.NotEmpty
    at org.apache.commons.lang3.Validate.notEmpty(Validate.java:349)
    at cz.jirutka.validator.collection.CommonEachValidator.initialize(CommonEachValidator.java:124)
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager.initializeConstraint(ConstraintValidatorManager.java:245)
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager.createAndInitializeValidator(ConstraintValidatorManager.java:147)
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager.getInitializedValidator(ConstraintValidatorManager.java:101)
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:125)
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:91)
    at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:83)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:547)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:487)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:451)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:403)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateCascadedConstraint(ValidatorImpl.java:723)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateCascadedConstraints(ValidatorImpl.java:617)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:412)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateCascadedConstraint(ValidatorImpl.java:723)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateCascadedConstraints(ValidatorImpl.java:601)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:412)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:206)
    at org.springframework.validation.beanvalidation.SpringValidatorAdapter.validate(SpringValidatorAdapter.java:108)
    at org.springframework.validation.DataBinder.validate(DataBinder.java:781)

I had a look inside the hibernate-validator jar and within the package org.hibernate.validator.internal.constraintvalidator I can see a NotNullValidator but cannot see one for NotEmpty so they must be using a different strategy.

Only workaround I can see for now is to use a different annotation such as @EachNotNull for now and that works.

Issue when more than 1 validator factory are present in classpath

In my project, I have an additional validator factory for Method validation along with the validator auto registered by spring boot (with name mvcValidator) in classpath

  @Bean
  public LocalValidatorFactoryBean validatorFactory(MessageSource messageSource) {
    LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
    factoryBean.setValidationMessageSource(messageSource);
    return factoryBean;
  }

  @Bean
  public MethodValidationPostProcessor methodValidationPostProcessor(
      LocalValidatorFactoryBean validatorFactory) {
    MethodValidationPostProcessor validationPostProcessor = new MethodValidationPostProcessor();
    validationPostProcessor.setValidator(validatorFactory);
    return validationPostProcessor;
  }

When I try to validate a collection, I get the following exception

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cz.jirutka.validator.collection.CommonEachValidator': Unsatisfied dependency expressed through field 'factory': No qualifying bean of type [javax.validation.ValidatorFactory] is defined: expected single matching bean but found 2: mvcValidator,validatorFactory; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.validation.ValidatorFactory] is defined: expected single matching bean but found 2: mvcValidator,validatorFactory

Is there a way to configure hibernate and spring to use mvcValidator with CommonEachValidator when more than one validators exist in classpath?

@EachNotBlank does not fail nulls

In EachAnnotationIT.groovy, at line 133 if you add another entry to your table it will fail

EachNotBlank | [:] | ['foo', 'bar'] | ['foo', null]

Validator allows nulls through.

Expand @Target to method and constructor arguments

Hi Jakob,

Nice set of handy validators, thanks! (and shame on http://beanvalidation.org to not support them out of the box though).

But I'm curious if it's possible to extend annotations' target to method params and constructor arguments as well?

E.g. for @Size annotation:

  • original annotation:
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = { })
public @interface Size {
  • each-annotation:
@Documented
@Retention(RUNTIME)
@Target({METHOD, FIELD, ANNOTATION_TYPE})
@EachConstraint(validateAs = Size.class)
@Constraint(validatedBy = CommonEachValidator.class)
public @interface EachSize {

Having taken a quick look through the code I'd guess it should be as easy as to add those two target enum values.

Otherwise it appears to be pretty useless in a typical situation when you need to annotate multi-value query param in JAX-RS resource method definition, like this:

@Path("/")
public interface MyResource {

   @Path("/by-tags")
   List<MyDto> searchByTags(@QueryParam("tag") @EachSize(min = 2, max = 127) Set<String> tags);

}

Validation of entity collections?

From what I can tell, this looks like it validates collections of primitives (strings, ints) just fine. However I need to validate collections of entities. For single entities, I can mark @Valid, but that doesn't work on collections of entities.

Can a @EachValid annotation be added to recursively validate each element? I am just not sure if it can be added easily since @Valid is not technically a constraint.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.