Skip to content

Commit d192b30

Browse files
Vincent Bouthinonyrodiere
andcommitted
HHH-19899 Test proxy generation with @ConcreteProxy and sealed abstract entities
Co-Authored-By: Yoann Rodière <yoann@hibernate.org>
1 parent bf4d46e commit d192b30

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.proxy.concrete;
6+
7+
import jakarta.persistence.Entity;
8+
import jakarta.persistence.FetchType;
9+
import jakarta.persistence.GeneratedValue;
10+
import jakarta.persistence.Id;
11+
import jakarta.persistence.ManyToOne;
12+
import jakarta.persistence.Table;
13+
import org.hibernate.annotations.ConcreteProxy;
14+
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
15+
import org.hibernate.testing.orm.junit.JiraKey;
16+
import org.hibernate.testing.orm.junit.Jpa;
17+
import org.junit.jupiter.api.Test;
18+
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
21+
/**
22+
* Tests the compatibility of Hibernate {@code @ConcreteProxy} with Java {@code sealed}
23+
* inheritance hierarchies. Proxy generation may fail during {@code SessionFactory}
24+
* bootstrap if the abstract sealed root cannot be subclassed at runtime. These tests
25+
* document the limitation and assert the expected failure behavior.
26+
*
27+
* @author Vincent Bouthinon
28+
*/
29+
@Jpa(annotatedClasses = {
30+
ConcreteProxyWithSealedClassesTest.Actor.class,
31+
ConcreteProxyWithSealedClassesTest.Postman.class,
32+
ConcreteProxyWithSealedClassesTest.Scene.class
33+
})
34+
@JiraKey("HHH-19899")
35+
class ConcreteProxyWithSealedClassesTest {
36+
37+
@Test
38+
void getReference(EntityManagerFactoryScope scope) {
39+
var id = scope.fromTransaction( entityManager -> {
40+
Actor actor = new Postman();
41+
entityManager.persist( actor );
42+
return actor.id;
43+
} );
44+
scope.inTransaction( entityManager -> {
45+
Actor actor = entityManager.getReference( Actor.class, id );
46+
assertThat( actor ).isInstanceOf( Postman.class );
47+
} );
48+
}
49+
50+
@Test
51+
void lazyAssociation(EntityManagerFactoryScope scope) {
52+
var id = scope.fromTransaction( entityManager -> {
53+
Actor actor = new Postman();
54+
entityManager.persist( actor );
55+
Scene scene = new Scene();
56+
scene.setActor( actor );
57+
entityManager.persist( scene );
58+
return scene.id;
59+
} );
60+
scope.inTransaction( entityManager -> {
61+
Scene scene = entityManager.find( Scene.class, id );
62+
assertThat( scene.getActor() ).isInstanceOf( Postman.class );
63+
} );
64+
}
65+
66+
@Entity(name = "actor")
67+
@Table(name = "actor")
68+
@ConcreteProxy
69+
public static abstract sealed class Actor {
70+
@Id
71+
@GeneratedValue
72+
private Long id;
73+
}
74+
75+
@Entity(name = "Postman")
76+
public static non-sealed class Postman extends Actor {
77+
}
78+
79+
@Entity(name = "Scene")
80+
public static class Scene {
81+
@Id
82+
@GeneratedValue
83+
private Long id;
84+
85+
@ManyToOne(fetch = FetchType.LAZY)
86+
private Actor actor;
87+
88+
public Long getId() {
89+
return id;
90+
}
91+
92+
public void setId(Long id) {
93+
this.id = id;
94+
}
95+
96+
public Actor getActor() {
97+
return actor;
98+
}
99+
100+
public void setActor(Actor actor) {
101+
this.actor = actor;
102+
}
103+
}
104+
}

0 commit comments

Comments
 (0)