jamesfredley commented on code in PR #16696:
URL: https://github.com/apache/grails-core/pull/16696#discussion_r4341352815


##########
.github/workflows/gradle.yml:
##########
@@ -19,6 +19,8 @@ on:
     branches:
       - '[0-9]+.[0-9]+.x'
   pull_request:
+    # CHANGEME FOR ACCEPTANCE: PR triggers disabled on this stacked branch; 
revert before merge
+    branches: ['CHANGEME-FOR-ACCEPTANCE']

Review Comment:
   `branches` here filters the pull request base. `CHANGEME-FOR-ACCEPTANCE` 
matches no release branch, so this workflow does not run for this pull request 
or for a pull request targeting `9.0.x` / `8.0.x` / `7.0.x`.
   
   The same placeholder is in the other 12 workflow files in this delta: 
benchmark, build-health, codeanalysis, codeql, codestyle, coverage, end-to-end, 
groovy-snapshot-canary, rat, sitemesh2, validate-actions, and 
vulnerability-scan.
   
   Restore those trigger blocks to the base versions before merge.



##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/PredicateGenerator.groovy:
##########
@@ -111,20 +178,113 @@ class PredicateGenerator {
 
     }
 
+    /**
+     * Extension point for ordering a criteria query by something other than a 
property. Register a handler for a
+     * {@link Query.Order} subclass to have it converted to a JPA {@link 
jakarta.persistence.criteria.Order}, in
+     * the place the order has among the query's orders. The order reaches the 
query through
+     * {@code order(Query.Order)} of the criteria builder or of a detached 
criteria.
+     *
+     * <pre>
+     *     class ByRandom extends Query.Order {
+     *         ByRandom() { super('random') }
+     *     }
+     *     PredicateGenerator.registerOrderHandler(ByRandom) { query, root, 
cb, order, context -&gt;
+     *         cb.asc(cb.function('random', Double))
+     *     }
+     * </pre>
+     *
+     * @since 10.0
+     */
+    @FunctionalInterface
+    static interface OrderHandler {
+
+        /**
+         * @param criteriaQuery the query, whose result type tells a query for 
the entity from a projection
+         * @param root the root of the query
+         * @param criteriaBuilder the criteria builder
+         * @param order the order to convert
+         * @param context the context of the query: its root, its joins and 
its aliases
+         * @return the JPA order, or {@code null} to leave this order out of 
the query
+         */
+        jakarta.persistence.criteria.Order handle(
+            CriteriaQuery<?> criteriaQuery,
+            From<?, ?> root,
+            HibernateCriteriaBuilder criteriaBuilder,
+            Query.Order order,
+            JpaQueryContext context
+        )
+
+    }
+
+    /**
+     * SPI for contributing an {@link OrderHandler} via {@link ServiceLoader}. 
Register an implementation in
+     * {@code 
META-INF/services/org.grails.orm.hibernate.query.PredicateGenerator$OrderHandlerProvider};
 it is
+     * discovered on first query execution, like a {@link 
CriterionHandlerProvider}.
+     *
+     * @since 10.0
+     */
+    static interface OrderHandlerProvider {
+
+        Class<? extends Query.Order> orderType()
+
+        OrderHandler orderHandler()
+
+    }
+
     public static final Map<Class<? extends Query.Criterion>, 
CriterionHandler> CUSTOM_HANDLERS =
         new ConcurrentHashMap<>()
 
+    public static final Map<Class<? extends Query.Order>, OrderHandler> 
CUSTOM_ORDER_HANDLERS =
+        new ConcurrentHashMap<>()
+
     private static final AtomicBoolean SERVICE_LOADERS_INITIALIZED = new 
AtomicBoolean(false)
 
     private static void loadServiceProviders() {
         if (SERVICE_LOADERS_INITIALIZED.compareAndSet(false, true)) {

Review Comment:
   `compareAndSet(false, true)` runs before `ServiceLoader` finishes. A second 
request sees the flag already true, skips `loadServiceProviders()`, and 
`orderHandler()` returns null. `JpaCriteriaQueryCreator` then treats the custom 
order as a property order. A synthetic property such as the documented `random` 
sorts wrong or throws.
   
   The early flag is older than this delta. This change is what puts 
order-handler discovery on that path.
   
   Make concurrent callers wait until discovery finishes. Keep programmatic 
registration ahead of a discovered handler. Please add a test where one thread 
is blocked inside order-provider loading and a second query still receives the 
handler.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to