Red Hat

In Relation To Hibernate Validator

In Relation To Hibernate Validator

Hibernate Validator 5.3.0.CR1 is out

Posted by    |       |    Tagged as Hibernate Validator Releases

We are making good progress working on Bean Validation 2.0 and we decided to move the target version for BV 2.0 to Hibernate Validator 6 (see more at the end of this post!).

We did not want to leave 5.3 half backed so we are preparing a 5.3 release with bugfixes, additional translations…​ and a few new features. This Candidate Release 1 is the first step towards this process. Expect a quick 5.3.0.Final release after that so please test this version as thoroughly as possible and report any bugs you may find in it!

Programmatic API for constraint definition and declaration

The experimental notion of ConstraintDefinitionContributor has been removed in favor of a new fluid API, more consistent with what already existed in Validator.

If you want to define a new ValidPassengerCount constraint annotation which relies on a ValidPassengerCountValidator validator, you can use the API as follows:

ConstraintMapping constraintMapping = configuration.createConstraintMapping();

constraintMapping
    .constraintDefinition( ValidPassengerCount.class )
        .validatedBy( ValidPassengerCountValidator.class );

It can also be used to replace the implementation of the validator used for a given annotation constraint. Say you need to support International Domain Names (IDN) in your URL validation, the default URLValidator won’t work for you as it uses java.net.URL which does not support IDN. We provide an alternative RegexpURLValidator and you might want to use it in this case:

ConstraintMapping constraintMapping = configuration.createConstraintMapping();

constraintMapping
    .constraintDefinition( URL.class )
        .includeExistingValidators( false )
        .validatedBy( RegexpURLValidator.class );

Constraint mapping contributor*s*

Thanks to the new hibernate.validator.constraint_mapping_contributors property, you can now declare several constraint mapping contributors separated by a comma, whereas you were limited to only one before.

Note that in 5.3, the existing hibernate.validator.constraint_mapping_contributor property is still supported but has been deprecated.

The deprecated hibernate.validator.constraint_mapping_contributor property will be removed as of Hibernate Validator 6.

Email validation

We changed the way email validation is done. It is now both more correct and stricter. We know of a few people running random tests on the constraints and they might have to update their tests: the domain of the email now needs to be a valid domain with each label (part between 2 dots) being at most 63 characters long. So you can’t just generate a 80 characters long domain with random characters, you need to be a bit more careful.

Translations

We added a few new translations of messages of the constraints we provide:

  • an Arabic translation thanks to Kathryn Killebrew

  • a Russian translation thanks to Andrey Derevyanko

Several other translations were updated.

What else is there?

Other changes of this release are an upgrade of all our Maven dependencies and a few fixes and polishing here and there.

You can find the complete list of all addressed issues in the change log.

To get the release with Maven, Gradle etc. use the GAV coordinates org.hibernate:{hibernate-validator|hibernate-validator-cdi|hibernate-validator-annotation-processor}:5.3.0.CR1.

Alternatively, a distribution bundle containing all the bits is provided on on SourceForge (TAR.GZ, ZIP).

To get in touch, use the following channels:

Next stop?

We are actively working on Bean Validation 2.0 and Hibernate Validator 6 with a strong focus on supporting Java 8 new features (and much more!). The more the merrier, so feel free to join us: drop ideas, comment on others' proposals, now is the time to define the future of Bean Validation. You can find all the necessary information on the Bean Validation website.

Hibernate Validator 5.2.4.Final is out

Posted by    |       |    Tagged as Hibernate Validator Releases

It’s my pleasure to announce the release of Hibernate Validator 5.2.4.Final!

This is a rather small bugfix release which addresses two nasty issues around one of the more advanced features of Bean Validation, redefined default group sequences.

Please refer to the issues themselves (HV-1055, HV-1057) for all the details.

Where do I get it?

Use the GAV coordinates org.hibernate:{hibernate-validator|hibernate-validator-cdi|hibernate-validator-annotation-processor}:5.2.4.Final to fetch the release with Maven, Gradle etc. Alternatively, you can find distribution bundles containing all the bits on SourceForge (TAR.GZ, ZIP).

Found a bug? Have a feature request? Then let us know through the following channels:

It’s my pleasure to announce the release of Hibernate Validator 5.2.3.Final!

