Skip to content

Commit 74c5c84

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

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
@@ -462,6 +462,11 @@ else if (methodName.startsWith("get") ||
462462
// convert field letter to lower case
463463
methodFieldName = methodFieldName.substring(0, 1).toLowerCase() + methodFieldName.substring(1);
464464
TypeList typeList = methodDescription.getDeclaredAnnotations().asTypeList();
465+
if (typeList.stream().anyMatch(typeDefinitions ->
466+
(typeDefinitions.getName().equals("jakarta.persistence.Transient")))) {
467+
// transient property so ignore it
468+
continue;
469+
}
465470
if (typeList.stream().anyMatch(typeDefinitions ->
466471
(typeDefinitions.getName().contains("jakarta.persistence")))) {
467472
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
@@ -4,9 +4,19 @@
44
*/
55
package org.hibernate.orm.test.bytecode.enhancement.access;
66

7-
import jakarta.persistence.*;
7+
import jakarta.persistence.Access;
8+
import jakarta.persistence.AccessType;
9+
import jakarta.persistence.Basic;
10+
import jakarta.persistence.Entity;
11+
import jakarta.persistence.Id;
12+
import jakarta.persistence.Table;
13+
import jakarta.persistence.Transient;
814
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
9-
import org.hibernate.testing.orm.junit.*;
15+
import org.hibernate.testing.orm.junit.DomainModel;
16+
import org.hibernate.testing.orm.junit.FailureExpected;
17+
import org.hibernate.testing.orm.junit.JiraKey;
18+
import org.hibernate.testing.orm.junit.SessionFactory;
19+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
1020
import org.junit.jupiter.api.AfterEach;
1121
import org.junit.jupiter.api.Test;
1222

@@ -15,16 +25,17 @@
1525
@DomainModel(
1626
annotatedClasses = {
1727
InvalidPropertyNameTest.SomeEntity.class,
28+
InvalidPropertyNameTest.SomeEntityWithFalsePositive.class
1829
}
1930
)
2031
@SessionFactory
21-
@JiraKey("HHH-16572")
2232
@BytecodeEnhanced
2333
public class InvalidPropertyNameTest {
2434

2535

2636
@Test
2737
@FailureExpected(jiraKey = "HHH-16572")
38+
@JiraKey("HHH-16572")
2839
public void test(SessionFactoryScope scope) {
2940
scope.inTransaction( session -> {
3041
session.persist( new SomeEntity( 1L, "field", "property" ) );
@@ -43,15 +54,40 @@ public void test(SessionFactoryScope scope) {
4354
} );
4455
}
4556

57+
@Test
58+
@JiraKey("HHH-18832")
59+
public void testNoFalsePositive(SessionFactoryScope scope) {
60+
scope.inTransaction( session -> {
61+
session.persist( new SomeEntityWithFalsePositive( 1L, "property1-initial", "property2-initial" ) );
62+
} );
63+
64+
// Before HHH-18832 was fixed, lazy-loading enhancement was (incorrectly) skipped,
65+
// resulting at best in `property1` being null in the code below,
66+
// 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()'
67+
// (see https://hibernate.zulipchat.com/#narrow/channel/132094-hibernate-orm-dev/topic/HHH-16572/near/481330806)
68+
scope.inTransaction( session -> {
69+
SomeEntityWithFalsePositive entity = session.getReference( SomeEntityWithFalsePositive.class, 1L );
70+
// Lazy-loading triggered by field access
71+
// Proves bytecode enhancement is effective
72+
assertThat( entity.property1 ).isEqualTo( "property1-initial" );
73+
} );
74+
75+
scope.inTransaction( session -> {
76+
SomeEntityWithFalsePositive entity = session.getReference( SomeEntityWithFalsePositive.class, 1L );
77+
// Proves bytecode enhancement is effective even for the transient method
78+
assertThat( entity.getProperty() ).isEqualTo( "property1-initial property2-initial" );
79+
} );
80+
}
81+
4682
@AfterEach
4783
public void cleanup(SessionFactoryScope scope) {
48-
// uncomment the following when @FailureExpected is removed above
49-
// scope.inTransaction( session -> {
50-
// session.remove( session.get( SomeEntity.class, 1L ) );
51-
// PropertyAccessTest} );
84+
scope.inTransaction( session -> {
85+
session.createQuery( "delete from SomeEntity" ).executeUpdate();
86+
session.createQuery( "delete from SomeEntityWithFalsePositive" ).executeUpdate();
87+
} );
5288
}
5389

54-
@Entity
90+
@Entity(name = "SomeEntity")
5591
@Table(name = "SOME_ENTITY")
5692
static class SomeEntity {
5793
@Id
@@ -88,4 +124,53 @@ public void setPropertyMethod(String property) {
88124
this.property = property;
89125
}
90126
}
127+
128+
@Entity(name = "SomeEntityWithFalsePositive")
129+
static class SomeEntityWithFalsePositive {
130+
131+
private Long id;
132+
133+
private String property1;
134+
135+
private String property2;
136+
137+
public SomeEntityWithFalsePositive() {
138+
}
139+
140+
public SomeEntityWithFalsePositive(Long id, String property1, String property2) {
141+
this.id = id;
142+
this.property1 = property1;
143+
this.property2 = property2;
144+
}
145+
146+
@Id
147+
public long getId() {
148+
return id;
149+
}
150+
151+
public void setId(long id) {
152+
this.id = id;
153+
}
154+
155+
public String getProperty1() {
156+
return property1;
157+
}
158+
159+
public void setProperty1(String property1) {
160+
this.property1 = property1;
161+
}
162+
163+
public String getProperty2() {
164+
return property2;
165+
}
166+
167+
public void setProperty2(String property2) {
168+
this.property2 = property2;
169+
}
170+
171+
@Transient
172+
public String getProperty() {
173+
return property1 + " " + property2;
174+
}
175+
}
91176
}

0 commit comments

Comments
 (0)