[JIRA] (HV-1928) Bad validator performance when adding obsolete @Validated to Java value objects
by Peter Walser (JIRA)
Peter Walser ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=557058%... ) *created* an issue
Hibernate Validator ( https://hibernate.atlassian.net/browse/HV?atlOrigin=eyJpIjoiMDRjNDA3ZmE4N... ) / Bug ( https://hibernate.atlassian.net/browse/HV-1928?atlOrigin=eyJpIjoiMDRjNDA3... ) HV-1928 ( https://hibernate.atlassian.net/browse/HV-1928?atlOrigin=eyJpIjoiMDRjNDA3... ) Bad validator performance when adding obsolete @Validated to Java value objects ( https://hibernate.atlassian.net/browse/HV-1928?atlOrigin=eyJpIjoiMDRjNDA3... )
Issue Type: Bug Affects Versions: 6.2.0.Final Assignee: Unassigned Components: performance Created: 08/Nov/2022 02:18 AM Environment: Java 11, Linux, Hibernate Validator 6.2.0.Final Priority: Major Reporter: Peter Walser ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=557058%... )
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:
public class Order {
private List<Item> items = new ArrayList<>();
@Valid public List<Item> getItems() { return items; }
public void setItems(List<Item> items) { this.items = items; }
}
The Items look like this:
public class Item {
private Long id;
private int quantity;
@NotNull @Valid public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
@Min(1) @Valid public int getQuantity() { return quantity; }
public void setQuantity(int quantity) { this.quantity = quantity; }
}
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):
class ValidationBenchmarkTest {
private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
@Test
void shouldValidateLargeMessage() {
Order order = new Order();
AtomicLong sequence = new AtomicLong();
for (int i = 0; i < 20000; i++) {
Item item = new Item();
item.setId(sequence.getAndIncrement());
item.setQuantity(1);
order.getItems().add(item);
}
// add invalid item
Item item = new Item();
item.setId(sequence.getAndIncrement());
item.setQuantity(-5);
order.getItems().add(item);
for (int i = 1; i <= 100; i++) {
long time = System.nanoTime();
var constraintViolations = validator.validate(order);
time = System.nanoTime() - time;
System.out.println("validate: " + (time / 1000000d) + " ms");
Assertions.assertThat(constraintViolations.size()).isEqualTo(1);
}
}
}
Benchmark times:
validate: 8469.735456 ms
validate: 8703.256756 ms
validate: 8544.319874 ms
validate: 8452.748767 ms
validate: 8572.898554 ms
The issue
---------
Obviously, the @Valid annotations on the Item id (Long) and quantity (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):
public class Item {
private Long id;
private int quantity;
@NotNull public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
@Min(1) public int getQuantity() { return quantity; }
public void setQuantity(int quantity) { this.quantity = quantity; }
}
validate: 23.015353 ms
validate: 23.239134 ms
validate: 22.970314 ms
validate: 22.875604 ms
This basically affects all value objects, where a @Valid was annotated:
* String and Character
* all Number classes ( Integer , Long , …, BigInteger , BigDecimal )
* all enum types
* Java 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.
( https://hibernate.atlassian.net/browse/HV-1928#add-comment?atlOrigin=eyJp... ) Add Comment ( https://hibernate.atlassian.net/browse/HV-1928#add-comment?atlOrigin=eyJp... )
Get Jira notifications on your phone! Download the Jira Cloud app for Android ( https://play.google.com/store/apps/details?id=com.atlassian.android.jira.... ) or iOS ( https://itunes.apple.com/app/apple-store/id1006972087?pt=696495&ct=EmailN... ) This message was sent by Atlassian Jira (v1001.0.0-SNAPSHOT#100210- sha1:ffe1a02 )
1 year, 10 months
[JIRA] (HHH-15688) Entity with lazy loaded association ignores filters
by Martin Hlavňa (JIRA)
Martin Hlavňa ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=557058%... ) *created* an issue
Hibernate ORM ( https://hibernate.atlassian.net/browse/HHH?atlOrigin=eyJpIjoiODNkOGIzZTA1... ) / Bug ( https://hibernate.atlassian.net/browse/HHH-15688?atlOrigin=eyJpIjoiODNkOG... ) HHH-15688 ( https://hibernate.atlassian.net/browse/HHH-15688?atlOrigin=eyJpIjoiODNkOG... ) Entity with lazy loaded association ignores filters ( https://hibernate.atlassian.net/browse/HHH-15688?atlOrigin=eyJpIjoiODNkOG... )
Issue Type: Bug Affects Versions: 6.1.3 Assignee: Unassigned Created: 08/Nov/2022 02:10 AM Environment: Wildfly 27.Beta.1 , Java 17
Probably also affects 6.1.4 and 6.1.5 but we are using Hibernate provided in platform. Priority: Major Reporter: Martin Hlavňa ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=557058%... )
I am implementing soft delete with Hibernate. Each entity that supports soft-deleting has an attribute for it.
@Column(name = "DELETED")
private boolean deleted;
I have created @FilterDef in package-info.java for package with domain objects.
@FilterDef(name = "deletedFilter",
parameters = @ParamDef(name = "includeDeleted", type = Boolean.class),
defaultCondition = ":includeDeleted = true OR DELETED = false"
)
applied it to all DeleteAware entities
@Filter(name = "deletedFilter")
public class CustomerGroup
and enabled in when using in queries
Session session = em.unwrap(Session.class);
session.enableFilter("deletedFilter")
.setParameter("includeDeleted", fp.isDeleted());
Filter is applied and works correctly for primary entity (for example when I query customers I can see that additional where condition is always applied as needed).
Problem is with filter of association. Let's say Customer entity has collection of CustomerGroup.
@ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
@JoinTable(name = "CUSTOMER_CUSTOMER_GROUP",
joinColumns = @JoinColumn(name = "CUSTOMER_ID"),
inverseJoinColumns = @JoinColumn(name = "CUSTOMER_GROUP_ID"))
private Set<CustomerGroup> groups;
However when I query for Customer, groups collection contains deleted entities. I have turned on sql logging and I can see that condition is not applied for lazy query. However if I change
@ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
to
@ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.EAGER)
it works.
Both entities are annotated with @Filter. I have also tried applying @Filter annotation to collection itself without success. For initial testing I have also ensured that filters are not disabled and includeDeleted parameter is always false.
@Where annotation on entities works like a charm, but cannot be disabled (99% of queries we want to filter out deleted objects but there is that pesky 1% where we need deleted ones).
Looks like filters are not applied when relation is lazy loaded.
( https://hibernate.atlassian.net/browse/HHH-15688#add-comment?atlOrigin=ey... ) Add Comment ( https://hibernate.atlassian.net/browse/HHH-15688#add-comment?atlOrigin=ey... )
Get Jira notifications on your phone! Download the Jira Cloud app for Android ( https://play.google.com/store/apps/details?id=com.atlassian.android.jira.... ) or iOS ( https://itunes.apple.com/app/apple-store/id1006972087?pt=696495&ct=EmailN... ) This message was sent by Atlassian Jira (v1001.0.0-SNAPSHOT#100210- sha1:ffe1a02 )
1 year, 10 months