Skip to content

Commit

Permalink
jakartaee/persistence#395 - JPQL cast() function
Browse files Browse the repository at this point in the history
jakartaee/persistence#438 - add Expression.equalTo() and Expression.notEqualTo()

Signed-off-by: Tomáš Kraus <tomas.kraus@oracle.com>
  • Loading branch information
Tomas-Kraus committed Oct 17, 2023
1 parent e57f189 commit 4bb0a5c
Show file tree
Hide file tree
Showing 6 changed files with 254 additions and 101 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {

Expand Down Expand Up @@ -260,7 +261,7 @@ public <X extends Comparable<? super X>> Expression<X> greatest(Expression<X> 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());
}

/**
Expand All @@ -276,7 +277,7 @@ public <X extends Comparable<? super X>> Expression<X> least(Expression<X> 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());
}

/**
Expand Down Expand Up @@ -883,11 +884,11 @@ public <Y extends Comparable<? super Y>> Predicate between(Expression<? extends
return new CompoundExpressionImpl(this.metamodel, ((ExpressionImpl)v).getCurrentNode().between(x, y), buildList(v, internalLiteral(x), internalLiteral(y)), "between");
}

protected List<Expression<?>> buildList(Expression<?>... expressions){
List<Expression<?>> list = new ArrayList<>();
for(Expression<?> exp : expressions){
list.add(exp);
}
protected List<Expression<?>> 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<Expression<?>> list = new ArrayList<>(expressions.length + 2);
Collections.addAll(list, expressions);
return list;
}

Expand Down Expand Up @@ -1485,7 +1486,7 @@ public <T> Expression<T> literal(T value){
if (value == null) {
throw new IllegalArgumentException( ExceptionLocalization.buildMessage("jpa_criteriaapi_null_literal_value", new Object[]{}));
}
return new ExpressionImpl<T>(metamodel, (Class<T>) (value.getClass()), new ConstantExpression(value, new ExpressionBuilder()), value);
return ExpressionImpl.createLiteral(value, metamodel);
}

/**
Expand All @@ -1495,8 +1496,8 @@ public <T> Expression<T> literal(T value){
* @return null expression literal
*/
@Override
public <T> Expression<T> nullLiteral(Class<T> resultClass){
return new ExpressionImpl<T>(metamodel, resultClass, new ConstantExpression(null, new ExpressionBuilder()), null);
public <T> Expression<T> nullLiteral(Class<T> resultClass) {
return ExpressionImpl.createLiteral(null, metamodel, resultClass);
}

/**
Expand All @@ -1505,14 +1506,14 @@ public <T> Expression<T> nullLiteral(Class<T> resultClass){
* @return expression literal
*/
protected <T> Expression<T> internalLiteral(T value){
return new ExpressionImpl<T>(metamodel, (Class<T>) (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
*/
Expand Down Expand Up @@ -2297,7 +2298,7 @@ public Expression<Integer> locate(Expression<String> x, String pattern, int from
*/
@Override
public Expression<java.sql.Date> currentDate(){
return new ExpressionImpl(metamodel, ClassConstants.SQLDATE, new ExpressionBuilder().currentDateDate());
return new ExpressionImpl<>(metamodel, ClassConstants.SQLDATE, new ExpressionBuilder().currentDateDate());
}

/**
Expand All @@ -2307,7 +2308,7 @@ public Expression<java.sql.Date> currentDate(){
*/
@Override
public Expression<java.sql.Timestamp> currentTimestamp(){
return new ExpressionImpl(metamodel, ClassConstants.TIMESTAMP, new ExpressionBuilder().currentTimeStamp());
return new ExpressionImpl<>(metamodel, ClassConstants.TIMESTAMP, new ExpressionBuilder().currentTimeStamp());
}

/**
Expand All @@ -2317,7 +2318,7 @@ public Expression<java.sql.Timestamp> currentTimestamp(){
*/
@Override
public Expression<java.sql.Time> currentTime(){
return new ExpressionImpl(metamodel, ClassConstants.TIME, new ExpressionBuilder().currentTime());
return new ExpressionImpl<>(metamodel, ClassConstants.TIME, new ExpressionBuilder().currentTime());
}

/**
Expand All @@ -2327,7 +2328,7 @@ public Expression<java.sql.Time> currentTime(){
*/
@Override
public Expression<java.time.LocalDateTime> localDateTime() {
return new ExpressionImpl(metamodel, ClassConstants.LOCAL_DATETIME, new ExpressionBuilder().localDateTime());
return new ExpressionImpl<>(metamodel, ClassConstants.LOCAL_DATETIME, new ExpressionBuilder().localDateTime());
}

/**
Expand All @@ -2337,7 +2338,7 @@ public Expression<java.time.LocalDateTime> localDateTime() {
*/
@Override
public Expression<java.time.LocalDate> localDate() {
return new ExpressionImpl(metamodel, ClassConstants.LOCAL_DATE, new ExpressionBuilder().localDate());
return new ExpressionImpl<>(metamodel, ClassConstants.LOCAL_DATE, new ExpressionBuilder().localDate());
}

/**
Expand All @@ -2347,7 +2348,7 @@ public Expression<java.time.LocalDate> localDate() {
*/
@Override
public Expression<java.time.LocalTime> localTime() {
return new ExpressionImpl(metamodel, ClassConstants.LOCAL_TIME, new ExpressionBuilder().localTime());
return new ExpressionImpl<>(metamodel, ClassConstants.LOCAL_TIME, new ExpressionBuilder().localTime());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -45,66 +47,82 @@ public class ExpressionImpl<X> extends SelectionImpl<X> implements Expression<X>
protected boolean isLiteral;
protected Object literal;

protected ExpressionImpl(Metamodel metamodel, Class<X> javaType, org.eclipse.persistence.expressions.Expression expressionNode){
// Non literal value
protected ExpressionImpl(Metamodel metamodel, Class<? extends X> javaType, org.eclipse.persistence.expressions.Expression expressionNode){
super(javaType, expressionNode);
this.metamodel = metamodel;
}

public ExpressionImpl(Metamodel metamodel, Class<X> javaType, org.eclipse.persistence.expressions.Expression expressionNode, Object value){
super(javaType, expressionNode);
// Literal value
public ExpressionImpl(Metamodel metamodel, Class<? extends X> 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<? extends X> 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 <T> Expression<T> as(Class<T> 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<T>) 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 <X1> Expression<X1> cast(Class<X1> 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 <T> Expression<T> buildExpressionForAs(Class<T> type) {
return (Expression<T>) 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
Expand Down Expand Up @@ -229,4 +247,24 @@ public void findRootAndParameters(CommonAbstractCriteriaImpl criteriaQuery){
//no-op because an expression will have no root
}

// Literal Expression factory method
static <T> Expression<T> createLiteral(T value, Metamodel metamodel, Class<T> resultClass) {
return new ExpressionImpl<T>(
metamodel,
resultClass,
new ConstantExpression(value, new ExpressionBuilder()), value);

}

// Literal Expression factory method
@SuppressWarnings("unchecked")
static <T> Expression<T> createLiteral(T value, Metamodel metamodel) {
return createLiteral(value, metamodel, value == null ? null : (Class<T>) value.getClass());
}

// Shortcut to return current expression node
static org.eclipse.persistence.expressions.Expression currentNode(Expression<?> expression) {
return ((InternalSelection)expression).getCurrentNode();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,10 @@ public Integer getPosition(){
* native query when the implementation does not support this
* use.
*/
@Override
@Override
@SuppressWarnings("unchecked")
public Class<T> getParameterType(){
return this.javaType;
return (Class<T>) this.javaType;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
*/
public abstract class SelectionImpl<X> implements Selection<X>, InternalSelection, Serializable{

protected Class<X> javaType;
protected Class<? extends X> javaType;
protected Expression currentNode;

/**
Expand All @@ -52,11 +52,18 @@ public Expression getCurrentNode() {

protected String alias;

public <T> SelectionImpl(Class<X> javaType, Expression expressionNode){
public SelectionImpl(Class<? extends X> javaType, Expression expressionNode){
this.javaType = javaType;
this.currentNode = expressionNode;
}

// Allows complete clone of the instance
protected SelectionImpl(Class<? extends X> javaType, Expression expressionNode, String alias) {
this.javaType = javaType;
this.currentNode = expressionNode;
this.alias = alias;
}

//SELECTION
/**
* Assign an alias to the selection.
Expand Down

0 comments on commit 4bb0a5c

Please sign in to comment.