HHH-16940 add typesafe ref to ManagedType in metamodel classes

This commit is contained in:
Gavin King 2023-07-16 14:34:46 +02:00
parent 8611abe902
commit 5cee742698
5 changed files with 148 additions and 39 deletions

View File

@ -655,6 +655,12 @@ public class MetadataContext {
final Class<?> metamodelClass = Class.forName( metamodelClassName, true, managedTypeClass.getClassLoader() ); final Class<?> metamodelClass = Class.forName( metamodelClassName, true, managedTypeClass.getClassLoader() );
// we found the class; so populate it... // we found the class; so populate it...
registerAttributes( metamodelClass, managedType ); registerAttributes( metamodelClass, managedType );
try {
injectField( metamodelClass, "class_", managedType, false );
}
catch (NoSuchFieldException e) {
// ignore
}
} }
catch (ClassNotFoundException ignore) { catch (ClassNotFoundException ignore) {
// nothing to do... // nothing to do...
@ -715,25 +721,39 @@ public class MetadataContext {
attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.EMBEDDED attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.EMBEDDED
|| attribute.getDeclaringType().getPersistenceType() == Type.PersistenceType.EMBEDDABLE; || attribute.getDeclaringType().getPersistenceType() == Type.PersistenceType.EMBEDDABLE;
final Field field = allowNonDeclaredFieldReference injectField( metamodelClass, name, attribute, allowNonDeclaredFieldReference );
? metamodelClass.getField( name ) }
: metamodelClass.getDeclaredField( name ); catch (NoSuchFieldException e) {
try { LOG.unableToLocateStaticMetamodelField( metamodelClass.getName(), name );
// should be public anyway, but to be sure... // throw new AssertionFailure(
ReflectHelper.ensureAccessibility( field ); // "Unable to locate static metamodel field : " + metamodelClass.getName() + '#' + name
field.set( null, attribute ); // );
} }
catch (IllegalAccessException e) { }
// todo : exception type?
throw new AssertionFailure( private static <X> void injectField(
"Unable to inject static metamodel attribute : " + metamodelClass.getName() + '#' + name, Class<?> metamodelClass, String name, Object model,
e boolean allowNonDeclaredFieldReference)
); throws NoSuchFieldException {
} final Field field = allowNonDeclaredFieldReference
catch (IllegalArgumentException e) { ? metamodelClass.getField(name)
// most likely a mismatch in the type we are injecting and the defined field; this represents a : metamodelClass.getDeclaredField(name);
// mismatch in how the annotation processor interpreted the attribute and how our metamodel try {
// and/or annotation binder did. // 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 // 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() // + "; expected type : " + attribute.getClass().getName()
// + "; encountered type : " + field.getType().getName() // + "; encountered type : " + field.getType().getName()
// ); // );
LOG.illegalArgumentOnStaticMetamodelFieldInjection( LOG.illegalArgumentOnStaticMetamodelFieldInjection(
metamodelClass.getName(), metamodelClass.getName(),
name, name,
attribute.getClass().getName(), model.getClass().getName(),
field.getType().getName() field.getType().getName()
); );
}
}
catch (NoSuchFieldException e) {
LOG.unableToLocateStaticMetamodelField( metamodelClass.getName(), name );
// throw new AssertionFailure(
// "Unable to locate static metamodel field : " + metamodelClass.getName() + '#' + name
// );
} }
} }

View File

