Bad validator performance when adding obsolete @Validated to Java value objects
Description
Environment
Attachments
Activity

Anatoliy BalakirevJanuary 10, 2023 at 5:05 PM
Just to give more use-cases to this issue: we now have exactly the same problem for beans, generated by the “openapi-generator-maven-plugin”. I’ve described it here: And in our case the fix is not so trivial, as it will have to go to that plugin eventually.

Peter WalserNovember 11, 2022 at 11:16 AM
Profiled with JVisualVM:
Almost all of the time is burnt in AbstractValidationContext.isAlreadyValidatedForPath
calling AbstractValidationContext.isSubPathOf
.

Peter WalserNovember 11, 2022 at 11:04 AMEdited
When I wrap the values into value objects (with @Valid), the validation runs very fast (although it supposedly does the same: recurse into values with @Valid and validate with @NotNull and @Min ):
0 items, avg. validation time: 49.520402 ms
1 items, avg. validation time: 50.609528 ms
2 items, avg. validation time: 50.88673 ms
5 items, avg. validation time: 50.236684 ms
10 items, avg. validation time: 49.789304 ms
20 items, avg. validation time: 48.713483 ms
50 items, avg. validation time: 50.069192 ms
100 items, avg. validation time: 50.027649 ms
200 items, avg. validation time: 49.037075 ms
500 items, avg. validation time: 50.690123 ms
1000 items, avg. validation time: 50.057061 ms
2500 items, avg. validation time: 49.99966 ms
5000 items, avg. validation time: 48.518808 ms
7500 items, avg. validation time: 50.0492 ms
10000 items, avg. validation time: 50.01165 ms
20000 items, avg. validation time: 48.984054 ms
30000 items, avg. validation time: 51.152249 ms
40000 items, avg. validation time: 50.320894 ms
50000 items, avg. validation time: 50.039272 ms
That would actually be the expected outcome if I add a @Validated onto a value object: a slight overhead, but no exponential growth.

Peter WalserNovember 11, 2022 at 10:55 AM
The validation time also grows exponentially with the number of items:
0 items, avg. validation time: 0.078653 ms
1 items, avg. validation time: 0.233635 ms
2 items, avg. validation time: 0.277518 ms
5 items, avg. validation time: 0.442096 ms
10 items, avg. validation time: 0.386543 ms
20 items, avg. validation time: 0.352659 ms
50 items, avg. validation time: 0.69204 ms
100 items, avg. validation time: 1.090923 ms
200 items, avg. validation time: 2.762619 ms
500 items, avg. validation time: 7.474321 ms
1000 items, avg. validation time: 27.675976 ms
2500 items, avg. validation time: 184.583688 ms
5000 items, avg. validation time: 624.382551 ms
7500 items, avg. validation time: 1262.320178 ms
10000 items, avg. validation time: 2125.455512 ms
20000 items, avg. validation time: 8322.531352 ms
30000 items, avg. validation time: 19281.462 ms

Guillaume SmetNovember 9, 2022 at 1:22 PM
I’m not sure “obsolete” is the right word. @Valid
was always supposed to only be used to cascade the validation to beans. You should only use it when you want the validation to cascade. The way you used it has always been not recommended at all.
I’m not sure we can really ignore internal types as we could imagine someone adding constraints to these types via the programmatic API. Even if it’s far fetched, it would still be a valid use case of Hibernate Validator.
Now I wonder if we could optimize the case if we don’t have any constraints for this particular class. I’m not sure we have the information when gathering the metadata though.
And really, you shouldn’t have used @Valid
in the first place so that’s an easy fix.
We are making progress to disable bean tracking in certain cases but it will only be doable for projects using Quarkus (or a similar infrastructure) as it requires to live in a closed world assumption and have the list of all the potentially validated beans.
Now, it might be a good idea to run your benchmark with async profiler and share the flame graphs. There might be some improvements we could do.
Details
Assignee
UnassignedUnassignedReporter
Peter WalserPeter WalserBug Testcase Reminder (view)
Bug reports should generally be accompanied by a test case!
Bug Testcase Reminder (edit)
Bug reports should generally be accompanied by a test case!
backPortable
Backport?Participants
Anatoliy Balakirev
Guillaume Smet
Peter WalserComponents
Affects versions
Priority
Major
Details
Details
Assignee
Reporter

Bug Testcase Reminder (view)
Bug reports should generally be accompanied by a test case!
Bug Testcase Reminder (edit)
Bug reports should generally be accompanied by a test case!
backPortable
Participants



I ran into a performance issue with Java Bean Validation (Hibernate Validator) on a large object, which caused the validation to run several orders slower.
I was able to isolate and reproduce it with the following example code:
Example DTOs
Let's say we have a Order with Items:
The Items look like this:
Bean Validation and Benchmark
Let's create an order with 20000 items, and benchmark how long it takes to validate it (while also verifying that it is validated):
Benchmark times:
The issue
Obviously, the
@Valid
annotations on theItem
id (Long)
andquantity (int)
are obsolete (this annotation hints that the validation should recurse into a bean or collection, which neither of these values are). If I remove them and run the validation benchmark again, the times look good (while still having the correct validation outcome):This basically affects all value objects, where a
@Valid
was annotated:String
andCharacter
all
Number
classes (Integer
,Long
, …,BigInteger
,BigDecimal
)all
enum
typesJava Date/Time value objects (
LocalDate
,LocalTime
,LocalDateTime
,OffsetDateTime
, …)other Java value objects (
UUID
,InetAddress
, …)The performance impact is non-linear, and seems to grow exponentially with the number of items in that list.
Expectation: the
@Valid
should be ignored for Java-internal value objects (as listed above), as it is obsolete, and has a critical performance impact.