As you may have noticed, it's almost spring cleaning time and everyone pushes its new JSR proposal following EE 7. I wanted to share with you what I had in mind for Bean Validation. This is by no mean a definite list but more a starting point to discuss things further. In the end the EG and the community will shape the spec.
First off, I think people have been very pleased with Bean Validation (no major flaw nor big limitation). So the idea is to go for a version 1.1 rather than a 2.0.
Integration with other specs
While not part of the Bean Validation JSR, I think it is important to pursue further collaborative work with some other JSR leads on how to integrate Bean Validation into the various lifecycles of the SE/EE platforms. Certainly nobody wants each specification to invent its own validation mechanism and its own annotations. The work we did with JPA 2 and JSF 2 showed that it is possible and beneficial for the platform and developers.
- JAX-RS: call Bean Validation upon HTTP method calls on parameters. If a parameter is not valid, JAX-RS could return the appropriate HTTP error code as well as some payload describing the error.
- JAXB: some people have asked for integration between Bean Validation and JAXB. Basically, the Bean Validation constraints (at least the fundamental ones) could be converted into the XML schema descriptor (and vice versa) to guarantee a unified propagation between the Java land and the XML land. I have been exploring some of the needs with Martin Grebac and I hope we can converge.
- JPA: improve the integration by letting Bean Validation constraints influence the DDL generated with the constraints declared on the entity model
- CDI: offer a way for Bean Validation pluggable components to allow CDI style injection (in particular constraint validator implementations)
- CDI: integrate method-level validation (see below)
Method level validation
The idea is to offer APIs to validate parameters and return values of method calls. These APIs would be used by any injection or AOP framework around method invocations. If a constraint violation is detected, an exception (eg. ConstraintViolationException) would be raised.
public class OrderManager {
public void processOrder(@Valid Order order, @Min(0) @Max(30) int retry) {
doProcessOrder(...)
}
}
if Order contains constraint violations or if retry's value is not between 0 and 30, a ConstraintViolationException will be raised by the interceptor framework.
Interceptor frameworks could be:
- CDI: some stereotyped interceptor could trigger the method validations when accessed
- AOP style framework like Javassist or AspectJ
@Valid and group propagation
Some people have required the ability to translate a group into another group while cascading the validation. This can help reduce the number of groups and increase reuse.
public class Address {
@NotNull String city;
@Valid(from=Default.class, to=EnhancedGroup.class)
Country country;
}
public class Country {
@NotNull(groups=EnhancedGroup.class)
String name;
@Size(min=2, max=2, groups=EnhancedGroup.class)
String iso2;
}
Apply constraints on elements of collection
While we can validate constraints on the collection itself and ask to cascade validation to the elements of the collection, we cannot put constraints on the collection element itself. This is annoying for collection of native types in particular. There are several not so elegant solutions to this problem, the real solution is to wait for Annotations on Java types (JSR-308)
Collection<@NotNull String> names;
Depending on when JSR-308 finally comes out, we might want to delay this feature.
Various issues
In no particular order, here are a few issues or features we can also try to tackle.
Constraint composition
Today constraint composition is done with a logical AND (all constraints must be valid). We could also support logical OR composition.
@ConstraintComposition(OR)
@SSN
@TemporarySSN
@Constraint(validatedBy = { })
@ReportAsSingleViolation
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface ValidSSN {
String message() default "Not a valid social security number";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
JTA and exception propagation
In EE, there are some inconsistencies on how exceptions are raised:
- while in the process of a business method
- raised by the declarative or explicit commit() calls
Basically when operations (like validation) are triggered within the declarative commit(), everything I believe is wrapped into a RollbackException. Which means that depending when JPA's flush() is called, ConstraintViolationException (raised by JPA) comes either untainted or comes wrapped in RollbackException. I wonder if we can fix this inconsistency.
Better rules for OSGi style containers
Some extreme modularity fanboys have complained about some fuzziness in the spec around visibility and classloaders. We should clarify that.
Exclusive flag on @BigDecimal / @BigInteger
Allow to exclude limits.
ConstraintViolationException builder
The idea is to provide a simple API to build consistent ConstraintViolationExceptions. Because Bean Validation is usually called by the lifecycle of other specifications or frameworks, it is their responsibility to raise the exception.
Your participation
That's all I have. I am sure I'm missing many improvements so please speak up. You can do it however it pleases you:
- comment on this blog entry
- open an issue on the specification issue tracker
- discuss on the Bean Validation forum
And of course, you can always go one fork ahead.
From this first wave of feedback, I plan to propose a JSR to the JCP.
Note that Hibernate Validator 4.2 has or will integrate some of these features which will provide us feedback.
Emmanuel
From the hip:
Hi Nicklas,
Your last two points seem to be JSF specific. for the last point, JSF does pass the group to Bean Validation.
About your first point, what do you have in mind? We do expose today a metadata API to explore a property and get the list of constraints. That's how we envision other (non java) frameworks would gather the constraints and apply then in their world. For example a Javacript library could invoke the metadata API, get the list of constraints and apply the one that can be reproduced. This metadata API is available in Bean Validation 1.0
I know JSF / RichFaces does not have such support yet. We had this feature speced for a long time so yell on Jay to get it implemented and out ;)
Standardizing such integration in JSF n+1 would make sense.
- JPA : letting Bean Validation constraints influence the DDL generated
and
- Apply constraints on elements of collection
Maybye some nonscalar type constraints like SQL UNIQUE can be bounded to Java land level
Thus these implies global data fetch from the db to keep coherence
My two cents ...
That's a quite requested feature but a tough one. Basically in most cases, it would be implemented wrong and would only give the illusion of consistency.
We can evaluate the idea of using @Unique to only influence the DDL.
Multi-row constraint validation requires database table locks. Many DBMS out there have a long list of restrictions with table locking. Or you are happy with the guarantee that any validation result is merely a proposal, and that a future insert of the same data might fail.
I'd rather see improvement of message propagation/mapping when an integrity rule inside the database has been violated. Like, turning a fatal database transaction exception (JDBCException wrapped etc.) into a clean error message, with a strong and stable mapping across DBMS products. If a UNIQUE constraint has been violated at the database level, I'd like to it and turn it into a Bean Validation error for my client.
We have discussed this >5 years ago and at that time there was just no way to really guarantee that a JDBCException can tell you what the real cause of the problem was. Nobody standardized or required that the catalog name of the violated constraint is included so you couldn't map it. Maybe that's possible now. If not, at least the generic ConstraintViolationException should be an SPI of Bean Validation that JPA providers can throw.
Client side validation already implemented in coming RichFaces 4.0 release, that's not a subject for bean validation. From the JSF side, the cool feature would be object validation that doesn't touch model itself. Currently, we can only validate a single bean attribute aganist new value, that doesn't allow. In richfaces, I do make a 'clone' of target object, update it with new values and perform validation on the cloned object. Would be nice to have something like: validator.validateObject(Object model,Map<String,Object> newValues, Class ...profile) that does a similar work.
WRT I had a similar need, and extended the Validator interface for this purpose. The code is still currently in a sandbox in the Apache Bean Validation podling: My Link
Ability to use interpolated message with arguments other than annotation attribute when using the API buildConstraintViolationWithTemplate.
This would really enable a full usage of Hibernate Validator / JSR 303 to validate a set of business rule ; displayed user messages need to be context aware and not only parametrized by annotation attribute like min() with @Min.
Hi Christian,
Big +1. I'll discuss with Linda on this subject. Not sure that will make it but one can try :)
Hi Alex,
Indeed that's a use case we should address. I've created BVAL-214 to capture it. Note that Map<String, Object> is not the only approach, I've listed some in the issue.
Matt,
I don't think cascading @Valid for validateProperty solves Alex's issue. What is the use case you are trying to solve with these new methods (which could be options in the Validator context).
Hi Vladislav,
You can already do that with the current version, simply pass a custom MessageInterpolator implementation either during the ValidatorFactory or the Validator construction
Validator validator = validatorFactory .usingContext() .messageInterpolator(customMessageInterpolator) .getValidator();Your customMessageInterpolator can interpolate anything.
Out of curiosity, what were the type of things you wanted to interpolate? We might try and standardize them.
What really bugged me in the current Bean Validation Impl is that you now and then may get a ConstraintViolationException, but in the logs it only shows a generic error message referencing to the inner exceptions. When looking through the logs, its impossible to find out which field caused the violation exception.
so, when throwing a constraintViolationException, make sure the getMessage() method prints out at least the messages of the constraints violated to make it easier to debug that stuff without either putting a try/catch around every possible call or trying to somehow reproduce the issue and then attach a debugger to the jvm, just to find out whats really causing the exception.
client-side bean validation (based on JSR-303) is supported as part of SeamRemoting Module 3.0.0.Beta2
Hi Dominik,
Do you know which software raises the ConstraintViolationException? Hibernate Validator itself does not raise the exception.
Hibernate Core (the ORM), used to be sparse with the error message but we have fixed that in the latest versions and the full constraint detail is part of the exception message. If you know the software that raised the exception (check the stack trace), you will be able to ask them to improve their message,
Note that the planned ConstraintViolationException builder will be here to normalize the message created so that all libs will be uniformed. That will hopefully fix the issue in the long term.
Hi Matt,
The sad thing is that the API is present on the Bean Validation side but presentation frameworks are slow to adopt it and use it :(
RichFaces 4 now has support for it but I wished more presentation frameworks had worked on the integration. If you can convince a few people or have access to a few people, feel free to send them by me :)
The integration API is described here. Let me know if you think some parts are missing or should be improved. We should definitely do some more buzz around it.
declares "null" elements as invalid (see spec 1.0-final, p107, example 6.9)
This is probably most relevant with JSF 2.x: if you enable javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL
you have to add a second @NotNull check to any field even if it is already checked by @Size.
Hi.
I’m concerned about Bean Validation integration with other specs and the recommendations done so far, as it is possible that they are not really about the same thing. I’ll give some examples, all with JPA and DDL influence:
I don’t know if there are similar issues with other specs and I know that this is handy for a lot of new projects and that DDL can be tweaked in the end and left as you need, but anyway I don’t feel it’s a good idea to mix some things because they are truly different things. So at least I think that there should be some way to disable this influence on other specs or at least give a very strong recommendation to frameworks to implement one in addition to ignore validation annotations if other constraints are present on the own other spec’s annotations (but even with this there should be a disable option).
I’m far from being an expert, so please correct me if I’m wrong.
public boolean isValid(Map<String, String> target, ConstraintValidatorContext context) {
context.buildConstraintViolationWithTemplate("oh noes")
.addNode(somekey)
.addConstraintViolation();
return false;
}
It would be nice if that resulted in a violation at path someobject.mapproperty[somekey] rather than someobject.mapproperty.somekey.
Hi Emmanuel,
Let's take the following message key my.custom.default.message with the value . The parameter {0} is contextual, meaning it cannot be interpolated with the annotation attributes.
I may have missed something in the API but either we :
- use the default annotation message, like String message() default ; and return true or false in the isValid method ; Then, Hibernate Validator will try to interpolate the {0} parameter than won't be found in the annotation attributes.
- call the following sequence of API: context.disableDefaultConstraintViolation(); ConstraintViolationBuilder builder = context.buildConstraintViolationWithTemplate(); builder.addNode(); builder.addConstraintViolation(); return false;
In this last case, the message will be, like you said transmitted to my customMessageInterpolator. But it seeems there is no way to pass a array or a varargs of contextual parameters to the buildConstraintViolationWithTemplate method to be interpolated later by my customMessageInterpolator. Similar, the method interpolate of the interface MessageInterpolator has only String message, Context context. So there is no way either to get a specific contextual parameter.
To answer your question, we have a set of custom constraints applied at class level via a composite constraint. Each of them implements a specific business rule. So the validation message contained in the ConstraintViolation has to be contextual in order to get a meaningfull feedback to the user and not only a generic message. I take a look at the last beta that allow to use format on the value but this doesn't match my specific context since the constraint is applied a class level, meaning I may need other values.
Hi Markus,
It probably comes from my database background but null means you don't know the data or there is no data. That's the reason why any constraint (including @Size) is a noop on null values.
You can write your own @MySize constraint that does what you want (composing both @Size and @NotNull) but I still think it's a bad idea :)
Hi Xavi,
You are correct. If you look at how we have integrated Bean Validation with other specs so far, we have used the following approach:
I think this approach addresses your concerns. In your legacy app example, you would have a Legacy or Database group which would contain the constraints applied to your database.
Btw to your point 2., I think it makes your app future fail but that's another story :)
to your point 3., yes Hibernate Core does not apply @NotNull constraints for properties hosted by subclasses of a class mapped with a single table approach.
Ah good catch, there is a hole in the current API. I've opened a ticket
I think the API call should look like
public boolean isValid(Map<String, String> target, ConstraintValidatorContext context) { context.buildConstraintViolationWithTemplate("oh noes") .addNode(null) //ie the contained element inIterable().atKey(someKey) .addConstraintViolation(); return false; }Vladislav,
Could you open a ticket here. I'm not sure I've followed your use case entirely but we will be able to explore it there.
Thanks
Hi Emmanuel.
I agree with you on the validation part, but my concerns where about the influence on the DDL generation, which is why I was saying that they are different things. I mean you are influencing something that is a different thing from validation (DDL) with the validation configuration.
Is the property to disable validation defined to also affect DDL generation and other aspects or is there any recommendation in this sense?
Maybe I should had been more clear and instead of talking about disabling influence on other specs I should had talked about disabling influence on other aspects of other specs. I meant to do recommendation to frameworks in these sense.
Thanks for your response.
Hi,
this thread describe the same problem : http://www.mail-archive.com/hibernate-dev@lists.jboss.org/msg03380.html
Hi Emmanuel,
some ideas for BV 1.1:
@CopyConstraints(MyBean.class) MyDto { //... }My ideas,
1) Having more built-in annotations
2) Increasing support for OSGI
3) Current Bean Validation is great for partial validation via Groups however I have still difficulties in order to express validation order per fiels. I have opened a topic regarding it but it seems that it could not take enough attention.
https://forum.hibernate.org/viewtopic.php?f=26&t=1009999
I believe that this part of the validation is little bid restrictive. Ordering validation for fiels and partial validation is great however per field ordering is still one of the limitation that could not resolved for me. I hope that it is because of my lack of knowledge.
Sorry I wasn't tracking this. I suppose you're right; Alex's issue was more about setting multiple properties on the root bean. My use-case could be seen as addressing the idea of validating a subordinate domain entity of type B relative to a prospective parent bean of type A before actually adding it. And, given that, this is not fully relevant to bean validation because you could simply validate B as a bean, then add to A; as has been discussed one cannot, per the basic spec, constrain iterable elements from the parent (my sandboxed dynamic bean validation component supports adding these types of constraints).
It would be useful to permit property validation calls to be made using (potentially custom) Path implementations as opposed to (or more likely in addition to) strings.
In my opinion it should be possible to define a @ConstraintComposition(OR) on bean/property level and not in the constraint implementation.
Maybe something like that:
@Min(5) @Max(10, ConstraintComposition.Or) ....
Emmanuel, hibernate-core (3.6) throws it.
Hi Emanuel
I'm using the Hibernate Validators since the day it got released. I wrote some extensions which also might be useful to other users:
I extended the MessageInterpolator so that I can use the rootBean, leafBean and the invalidValue in the message templates. Further I added support for nested properties. Here are some samples for (extended) message templates: - => - - While this information is unnecessary while you are typing the data and see the whole record, it might be essential if the input is a file and the message is written to a log.
It would also useful to provide some custom properties in the MessageInterpolator context:
beanValidator.validateValue(Person.class, , person.getFirstName); ... ctx.put(, ); msgInterpolator.interpolate(constraintViolation.getMessageTemplate(), ctx); -
While the leafBean is available as in the MessageInterpolator.Context, I had to extend the context to provide the other values.
The validator has only access to the validated object and the annotation. It is not always possible and reasonable to set the context information on the validated object. It would be good to have some context available in the validator. Now I pass the context information through a threadlocal variable which is very ugly and error prone. E.g. a validator could check if a value is equal to an entry of a dynamic list which depends on the context.
Huge + 1 here!
IMHO The following method is essential to avoid plugging a (horrible) custom MessageInterpolator
public class ConstraintValidatorContext { addInterpolatedParameter(String name, String value); }
All,
What about cross field validation. A few common use cases are two fields that can't have the same value (or needs to have the same value) and date fields that have a specific order.
MyFaces ExtVal has the crossfield validation (not JSR-303 related) and I'm trying to create something similar with BeanValidation API at this moment.
An example
Regards Rudy
It is essential. I'm very interested in René Grob's custom interpolator, especially the that would allow mapping of field paths to UI field labels.
Have you published your custom interpolator?
I'm particularly interested in how your interpolator has access to the {rootBean} and {leafBean}. ThreadLocal? (eww...)
My project's business owners demand nice error messages, often with context like this (hypothetical but illustrative).
class User {
@NotNull String name;
@NotNull(message="#{leafBean.name}'s password is required.")
String password;
}
Obviously you have put a lot of effort into this interpolator -- because I have tried with somewhat less success myself!
I believe two things are essential for JSR 303 1.1:
- more flexible message interpolation
- @Valid with groups propagation
We're currently purely using the XML side of the Validation API, as we need to change validations on-the-fly. I've build an RefreshableValidatoFactoryBean base on Spring' CustomValidatorBean, which can refresh the Validator with XML based constraints when wanted.
Things we're really missing is documentation of the XML side of the Validation API, the annotated sides is documented very nicely but there's almost non for XML.
Hi,
Just wondering whether it might be a good idea to default the message property on the annotation type to the name of the annotation type. So for example for the CheckCase annotation, if a message key was not specified, it would default to:
com.mycompany.CheckCase
Thoughts? - Ole
1 for the JAXB bridge.
XML representation of validation would be very useful.
How about a annotation processor that would generate the XML at compile time?
BTW, what is the timeline for 1.1, is this work part of JEE7?
Thanks for a good spec.