Java bean validation: Optional fields annotation - bean-validation

I would like to treat some fields as Optional, if the value is null or blank don't go with the checks of the other annotated constraints.
There is some way to achieve it!
Reading this tread Java bean validation: Enforce a #Pattern only when the property is not blank don't seems cover my needs.
Below an example to explain what I mean:
public class Test {
#Max(value=100) // <--mandatory
private int parA;
#Optional // <-Custom annotation telling "do not check other if null or blank"
#Range(min=10, max=200)
private int parB;
...
}

Now you can!
https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#example-container-element-constraints-optional
public Optional<#Size(min=1, max=128) String> first_name = Optional.empty();

You cannot do what you want with Bean Validation. You cannot establish a "connection" between two constraints placed on a property. Also, if I understand correctly, your #Optional is not even a constraint annotation, but rather just a marker annotation. Note though, that all default constraints are implemented in a way that a constraint validates for null values. So in most cases you get what you want either way. In your example, you also have the problem that you are dealing with a primitive int. This will always have a value, so the range constraint would be evaluated either way.

Related

javax validation OneOf constraint

Is there an annotation in javax validation, so it should constraint that value is one of predefined values.
Example
#OneOf(values = "12-14m, 16m, 18m")
private String size;
No, there is no such constraint and you have to write it's own.
Here is the example that does mostly the same but opposite #DenyValues:
annotation usage on a class: https://github.com/php-coder/mystamps/blob/66a2254e6d78c03d0b50531752d860efe784a1fd/src/main/java/ru/mystamps/web/controller/dto/AddCountryForm.java#L87
annotation definition: https://github.com/php-coder/mystamps/blob/66a2254e6d78c03d0b50531752d860efe784a1fd/src/main/java/ru/mystamps/web/support/beanvalidation/DenyValues.java#L35-L44
validator implementation: https://github.com/php-coder/mystamps/blob/66a2254e6d78c03d0b50531752d860efe784a1fd/src/main/java/ru/mystamps/web/support/beanvalidation/DenyValuesValidator.java#L26-L51
If you are using hibernate-validator, you can declare new annotation using #ConstraintComposition. This is a good example here.

Javax validation - constraint composition

i have a little problem with implementing properly my own validation annotation.
Here is sample code:
#Pattern(regexp="[0-9]*")
#Size(min=3, max=10)
#Constraint(validatedBy = SampleValidator.class)
#Documented
#Target({ANNOTATION_TYPE, METHOD, FIELD, CONSTRUCTOR, PARAMETER})
#Retention(RUNTIME)
public #interface MyAnnotation {
String message() default "Wrong!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
#Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
#Retention(RUNTIME)
#Documented
#interface List {
MyAnnotation[] value();
}
}
My problem is, I want my annotation to work in the way, that #Size and #Pattern annotation run first and if they're valid then (and only then) run validator provided by #Constraint annotation (SampleValidator.class).
Put it simple:
I want to run SampleValidator only if #Pattern and #Size are valid
(I implementes SampleValidator just as additional validator that should be called only in some specific circumstances)
How can I obtain such behaviour?
Thanks in advance!
Obviously, I can't do anything like that:
#GroupSequence({ Step1.class, Step2.class })
#Constraint(validatedBy = SampleValidator.class, groups = Step1.class) // no 'groups' attribute
#Size(min=3, max=10, groups = Step2.class)
#Pattern(regexp="[0-9]*", groups = Step2.class)
#Documented
#Target({ANNOTATION_TYPE, METHOD, FIELD, CONSTRUCTOR, PARAMETER})
#Retention(RUNTIME)
public #interface MyAnnotation {
...
}
Try adding the #ReportAsSingleViolation annotation. According to the specification:
"More specifically, if a composed constraint is marked as #ReportAsSingleViolation, the evaluation of the composing constraints stops at the first failing constraint and the error report corresponding to the composed constraint is generated and returned."
http://beanvalidation.org/1.1/spec/#constraintsdefinitionimplementation-constraintcomposition
The answer is only partly correct. Yes #ReportAsSingleViolation that only one single violations will be generated and validation will stop after first failure in this case. However, the specification gives no guarantee in which order constraints are evaluated. It could be the composing constraints first or the validator specified via #Constraint. If anything you would rely on some implementation detail which could change any time. Also there is no order defined in which #Size and #Pattern are evaluated. Bottom line, you cannot achieve your wanted behaviour with constraint composition.
If you want to guarantee a sequenced execution you need to look at the GroupSequence feature.

Why must JSR303 custom annotation's constrain group default to empty array?

