From 0adf44a54d444b6a011af591fcf8249b6869136b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kraus?= Date: Fri, 15 Sep 2023 15:03:19 +0200 Subject: [PATCH] jakartaee/persistence#395 - JPQL cast() function jakartaee/persistence#438 - add Expression.equalTo() and Expression.notEqualTo() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomáš Kraus --- .../persistence32/CriteriaBuilderTest.java | 205 ++++++++++++++---- .../jpa/querydef/CriteriaBuilderImpl.java | 39 ++-- .../internal/jpa/querydef/ExpressionImpl.java | 90 +++++--- .../jpa/querydef/InternalSelection.java | 5 - .../jpa/querydef/ParameterExpressionImpl.java | 5 +- .../internal/jpa/querydef/SelectionImpl.java | 11 +- 6 files changed, 254 insertions(+), 101 deletions(-) diff --git a/jpa/eclipselink.jpa.testapps/jpa.test.persistence32/src/test/java/org/eclipse/persistence/testing/tests/jpa/persistence32/CriteriaBuilderTest.java b/jpa/eclipselink.jpa.testapps/jpa.test.persistence32/src/test/java/org/eclipse/persistence/testing/tests/jpa/persistence32/CriteriaBuilderTest.java index 35d08d8b76e..b809a81eacb 100644 --- a/jpa/eclipselink.jpa.testapps/jpa.test.persistence32/src/test/java/org/eclipse/persistence/testing/tests/jpa/persistence32/CriteriaBuilderTest.java +++ b/jpa/eclipselink.jpa.testapps/jpa.test.persistence32/src/test/java/org/eclipse/persistence/testing/tests/jpa/persistence32/CriteriaBuilderTest.java @@ -25,6 +25,7 @@ import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.LocalDateField; import jakarta.persistence.criteria.LocalTimeField; import jakarta.persistence.criteria.ParameterExpression; @@ -36,7 +37,6 @@ import org.eclipse.persistence.testing.framework.jpa.junit.JUnitTestCase; import org.eclipse.persistence.testing.models.jpa.persistence32.Persistence32TableCreator; import org.eclipse.persistence.testing.models.jpa.persistence32.SyntaxEntity; -import org.junit.Assert; public class CriteriaBuilderTest extends JUnitTestCase { @@ -51,6 +51,8 @@ public class CriteriaBuilderTest extends JUnitTestCase { new SyntaxEntity(5L, null, null, null, null, LocalDate.of(1918, 9, 28), null) }; + private static final int ENTITIES_COUNT = ENTITIES.length - 1; + private JpaEntityManagerFactory emf = null; public static Test suite() { @@ -81,6 +83,11 @@ public static Test suite() { suite.addTest(new CriteriaBuilderTest("testExtractDayFromDate")); suite.addTest(new CriteriaBuilderTest("testExtractQuarterFromDate")); suite.addTest(new CriteriaBuilderTest("testExtractWeekFromDate")); + suite.addTest(new CriteriaBuilderTest("testExpressionEqualToExpression")); + suite.addTest(new CriteriaBuilderTest("testExpressionEqualToObject")); + suite.addTest(new CriteriaBuilderTest("testExpressionNotEqualToExpression")); + suite.addTest(new CriteriaBuilderTest("testExpressionNotEqualToObject")); + suite.addTest(new CriteriaBuilderTest("testExpressionCast")); return suite; } @@ -137,7 +144,7 @@ public void testAndPredicateAsListOf0() { cQuery.where(cb.and(Collections.emptyList())); TypedQuery query = em.createQuery(cQuery); List result = query.getResultList(); - Assert.assertEquals(ENTITIES.length - 1, result.size()); + assertEquals(ENTITIES.length - 1, result.size()); et.commit(); } catch (Exception e) { et.rollback(); @@ -158,7 +165,7 @@ public void testOrPredicateAsListOf0() { cQuery.where(cb.or(Collections.emptyList())); TypedQuery query = em.createQuery(cQuery); List result = query.getResultList(); - Assert.assertEquals(0, result.size()); + assertEquals(0, result.size()); et.commit(); } catch (Exception e) { et.rollback(); @@ -182,8 +189,8 @@ public void testAndPredicateAsListOf1() { TypedQuery query = em.createQuery(cQuery); query.setParameter("strParam1", "LeftToken"); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(3L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(3L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -207,8 +214,8 @@ public void testOrPredicateAsListOf1() { TypedQuery query = em.createQuery(cQuery); query.setParameter("strParam1", "LeftToken"); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(3L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(3L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -234,8 +241,8 @@ public void testAndPredicateAsListOf2() { query.setParameter("strParam1", "LeftToken"); query.setParameter("strParam2", "TokenRight"); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(3L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(3L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -261,7 +268,7 @@ public void testOrPredicateAsListOf2() { query.setParameter("strParam1", "Left"); query.setParameter("strParam2", "right"); List result = query.getResultList(); - Assert.assertEquals(2, result.size()); + assertEquals(2, result.size()); assertFromSet(Set.of(1L, 2L), result.stream().map(SyntaxEntity::getId).toList()); et.commit(); } catch (Exception e) { @@ -290,8 +297,8 @@ public void testAndPredicateAsListOfN() { query.setParameter("strParam1", "LeftToken"); query.setParameter("strParam2", "TokenRight"); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(3L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(3L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -321,7 +328,7 @@ public void testOrPredicateAsListOfN() { query.setParameter("timeParam", LocalTime.of(10, 11, 12)); query.setParameter("dateParam", LocalDate.of(1918, 9, 28)); List result = query.getResultList(); - Assert.assertEquals(4, result.size()); + assertEquals(4, result.size()); assertFromSet(Set.of(1L, 2L, 4L, 5L), result.stream().map(SyntaxEntity::getId).toList()); et.commit(); } catch (Exception e) { @@ -344,8 +351,8 @@ public void testLeftIntLen() { TypedQuery query = em.createQuery(cQuery); query.setParameter(strParam1, "Left substring to extract"); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(1L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(1L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -367,8 +374,8 @@ public void testLeftExprLen() { TypedQuery query = em.createQuery(cQuery); query.setParameter(strParam1, "Left substring to extract"); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(1L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(1L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -390,8 +397,8 @@ public void testRightIntLen() { TypedQuery query = em.createQuery(cQuery); query.setParameter(strParam1, "Extract substring from right"); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(2L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(2L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -413,8 +420,8 @@ public void testRightExprLen() { TypedQuery query = em.createQuery(cQuery); query.setParameter(strParam1, "Extract substring from right"); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(2L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(2L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -440,8 +447,8 @@ public void testReplaceExprExpr() { TypedQuery query = em.createQuery(cQuery); query.setParameter(strParam1, "UnknownToken"); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(3L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(3L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -467,8 +474,8 @@ public void testReplaceExprStr() { TypedQuery query = em.createQuery(cQuery); query.setParameter(strParam2, "TokenUnknown"); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(3L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(3L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -494,8 +501,8 @@ public void testReplaceStrExpr() { TypedQuery query = em.createQuery(cQuery); query.setParameter(strParam1, "UnknownToken"); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(3L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(3L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -521,8 +528,8 @@ public void testReplaceStrStr() { TypedQuery query = em.createQuery(cQuery); query.setParameter(strParam2, "TokenUnknown"); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(3L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(3L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -545,8 +552,8 @@ public void testExtractHourFromTime() { TypedQuery query = em.createQuery(cQuery); query.setParameter("timeParam", 10); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(4L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(4L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -569,8 +576,8 @@ public void testExtractMinuteFromTime() { TypedQuery query = em.createQuery(cQuery); query.setParameter("timeParam", 11); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(4L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(4L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -593,8 +600,8 @@ public void testExtractSecondFromTime() { TypedQuery query = em.createQuery(cQuery); query.setParameter("timeParam", 12); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(4L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(4L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -617,8 +624,8 @@ public void testExtractYearFromDate() { TypedQuery query = em.createQuery(cQuery); query.setParameter("dateParam", 1918); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(5L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(5L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -641,8 +648,8 @@ public void testExtractMonthFromDate() { TypedQuery query = em.createQuery(cQuery); query.setParameter("dateParam", 9); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(5L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(5L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -665,8 +672,8 @@ public void testExtractDayFromDate() { TypedQuery query = em.createQuery(cQuery); query.setParameter("dateParam", 28); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(5L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(5L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -689,8 +696,8 @@ public void testExtractQuarterFromDate() { TypedQuery query = em.createQuery(cQuery); query.setParameter("dateParam", 3); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(5L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(5L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -718,8 +725,53 @@ public void testExtractWeekFromDate() { // Number of the week for 28th September 1918 is 39 query.setParameter("dateParam", 39); List result = query.getResultList(); - Assert.assertEquals(1, result.size()); - Assert.assertEquals(5L, result.get(0).getId()); + assertEquals(1, result.size()); + assertEquals(5L, result.get(0).getId()); + et.commit(); + } catch (Exception e) { + et.rollback(); + throw e; + } + } + } + + public void testExpressionEqualToExpression() { + try (EntityManager em = emf.createEntityManager()) { + EntityTransaction et = em.getTransaction(); + try { + et.begin(); + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery cQuery = cb.createQuery(SyntaxEntity.class); + Root root = cQuery.from(SyntaxEntity.class); + cQuery.where( + root.get("strVal1").equalTo(cb.parameter(Integer.class, "strParam"))); + TypedQuery query = em.createQuery(cQuery); + query.setParameter("strParam", "LeftToken"); + List result = query.getResultList(); + assertEquals(1, result.size()); + assertEquals(3L, result.get(0).getId()); + et.commit(); + } catch (Exception e) { + et.rollback(); + throw e; + } + } + } + + public void testExpressionEqualToObject() { + try (EntityManager em = emf.createEntityManager()) { + EntityTransaction et = em.getTransaction(); + try { + et.begin(); + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery cQuery = cb.createQuery(SyntaxEntity.class); + Root root = cQuery.from(SyntaxEntity.class); + cQuery.where( + root.get("strVal1").equalTo("LeftToken")); + TypedQuery query = em.createQuery(cQuery); + List result = query.getResultList(); + assertEquals(1, result.size()); + assertEquals(3L, result.get(0).getId()); et.commit(); } catch (Exception e) { et.rollback(); @@ -728,6 +780,65 @@ public void testExtractWeekFromDate() { } } + public void testExpressionNotEqualToExpression() { + try (EntityManager em = emf.createEntityManager()) { + EntityTransaction et = em.getTransaction(); + try { + et.begin(); + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery cQuery = cb.createQuery(SyntaxEntity.class); + Root root = cQuery.from(SyntaxEntity.class); + cQuery.where( + root.get("strVal1").notEqualTo(cb.parameter(Integer.class, "strParam"))); + TypedQuery query = em.createQuery(cQuery); + query.setParameter("strParam", "LeftToken"); + List result = query.getResultList(); + assertEquals(2, result.size()); + assertFromSet(Set.of(1L, 2L), result.stream().map(SyntaxEntity::getId).toList()); + et.commit(); + } catch (Exception e) { + et.rollback(); + throw e; + } + } + } + + public void testExpressionNotEqualToObject() { + try (EntityManager em = emf.createEntityManager()) { + EntityTransaction et = em.getTransaction(); + try { + et.begin(); + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery cQuery = cb.createQuery(SyntaxEntity.class); + Root root = cQuery.from(SyntaxEntity.class); + cQuery.where( + root.get("strVal1").notEqualTo("LeftToken")); + TypedQuery query = em.createQuery(cQuery); + List result = query.getResultList(); + assertEquals(2, result.size()); + assertFromSet(Set.of(1L, 2L), result.stream().map(SyntaxEntity::getId).toList()); + et.commit(); + } catch (Exception e) { + et.rollback(); + throw e; + } + } + } + + public void testExpressionCast() { + try (EntityManager em = emf.createEntityManager()) { + CriteriaBuilder cb = em.getCriteriaBuilder(); + // Create expression with Integer java type + Expression source = cb.parameter(Integer.class, "intParam"); + assertEquals(Integer.class, source.getJavaType()); + // Cast it to Long java type + Expression target = source.cast(Long.class); + assertEquals(Long.class, target.getJavaType()); + // Cast shall not return the same instance + assertNotSame(source, target); + } + } + // Evaluate assertions on set of expected values private static void assertFromSet(Set expected, Collection actual) { // Make sure to have mutable set @@ -737,7 +848,7 @@ private static void assertFromSet(Set expected, Collection actual) { if (expectedInternal.contains(value)) { expectedInternal.remove(value); } else { - Assert.fail(String.format( + fail(String.format( "Actual value %s is not from expected set of values %s", value, setToString(expected))); } @@ -745,7 +856,7 @@ private static void assertFromSet(Set expected, Collection actual) { ); // Make sure that all values from set were checked if (!expectedInternal.isEmpty()) { - Assert.fail(String.format("Missing values %s from expected set %s", + fail(String.format("Missing values %s from expected set %s", setToString(expectedInternal), setToString(expected))); } } diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaBuilderImpl.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaBuilderImpl.java index 9276e1c922e..4b16d34ea73 100644 --- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaBuilderImpl.java +++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaBuilderImpl.java @@ -27,6 +27,7 @@ import java.time.temporal.Temporal; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; @@ -72,7 +73,7 @@ import org.eclipse.persistence.jpa.JpaCriteriaBuilder; import org.eclipse.persistence.queries.ReportQuery; -import static org.eclipse.persistence.internal.jpa.querydef.InternalSelection.currentNode; +import static org.eclipse.persistence.internal.jpa.querydef.ExpressionImpl.currentNode; public class CriteriaBuilderImpl implements JpaCriteriaBuilder, Serializable { @@ -260,7 +261,7 @@ public > Expression greatest(Expression x) if (((InternalSelection)x).getCurrentNode() == null){ throw new IllegalArgumentException(ExceptionLocalization.buildMessage("OPERATOR_EXPRESSION_IS_CONJUNCTION")); } - return new ExpressionImpl(this.metamodel, x.getJavaType(),((InternalSelection)x).getCurrentNode().maximum()); + return new ExpressionImpl<>(this.metamodel, x.getJavaType(), ((InternalSelection)x).getCurrentNode().maximum()); } /** @@ -276,7 +277,7 @@ public > Expression least(Expression x){ if (((InternalSelection)x).getCurrentNode() == null){ throw new IllegalArgumentException(ExceptionLocalization.buildMessage("OPERATOR_EXPRESSION_IS_CONJUNCTION")); } - return new ExpressionImpl(this.metamodel, x.getJavaType(),((InternalSelection)x).getCurrentNode().minimum()); + return new ExpressionImpl<>(this.metamodel, x.getJavaType(),((InternalSelection)x).getCurrentNode().minimum()); } /** @@ -883,11 +884,11 @@ public > Predicate between(Expression> buildList(Expression... expressions){ - List> list = new ArrayList<>(); - for(Expression exp : expressions){ - list.add(exp); - } + protected List> buildList(Expression... expressions) { + // Immutable List causes test failures. + // Those lists are usually small (size 1-2) and modifications are rare. Default list size is too much. + List> list = new ArrayList<>(expressions.length + 2); + Collections.addAll(list, expressions); return list; } @@ -1485,7 +1486,7 @@ public Expression literal(T value){ if (value == null) { throw new IllegalArgumentException( ExceptionLocalization.buildMessage("jpa_criteriaapi_null_literal_value", new Object[]{})); } - return new ExpressionImpl(metamodel, (Class) (value.getClass()), new ConstantExpression(value, new ExpressionBuilder()), value); + return ExpressionImpl.createLiteral(value, metamodel); } /** @@ -1495,8 +1496,8 @@ public Expression literal(T value){ * @return null expression literal */ @Override - public Expression nullLiteral(Class resultClass){ - return new ExpressionImpl(metamodel, resultClass, new ConstantExpression(null, new ExpressionBuilder()), null); + public Expression nullLiteral(Class resultClass) { + return ExpressionImpl.createLiteral(null, metamodel, resultClass); } /** @@ -1505,14 +1506,14 @@ public Expression nullLiteral(Class resultClass){ * @return expression literal */ protected Expression internalLiteral(T value){ - return new ExpressionImpl(metamodel, (Class) (value == null? null: value.getClass()), new ConstantExpression(value, new ExpressionBuilder()), value); + return ExpressionImpl.createLiteral(value, metamodel); } // parameters: /** * Create a parameter. - * * Create a parameter expression. + * * @param paramClass parameter class * @return parameter expression */ @@ -2297,7 +2298,7 @@ public Expression locate(Expression x, String pattern, int from */ @Override public Expression currentDate(){ - return new ExpressionImpl(metamodel, ClassConstants.SQLDATE, new ExpressionBuilder().currentDateDate()); + return new ExpressionImpl<>(metamodel, ClassConstants.SQLDATE, new ExpressionBuilder().currentDateDate()); } /** @@ -2307,7 +2308,7 @@ public Expression currentDate(){ */ @Override public Expression currentTimestamp(){ - return new ExpressionImpl(metamodel, ClassConstants.TIMESTAMP, new ExpressionBuilder().currentTimeStamp()); + return new ExpressionImpl<>(metamodel, ClassConstants.TIMESTAMP, new ExpressionBuilder().currentTimeStamp()); } /** @@ -2317,7 +2318,7 @@ public Expression currentTimestamp(){ */ @Override public Expression currentTime(){ - return new ExpressionImpl(metamodel, ClassConstants.TIME, new ExpressionBuilder().currentTime()); + return new ExpressionImpl<>(metamodel, ClassConstants.TIME, new ExpressionBuilder().currentTime()); } /** @@ -2327,7 +2328,7 @@ public Expression currentTime(){ */ @Override public Expression localDateTime() { - return new ExpressionImpl(metamodel, ClassConstants.LOCAL_DATETIME, new ExpressionBuilder().localDateTime()); + return new ExpressionImpl<>(metamodel, ClassConstants.LOCAL_DATETIME, new ExpressionBuilder().localDateTime()); } /** @@ -2337,7 +2338,7 @@ public Expression localDateTime() { */ @Override public Expression localDate() { - return new ExpressionImpl(metamodel, ClassConstants.LOCAL_DATE, new ExpressionBuilder().localDate()); + return new ExpressionImpl<>(metamodel, ClassConstants.LOCAL_DATE, new ExpressionBuilder().localDate()); } /** @@ -2347,7 +2348,7 @@ public Expression localDate() { */ @Override public Expression localTime() { - return new ExpressionImpl(metamodel, ClassConstants.LOCAL_TIME, new ExpressionBuilder().localTime()); + return new ExpressionImpl<>(metamodel, ClassConstants.LOCAL_TIME, new ExpressionBuilder().localTime()); } @Override diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/ExpressionImpl.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/ExpressionImpl.java index 76dddfa41f8..65b353f5bce 100644 --- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/ExpressionImpl.java +++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/ExpressionImpl.java @@ -24,6 +24,8 @@ import jakarta.persistence.metamodel.Metamodel; import org.eclipse.persistence.descriptors.ClassDescriptor; +import org.eclipse.persistence.expressions.ExpressionBuilder; +import org.eclipse.persistence.internal.expressions.ConstantExpression; import org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl; import org.eclipse.persistence.internal.localization.ExceptionLocalization; import org.eclipse.persistence.sessions.Project; @@ -45,66 +47,82 @@ public class ExpressionImpl extends SelectionImpl implements Expression protected boolean isLiteral; protected Object literal; - protected ExpressionImpl(Metamodel metamodel, Class javaType, org.eclipse.persistence.expressions.Expression expressionNode){ + // Non literal value + protected ExpressionImpl(Metamodel metamodel, Class javaType, org.eclipse.persistence.expressions.Expression expressionNode){ super(javaType, expressionNode); this.metamodel = metamodel; } - public ExpressionImpl(Metamodel metamodel, Class javaType, org.eclipse.persistence.expressions.Expression expressionNode, Object value){ - super(javaType, expressionNode); + // Literal value + public ExpressionImpl(Metamodel metamodel, Class javaType, org.eclipse.persistence.expressions.Expression expressionNode, Object value) { + this(metamodel, javaType, expressionNode, value, true, null); + } + + // Allows complete clone of the instance + private ExpressionImpl( + Metamodel metamodel, + Class javaType, + org.eclipse.persistence.expressions.Expression expressionNode, + Object value, + boolean isLiteral, + String alias) { + super(javaType, expressionNode, alias); this.metamodel = metamodel; this.literal = value; - this.isLiteral = true; + this.isLiteral = isLiteral; } @Override public Expression as(Class type) { - Project project = ((MetamodelImpl)metamodel).getProject(); - if (project != null){ - ClassDescriptor descriptor = project.getClassDescriptor(javaType); - if (descriptor != null && descriptor.hasInheritance()){ - descriptor = descriptor.getInheritancePolicy().getSubclassDescriptor(type); - if (descriptor != null){ - return buildExpressionForAs(type); - } - } - } - return (Expression) this; + // JPA spec: This shall return new instance according to spec, but historical code does only cast + return buildExpressionForAs(type); } - // TODO-API-3.2 @Override public Expression cast(Class type) { - throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet"); + // JPA spec: New instance with provided Java type + return new ExpressionImpl<>(metamodel, type, currentNode, literal, isLiteral, alias); } + @SuppressWarnings("unchecked") protected Expression buildExpressionForAs(Class type) { return (Expression) this; } - - // TODO-API-3.2 @Override public Predicate equalTo(Expression value) { - throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet"); + return new CompoundExpressionImpl( + this.metamodel, + this.currentNode.equal(currentNode(value)), + List.of(this, value), + "equals"); } - // TODO-API-3.2 @Override public Predicate equalTo(Object value) { - throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet"); + return new CompoundExpressionImpl( + this.metamodel, + this.currentNode.equal(value), + List.of(this, createLiteral(value, metamodel)), + "equals"); } - // TODO-API-3.2 @Override public Predicate notEqualTo(Expression value) { - throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet"); + return new CompoundExpressionImpl( + this.metamodel, + this.currentNode.notEqual(currentNode(value)), + List.of(this, value), + "not equal"); } - // TODO-API-3.2 @Override public Predicate notEqualTo(Object value) { - throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet"); + return new CompoundExpressionImpl( + this.metamodel, + this.currentNode.notEqual(value), + List.of(this, createLiteral(value, metamodel)), + "not equal"); } @Override @@ -229,4 +247,24 @@ public void findRootAndParameters(CommonAbstractCriteriaImpl criteriaQuery){ //no-op because an expression will have no root } + // Literal Expression factory method + static Expression createLiteral(T value, Metamodel metamodel, Class resultClass) { + return new ExpressionImpl( + metamodel, + resultClass, + new ConstantExpression(value, new ExpressionBuilder()), value); + + } + + // Literal Expression factory method + @SuppressWarnings("unchecked") + static Expression createLiteral(T value, Metamodel metamodel) { + return createLiteral(value, metamodel, value == null ? null : (Class) value.getClass()); + } + + // Shortcut to return current expression node + static org.eclipse.persistence.expressions.Expression currentNode(Expression expression) { + return ((InternalSelection)expression).getCurrentNode(); + } + } diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/InternalSelection.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/InternalSelection.java index b5bdcfe8217..27b0f648c7e 100644 --- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/InternalSelection.java +++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/InternalSelection.java @@ -40,9 +40,4 @@ public interface InternalSelection { boolean isRoot(); boolean isConstructor(); - // Shortcut to return current expression node - static org.eclipse.persistence.expressions.Expression currentNode(Expression expression) { - return ((InternalSelection)expression).getCurrentNode(); - } - } diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/ParameterExpressionImpl.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/ParameterExpressionImpl.java index aadb30cb637..088338c65cf 100644 --- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/ParameterExpressionImpl.java +++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/ParameterExpressionImpl.java @@ -90,9 +90,10 @@ public Integer getPosition(){ * native query when the implementation does not support this * use. */ - @Override + @Override + @SuppressWarnings("unchecked") public Class getParameterType(){ - return this.javaType; + return (Class) this.javaType; } @Override diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/SelectionImpl.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/SelectionImpl.java index ef08dec53ff..610c1757490 100644 --- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/SelectionImpl.java +++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/SelectionImpl.java @@ -38,7 +38,7 @@ */ public abstract class SelectionImpl implements Selection, InternalSelection, Serializable{ - protected Class javaType; + protected Class javaType; protected Expression currentNode; /** @@ -52,11 +52,18 @@ public Expression getCurrentNode() { protected String alias; - public SelectionImpl(Class javaType, Expression expressionNode){ + public SelectionImpl(Class javaType, Expression expressionNode){ this.javaType = javaType; this.currentNode = expressionNode; } + // Allows complete clone of the instance + protected SelectionImpl(Class javaType, Expression expressionNode, String alias) { + this.javaType = javaType; + this.currentNode = expressionNode; + this.alias = alias; + } + //SELECTION /** * Assign an alias to the selection.