Wait, didn’t we already do another Hibernate Validator release earlier this month? That’s right, indeed we pushed out the first Alpha of the 5.3 family a couple of days ago. And normally, that’d mean that there would be no further releases of earlier version families.

But in this case we decided to do an exception from the rule as we noticed that Hibernate Validator couldn’t be used with Java 9 (check out issue HV-1048 if you are interested in the details). As we don’t want to keep integrators and users of Hibernate Validator from testing their own software on Java 9, we decided to fix that issue on the current stable release line (in fact we strongly encourage you to test your applications on Java 9 to learn as early as possible about any potential changes you might need to make).

While we were at it, we backported some further bugfixes from 5.3 to 5.2, amongst them one for ensuring compatability with the Google App Engine. As always, you can find the complete list of fixes in the changelog.

Where do I get it?

Use the GAV coordinates org.hibernate:{hibernate-validator|hibernate-validator-cdi|hibernate-validator-annotation-processor}:5.2.3.Final to fetch the release with Maven, Gradle etc. Alternatively, you can find distribution bundles containing all the bits on SourceForge (TAR.GZ, ZIP).

Found a bug? Have a feature request? Then let us know through the following channels:

Hibernate Validator 5.3.0.Alpha1 is out

Posted by    |       |    Tagged as Hibernate Validator Releases

It’s my pleasure to announce the first release of Hibernate Validator 5.3!

The overarching idea for the 5.3 timeline is to prototype several features which may potentially be standardized in the Bean Validation 2.0 specification. For instance we’ll work on a solution for the long-standing request for sorting the constraints on single properties.

If you’d like to see any specific features addressed in that prototyping work (and eventually included in BV 2.0), then please get in touch and let us know which are the most important things you are missing from the spec. We’ve compiled a first list of issues we are considering for inclusion in BV 2.0. For sure we cannot address all of them, so it’ll greatly help if you tell us what would be most helpful to you.

Dynamic payloads for constraints

To get things rolling, the Alpha 1 allows to you to enrich custom constraint violations with additional context data. Code examining constraint violations can access and interpret this data in a safer way than by parsing string-based constraint violation messages. Think of it as a dynamic variant of the existing Bean Validation payload feature.

As an example, let’s assume we have a constraint @Matches for making sure a long property matches a given value with some tolerance:

public static class Package {

    @Matches(value=1000, tolerance=100)
    public long weight;
}

If the annotated value is invalid, the resulting constraint violation should have a specific severity, depending on whether the value lies within the given tolerance or not. That severity value could then for instance be used for formatting the error specifically in a UI.

The definition of the @Matches constraint is nothing new, it’s just a regular custom constraint annotation:

@Retention(RUNTIME)
@Constraint(validatedBy = { MatchesValidator.class })
@Documented
public @interface Matches {

    public enum Severity { WARN, ERROR; }

    String message() default "Must match {value} with a tolerance of {tolerance}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

    long value();
    long tolerance();
}

The constraint validator is where it’s getting interesting:

public class MatchesValidator implements ConstraintValidator<Matches, Long> {

    private long tolerance;
    private long value;

    @Override
    public void initialize(Matches constraintAnnotation) {
        this.value = constraintAnnotation.value();
        this.tolerance = constraintAnnotation.tolerance();
    }

    @Override
    public boolean isValid(Long value, ConstraintValidatorContext context) {
        if ( value == null ) {
            return true;
        }

        if ( this.value == value.longValue() ) {
            return true;
        }

        HibernateConstraintValidatorContext hibernateContext = context.unwrap(
                HibernateConstraintValidatorContext.class
        );
        hibernateContext.withDynamicPayload(
                Math.abs( this.value - value ) < tolerance ? Severity.WARN : Severity.ERROR
        );

        return false;
    }
}

In isValid() the severity object is set via HibernateConstraintValidatorContext#withDynamicPayload(). Note that the payload object must be serializable in case constraint violations are sent to remote clients, e.g. via RMI.

Validation clients may then access the dynamic payload like so:

HibernateConstraintViolation<?> violation = violations.iterator()
    .next()
    .unwrap( HibernateConstraintViolation.class );

if ( violation.getDynamicPayload( Severity.class ) == Severity.ERROR ) {
    // ...
}

What else is there?