I'm writing a custom validator for a specific constrain group (not Default), but the runtime gives me the below error.
I'm just curious why they need the default values to be empty. Appreciate if you can share your opinion. Thanks :)
xxx.model.validation.CustomValidation contains Constraint annotation, but the groups parameter default value is not the empty array.
StackTrace: org.hibernate.validator.metadata.ConstraintHelper.assertGroupsParameterExists(ConstraintHelper.java:335)
org.hibernate.validator.metadata.ConstraintHelper.isConstraintAnnotation(ConstraintHelper.java:282)
I can't figure out in which scenario it can be useful to bind a constraint to a specific group.
A group is used for partial validation (and sequence validation). If you have 10 fields in a class you can mark 8 of them with A and 2 with B. Then you can decide to validate only the fields in the A group or in the B group. Conversely you want that #MyConstraint belongs to a specific group named C. It makes no sense. A group is more or less a name used to distinguish some fields from others in the same class. It has no absolute meaning. Groups are useful in validation not in constraint definition, they are related to fields not to constraints.
Furthermore if you hide the group name in the constraint definition you may run into errors because you can think that the fields are validated all togheter.
#Email
private String mail;
#Password
private String pass;
#VAT
private String vatCode;
Are you able to see if there is a partial validation?
EDIT
In relation to the second comment:
Suppose you have a class with 5 fields with no constraint at all. Three of them are integers. If you want to validate the sum of these three fields you have to create a class-level constraint as you suggest. In this way your custom annotation is applied to the class not to fields so, how can you define groups on fields?
Instead, you may use something like this:
#Sum(min = 250, fields = {"length", "width", "height"})
public class MyClass {
private String type;
private String code;
private int length;
private int width;
private int height;
...
}

DataMember Emit Default Value

I have a .Net Web Service function that can accept one string.
That function will then serialize that string to JSON, but I only want to serialize it if it's value is not "".
I found these instructions:
http://msdn.microsoft.com/en-us/library/aa347792.aspx
[DataContract]
public class MyClass
{
[DataMember (EmitDefaultValue=false)]
public string myValue = ""
}
Unfortunatelly I can not hide the myValue from the serialization because "" is not the .Net default value for a string (how dumb is that!)
One of two option ocurred
On the web service have some kind of attribute that sets the "" to null
Have some condition on the class
I would prefer the 1st because it makes the code cleaner but an opinion would be great.
Thanks
You can explicitly set what the default value is (for the purposes of serialization) using the DefaultValueAttribute class:
[DataContract]
public class MyClass
{
[DataMember (EmitDefaultValue=false)]
[DefaultValue("")]
public string myValue = ""
}
I think you have at least a couple of options here. It's extra work but worth it.
You can encapsulate the string in a reference type. Since reference types are null if not present, that lets you know right away if a string was present or not (because the encapsulating reference type would be either non-null or null, if the string is non-empty or not.)
A final option you have is to add an extra complementary variable (perhaps a boolean) that is set on OnDeserializing/OnDeserialized/OnSerializing/OnSerialized and use this to track whether or not something was actually present on the wire. You might, for example, set this complementary variable to true only when you're actually serializing out a non-empty string and similarly

Why does Hibernate Validator #NotEmpty produce duplicate messages?

While working with Hibernate Validator, I noticed that the #NotEmpty and #NotNull annotations produce duplicate messages in the InvalidValue array returned by getInvalidValues(...).
If I specify a message like #NotEmpty(message = "My error message."), then I'll get one InvalidValue of "My error message." and a second of "may not be null or empty"
If i don't include a message (eg #NotEmpty by itself), then I get two copies of the InvalidValue with a message field of "may not be null or empty".
Why does Hibernate Validator do this?? Shouldn't I get one message, either the value that I override using the parameter, or the default message, but not both??
For some more context:
I am extending ClassValidator<T> with my own ClassValidator<MyClass> implementation. I do so to add some custom validations which cannot be done by annotation. I need to see the run time value of more than one property of the class in order to determine the validation.
I get the validations when I call myClassValidator.getInvalidValues(), which I override. Inside my implementation of getInvalidValues() I call super.getInvalidValues() to create the initial error list, and then I add my custom errors to that list. In any case, the call to super.getInvalidValues() contains the duplicate messages, one matching the message property passed into the annotation, and a second with the stock value of the annotation message.
Justin,
I've been working with Hibernate Validator for the last couple of months. While I have not run into the same issue that you've described, I also have not extended ClassValidator. For custom validation, the Hibernate Reference Guide indicates that writing custom constraints is the way to go.
I have been able to use the built-in constraints almost exclusively on my current project. In one case, where I needed to do some very specific calculations on an integer field, I wrote a custom constraint as described in the reference guide; it was a breeze.
Speaking to your specific problem, I wrote a simple test app as a sort of sanity check on my part:
import org.hibernate.validator.*;
public class HibernateValidatorTest {
#NotEmpty
#NotNull
private String validateMe;
public static void main ( String[] args ) {
ClassValidator<HibernateValidatorTest> validator =
new ClassValidator<HibernateValidatorTest>( HibernateValidatorTest.class );
InvalidValue[] inVals =
validator.getInvalidValues( new HibernateValidatorTest() );
for ( InvalidValue inVal : inVals ) {
System.out.println( inVal.getMessage() );
}
}
}
With both Hibernate constraints on the validateMe field, the console output is:
may not be null or empty
may not be null
Removing one or the other has the expected effect of printing only a single message to the console.
I hope this is helpful.
Brian T. Grant

Resources