Javax validation - constraint composition - bean-validation

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.

Related

Micronaut custom validation Annotation does not work

I was trying to write a custom annotation to validate a field in a Micronaut project, I came across this section in their documentation Defining Additional Constraints
My understanding was that is completely possible to write my own annotation to validate a field in my POJO but after trying for hours, I can't get my validation to work, it simply does not get invoked, could it be I'm missing something fundamental about the way how Micronaut works?
Annotation
#Retention(RUNTIME)
#Constraint(validatedBy = [])
annotation class FieldValidator(
val message: String = "invalid format ({validatedValue})"
)
Factory
#Factory
class ValidatorFactory {
#Singleton
fun fieldPatternValidator(): ConstraintValidator<FieldValidator, CharSequence> {
return ConstraintValidator { value, annotation, context ->
context.messageTemplate("invalid format ({validatedValue}), should be test")
value == "test"
}
}
}
Filter
#Introspected
data class HelloWorldFilter(
#FieldValidator
val field: String?
)
Controller
#Controller("/hello")
open class HelloController() {
#Get("{?filters*}")
#Produces(MediaType.TEXT_PLAIN)
open fun index(#Valid filters: HelloWorldFilter): String {
return filters.toString()
}
}
I have a small demo on Github, to reproduce
run ./gradlew run
call http://localhost:8080/hello?field=abc that expected behaviour should be bad request since the field is matching the desired value.
Using your demo project, I changed your HelloWorldFilter class to
#Introspected
data class HelloWorldFilter(
#field:FieldValidator
val field: String?
)
Ran it, then:
curl "http://localhost:8080/hello?field=abc"
Output was as you expect:
{"message":"Bad Request","_embedded":{"errors":[{"message":"filters.field: invalid format (abc), should be test"}]},"_links":{"self":{"href":"/hello?field=abc","templated":false}}}
With:
curl "http://localhost:8080/hello?field=test"
Output:
HelloWorldFilter(field=test)

Unique constraint at field in collection

is it possible to make this validation:
class Man {
#Unique
String name;
}
class Order {
#Valid
List<Man> manCollection;
}
where is unique logic is: every item in collection manCollection is unique.
You could make this snippet ambiguous just by adding a Customer class that contains a List of Orders:
class Man {
#Unique
String name;
}
class Order {
#Valid
List<Man> manCollection;
}
class Customer {
#Valid
List<Order> orderCollection;
}
Then one couldn't possibly know whether the Man objects must be unique within a given Order or within a given Customer (or both).
So I don't think it's possible with this exact syntax, regardless of what the Bean Validation APIs allow.
What you could do is move the annotation to manCollection, e.g. #UniqueMen List<Man> manCollection;, and implement a ConstraintValidator<List<Man>>.
If it's useful to you, you could even make a more generic #UniqueContent annotation, but that would be much more complex. You would need to pass the target type as a parameter (#UniqueContent(target = Man.class)) and write a validator that parses annotations on the target class in its initialize method. Be careful to use some caching mechanism, though, because annotation parsing is quite slow.

why does the compiler complain about missing ctor of WebSocketHandler?

I'm trying to use websocket in my project.
to do so, I installed the package Microsoft Asp.Net SignalR, which consists of WebSocketHandler abstract class.
i defined a class inheriting WebSocketHandler, but then the compiler complains:
'Microsoft.AspNet.SignalR.WebSockets.WebSocketHandler' does not contain a constructor that takes 0 arguments'.
It seems wierd to me, because the definitioin of WebSocketHandler ctor gets a nullable value, which means the ctor could get no parameter,
the definition looks like this:
protected WebSocketHandler(int? maxIncomingMessageSize);
can anybody tell me what the problem is?
thanks.
It seems wierd to me, because the definitioin of WebSocketHandler ctor gets a nullable value, which means the ctor could get no parameter
No, it doesn't. There's a big difference between receiving a null value for a nullable type, and not receiving a value at all.
If the parameter were optional, that would be a different matter - but it's not. You have to supply an argument convertible to int? in the call. If you want to provide the null value for int?, do so:
var handler = new WebSocketHandler(null);
Or if you want to avoid accidentally using any other single-parameter constructor definitions which may be applicable with a null literal as the argument, you could use:
var handler = new WebSocketHandler((int?) null);
Or:
var handler = new WebSocketHandler(default(int?));
protected member is accessible by derived class instances and there's nothing special about it. Nothing special in the class itself, either # WebSocketHandler.cs.
It just mens you need to pass in a nullable type, it does not mean it can't get any arguments.
int? maxIncomingMessageSize = 0;
var socket = new WebSocketHandler(maxIncomingMessageSize);
In your derived class you could/should define a "constructor that takes 0 arguments".
public class MyHandler : WebSocketHandler
{
// not mandatory
public MyHandler()
:this(null)
{}
// mandatory
public MyHandler(int? maxIncomingMessageSize)
:base(maxIncomingMessageSize)
{}
}

Java bean validation: Optional fields annotation

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.

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