Other features of the Alpha 1 releases are improved OSGi support (many thanks to Benson Margulies for this!), optional relaxation of parameter constraints (kudos to Chris Beckey!) and several bug fixes and improvements, amongst them support for cross-parameter constraints in the annotation processor (cheers to Nicola Ferraro!).

You can find the complete list of all addressed issues in the change log. To get the release with Maven, Gradle etc. use the GAV coordinates org.hibernate:{hibernate-validator|hibernate-validator-cdi|hibernate-validator-annotation-processor}:5.3.0.Alpha1. Alternatively, a distribution bundle containing all the bits is provided on on SourceForge (TAR.GZ, ZIP).

To get in touch, use the following channels:

Hibernate Validator 5.2.2 released

Posted by    |       |    Tagged as Hibernate Validator Releases

I am happy to announce the availability of Hibernate Validator 5.2.2.Final.

This release fixes several bugs, including a nasty regression around private property declarations in inheritance hierarchies and a tricky issue related to classloading in environments such as OSGi.

We also closed a gap in the API for constraint declaration which allows to ignore annotation-based constraints for specific methods, parameters etc.:

HibernateValidatorConfiguration config = Validation.byProvider( HibernateValidator.class ).configure();

ConstraintMapping mapping = config.createConstraintMapping();
mapping.type( OrderService.class )
    .method( "placeOrder", Item.class, int.class )
        .ignoreAnnotations( true )
        .parameter( 0 )
            .ignoreAnnotations( false );
config.addMapping( mapping );

Validator validator = config.buildValidatorFactory().getValidator();

Please refer to the change log for the complete list of all issues. You can get the release with Maven, Gradle etc. using the GAV coordinates org.hibernate:hibernate-validator::5.2.2.Final. Alternatively, a distribution bundle is provided on on SourceForge (TAR.GZ, ZIP).

Get in touch through the following channels:

Hibernate Validator 5.2.1.Final*

Posted by    |       |    Tagged as Hibernate Validator

I know you have been waiting in anticipation, but now it is available - Hibernate Validator 5.2.1.Final :-). Given that it is a drop-in replacement for all 5.x releases, there is no reason to delay an upgrade. Just go and get it.

For the more cautious, here again the highlights of the 5.2 release with pointers to more information.

The highlights

  • Java 8 Support, most notably the ability to validate Optional and the new date/time types. Types, which do not represent an instant on the time-line, however, are not supported out of the box. This includes, for example, LocalDate and its sub-types. Semantically it does not make sense to talk about future and past, if your data type cannot be unambiguously tied to an instant in time. This is still a bit of a open discussion (see HV-981) though. Contact us if you have an opinion.

    Support for Java 8 also includes the use of type annotation constraints like:

    private List<@AcmeEmail String> emails;

    In this case each element of the emails list (or more generally of any Iterable) will be validated using the @AcmeEmail. Note the use of a custom constraint and not the Hibernate Validator provided @Email. The reason is that all provided constraints are missing java.lang.annotation.ElementType.TYPE_USE in their definition for now. Adding it would break backwards compatibility to Java 6.

    Java 8 is not a requirement for Hibernate Validator 5.2. It is still backward compatible with Java 6. Java 8 specific features are only enabled in case a Java 8 runtime is detected.

  • Ability to provide custom constraints discoverable via the Java ServiceLoader mechanism. Under the hood this uses the new ConstraintMappingContributor SPI. read more…​

  • Ability to use Hibernate Validator without dependency to the Expression Language libraries by using the new ParameterMessageInterpolator. read more…​

  • Ability to provide an external ClassLoader. Potentially handy for modularized environments. read more…​

  • Apache Karaf feature file. read more…​

  • Extension of the Path API for nodes of type ElementKind.PROPERTY, which allows to obtain the value of the represented property. read more…​

  • TimeProvider contract. read more…​

  • Tons of bug fixes

Where to get it

Maven artifacts can be found in the JBoss Maven repository, as well as in Maven Central. The GAV is org.hibernate:hibernate-validator:5.2.1.Final. Distribution bundles will be uploaded to SourceForge once it has recovered from its storage fault.

What’s next

Further development will be driven by the upcoming Bean Validation update - Bean Validation 1.2. Most likely this will align with a Hibernate Validator 6 requiring Java 8. This will be necessary to make use of all the new features Java 8 offers, amongst others the use of @Repeatable. This is in alignment with other technologies which are part of the Java EE 8 standard.

