Skip to content

Commit 537dc79

Browse files
authored
Merge pull request #50157 from marko-bekhta/test/i49865-add-test-for-hr-and-validator-traversable-resolver
Test that Hibernate Validator does not attempt to fetch lazy associations with Hibernate Reactive
2 parents d862a45 + df29637 commit 537dc79

File tree

4 files changed

+226
-0
lines changed

4 files changed

+226
-0
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package io.quarkus.hibernate.reactive.validation;
2+
3+
import jakarta.persistence.Entity;
4+
import jakarta.persistence.GeneratedValue;
5+
import jakarta.persistence.GenerationType;
6+
import jakarta.persistence.Id;
7+
import jakarta.persistence.ManyToOne;
8+
import jakarta.persistence.Table;
9+
import jakarta.validation.constraints.Size;
10+
11+
@Table(name = "my_lazy_entity_child_table")
12+
@Entity
13+
public class MyLazyChildEntity {
14+
public interface SomeGroup {
15+
}
16+
17+
public static final String ENTITY_NAME_TOO_LONG = "entity name too long";
18+
private long id;
19+
20+
// Use a non-default validation group so that validation won't trigger an exception on persist:
21+
@Size(max = 5, message = ENTITY_NAME_TOO_LONG, groups = { SomeGroup.class })
22+
private String name;
23+
24+
private MyLazyEntity parent;
25+
26+
public MyLazyChildEntity() {
27+
}
28+
29+
public MyLazyChildEntity(String name) {
30+
this.name = name;
31+
}
32+
33+
@Id
34+
@GeneratedValue(strategy = GenerationType.IDENTITY)
35+
public long getId() {
36+
return id;
37+
}
38+
39+
public void setId(long id) {
40+
this.id = id;
41+
}
42+
43+
public String getName() {
44+
return name;
45+
}
46+
47+
public void setName(String name) {
48+
this.name = name;
49+
}
50+
51+
@ManyToOne
52+
public MyLazyEntity getParent() {
53+
return parent;
54+
}
55+
56+
public void setParent(MyLazyEntity parent) {
57+
this.parent = parent;
58+
}
59+
60+
@Override
61+
public String toString() {
62+
return "MyLazyChildEntity:" + name;
63+
}
64+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package io.quarkus.hibernate.reactive.validation;
2+
3+
import java.util.Set;
4+
5+
import jakarta.persistence.CascadeType;
6+
import jakarta.persistence.Entity;
7+
import jakarta.persistence.GeneratedValue;
8+
import jakarta.persistence.GenerationType;
9+
import jakarta.persistence.Id;
10+
import jakarta.persistence.OneToMany;
11+
import jakarta.persistence.Table;
12+
import jakarta.validation.Valid;
13+
14+
@Table(name = "my_lazy_entity_table")
15+
@Entity
16+
public class MyLazyEntity {
17+
private long id;
18+
19+
private String name;
20+
21+
private Set<@Valid MyLazyChildEntity> children;
22+
23+
public MyLazyEntity() {
24+
}
25+
26+
public MyLazyEntity(String name) {
27+
this.name = name;
28+
}
29+
30+
@Id
31+
@GeneratedValue(strategy = GenerationType.IDENTITY)
32+
public long getId() {
33+
return id;
34+
}
35+
36+
public void setId(long id) {
37+
this.id = id;
38+
}
39+
40+
public String getName() {
41+
return name;
42+
}
43+
44+
public void setName(String name) {
45+
this.name = name;
46+
}
47+
48+
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
49+
public Set<MyLazyChildEntity> getChildren() {
50+
return children;
51+
}
52+
53+
public void setChildren(Set<MyLazyChildEntity> children) {
54+
this.children = children;
55+
}
56+
57+
@Override
58+
public String toString() {
59+
return "MyLazyEntity:" + name;
60+
}
61+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package io.quarkus.hibernate.reactive.validation;
2+
3+
import java.util.Set;
4+
5+
import jakarta.enterprise.context.ApplicationScoped;
6+
import jakarta.inject.Inject;
7+
import jakarta.validation.Validator;
8+
import jakarta.ws.rs.GET;
9+
import jakarta.ws.rs.POST;
10+
import jakarta.ws.rs.Path;
11+
import jakarta.ws.rs.PathParam;
12+
13+
import org.hibernate.reactive.mutiny.Mutiny;
14+
15+
import io.smallrye.mutiny.Uni;
16+
17+
@Path("/validation")
18+
@ApplicationScoped
19+
public class ReactiveTestValidationTraversableResolverResource {
20+
21+
@Inject
22+
Mutiny.SessionFactory sessionFactory;
23+
24+
@Inject
25+
Validator validator;
26+
27+
@POST
28+
public Uni<Long> save() {
29+
return sessionFactory.withTransaction(s -> {
30+
MyLazyEntity entity = new MyLazyEntity();
31+
entity.setName("name");
32+
MyLazyChildEntity childEntity = new MyLazyChildEntity();
33+
childEntity.setParent(entity);
34+
childEntity.setName("123456789012345"); // should fail validation for the `SomeGroup` validation group.
35+
entity.setChildren(Set.of(childEntity));
36+
return s.persist(entity).map(v -> entity.getId());
37+
});
38+
}
39+
40+
@GET
41+
@Path("/{id}")
42+
public Uni<String> testPass(@PathParam("id") Long id) {
43+
return sessionFactory.withTransaction(s -> s.find(MyLazyEntity.class, id)
44+
// since the Validator shouldn't fetch a lazy association, there should be no failures here:
45+
.map(e -> validator.validate(e, MyLazyChildEntity.SomeGroup.class).isEmpty() ? "OK" : "KO"));
46+
}
47+
48+
@GET
49+
@Path("/fail/{id}")
50+
public Uni<String> testFail(@PathParam("id") Long id) {
51+
return sessionFactory.withTransaction(s -> s.find(MyLazyEntity.class, id)
52+
.chain(e -> Mutiny.fetch(e.getChildren()).map(c -> e))
53+
// Validating for a SomeGroup validation group should trigger a single constraint failure on a child object
54+
.map(e -> validator.validate(e, MyLazyChildEntity.SomeGroup.class).size() == 1 ? "OK" : "KO"));
55+
}
56+
57+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package io.quarkus.hibernate.reactive.validation;
2+
3+
import static org.hamcrest.Matchers.containsString;
4+
5+
import org.jboss.shrinkwrap.api.asset.StringAsset;
6+
import org.junit.jupiter.api.Test;
7+
import org.junit.jupiter.api.extension.RegisterExtension;
8+
9+
import io.quarkus.test.QuarkusUnitTest;
10+
import io.restassured.RestAssured;
11+
12+
public class ReactiveValidationTraversableResolverTestCase {
13+
14+
@RegisterExtension
15+
static QuarkusUnitTest runner = new QuarkusUnitTest()
16+
.withApplicationRoot((jar) -> jar
17+
.addClasses(MyLazyEntity.class, MyLazyChildEntity.class,
18+
ReactiveTestValidationTraversableResolverResource.class)
19+
.addAsResource("application.properties")
20+
.addAsResource(new StringAsset(""), "import.sql")); // define an empty import.sql file
21+
22+
@Test
23+
public void testPass() {
24+
Long id = Long.parseLong(RestAssured.post("/validation")
25+
.body()
26+
.asString());
27+
RestAssured.get("/validation/{id}", id)
28+
.then()
29+
.statusCode(200)
30+
.body(containsString("OK"));
31+
}
32+
33+
@Test
34+
public void testFail() {
35+
Long id = Long.parseLong(RestAssured.post("/validation")
36+
.body()
37+
.asString());
38+
RestAssured.get("/validation/fail/{id}", id)
39+
.then()
40+
.statusCode(200)
41+
.body(containsString("OK"));
42+
}
43+
44+
}

0 commit comments

Comments
 (0)