HHH-18832 Don't skip bytecode enhancement just because an entity has a `@Transient` getter

This commit is contained in:
Yoann Rodière 2024-11-08 16:06:15 +01:00
parent 9c96e84a58
commit 74c5c844c0
2 changed files with 100 additions and 10 deletions

View File

@ -462,6 +462,11 @@ public class EnhancerImpl implements Enhancer {
// convert field letter to lower case
methodFieldName = methodFieldName.substring(0, 1).toLowerCase() + methodFieldName.substring(1);
TypeList typeList = methodDescription.getDeclaredAnnotations().asTypeList();
if (typeList.stream().anyMatch(typeDefinitions ->
(typeDefinitions.getName().equals("jakarta.persistence.Transient")))) {
// transient property so ignore it
continue;
}
if (typeList.stream().anyMatch(typeDefinitions ->
(typeDefinitions.getName().contains("jakarta.persistence")))) {
propertyHasAnnotation = true;

View File

@ -4,9 +4,19 @@
*/
package org.hibernate.orm.test.bytecode.enhancement.access;
import jakarta.persistence.*;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Basic;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
import org.hibernate.testing.orm.junit.*;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.FailureExpected;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
@ -15,16 +25,17 @@ import static org.assertj.core.api.Assertions.assertThat;
@DomainModel(
annotatedClasses = {
InvalidPropertyNameTest.SomeEntity.class,
InvalidPropertyNameTest.SomeEntityWithFalsePositive.class
}
)
@SessionFactory
@JiraKey("HHH-16572")
@BytecodeEnhanced
public class InvalidPropertyNameTest {
@Test
@FailureExpected(jiraKey = "HHH-16572")
@JiraKey("HHH-16572")
public void test(SessionFactoryScope scope) {
scope.inTransaction( session -> {
session.persist( new SomeEntity( 1L, "field", "property" ) );
@ -43,15 +54,40 @@ public class InvalidPropertyNameTest {
} );
}
@AfterEach
public void cleanup(SessionFactoryScope scope) {
// uncomment the following when @FailureExpected is removed above
// scope.inTransaction( session -> {
// session.remove( session.get( SomeEntity.class, 1L ) );
// PropertyAccessTest} );
@Test
@JiraKey("HHH-18832")
public void testNoFalsePositive(SessionFactoryScope scope) {
scope.inTransaction( session -> {
session.persist( new SomeEntityWithFalsePositive( 1L, "property1-initial", "property2-initial" ) );
} );
// Before HHH-18832 was fixed, lazy-loading enhancement was (incorrectly) skipped,
// resulting at best in `property1` being null in the code below,
// 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()'
// (see https://hibernate.zulipchat.com/#narrow/channel/132094-hibernate-orm-dev/topic/HHH-16572/near/481330806)
scope.inTransaction( session -> {
SomeEntityWithFalsePositive entity = session.getReference( SomeEntityWithFalsePositive.class, 1L );
// Lazy-loading triggered by field access
// Proves bytecode enhancement is effective
assertThat( entity.property1 ).isEqualTo( "property1-initial" );
} );
scope.inTransaction( session -> {
SomeEntityWithFalsePositive entity = session.getReference( SomeEntityWithFalsePositive.class, 1L );
// Proves bytecode enhancement is effective even for the transient method
assertThat( entity.getProperty() ).isEqualTo( "property1-initial property2-initial" );
} );
}
@Entity
@AfterEach
public void cleanup(SessionFactoryScope scope) {
scope.inTransaction( session -> {
session.createQuery( "delete from SomeEntity" ).executeUpdate();
session.createQuery( "delete from SomeEntityWithFalsePositive" ).executeUpdate();
} );
}
@Entity(name = "SomeEntity")
@Table(name = "SOME_ENTITY")
static class SomeEntity {
@Id
@ -88,4 +124,53 @@ public class InvalidPropertyNameTest {
this.property = property;
}
}
@Entity(name = "SomeEntityWithFalsePositive")
static class SomeEntityWithFalsePositive {
private Long id;
private String property1;
private String property2;
public SomeEntityWithFalsePositive() {
}
public SomeEntityWithFalsePositive(Long id, String property1, String property2) {
this.id = id;
this.property1 = property1;
this.property2 = property2;
}
@Id
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getProperty1() {
return property1;
}
public void setProperty1(String property1) {
this.property1 = property1;
}
public String getProperty2() {
return property2;
}
public void setProperty2(String property2) {
this.property2 = property2;
}
@Transient
public String getProperty() {
return property1 + " " + property2;
}
}
}