Watch for changes to the Hibernate Validator roadmap, as well as announcements on this and the Bean Validation blog.

Let us know what you think

Feedback and questions are welcome via the Hibernate Validator forum or on stackoverflow using the hibernate-validator tag. If that is not enough, check out the other ways you can get in contact with us.

Thank you

Last but not least, a big thank you to all of you who were lending a helping hand along the way, be it via a bug report or more hands on via a pull request. Special thanks to Khalid who kicked of the work on the 5.2 release series with his Google Summer of Code work. Thank you also for the smaller contributions provided by Denis Tiago, Nicolas Francois, Xavier Sosnovsky, dernasherbrezon, stawny and tonnyyi. Finally a thank you to all other Hibernate team members who were involved.

Enjoy!


* In case you are wondering what happened with 5.2.0.Final, it became obsolete while waiting for SourceForge to recover. In the meantime an IBM JVM specific issue (HV-1007) was reported and fixed.

Moving along towards a 5.2 Final, we are happy to announce the release of Hibernate Validator 5.2.0.CR1. The main goal of this release was to fix bugs and polish some of the new features. For example, we reviewed the Optional validation support and made sure its behavior is (what we think) consistent in all cases. You can find the full change log on JIRA.

Despite the focus on bug fixes, we still managed to sneak in a couple of new features. Hibernate Validator offers now a TimeProvider contract, as well as an extension of the Path API which allows to obtain the value of the represented property. Refer to the online documentation for more information.

Another more general question, which created quite a bit of discussion, revolved around the validation of Java 8 date/time types (JSR 310) (see HV-874). The question is, whether we can/should provide default ConstraintValidator implementations for @Past and @Future validating LocalDate (or any of the other date/time types which do not represent a instant in time). The Javadocs tells us:

This class does not store or represent a time or time-zone. Instead, it is a description of the date, as used for birthdays. It cannot represent an instant on the time-line without additional information such as an offset or time-zone.

Without a instant in time, however, past and future are undefined. One can only validate such an instant by associating a timezone with it. But which one? The time zone of the current JVM? That could lead to unexpected behavior for example in client-server applications. If you have an opinion on this or an idea on how to solve this, please leave a comment or use any of the other means listed below to get into touch with us. We would love to hear from you. For now, Hibernate Validator will not support LocalDate out of the box. We will see how this pans out.

Where do I get the release?

Maven artifacts can be found in the JBoss Maven repository (GAV org.hibernate:hibernate-validator:5.2.0.CR1) and will within a short time also be synced to Maven Central. Distribution bundles are as usual available on SourceForge.

Feedback and questions are welcome via the Hibernate Validator forum or on stackoverflow using the hibernate-validator tag.

Enjoy!

Hibernate Validator 5.2.0.Beta1 - a joint effort!

Posted by    |       |    Tagged as Hibernate Validator

We are happy to announce the release of Hibernate Validator 5.2.0.Beta1. This time a whole bunch of Hibernate team members (Davide, Emmanuel, Gunnar, Sanne and myself) joined forces to make this release happen. Thanks everyone!

In total we were able to resolve 30 issues. Here are some highlights.

Ability to provide external ClassLoader

There are several cases in which Hibernate Validator needs to load resources or classes:

  • XML descriptors (META-INF/validation.xml as well as XML constraint mappings)
  • Classes specified by name in XML descriptors
  • ValidationMessages resource bundle

By default Hibernate Validator tries to load these resources via the current thread context classloader. If that’s not successful, Hibernate Validator’s own class loader will used as a fall-back. For cases where this strategy is not appropriate (e.g. modularized environments such as OSGi), you can now provide an external class loader during bootstrapping:

Validator validator = Validation.byProvider( HibernateValidator.class )
    .configure()
    .externalClassLoader( classLoader )
    .buildValidatorFactory()
    .getValidator();

Hibernate Validator features.xml for Apache Karaf

As a side effect of the class loader improvements we were able to write some OSGi integration tests between Apache Karaf and Hibernate Valdiator. The tests themselves are not so important, but we decided to release the required Karaf features.xml file as part of our regular build artifacts. You can view the first version of this file here.

Programmatic constraint mapping via ConstraintMappingContributor

