From 5cee742698ea36c4d830b129f6f3d2187bc950df Mon Sep 17 00:00:00 2001 From: Gavin King Date: Sun, 16 Jul 2023 14:34:46 +0200 Subject: [PATCH] HHH-16940 add typesafe ref to ManagedType in metamodel classes --- .../metamodel/internal/MetadataContext.java | 77 ++++++++++------- .../JPAMetaModelEntityProcessor.java | 8 +- .../annotation/AnnotationMetaEntity.java | 12 ++- .../annotation/AnnotationMetaType.java | 86 +++++++++++++++++++ .../hibernate/jpamodelgen/util/TypeUtils.java | 4 + 5 files changed, 148 insertions(+), 39 deletions(-) create mode 100644 tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaType.java diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java index f4e0b31bbb..5855ac0fc3 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java @@ -655,6 +655,12 @@ public class MetadataContext { final Class metamodelClass = Class.forName( metamodelClassName, true, managedTypeClass.getClassLoader() ); // we found the class; so populate it... registerAttributes( metamodelClass, managedType ); + try { + injectField( metamodelClass, "class_", managedType, false ); + } + catch (NoSuchFieldException e) { + // ignore + } } catch (ClassNotFoundException ignore) { // nothing to do... @@ -715,25 +721,39 @@ public class MetadataContext { attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.EMBEDDED || attribute.getDeclaringType().getPersistenceType() == Type.PersistenceType.EMBEDDABLE; - final Field field = allowNonDeclaredFieldReference - ? metamodelClass.getField( name ) - : metamodelClass.getDeclaredField( name ); - try { - // should be public anyway, but to be sure... - ReflectHelper.ensureAccessibility( field ); - field.set( null, attribute ); - } - catch (IllegalAccessException e) { - // todo : exception type? - throw new AssertionFailure( - "Unable to inject static metamodel attribute : " + metamodelClass.getName() + '#' + name, - e - ); - } - catch (IllegalArgumentException e) { - // most likely a mismatch in the type we are injecting and the defined field; this represents a - // mismatch in how the annotation processor interpreted the attribute and how our metamodel - // and/or annotation binder did. + injectField( metamodelClass, name, attribute, allowNonDeclaredFieldReference ); + } + catch (NoSuchFieldException e) { + LOG.unableToLocateStaticMetamodelField( metamodelClass.getName(), name ); +// throw new AssertionFailure( +// "Unable to locate static metamodel field : " + metamodelClass.getName() + '#' + name +// ); + } + } + + private static void injectField( + Class metamodelClass, String name, Object model, + boolean allowNonDeclaredFieldReference) + throws NoSuchFieldException { + final Field field = allowNonDeclaredFieldReference + ? metamodelClass.getField(name) + : metamodelClass.getDeclaredField(name); + try { + // should be public anyway, but to be sure... + ReflectHelper.ensureAccessibility( field ); + field.set( null, model); + } + catch (IllegalAccessException e) { + // todo : exception type? + throw new AssertionFailure( + "Unable to inject static metamodel attribute : " + metamodelClass.getName() + '#' + name, + e + ); + } + catch (IllegalArgumentException e) { + // most likely a mismatch in the type we are injecting and the defined field; this represents a + // mismatch in how the annotation processor interpreted the attribute and how our metamodel + // and/or annotation binder did. // This is particularly the case as arrays are not handled properly by the StaticMetamodel generator @@ -742,19 +762,12 @@ public class MetadataContext { // + "; expected type : " + attribute.getClass().getName() // + "; encountered type : " + field.getType().getName() // ); - LOG.illegalArgumentOnStaticMetamodelFieldInjection( - metamodelClass.getName(), - name, - attribute.getClass().getName(), - field.getType().getName() - ); - } - } - catch (NoSuchFieldException e) { - LOG.unableToLocateStaticMetamodelField( metamodelClass.getName(), name ); -// throw new AssertionFailure( -// "Unable to locate static metamodel field : " + metamodelClass.getName() + '#' + name -// ); + LOG.illegalArgumentOnStaticMetamodelFieldInjection( + metamodelClass.getName(), + name, + model.getClass().getName(), + field.getType().getName() + ); } } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java index d485197d91..fd2272d12a 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java @@ -187,7 +187,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor { final TypeElement typeElement = context.getElementUtils().getTypeElement( elementName ); try { final AnnotationMetaEntity metaEntity = - AnnotationMetaEntity.create( typeElement, context, false ); + AnnotationMetaEntity.create( typeElement, context, false, false ); context.addMetaAuxiliary( metaEntity.getQualifiedName(), metaEntity ); context.removeElementToRedo( elementName ); } @@ -212,7 +212,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor { if ( containsAnnotation( member, HQL, SQL, FIND ) ) { context.logMessage( Diagnostic.Kind.OTHER, "Processing annotated class '" + element + "'" ); final AnnotationMetaEntity metaEntity = - AnnotationMetaEntity.create( typeElement, context, false ); + AnnotationMetaEntity.create( typeElement, context, false, false ); context.addMetaAuxiliary( metaEntity.getQualifiedName(), metaEntity ); break; } @@ -357,7 +357,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor { = containsAnnotation( element, Constants.EMBEDDABLE ) || containsAnnotation( element, Constants.MAPPED_SUPERCLASS ); final AnnotationMetaEntity metaEntity = - AnnotationMetaEntity.create( typeElement, context, requiresLazyMemberInitialization ); + AnnotationMetaEntity.create( typeElement, context, requiresLazyMemberInitialization, true ); if ( alreadyExistingMetaEntity != null ) { metaEntity.mergeInMembers( alreadyExistingMetaEntity ); } @@ -370,7 +370,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor { private void handleRootElementAuxiliaryAnnotationMirrors(final Element element) { if ( element instanceof TypeElement ) { final AnnotationMetaEntity metaEntity = - AnnotationMetaEntity.create( (TypeElement) element, context, false ); + AnnotationMetaEntity.create( (TypeElement) element, context, false, false ); context.addMetaAuxiliary( metaEntity.getQualifiedName(), metaEntity ); } else if ( element instanceof PackageElement ) { diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java index 1cd28950bf..744fdceed9 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java @@ -85,6 +85,7 @@ public class AnnotationMetaEntity extends AnnotationMeta { private final TypeElement element; private final Map members; private final Context context; + private final boolean managed; private AccessTypeInformation entityAccessTypeInfo; @@ -120,15 +121,16 @@ public class AnnotationMetaEntity extends AnnotationMeta { private final Map memberTypes = new HashMap<>(); - public AnnotationMetaEntity(TypeElement element, Context context) { + public AnnotationMetaEntity(TypeElement element, Context context, boolean managed) { this.element = element; this.context = context; + this.managed = managed; this.members = new HashMap<>(); this.importContext = new ImportContextImpl( getPackageName( context, element ) ); } - public static AnnotationMetaEntity create(TypeElement element, Context context, boolean lazilyInitialised) { - final AnnotationMetaEntity annotationMetaEntity = new AnnotationMetaEntity( element, context ); + public static AnnotationMetaEntity create(TypeElement element, Context context, boolean lazilyInitialised, boolean managed) { + final AnnotationMetaEntity annotationMetaEntity = new AnnotationMetaEntity( element, context, managed ); if ( !lazilyInitialised ) { annotationMetaEntity.init(); } @@ -283,6 +285,10 @@ public class AnnotationMetaEntity extends AnnotationMeta { findSessionGetter( methodsOfClass ); + if ( managed ) { + putMember( "class", new AnnotationMetaType(this) ); + } + addPersistentMembers( fieldsOfClass, AccessType.FIELD ); addPersistentMembers( gettersAndSettersOfClass, AccessType.PROPERTY ); diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaType.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaType.java new file mode 100644 index 0000000000..761b2b86d4 --- /dev/null +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaType.java @@ -0,0 +1,86 @@ +/* + * 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.jpamodelgen.annotation; + +import org.hibernate.jpamodelgen.model.MetaAttribute; +import org.hibernate.jpamodelgen.model.Metamodel; +import org.hibernate.jpamodelgen.util.Constants; +import org.hibernate.metamodel.model.domain.ManagedDomainType; + +import static org.hibernate.jpamodelgen.util.TypeUtils.hasAnnotation; + +/** + * @author Gavin King + */ +public class AnnotationMetaType implements MetaAttribute { + + private final AnnotationMetaEntity annotationMetaEntity; + + public AnnotationMetaType(AnnotationMetaEntity annotationMetaEntity) { + this.annotationMetaEntity = annotationMetaEntity; + } + + @Override + public boolean hasTypedAttribute() { + return true; + } + + @Override + public boolean hasStringAttribute() { + return false; + } + + @Override + public String getAttributeDeclarationString() { + return new StringBuilder() + .append("\n/**\n * @see ") + .append( annotationMetaEntity.getQualifiedName() ) + .append( "\n **/\n" ) + .append("public static volatile ") + .append(annotationMetaEntity.importType(getTypeDeclaration())) + .append("<") + .append(annotationMetaEntity.importType(annotationMetaEntity.getQualifiedName())) + .append(">") + .append(" class_;").toString(); + } + + @Override + public String getAttributeNameDeclarationString() { + throw new UnsupportedOperationException(); + } + + @Override + public String getMetaType() { + return ManagedDomainType.class.getName(); + } + + @Override + public String getPropertyName() { + return "class"; + } + + @Override + public String getTypeDeclaration() { + if ( hasAnnotation(annotationMetaEntity.getElement(), Constants.ENTITY) ) { + return "jakarta.persistence.metamodel.EntityType"; + } + else if ( hasAnnotation(annotationMetaEntity.getElement(), Constants.EMBEDDABLE) ) { + return "jakarta.persistence.metamodel.EmbeddableType"; + } + else if ( hasAnnotation(annotationMetaEntity.getElement(), Constants.MAPPED_SUPERCLASS) ) { + return "jakarta.persistence.metamodel.MappedSuperclassType"; + } + else { + return "jakarta.persistence.metamodel.ManagedType"; + } + } + + @Override + public Metamodel getHostingEntity() { + return annotationMetaEntity; + } +} diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java index ce48d9fe5f..04c1a91697 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java @@ -211,6 +211,10 @@ public final class TypeUtils { return null; } + public static boolean hasAnnotation(Element element, String qualifiedName) { + return getAnnotationMirror( element, qualifiedName ) != null; + } + public static @Nullable Object getAnnotationValue(AnnotationMirror annotationMirror, String parameterValue) { assert annotationMirror != null; assert parameterValue != null;