From b1998782e9027ca1cca65f8a2b4f029d7309ed46 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Sat, 17 Jun 2023 09:58:57 +0200 Subject: [PATCH] HHH-16633 introduce new package for @HQL, @SQL, @CheckHQL annotations --- .../annotations/processing/CheckHQL.java | 70 +++++++++++++++++++ .../processing/GenericDialect.java | 14 ++++ .../{Hql.java => processing/HQL.java} | 28 ++++---- .../{Sql.java => processing/SQL.java} | 28 ++++---- .../annotations/processing/package-info.java | 23 ++++++ .../hibernate/jpamodelgen/util/Constants.java | 4 +- .../jpamodelgen/test/namedquery/Dao.java | 12 ++-- 7 files changed, 141 insertions(+), 38 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/annotations/processing/CheckHQL.java create mode 100644 hibernate-core/src/main/java/org/hibernate/annotations/processing/GenericDialect.java rename hibernate-core/src/main/java/org/hibernate/annotations/{Hql.java => processing/HQL.java} (65%) rename hibernate-core/src/main/java/org/hibernate/annotations/{Sql.java => processing/SQL.java} (64%) create mode 100644 hibernate-core/src/main/java/org/hibernate/annotations/processing/package-info.java diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/processing/CheckHQL.java b/hibernate-core/src/main/java/org/hibernate/annotations/processing/CheckHQL.java new file mode 100644 index 0000000000..a68847a8af --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/annotations/processing/CheckHQL.java @@ -0,0 +1,70 @@ +/* + * 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.annotations.processing; + +import org.hibernate.Incubating; +import org.hibernate.dialect.Dialect; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.PACKAGE; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.CLASS; + +/** + * Indicates that a package or top-level type contains HQL or JPQL + * queries encoded as static strings that should be validated at + * compile time by the Hibernate Query Validator. The Query Validator + * must be enabled as an annotation processor in the project build. + * Otherwise, this annotation has no effect. + *

+ * Within a scope annotated {@code @CheckHQL}, any static string + * argument to any one the methods: + *

+ * or to any one of the annotation members: + * + *

+ * is interpreted as HQL/JPQL and validated. Errors in the query are + * reported by the Java compiler. + *

+ * The entity classes referred to in the queries must be annotated + * with basic JPA metadata annotations like {@code @Entity}, + * {@code @ManyToOne}, {@code @Embeddable}, {@code @MappedSuperclass}, + * {@code @ElementCollection}, and {@code @Access}. Metadata specified + * in XML mapping documents is ignored by the query validator. + *

+ * Syntax errors, unknown entity names and unknown entity member names, + * and typing errors all result in compile-time errors. + * + * @see HQL#value() + * @see jakarta.persistence.NamedQuery#query() + * @see jakarta.persistence.EntityManager#createQuery(String,Class) + * @see org.hibernate.Session#createSelectionQuery(String,Class) + * + * @author Gavin King + */ +@Target({PACKAGE, TYPE}) +@Retention(CLASS) +@Incubating +public @interface CheckHQL { + /** + * A Hibernate {@linkplain Dialect dialect} to use. + * + * @see Dialect + */ + Class dialect() default GenericDialect.class; +} diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/processing/GenericDialect.java b/hibernate-core/src/main/java/org/hibernate/annotations/processing/GenericDialect.java new file mode 100644 index 0000000000..861368d9e1 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/annotations/processing/GenericDialect.java @@ -0,0 +1,14 @@ +/* + * 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.annotations.processing; + +import org.hibernate.dialect.Dialect; + +class GenericDialect extends Dialect { + GenericDialect() { + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/Hql.java b/hibernate-core/src/main/java/org/hibernate/annotations/processing/HQL.java similarity index 65% rename from hibernate-core/src/main/java/org/hibernate/annotations/Hql.java rename to hibernate-core/src/main/java/org/hibernate/annotations/processing/HQL.java index 636ef057a0..85a7e8310d 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/Hql.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/processing/HQL.java @@ -4,7 +4,7 @@ * 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.annotations; +package org.hibernate.annotations.processing; import org.hibernate.Incubating; @@ -15,29 +15,27 @@ import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.CLASS; /** - * Identifies a method of an abstract class or interface - * as defining the signature of a method which is used to - * execute the given {@linkplain #value HQL query}, and is - * generated automatically by the Hibernate Metamodel - * Generator. + * Identifies a method of an abstract class or interface as defining + * the signature of a method which is used to execute the given + * {@linkplain #value HQL query}, and is generated automatically by + * the Hibernate Metamodel Generator. *

* For example: *

  * public interface Books {
- *     @Hql("from Book where isbn = :isbn")
+ *     @HQL("from Book where isbn = :isbn")
  *     Book findBookByIsbn(String isbn);
  *
- *     @Hql("from Book where title like ?1 order by title offset ?3 fetch first ?2 rows only")
+ *     @HQL("from Book where title like ?1 order by title offset ?3 fetch first ?2 rows only")
  *     List<Book> findBooksByTitleWithPagination(String title, int max, int start);
  *
- *     @Hql("from Book where title like ?1")
+ *     @HQL("from Book where title like ?1")
  *     TypedQuery<Book> findBooksByTitle(String title);
  * }
  * 
*

- * The Metamodel Generator automatically creates an - * "implementation" of these methods in the static metamodel - * class {@code Books_}. + * The Metamodel Generator automatically creates an "implementation" + * of these methods in the static metamodel class {@code Books_}. *

  * Book book = Books_.findBookByIsbn(session, isbn);
  * List<Book> books = Books_.findBooksByTitleWithPagination(session, pattern, 10, 0);
@@ -52,8 +50,8 @@ import static java.lang.annotation.RetentionPolicy.CLASS;
  * 
  • {@link jakarta.persistence.TypedQuery}. * *

    - * The method parameters must match the parameters of the - * HQL query, either by name or by position. + * The method parameters must match the parameters of the HQL query, + * either by name or by position. * * @author Gavin King * @since 6.3 @@ -61,6 +59,6 @@ import static java.lang.annotation.RetentionPolicy.CLASS; @Target(METHOD) @Retention(CLASS) @Incubating -public @interface Hql { +public @interface HQL { String value(); } diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/Sql.java b/hibernate-core/src/main/java/org/hibernate/annotations/processing/SQL.java similarity index 64% rename from hibernate-core/src/main/java/org/hibernate/annotations/Sql.java rename to hibernate-core/src/main/java/org/hibernate/annotations/processing/SQL.java index 20879b67bb..e761bd8086 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/Sql.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/processing/SQL.java @@ -4,7 +4,7 @@ * 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.annotations; +package org.hibernate.annotations.processing; import org.hibernate.Incubating; @@ -15,29 +15,27 @@ import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.CLASS; /** - * Identifies a method of an abstract class or interface - * as defining the signature of a method which is used to - * execute the given {@linkplain #value SQL query}, and is - * generated automatically by the Hibernate Metamodel - * Generator. + * Identifies a method of an abstract class or interface as defining + * the signature of a method which is used to execute the given + * {@linkplain #value SQL query}, and is generated automatically by + * the Hibernate Metamodel Generator. *

    * For example: *

      * public interface Books {
    - *     @Sql("select * from Book where isbn = :isbn")
    + *     @SQL("select * from Book where isbn = :isbn")
      *     Book findBookByIsbn(String isbn);
      *
    - *     @Sql("select * from Book where title like ?1 order by title offset ?3 fetch first ?2 rows only")
    + *     @SQL("select * from Book where title like ?1 order by title offset ?3 fetch first ?2 rows only")
      *     List<Book> findBooksByTitleWithPagination(String title, int max, int start);
      *
    - *     @Sql("select * from Book where title like ?1")
    + *     @SQL("select * from Book where title like ?1")
      *     Query findBooksByTitle(String title);
      * }
      * 
    *

    - * The Metamodel Generator automatically creates an - * "implementation" of these methods in the static metamodel - * class {@code Books_}. + * The Metamodel Generator automatically creates an "implementation" + * of these methods in the static metamodel class {@code Books_}. *

      * Book book = Books_.findBookByIsbn(session, isbn);
      * List<Book> books = Books_.findBooksByTitleWithPagination(session, pattern, 10, 0);
    @@ -52,8 +50,8 @@ import static java.lang.annotation.RetentionPolicy.CLASS;
      * 
  • {@link org.hibernate.query.NativeQuery}. * *

    - * The method parameters must match the parameters of the - * SQL query, either by name or by position. + * The method parameters must match the parameters of the SQL query, + * either by name or by position. * * @author Gavin King * @since 6.3 @@ -61,6 +59,6 @@ import static java.lang.annotation.RetentionPolicy.CLASS; @Target(METHOD) @Retention(CLASS) @Incubating -public @interface Sql { +public @interface SQL { String value(); } diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/processing/package-info.java b/hibernate-core/src/main/java/org/hibernate/annotations/processing/package-info.java new file mode 100644 index 0000000000..c475183242 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/annotations/processing/package-info.java @@ -0,0 +1,23 @@ +/* + * 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 . + */ + +/** + * Annotations used to drive annotation processors: + *

      + *
    • {@link org.hibernate.annotations.processing.HQL @HQL} + * and {@link org.hibernate.annotations.processing.SQL @SQL} + * are used to generate query methods using the + * Metamodel Generator, and + *
    • {@link org.hibernate.annotations.processing.CheckHQL} + * instructs the Query Validator to check all HQL queries + * in the annotated package or type. + *
    + */ +@Incubating +package org.hibernate.annotations.processing; + +import org.hibernate.Incubating; diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/Constants.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/Constants.java index 76a67c988c..605772f1db 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/Constants.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/Constants.java @@ -50,8 +50,8 @@ public final class Constants { public static final String HIB_FILTER_DEF = "org.hibernate.annotations.FilterDef"; public static final String HIB_FILTER_DEFS = "org.hibernate.annotations.FilterDefs"; - public static final String HQL = "org.hibernate.annotations.Hql"; - public static final String SQL = "org.hibernate.annotations.Sql"; + public static final String HQL = "org.hibernate.annotations.processing.HQL"; + public static final String SQL = "org.hibernate.annotations.processing.SQL"; public static final Map COLLECTIONS = allCollectionTypes(); diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/namedquery/Dao.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/namedquery/Dao.java index 08a5093003..27ecd015f8 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/namedquery/Dao.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/namedquery/Dao.java @@ -1,21 +1,21 @@ package org.hibernate.jpamodelgen.test.namedquery; import jakarta.persistence.TypedQuery; -import org.hibernate.annotations.Hql; -import org.hibernate.annotations.Sql; +import org.hibernate.annotations.processing.HQL; +import org.hibernate.annotations.processing.SQL; import java.util.List; public interface Dao { - @Hql("from Book where title like ?1") + @HQL("from Book where title like ?1") TypedQuery findByTitle(String title); - @Hql("from Book where title like ?1 order by title fetch first ?2 rows only") + @HQL("from Book where title like ?1 order by title fetch first ?2 rows only") List findFirstNByTitle(String title, int N); - @Hql("from Book where isbn = :isbn") + @HQL("from Book where isbn = :isbn") Book findByIsbn(String isbn); - @Sql("select * from Book where isbn = :isbn") + @SQL("select * from Book where isbn = :isbn") Book findByIsbnNative(String isbn); }