Skip to content

Commit 1ffde48

Browse files
committed
HHH-18832 Don't skip bytecode enhancement just because an entity has a @Transient getter
1 parent abfe6b9 commit 1ffde48

File tree

2 files changed

+98
-8
lines changed

2 files changed

+98
-8
lines changed

hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,11 @@ else if (methodName.startsWith("get") ||
464464
// convert field letter to lower case
465465
methodFieldName = methodFieldName.substring(0, 1).toLowerCase() + methodFieldName.substring(1);
466466
TypeList typeList = methodDescription.getDeclaredAnnotations().asTypeList();
467+
if (typeList.stream().anyMatch(typeDefinitions ->
468+
(typeDefinitions.getName().equals("jakarta.persistence.Transient")))) {
469+
// transient property so ignore it
470+
continue;
471+
}
467472
if (typeList.stream().anyMatch(typeDefinitions ->
468473
(typeDefinitions.getName().contains("jakarta.persistence")))) {
469474
propertyHasAnnotation = true;

hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/access/InvalidPropertyNameTest.java

Lines changed: 93 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
11
package org.hibernate.orm.test.bytecode.enhancement.access;
22

3-
import jakarta.persistence.*;
3+
import jakarta.persistence.Access;
4+
import jakarta.persistence.AccessType;
5+
import jakarta.persistence.Basic;
6+
import jakarta.persistence.Entity;
7+
import jakarta.persistence.Id;
8+
import jakarta.persistence.Table;
9+
import jakarta.persistence.Transient;
410
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
5-
import org.hibernate.testing.orm.junit.*;
11+
import org.hibernate.testing.orm.junit.DomainModel;
12+
import org.hibernate.testing.orm.junit.FailureExpected;
13+
import org.hibernate.testing.orm.junit.JiraKey;
14+
import org.hibernate.testing.orm.junit.SessionFactory;
15+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
616
import org.junit.jupiter.api.AfterEach;
717
import org.junit.jupiter.api.Test;
818

@@ -11,16 +21,17 @@
1121
@DomainModel(
1222
annotatedClasses = {
1323
InvalidPropertyNameTest.SomeEntity.class,
24+
InvalidPropertyNameTest.SomeEntityWithFalsePositive.class
1425
}
1526
)
1627
@SessionFactory
17-
@JiraKey("HHH-16572")
1828
@BytecodeEnhanced
1929
public class InvalidPropertyNameTest {
2030

2131

2232
@Test
2333
@FailureExpected(jiraKey = "HHH-16572")
34+
@JiraKey("HHH-16572")
2435
public void test(SessionFactoryScope scope) {
2536
scope.inTransaction( session -> {
2637
session.persist( new SomeEntity( 1L, "field", "property" ) );
@@ -39,15 +50,40 @@ public void test(SessionFactoryScope scope) {
3950
} );
4051
}
4152

53+
@Test
54+
@JiraKey("HHH-18832")
55+
public void testNoFalsePositive(SessionFactoryScope scope) {
56+
scope.inTransaction( session -> {
57+
session.persist( new SomeEntityWithFalsePositive( 1L, "property1-initial", "property2-initial" ) );
58+
} );
59+
60+
// Before HHH-18832 was fixed, lazy-loading enhancement was (incorrectly) skipped,
61+
// resulting at best in `property1` being null in the code below,
62+
// at worst in other errors such as java.lang.NoSuchMethodError: 'java.lang.String org.hibernate.orm.test.bytecode.enhancement.access.InvalidPropertyNameTest$SomeEntityWithFalsePositive.$$_hibernate_read_property1()'
63+
// (see https://hibernate.zulipchat.com/#narrow/channel/132094-hibernate-orm-dev/topic/HHH-16572/near/481330806)
64+
scope.inTransaction( session -> {
65+
SomeEntityWithFalsePositive entity = session.getReference( SomeEntityWithFalsePositive.class, 1L );
66+
// Lazy-loading triggered by field access
67+
// Proves bytecode enhancement is effective
68+
assertThat( entity.property1 ).isEqualTo( "property1-initial" );
69+
} );
70+
71+
scope.inTransaction( session -> {
72+
SomeEntityWithFalsePositive entity = session.getReference( SomeEntityWithFalsePositive.class, 1L );
73+
// Proves bytecode enhancement is effective even for the transient method
74+
assertThat( entity.getProperty() ).isEqualTo( "property1-initial property2-initial" );
75+
} );
76+
}
77+
4278
@AfterEach
4379
public void cleanup(SessionFactoryScope scope) {
44-
// uncomment the following when @FailureExpected is removed above
45-
// scope.inTransaction( session -> {
46-
// session.remove( session.get( SomeEntity.class, 1L ) );
47-
// PropertyAccessTest} );
80+
scope.inTransaction( session -> {
81+
session.createQuery( "delete from SomeEntity" ).executeUpdate();
82+
session.createQuery( "delete from SomeEntityWithFalsePositive" ).executeUpdate();
83+
} );
4884
}
4985

50-
@Entity
86+
@Entity(name = "SomeEntity")
5187
@Table(name = "SOME_ENTITY")
5288
static class SomeEntity {
5389
@Id
@@ -84,4 +120,53 @@ public void setPropertyMethod(String property) {
84120
this.property = property;
85121
}
86122
}
123+
124+
@Entity(name = "SomeEntityWithFalsePositive")
125+
static class SomeEntityWithFalsePositive {
126+
127+
private Long id;
128+
129+
private String property1;
130+
131+
private String property2;
132+
133+
public SomeEntityWithFalsePositive() {
134+
}
135+
136+
public SomeEntityWithFalsePositive(Long id, String property1, String property2) {
137+
this.id = id;
138+
this.property1 = property1;
139+
this.property2 = property2;
140+
}
141+
142+
@Id
143+
public long getId() {
144+
return id;
145+
}
146+
147+
public void setId(long id) {
148+
this.id = id;
149+
}
150+
151+
public String getProperty1() {
152+
return property1;
153+
}
154+
155+
public void setProperty1(String property1) {
156+
this.property1 = property1;
157+
}
158+
159+
public String getProperty2() {
160+
return property2;
161+
}
162+
163+
public void setProperty2(String property2) {
164+
this.property2 = property2;
165+
}
166+
167+
@Transient
168+
public String getProperty() {
169+
return property1 + " " + property2;
170+
}
171+
}
87172
}

0 commit comments

Comments
 (0)