HHH-18649 more work on TypedQueryReference in static metamodel

This commit is contained in:
Gavin King 2024-09-21 13:45:55 +02:00
parent 79d3a3410d
commit 8b83a53678
4 changed files with 73 additions and 21 deletions

View File

@ -13,7 +13,11 @@ import org.hibernate.processor.model.Metamodel;
import org.hibernate.processor.util.Constants; import org.hibernate.processor.util.Constants;
import org.hibernate.processor.validation.ProcessorSessionFactory; import org.hibernate.processor.validation.ProcessorSessionFactory;
import org.hibernate.processor.validation.Validation; import org.hibernate.processor.validation.Validation;
import org.hibernate.query.criteria.JpaEntityJoin;
import org.hibernate.query.criteria.JpaRoot;
import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.sqm.tree.SqmStatement; import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.select.SqmSelectClause;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement; import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationMirror;
@ -103,25 +107,56 @@ public abstract class AnnotationMeta implements Metamodel {
ProcessorSessionFactory.create( context.getProcessingEnvironment(), ProcessorSessionFactory.create( context.getProcessingEnvironment(),
context.getEntityNameMappings(), context.getEnumTypesByValue() ) context.getEntityNameMappings(), context.getEnumTypesByValue() )
); );
if ( statement instanceof SqmSelectStatement if ( statement instanceof SqmSelectStatement<?> selectStatement ) {
&& isQueryMethodName( name ) ) { if ( isQueryMethodName( name ) ) {
putMember( name, putMember( name,
new NamedQueryMethod( new NamedQueryMethod(
this, this,
(SqmSelectStatement<?>) statement, selectStatement,
name.substring(1), name.substring(1),
isRepository(), isRepository(),
getSessionType(), getSessionType(),
getSessionVariableName(), getSessionVariableName(),
context.addNonnullAnnotation() context.addNonnullAnnotation()
) )
); );
}
if ( !isJakartaDataStyle()
&& getAnnotationValue( mirror, "resultClass" ) == null ) {
final String resultType = resultType( selectStatement );
if ( resultType != null ) {
putMember( "QUERY_" + name,
new TypedMetaAttribute( this, name, "QUERY_", resultType,
"jakarta.persistence.TypedQueryReference" ) );
}
}
} }
} }
} }
} }
} }
private static @Nullable String resultType(SqmSelectStatement<?> selectStatement) {
final JpaSelection<?> selection = selectStatement.getSelection();
if (selection == null) {
return null;
}
else if (selection instanceof SqmSelectClause from) {
return from.getSelectionItems().size() > 1
? "Object[]"
: from.getSelectionItems().get(0).getJavaTypeName();
}
else if (selection instanceof JpaRoot<?> root) {
return root.getModel().getTypeName();
}
else if (selection instanceof JpaEntityJoin<?, ?> join) {
return join.getModel().getTypeName();
}
else {
return selection.getJavaTypeName();
}
}
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) == '#'
@ -165,8 +200,9 @@ public abstract class AnnotationMeta implements Metamodel {
private NameMetaAttribute auxiliaryMember(AnnotationMirror mirror, String prefix, String name) { private NameMetaAttribute auxiliaryMember(AnnotationMirror mirror, String prefix, String name) {
if ( !isJakartaDataStyle() && "QUERY_".equals(prefix) ) { if ( !isJakartaDataStyle() && "QUERY_".equals(prefix) ) {
final AnnotationValue resultClass = getAnnotationValue( mirror, "resultClass" ); final AnnotationValue resultClass = getAnnotationValue( mirror, "resultClass" );
//TODO: if there is no explicit result class, obtain the result class by // if there is no explicit result class, we will infer it later by
// type-checking the query (this is allowed but not required by JPA) // type checking the query (this is allowed but not required by JPA)
// and then we will replace this TypedMetaAttribute
return new TypedMetaAttribute( this, name, prefix, return new TypedMetaAttribute( this, name, prefix,
resultClass == null ? JAVA_OBJECT : resultClass.getValue().toString(), resultClass == null ? JAVA_OBJECT : resultClass.getValue().toString(),
"jakarta.persistence.TypedQueryReference" ); "jakarta.persistence.TypedQueryReference" );

View File

@ -54,7 +54,7 @@ class NameMetaAttribute implements MetaAttribute {
.toString(); .toString();
} }
private String fieldName() { String fieldName() {
return nameToFieldName(name.charAt(0) == '#' ? name.substring(1) : name); return nameToFieldName(name.charAt(0) == '#' ? name.substring(1) : name);
} }

View File

@ -12,6 +12,7 @@ import static org.hibernate.processor.util.StringUtil.nameToMethodName;
* @author Gavin King * @author Gavin King
*/ */
class TypedMetaAttribute extends NameMetaAttribute { class TypedMetaAttribute extends NameMetaAttribute {
private final String prefix;
private final String resultType; private final String resultType;
private final String referenceType; private final String referenceType;
@ -22,6 +23,7 @@ class TypedMetaAttribute extends NameMetaAttribute {
String resultType, String resultType,
String referenceType) { String referenceType) {
super( annotationMetaEntity, name, prefix ); super( annotationMetaEntity, name, prefix );
this.prefix = prefix;
this.resultType = resultType; this.resultType = resultType;
this.referenceType = referenceType; this.referenceType = referenceType;
} }
@ -34,8 +36,13 @@ class TypedMetaAttribute extends NameMetaAttribute {
@Override @Override
public String getAttributeDeclarationString() { public String getAttributeDeclarationString() {
final Metamodel entity = getHostingEntity(); final Metamodel entity = getHostingEntity();
return new StringBuilder() final StringBuilder declaration = new StringBuilder();
.append("\n/**\n * @see ") declaration
.append("\n/**")
.append("\n * The query named {@value ")
.append(prefix)
.append(fieldName())
.append("}\n *\n * @see ")
.append(entity.getQualifiedName()) .append(entity.getQualifiedName())
.append("\n **/\n") .append("\n **/\n")
.append("public static volatile ") .append("public static volatile ")
@ -45,8 +52,11 @@ class TypedMetaAttribute extends NameMetaAttribute {
.append('>') .append('>')
.append(' ') .append(' ')
.append('_') .append('_')
.append(nameToMethodName(getPropertyName())) .append(nameToMethodName(getPropertyName()));
.append(';') if ( "QUERY_".equals(prefix) ) { //UGLY!
.toString(); declaration.append('_');
}
declaration.append(';');
return declaration.toString();
} }
} }

View File

@ -11,6 +11,12 @@ import jakarta.persistence.NamedQuery;
@Entity @Entity
@NamedEntityGraph(name = "entityGraph") @NamedEntityGraph(name = "entityGraph")
@NamedQuery(name="booksByTitle",
query = "from Book where title = ?1")
@NamedQuery(name="booksByTitleVerbose",
query = "select book from Book book where book.title = ?1")
@NamedQuery(name = "titlesWithIsbns",
query = "select title, isbn from Book")
@NamedQuery(name = "#findByTitle", @NamedQuery(name = "#findByTitle",
query = "from Book where title like :titlePattern") query = "from Book where title like :titlePattern")
@NamedQuery(name = "#findByTitleAndType", @NamedQuery(name = "#findByTitleAndType",