In Hibernate Validator you can, as a provider specific feature, programmatically define constraint mappings. So far this feature was tied to a programmatic bootstrapping of the ValidatorFactory itself. However, often you are not bootstrapping the factory yourself, but work with the default factory as configured via META-INF/validation.xml. In these cases you can now add one or more programmatic constraint mappings by implementing a ConstraintMappingContributor:

public static class MyConstraintMappingContributor implements ConstraintMappingContributor {

        @Override
        public void createConstraintMappings(ConstraintMappingBuilder builder) {
                builder.addConstraintMapping()
                        .type( Marathon.class )
                                .property( "name", METHOD )
                                        .constraint( new NotNullDef() )
                                .property( "numberOfHelpers", FIELD )
                                        .constraint( new MinDef().value( 1 ) );

                builder.addConstraintMapping()
                        .type( Runner.class )
                                .property( "paidEntryFee", FIELD )
                                        .constraint( new AssertTrueDef() );
        }
}

In order for this ConstraintMappingContributor to get picked up by the bootstrap process, you then need to specify the fully-qualified class name of the contributor implementation in META-INF/validation.xml, using the property key hibernate.validator.constraint_mapping_contributor.

ConstraintDefinitionContributor with resource bundles

We introduced ConstraintDefinitionContributor already in the Alpha1 release, but it so far only allowed you to contribute constraints. Default messages via a resource bundle were not covered. This has changed, and you can just place a ContributorValidationMessages.properties and/or its locale-specific specializations at the root your JAR. Hibernate Validator will aggregate the entries from all the bundles with this name found on the classpath.

Where do I get it?

Maven artifacts for this release are in the JBoss Maven repository (GAV org.hibernate:hibernate-validator:5.2.0.Beta1) and on SourceForge.

Feedback and questions are welcome via the Hibernate Validator forum or on stackoverflow using the hibernate-validator tag. If that is not enough, check out the other ways you can get in contact with us.

Enjoy!

After some time in the making, we are happy to announce the first Hibernate Validator release of the 5.2 series - 5.2.0.Alpha1. This release focuses mainly on Java 8 support, but we will get to this in a bit.

First a big thank you to Khalid Alqinyah who, as part of a Google Summer of Code project, implemented many of these new features.

So what's in it for you?

Java 8 support

Note: Java 8 is not a requirement for Hibernate Validator 5.2. Hibernate Validator is still backward compatible with Java 6. Java 8 specific features are only enabled when a Java 8 runtime is detected.

First off, the Java 8 date/time data types (JSR 310) are supported and can be validated via @Past and @Future. Also Optional and JavaFX types are supported via an improved ValidatedValueUnwrapper. ValidatedValueUnwrapper was already introduced in Validator 5.1, but works now in a more transparent way. Upon validation all registered ValidatedValueUnwrapper instances are checked. If a handler supports the validated type its handleValidatedValue method is called, provided that there exists no matching ConstraintValidator for the wrapper itself. This is best explained with an example:

@Size(min = 3) // the @Size constraint can only apply to the string value which gets automatically validated
private Optional<String> firstName = Optional.of( "John" );

@NotNull
@UnwrapValidatedValue(false) // Use @UnwrapValidatedValue(false) to ensure the wrapper itself is validated
private Optional<String> lastName = Optional.of( "Doe" );
Another Java 8 related feature is the ability to use type annotations on Iterable instances. Something like this:
private List<@AcmeEmail String> emails;
Note that the example is not using Hibernate Validator's @Email. Neither Bean Validation's built-in constraints nor Hibernate Validator specific ones, can be used. The simple reason is that these constraints are missing java.lang.annotation.ElementType.TYPE_USE in their definition and it cannot be added in a backwards compatible way. At the moment we have not yet decided what to do. Should we make Java 8 a requirement for Validator 5.2 or should we somehow provide JVM specific artifacts? What do you think? Right now we want to keep the options open and see which path Bean Validation 1.2 and other Java EE 8 standards are taking. For now this feature is limited to custom constraints where you can add the required ElementType yourself.

Last but not least, in the Java 8 driven feature list, is ReflectionParameterNameProvider. This new ParameterNameProvider makes use of enhancements in the Java 8 reflection API and reports actual parameter names instead of the generic arg0, arg1, etc. A requirement for this provider to work is that the sources are compiled with the -parameters compiler option. Refer to the docs to see how to configure a custom ParameterNameProvider.

