HHH-18649 TypedQueryReference and EntityGraph in static metamodel

This commit is contained in:
Gavin King 2024-09-21 12:17:20 +02:00
parent d53498910a
commit e13efce86b
5 changed files with 101 additions and 31 deletions

View File

@ -376,8 +376,7 @@ public class HibernateProcessor extends AbstractProcessor {
context.logMessage( Diagnostic.Kind.OTHER, "Processing annotated class '" + element + "'" ); context.logMessage( Diagnostic.Kind.OTHER, "Processing annotated class '" + element + "'" );
handleRootElementAuxiliaryAnnotationMirrors( element ); handleRootElementAuxiliaryAnnotationMirrors( element );
} }
else if ( element instanceof TypeElement ) { else if ( element instanceof TypeElement typeElement ) {
final TypeElement typeElement = (TypeElement) element;
final AnnotationMirror repository = getAnnotationMirror( element, JD_REPOSITORY ); final AnnotationMirror repository = getAnnotationMirror( element, JD_REPOSITORY );
if ( repository != null ) { if ( repository != null ) {
final AnnotationValue provider = getAnnotationValue( repository, "provider" ); final AnnotationValue provider = getAnnotationValue( repository, "provider" );

View File

@ -21,6 +21,9 @@ import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element; import javax.lang.model.element.Element;
import java.util.List; import java.util.List;
import static java.lang.Character.isJavaIdentifierStart;
import static org.hibernate.processor.util.Constants.JAVA_OBJECT;
import static org.hibernate.processor.util.Constants.NAMED_QUERY;
import static org.hibernate.processor.util.TypeUtils.containsAnnotation; import static org.hibernate.processor.util.TypeUtils.containsAnnotation;
import static org.hibernate.processor.util.TypeUtils.getAnnotationMirror; import static org.hibernate.processor.util.TypeUtils.getAnnotationMirror;
import static org.hibernate.processor.util.TypeUtils.getAnnotationValue; import static org.hibernate.processor.util.TypeUtils.getAnnotationValue;
@ -28,7 +31,7 @@ import static org.hibernate.processor.util.TypeUtils.getAnnotationValue;
public abstract class AnnotationMeta implements Metamodel { public abstract class AnnotationMeta implements Metamodel {
void addAuxiliaryMembers() { void addAuxiliaryMembers() {
addAuxiliaryMembersForAnnotation( Constants.NAMED_QUERY, "QUERY_" ); addAuxiliaryMembersForAnnotation( NAMED_QUERY, "QUERY_" );
addAuxiliaryMembersForRepeatableAnnotation( Constants.NAMED_QUERIES, "QUERY_" ); addAuxiliaryMembersForRepeatableAnnotation( Constants.NAMED_QUERIES, "QUERY_" );
addAuxiliaryMembersForAnnotation( Constants.NAMED_NATIVE_QUERY, "QUERY_" ); addAuxiliaryMembersForAnnotation( Constants.NAMED_NATIVE_QUERY, "QUERY_" );
addAuxiliaryMembersForRepeatableAnnotation( Constants.NAMED_NATIVE_QUERIES, "QUERY_" ); addAuxiliaryMembersForRepeatableAnnotation( Constants.NAMED_NATIVE_QUERIES, "QUERY_" );
@ -50,7 +53,7 @@ public abstract class AnnotationMeta implements Metamodel {
void checkNamedQueries() { void checkNamedQueries() {
boolean checkHql = containsAnnotation( getElement(), Constants.CHECK_HQL ) boolean checkHql = containsAnnotation( getElement(), Constants.CHECK_HQL )
|| containsAnnotation( getElement().getEnclosingElement(), Constants.CHECK_HQL ); || containsAnnotation( getElement().getEnclosingElement(), Constants.CHECK_HQL );
handleNamedQueryAnnotation( Constants.NAMED_QUERY, checkHql ); handleNamedQueryAnnotation( NAMED_QUERY, checkHql );
handleNamedQueryRepeatableAnnotation( Constants.NAMED_QUERIES, checkHql ); handleNamedQueryRepeatableAnnotation( Constants.NAMED_QUERIES, checkHql );
handleNamedQueryAnnotation( Constants.HIB_NAMED_QUERY, checkHql ); handleNamedQueryAnnotation( Constants.HIB_NAMED_QUERY, checkHql );
handleNamedQueryRepeatableAnnotation( Constants.HIB_NAMED_QUERIES, checkHql ); handleNamedQueryRepeatableAnnotation( Constants.HIB_NAMED_QUERIES, checkHql );
@ -86,9 +89,7 @@ public abstract class AnnotationMeta implements Metamodel {
final boolean reportErrors = context.checkNamedQuery( name ); final boolean reportErrors = context.checkNamedQuery( name );
final AnnotationValue value = getAnnotationValue( mirror, "query" ); final AnnotationValue value = getAnnotationValue( mirror, "query" );
if ( value != null ) { if ( value != null ) {
final Object query = value.getValue(); if ( value.getValue() instanceof String hql ) {
if ( query instanceof String ) {
final String hql = (String) query;
final SqmStatement<?> statement = final SqmStatement<?> statement =
Validation.validate( Validation.validate(
hql, hql,
@ -124,7 +125,7 @@ public abstract class AnnotationMeta implements Metamodel {
private static boolean isQueryMethodName(String name) { private static boolean isQueryMethodName(String name) {
return name.length() >= 2 return name.length() >= 2
&& name.charAt(0) == '#' && name.charAt(0) == '#'
&& Character.isJavaIdentifierStart( name.charAt(1) ) && isJavaIdentifierStart( name.charAt(1) )
&& name.substring(2).chars().allMatch(Character::isJavaIdentifierPart); && name.substring(2).chars().allMatch(Character::isJavaIdentifierPart);
} }
@ -155,13 +156,30 @@ public abstract class AnnotationMeta implements Metamodel {
if ( key.getSimpleName().contentEquals("name") ) { if ( key.getSimpleName().contentEquals("name") ) {
final String name = value.getValue().toString(); final String name = value.getValue().toString();
if ( !name.isEmpty() ) { if ( !name.isEmpty() ) {
putMember( prefix + name, putMember( prefix + name, auxiliaryMember( mirror, prefix, name ) );
new NameMetaAttribute( this, name, prefix ) );
} }
} }
}); });
} }
private NameMetaAttribute auxiliaryMember(AnnotationMirror mirror, String prefix, String name) {
if ( !isJakartaDataStyle() && "QUERY_".equals(prefix) ) {
final AnnotationValue resultClass = getAnnotationValue( mirror, "resultClass" );
//TODO: if there is no explicit result class, obtain the result class by
// type-checking the query (this is allowed but not required by JPA)
return new TypedMetaAttribute( this, name, prefix,
resultClass == null ? JAVA_OBJECT : resultClass.getValue().toString(),
"jakarta.persistence.TypedQueryReference" );
}
else if ( !isJakartaDataStyle() && "GRAPH_".equals(prefix) ) {
return new TypedMetaAttribute( this, name, prefix, getQualifiedName(),
"jakarta.persistence.EntityGraph" );
}
else {
return new NameMetaAttribute( this, name, prefix);
}
}
protected String getSessionVariableName() { protected String getSessionVariableName() {
return "entityManager"; return "entityManager";
} }

View File

@ -45,19 +45,20 @@ public abstract class AnnotationMetaAttribute implements MetaAttribute {
public String getAttributeDeclarationString() { public String getAttributeDeclarationString() {
return new StringBuilder() return new StringBuilder()
.append("\n/**\n * @see ") .append("\n/**\n * @see ")
.append( parent.getQualifiedName() ) .append(parent.getQualifiedName())
.append( "#") .append('#')
.append( element.getSimpleName() ) .append(element.getSimpleName())
.append( "\n **/\n" ) .append("\n **/\n")
.append( "public static volatile " ) .append("public static volatile ")
.append( parent.importType( getMetaType() ) ) .append(parent.importType(getMetaType()))
.append( "<" ) .append('<')
.append( parent.importType( parent.getQualifiedName() ) ) .append(parent.importType(parent.getQualifiedName()))
.append( ", " ) .append(", ")
.append( parent.importType( getTypeDeclaration() ) ) .append(parent.importType(getTypeDeclaration()))
.append( "> " ) .append('>')
.append( getPropertyName() ) .append(' ')
.append( ";" ) .append(getPropertyName())
.append(';')
.toString(); .toString();
} }
@ -66,13 +67,13 @@ public abstract class AnnotationMetaAttribute implements MetaAttribute {
return new StringBuilder() return new StringBuilder()
.append("public static final ") .append("public static final ")
.append(parent.importType(String.class.getName())) .append(parent.importType(String.class.getName()))
.append(" ") .append(' ')
.append(getUpperUnderscoreCaseFromLowerCamelCase(getPropertyName())) .append(getUpperUnderscoreCaseFromLowerCamelCase(getPropertyName()))
.append(" = ") .append(" = ")
.append("\"") .append('"')
.append(getPropertyName()) .append(getPropertyName())
.append("\"") .append('"')
.append(";") .append(';')
.toString(); .toString();
} }

View File

@ -43,14 +43,14 @@ class NameMetaAttribute implements MetaAttribute {
return new StringBuilder() return new StringBuilder()
.append("public static final ") .append("public static final ")
.append(annotationMetaEntity.importType(String.class.getName())) .append(annotationMetaEntity.importType(String.class.getName()))
.append(" ") .append(' ')
.append(prefix) .append(prefix)
.append(fieldName()) .append(fieldName())
.append(" = ") .append(" = ")
.append("\"") .append('"')
.append(name) .append(name)
.append("\"") .append('"')
.append(";") .append(';')
.toString(); .toString();
} }

View File

@ -0,0 +1,52 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.processor.annotation;
import org.hibernate.processor.model.Metamodel;
import static org.hibernate.processor.util.StringUtil.nameToMethodName;
/**
* @author Gavin King
*/
class TypedMetaAttribute extends NameMetaAttribute {
private final String resultType;
private final String referenceType;
public TypedMetaAttribute(
Metamodel annotationMetaEntity,
String name,
String prefix,
String resultType,
String referenceType) {
super( annotationMetaEntity, name, prefix );
this.resultType = resultType;
this.referenceType = referenceType;
}
@Override
public boolean hasTypedAttribute() {
return true;
}
@Override
public String getAttributeDeclarationString() {
final Metamodel entity = getHostingEntity();
return new StringBuilder()
.append("\n/**\n * @see ")
.append(entity.getQualifiedName())
.append("\n **/\n")
.append("public static volatile ")
.append(entity.importType(referenceType))
.append('<')
.append(entity.importType(resultType))
.append('>')
.append(' ')
.append('_')
.append(nameToMethodName(getPropertyName()))
.append(';')
.toString();
}
}