@ -187,7 +187,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
final TypeElement typeElement = context.getElementUtils().getTypeElement( elementName ); final TypeElement typeElement = context.getElementUtils().getTypeElement( elementName );
try { try {
final AnnotationMetaEntity metaEntity = final AnnotationMetaEntity metaEntity =
AnnotationMetaEntity.create( typeElement, context, false ); AnnotationMetaEntity.create( typeElement, context, false, false );
context.addMetaAuxiliary( metaEntity.getQualifiedName(), metaEntity ); context.addMetaAuxiliary( metaEntity.getQualifiedName(), metaEntity );
context.removeElementToRedo( elementName ); context.removeElementToRedo( elementName );
} }
@ -212,7 +212,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
if ( containsAnnotation( member, HQL, SQL, FIND ) ) { if ( containsAnnotation( member, HQL, SQL, FIND ) ) {
context.logMessage( Diagnostic.Kind.OTHER, "Processing annotated class '" + element + "'" ); context.logMessage( Diagnostic.Kind.OTHER, "Processing annotated class '" + element + "'" );
final AnnotationMetaEntity metaEntity = final AnnotationMetaEntity metaEntity =
AnnotationMetaEntity.create( typeElement, context, false ); AnnotationMetaEntity.create( typeElement, context, false, false );
context.addMetaAuxiliary( metaEntity.getQualifiedName(), metaEntity ); context.addMetaAuxiliary( metaEntity.getQualifiedName(), metaEntity );
break; break;
} }
@ -357,7 +357,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
= containsAnnotation( element, Constants.EMBEDDABLE ) = containsAnnotation( element, Constants.EMBEDDABLE )
|| containsAnnotation( element, Constants.MAPPED_SUPERCLASS ); || containsAnnotation( element, Constants.MAPPED_SUPERCLASS );
final AnnotationMetaEntity metaEntity = final AnnotationMetaEntity metaEntity =
AnnotationMetaEntity.create( typeElement, context, requiresLazyMemberInitialization ); AnnotationMetaEntity.create( typeElement, context, requiresLazyMemberInitialization, true );
if ( alreadyExistingMetaEntity != null ) { if ( alreadyExistingMetaEntity != null ) {
metaEntity.mergeInMembers( alreadyExistingMetaEntity ); metaEntity.mergeInMembers( alreadyExistingMetaEntity );
} }
@ -370,7 +370,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
private void handleRootElementAuxiliaryAnnotationMirrors(final Element element) { private void handleRootElementAuxiliaryAnnotationMirrors(final Element element) {
if ( element instanceof TypeElement ) { if ( element instanceof TypeElement ) {
final AnnotationMetaEntity metaEntity = final AnnotationMetaEntity metaEntity =
AnnotationMetaEntity.create( (TypeElement) element, context, false ); AnnotationMetaEntity.create( (TypeElement) element, context, false, false );
context.addMetaAuxiliary( metaEntity.getQualifiedName(), metaEntity ); context.addMetaAuxiliary( metaEntity.getQualifiedName(), metaEntity );
} }
else if ( element instanceof PackageElement ) { else if ( element instanceof PackageElement ) {

View File

@ -85,6 +85,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
private final TypeElement element; private final TypeElement element;
private final Map<String, MetaAttribute> members; private final Map<String, MetaAttribute> members;
private final Context context; private final Context context;
private final boolean managed;
private AccessTypeInformation entityAccessTypeInfo; private AccessTypeInformation entityAccessTypeInfo;
@ -120,15 +121,16 @@ public class AnnotationMetaEntity extends AnnotationMeta {
private final Map<String,String> memberTypes = new HashMap<>(); private final Map<String,String> memberTypes = new HashMap<>();
public AnnotationMetaEntity(TypeElement element, Context context) { public AnnotationMetaEntity(TypeElement element, Context context, boolean managed) {
this.element = element; this.element = element;
this.context = context; this.context = context;
this.managed = managed;
this.members = new HashMap<>(); this.members = new HashMap<>();
this.importContext = new ImportContextImpl( getPackageName( context, element ) ); this.importContext = new ImportContextImpl( getPackageName( context, element ) );
} }
public static AnnotationMetaEntity create(TypeElement element, Context context, boolean lazilyInitialised) { public static AnnotationMetaEntity create(TypeElement element, Context context, boolean lazilyInitialised, boolean managed) {
final AnnotationMetaEntity annotationMetaEntity = new AnnotationMetaEntity( element, context ); final AnnotationMetaEntity annotationMetaEntity = new AnnotationMetaEntity( element, context, managed );
if ( !lazilyInitialised ) { if ( !lazilyInitialised ) {
annotationMetaEntity.init(); annotationMetaEntity.init();
} }
@ -283,6 +285,10 @@ public class AnnotationMetaEntity extends AnnotationMeta {
findSessionGetter( methodsOfClass ); findSessionGetter( methodsOfClass );
if ( managed ) {
putMember( "class", new AnnotationMetaType(this) );
}
addPersistentMembers( fieldsOfClass, AccessType.FIELD ); addPersistentMembers( fieldsOfClass, AccessType.FIELD );
addPersistentMembers( gettersAndSettersOfClass, AccessType.PROPERTY ); addPersistentMembers( gettersAndSettersOfClass, AccessType.PROPERTY );

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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;
}
}

View File

@ -211,6 +211,10 @@ public final class TypeUtils {
return null; return null;
} }
public static boolean hasAnnotation(Element element, String qualifiedName) {
return getAnnotationMirror( element, qualifiedName ) != null;
}
public static @Nullable Object getAnnotationValue(AnnotationMirror annotationMirror, String parameterValue) { public static @Nullable Object getAnnotationValue(AnnotationMirror annotationMirror, String parameterValue) {
assert annotationMirror != null; assert annotationMirror != null;
assert parameterValue != null; assert parameterValue != null;