What else?

Here are a couple of more highlights from this release:

ConstraintDefinitionContributor and ServiceLoader for constraint definitions

The Bean Bean Validation specification allows to register new constraint definitions via XML mapping files. For example:

<constraint-definition annotation="org.hibernate.validator.constraints.URL">
  <validated-by include-existing-validators="false">
    <value>org.hibernate.validator.constraintvalidators.RegexpURLValidator</value>
  </validated-by>
</constraint-definition>

We offer now two more ways of contributing constraint definitions. The first is programmatically via the ConstraintDefinitionContributor SPI. The above example would look like:

HibernateValidatorConfiguration configuration = Validation
        .byProvider( HibernateValidator.class )
        .configure();

configuration.addConstraintDefinitionContributor(
        new ConstraintDefinitionContributor() {
                @Override
                public void collectConstraintDefinitions(ConstraintDefinitionBuilder builder) {
                        builder.constraint( URL.class )
                                .includeExistingValidators( false )
                                .validatedBy( RegexpURLValidator.class );
                }
        }
);

By the way, org.hibernate.validator.constraintvalidators.RegexpURLValidator is not a made up class. It is another new feature (HV-920) which allows to configure a regular expression based validator for the @URL constraint.

Back to constraint definition though. The second way to contribute constraint definitions is via the Java ServiceLoader mechanism. Just add META-INF/services/javax.validation.ConstraintValidator to your artifact listing the fully qualified classnames of your constraint validator classes (one per line). This mechanism works fine for adding constraint definitions for new types. You cannot as possible in XML or via the ConstraintDefinitionContributor disable default definitions.

ParameterMessageInterpolator

Hibernate Validator requires per default an implementation of the Unified EL to be available. For environments where you cannot or do not want to provide an EL implementation, we offer now a non EL based message interpolator - org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator.

Warning: Constraint messages containing EL expressions will be returned un-interpolated!

These were just the highlights. In total a whopping 40 issues got resolved. Be one of the early adopters and get the Maven artifacts from the JBoss Maven repository (GAV org.hibernate:hibernate-validator:5.2.Alpha1) or the SourceForge distribution bundles.


Simultaneously with the 5.2 alpha release we published a 5.1 maintenance release. We accidentally broke Java 6 backwards compatibility in 5.1.2.Final by using Collections#emptyIterator(). This is corrected in 5.1.3.Final and Java 6 compatibility is restored.

The second bug fixed in 5.1.3.Final is HV-930 where constraints were not validated when the internal weak reference cache of Hibernate Validator got partly invalidated due to memory pressure.

The full 5.1.3.Final change log can be found here. Maven artifacts are on the JBoss Maven repository under the GAV org.hibernate:hibernate-validator:5.1.3.Final and distribution bundles are available on SourceForge.

If you are using a 5.1 version of Validator it is highly recommended to upgrade to 5.1.3.Final. Or why not giving the 5.2 Alpha version a go?

Feedback and questions are welcome via the Hibernate Validator forum or on stackoverflow using the hibernate-validator tag.

Enjoy!

This post is about validation, Bean Validation specifically. And the what it solves. It is a reaction to a post by Julien Tournay which basically claims - if I sum it up - that:

  • Scala is faster than Java (he is coming from far far away on that one - du diable vauvert as we say in French)
  • Bean Validation is kind of crap
  • The new Play Unified Validation API is awesome

I usually am old and wise enough not to answer these kind of posts. But I want to feel the blood of my youth again damn it! After all I am from an era when The Server Side was all the rage, trolls had real teeth, things were black or white. That was good fun.

Why the You missed the point like Mars Climate Orbiter title? With a sensationalist title like Scala is faster than Java, I had to step up my game. Plus Mars Climate Orbiter missed Mars due to a conversion error and we will talk about conversion today.

I won't refute things point by point but rather highlight a few fundamental misunderstandings and explain why things are like they are in Bean Validation and why it makes sense.

Java was limiting

IMHO, @emmanuelbernard a créer son API avec les outils a sa disposition - @skaalf
IMHO, @emmanuelbernard has created his API with the tools he had at his disposal - @skaalf

