From c0652a5359fc5166d6f9f67b1f54992dae212225 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Thu, 24 May 2018 14:17:12 +0200 Subject: [PATCH] HHH-12579 Use the field description with type variables resolved to cast the return value of the $$_hibernate_read_() method --- .../bytebuddy/FieldReaderAppender.java | 25 ++++--- ...nValueMappedSuperclassEnhancementTest.java | 69 +++++++++++++++++++ 2 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/GenericReturnValueMappedSuperclassEnhancementTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldReaderAppender.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldReaderAppender.java index a23f0d9cbf..5098c04290 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldReaderAppender.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldReaderAppender.java @@ -24,19 +24,22 @@ abstract class FieldReaderAppender implements ByteCodeAppender { protected final TypeDescription managedCtClass; - protected final FieldDescription persistentFieldAsDefined; + protected final FieldDescription persistentField; - private FieldReaderAppender(TypeDescription managedCtClass, FieldDescription.InDefinedShape persistentFieldAsDefined) { + protected final FieldDescription.InDefinedShape persistentFieldAsDefined; + + private FieldReaderAppender(TypeDescription managedCtClass, FieldDescription persistentField) { this.managedCtClass = managedCtClass; - this.persistentFieldAsDefined = persistentFieldAsDefined; + this.persistentField = persistentField; + this.persistentFieldAsDefined = persistentField.asDefined(); } static ByteCodeAppender of(TypeDescription managedCtClass, FieldDescription persistentField) { if ( !persistentField.isVisibleTo( managedCtClass ) ) { - return new MethodDispatching( managedCtClass, persistentField.asDefined() ); + return new MethodDispatching( managedCtClass, persistentField ); } else { - return new FieldWriting( managedCtClass, persistentField.asDefined() ); + return new FieldWriting( managedCtClass, persistentField ); } } @@ -100,6 +103,10 @@ abstract class FieldReaderAppender implements ByteCodeAppender { // return field methodVisitor.visitVarInsn( Opcodes.ALOAD, 0 ); fieldRead( methodVisitor ); + if ( !persistentField.getType().isPrimitive() + && !persistentField.getType().asErasure().getInternalName().equals( persistentFieldAsDefined.getType().asErasure().getInternalName() ) ) { + methodVisitor.visitTypeInsn( Opcodes.CHECKCAST, persistentField.getType().asErasure().getInternalName() ); + } methodVisitor.visitInsn( Type.getType( persistentFieldAsDefined.getType().asErasure().getDescriptor() ).getOpcode( Opcodes.IRETURN ) ); return new Size( 4 + persistentFieldAsDefined.getType().getStackSize().getSize(), instrumentedMethod.getStackSize() ); } @@ -110,8 +117,8 @@ abstract class FieldReaderAppender implements ByteCodeAppender { private static class FieldWriting extends FieldReaderAppender { - private FieldWriting(TypeDescription managedCtClass, FieldDescription.InDefinedShape persistentFieldAsDefined) { - super( managedCtClass, persistentFieldAsDefined ); + private FieldWriting(TypeDescription managedCtClass, FieldDescription persistentField) { + super( managedCtClass, persistentField ); } @Override @@ -137,8 +144,8 @@ abstract class FieldReaderAppender implements ByteCodeAppender { private static class MethodDispatching extends FieldReaderAppender { - private MethodDispatching(TypeDescription managedCtClass, FieldDescription.InDefinedShape persistentFieldAsDefined) { - super( managedCtClass, persistentFieldAsDefined ); + private MethodDispatching(TypeDescription managedCtClass, FieldDescription persistentField) { + super( managedCtClass, persistentField ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/GenericReturnValueMappedSuperclassEnhancementTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/GenericReturnValueMappedSuperclassEnhancementTest.java new file mode 100644 index 0000000000..a4c6a59f26 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/GenericReturnValueMappedSuperclassEnhancementTest.java @@ -0,0 +1,69 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.basic; + +import static org.junit.Assert.assertEquals; + +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; + +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(BytecodeEnhancerRunner.class) +public class GenericReturnValueMappedSuperclassEnhancementTest { + + @Test + @TestForIssue(jiraKey = "HHH-12579") + public void enhanceClassWithGenericReturnValueOnMappedSuperclass() { + SimpleEntity implementation = new SimpleEntity(); + + implementation.setEntity( SimpleEntity.Type.ONE ); + + assertEquals( SimpleEntity.Type.ONE, implementation.getEntity() ); + } + + @MappedSuperclass + @Cache(usage = CacheConcurrencyStrategy.NONE) + public static class AbstractMappedSuperclassWithGenericReturnValue { + + @Id + @GeneratedValue + public int id; + + @Access(AccessType.PROPERTY) + private T entity; + + public T getEntity() { + return entity; + } + + public void setEntity(T entity) { + this.entity = entity; + } + } + + public interface Marker { + } + + @Entity + @Cache(usage = CacheConcurrencyStrategy.NONE) + public static class SimpleEntity extends AbstractMappedSuperclassWithGenericReturnValue { + + public enum Type implements Marker { + ONE + } + } +}