You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by rz...@apache.org on 2026/08/20 10:46:49 UTC
(openjpa) 01/03: [OPENJPA-2985] Implement EntityManager.createQuery(TypedQueryReference)
This is an automated email from the ASF dual-hosted git repository.
rzo1 pushed a commit to branch OPENJPA-2985
in repository https://gitbox.apache.org/repos/asf/openjpa.git
commit 674fe11d36ed0eddb41821815f55e5e50cf08283
Author: Richard Zowalla <rz...@apache.org>
AuthorDate: Thu Aug 20 12:29:47 2026 +0200
[OPENJPA-2985] Implement EntityManager.createQuery(TypedQueryReference)
EntityManagerImpl.createQuery(TypedQueryReference<T>) no longer throws
UnsupportedOperationException. It now:
- calls assertNotCloseInvoked() first, so a closed EntityManager yields
IllegalStateException;
- rejects a null reference (and a null reference name) with
IllegalArgumentException;
- delegates to createNamedQuery(name, resultType) so the named query
metadata (query string, hints, flush mode, max results, lock mode) is
applied and the reference's result type becomes the query result class;
an unknown query name propagates as ArgumentException, which extends
IllegalArgumentException, matching the createNamedQuery contract;
- applies the hints carried by the reference afterwards, so they take
precedence over hints declared on the @NamedQuery itself; failures there
go through translateException like the rest of the named query path.
A null result type falls back to createNamedQuery(name) defensively.
Tested by the new TestTypedQueryReference in
org.apache.openjpa.persistence.query, which covers query creation and
execution from a reference, the applied result class, reference hints
surviving in getHints(), positional parameters of the named query, null
reference, unknown query name and a closed EntityManager. All seven cases
failed against the previous UnsupportedOperationException.
---
.../persistence/query/TestTypedQueryReference.java | 156 +++++++++++++++++++++
.../openjpa/persistence/EntityManagerImpl.java | 23 ++-
2 files changed, 178 insertions(+), 1 deletion(-)
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestTypedQueryReference.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestTypedQueryReference.java
new file mode 100644
index 000000000..bcd60495f
--- /dev/null
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestTypedQueryReference.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.persistence.query;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.TypedQuery;
+import jakarta.persistence.TypedQueryReference;
+
+import org.apache.openjpa.persistence.OpenJPAQuery;
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+
+/**
+ * Tests {@code EntityManager.createQuery(TypedQueryReference)} added in JPA 3.2.
+ */
+public class TestTypedQueryReference extends SingleEMFTestCase {
+
+ private static final String TIMEOUT_HINT = "jakarta.persistence.query.timeout";
+
+ @Override
+ public void setUp() {
+ setUp(SimpleEntity.class, CLEAR_TABLES);
+ EntityManager em = emf.createEntityManager();
+ em.getTransaction().begin();
+ em.persist(new SimpleEntity("Name One", "Value One"));
+ em.persist(new SimpleEntity("Name Two", "Value Two"));
+ em.getTransaction().commit();
+ em.close();
+ }
+
+ private static <R> TypedQueryReference<R> ref(final String name, final Class<R> type,
+ final Map<String, Object> hints) {
+ return new TypedQueryReference<R>() {
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public Class<? extends R> getResultType() {
+ return type;
+ }
+
+ @Override
+ public Map<String, Object> getHints() {
+ return hints;
+ }
+ };
+ }
+
+ public void testCreateQueryFromReference() {
+ EntityManager em = emf.createEntityManager();
+ try {
+ TypedQuery<SimpleEntity> q =
+ em.createQuery(ref("FindAll", SimpleEntity.class, Collections.<String, Object>emptyMap()));
+ assertNotNull(q);
+ List<SimpleEntity> list = q.getResultList();
+ assertEquals(2, list.size());
+ for (SimpleEntity s : list) {
+ assertNotNull(s.getName());
+ }
+ } finally {
+ em.close();
+ }
+ }
+
+ public void testResultTypeIsApplied() {
+ EntityManager em = emf.createEntityManager();
+ try {
+ TypedQuery<SimpleEntity> q =
+ em.createQuery(ref("FindAll", SimpleEntity.class, Collections.<String, Object>emptyMap()));
+ assertEquals(SimpleEntity.class, ((OpenJPAQuery<?>) q).getResultClass());
+ } finally {
+ em.close();
+ }
+ }
+
+ public void testReferenceHintsAreApplied() {
+ EntityManager em = emf.createEntityManager();
+ try {
+ Map<String, Object> hints =
+ Collections.<String, Object>singletonMap(TIMEOUT_HINT, Integer.valueOf(12345));
+ TypedQuery<SimpleEntity> q = em.createQuery(ref("FindAll", SimpleEntity.class, hints));
+ assertEquals(Integer.valueOf(12345), q.getHints().get(TIMEOUT_HINT));
+ } finally {
+ em.close();
+ }
+ }
+
+ public void testParametersStillWork() {
+ EntityManager em = emf.createEntityManager();
+ try {
+ TypedQuery<SimpleEntity> q =
+ em.createQuery(ref("FindOne", SimpleEntity.class, Collections.<String, Object>emptyMap()));
+ q.setParameter(1, "Name One");
+ assertEquals("Value One", q.getSingleResult().getValue());
+ } finally {
+ em.close();
+ }
+ }
+
+ public void testNullReference() {
+ EntityManager em = emf.createEntityManager();
+ try {
+ em.createQuery((TypedQueryReference<SimpleEntity>) null);
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ // expected
+ } finally {
+ em.close();
+ }
+ }
+
+ public void testUnknownQueryName() {
+ EntityManager em = emf.createEntityManager();
+ try {
+ em.createQuery(ref("NoSuchNamedQuery", SimpleEntity.class, Collections.<String, Object>emptyMap()));
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ // expected
+ } finally {
+ em.close();
+ }
+ }
+
+ public void testClosedEntityManager() {
+ EntityManager em = emf.createEntityManager();
+ em.close();
+ try {
+ em.createQuery(ref("FindAll", SimpleEntity.class, Collections.<String, Object>emptyMap()));
+ fail("expected IllegalStateException");
+ } catch (IllegalStateException expected) {
+ // expected
+ }
+ }
+}
diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
index bd693bb52..d202c7ac8 100644
--- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
+++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
@@ -2775,8 +2775,29 @@ public class EntityManagerImpl
}
@Override
+ @SuppressWarnings("unchecked")
public <T> TypedQuery<T> createQuery(TypedQueryReference<T> reference) {
- throw new UnsupportedOperationException("Not yet implemented (JPA 3.2)");
+ assertNotCloseInvoked();
+ if (reference == null) {
+ throw new IllegalArgumentException("TypedQueryReference must not be null");
+ }
+ String name = reference.getName();
+ if (name == null) {
+ throw new IllegalArgumentException("TypedQueryReference name must not be null");
+ }
+ Class<? extends T> resultType = reference.getResultType();
+ Query query = (resultType == null) ? createNamedQuery(name) : createNamedQuery(name, resultType);
+ Map<String, Object> hints = reference.getHints();
+ if (hints != null) {
+ try {
+ for (Map.Entry<String, Object> hint : hints.entrySet()) {
+ query.setHint(hint.getKey(), hint.getValue());
+ }
+ } catch (RuntimeException re) {
+ throw translateException(re);
+ }
+ }
+ return (TypedQuery<T>) query;
}
@Override