We certainly pushed the boundaries of Java when both CDI and Bean Validation were designed and I wished I had more freedom here and there. But no Bean Validation is like it is because that's the most natural way validation is expressed in the Java ecosystem for what we wanted to achieve. It is no good to offer something that does not fit into the ecosystem.

For example, in Java, people use mutable objects. Mutable believe it or not is not a swear word in this language. My understanding is that Play Unified Validation API makes use of Scala's community incline for immutability.

Validation, conversion and marshalling

In the use case Julien takes as an example, a JSON string is unmarshalled, conversion is applied (for dates - darn JSON) and then values are validated. He considers it weird that Bean Validation only does the latter and finds the flow wrong.

We kept this separation on purpose. The expert group vastly agreed that Bean Validation was not in the business of conversion and that these steps ((un)marshalling, conversion, validation) should be separated. Here is a key reason:

  • marshalling and conversions are only at the Java boundaries (Web frameworks, services enpoints, datastores enpoints, etc)
  • validation happens both at these boundaries but also at key lifecycle events within the Java boundaries

Conceptually, separating validation from the rest makes a lot of sense to enable technology composition and avoid repetitions - more on that latter point later. What is important is that for a given boundary, they are properly integrated. It's not unlike inlining in compilation.

Bean Validation is in the business of not being called

One key point in the design of Bean Validation is that it has been built to be integrated within a cohesive stack more than to be used individually.

JPA transparently calls Bean Validation on your objects at the right time. JSF calls Bean Validation transparently before populating the beans. JAX-RS calls Bean Validation on the inbound and outbound resources transparently. Note that these three technologies do address the marshalling and conversion problem already. That's their job.

So the key is that an application rarely has to call the Bean Validation API. I consider it a failure or an unfinished work when it has to.

If you need to explicitly validate some piece of data in a fire and forget way, Bean Validation might not be the best tool. And that's OK.

Back to the JSON case. When the JSON Binding spec will be out, we will have the same integration that is currently present in Play Unified parsing, conversion and validation API (it could also be done today in Jackson, I'm not sure what extension points this library offers). While the three layers marshalling / conversion / validation will be conceptually separated - and I'm sure will report different types of error for better tracking - the implementation will use some specific APIs of Bean Validation to inline validation with the unmarshalling and conversion. That API exists BTW, it is Validator.validateValue which lets you validate a value without creating the POJO associated. It is used by web frameworks already. Pretty much what Play Unified Validation API does.

As for JAX-B and XML binding, well let's say that there is an X in it and that it's not safe for children. More seriously, we have integration plans with mapping between the XSD and the Bean Validation constraints but we haven't got around to do it yet.

Bean Validation is in the business of declaring constraints once

From what I see of the Play Unified Validation API, you put the declaration / implementation of the validation next the marshalling logic. In other words you cannot share the constraint declaration between different marshalling operations or even between object transformations.

Bean Validation has been designed to let the user declare the constraints once and have them validated across the whole stack. From the web form and service entry points down to the database input/output and schema definition. Some even use our metadata facility to propagate the constraints up to the client side (JavaScript).

And that's future proof, when we add JSON-B support, boom the constraints already declared are used automatically and for free.

Conclusion

Bean Validation cannot be understood if you take it in isolation. It is useful and works in isolation for sure but it shines when integrated in a platform from top to bottom. We did and keep doing it in Java EE but we also make sure to keep our APIs and SPIs open for other platforms to do the same. Spring famously has been doing some of it.

Let's mention a few key features of Bean Validation that are not addressed at all in Play's approach:

  • i18n
  • constraint inheritance
  • method validation
  • custom and context sensitive programmatic error report
  • partially valid object graph - yes that's important in a mutable world
  • etc

Even a few of these would make Play's stuff much much different.

Now with this context properly set, if you read back Julien's complaints about Bean Validation (especially about they design), they fall one by one pretty much. I have to admit their composition approach is much nicer than Bean Validation's which relies on annotated annotations. That's the main thing I miss.

Design is choice. Without knowledge to the designer's choices, you can too easily misunderstand her design and motives. Julien has been comparing Apples with Oranges, which is ironic for someone working on one of the most type-safe language out there :o)

But it's good that more people take data validation holistically and seriously and step up the game. Less work for app developers, safer apps, happier customers. Judging by the location, I could even share some thoughts over a few rounds of whisky with Julien :)

Peace.

back to top