All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.internal.jpa.querydef.CriteriaQueryImpl Maven / Gradle / Ivy

There is a newer version: 5.0.0-B03
Show newest version
/*
 * Copyright (c) 2011, 2022 Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 2021, 2022 IBM Corporation. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Gordon Yorke - Initial development
//     10/01/2018: Will Dazey
//       - #253: Add support for embedded constructor results with CriteriaBuilder
package org.eclipse.persistence.internal.jpa.querydef;

import java.lang.reflect.Constructor;
import java.security.AccessController;
import java.util.*;

import jakarta.persistence.Tuple;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Order;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Selection;
import jakarta.persistence.metamodel.Metamodel;
import jakarta.persistence.metamodel.Type.PersistenceType;

import org.eclipse.persistence.expressions.ExpressionBuilder;
import org.eclipse.persistence.internal.helper.BasicTypeHelperImpl;
import org.eclipse.persistence.internal.helper.ClassConstants;
import org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl;
import org.eclipse.persistence.internal.jpa.metamodel.TypeImpl;
import org.eclipse.persistence.internal.localization.ExceptionLocalization;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedGetConstructorFor;
import org.eclipse.persistence.queries.DatabaseQuery;
import org.eclipse.persistence.queries.ObjectLevelReadQuery;
import org.eclipse.persistence.queries.ReadAllQuery;
import org.eclipse.persistence.queries.ReportQuery;

/**
 * 

* Purpose: Contains the implementation of the CriteriaQuery interface of * the JPA criteria API. *

* Description: This is the container class for the components that * define a query. * * @see jakarta.persistence.criteria CriteriaQuery * * @author gyorke * @since EclipseLink 1.2 */ public class CriteriaQueryImpl extends AbstractQueryImpl implements CriteriaQuery { protected SelectionImpl selection; protected List orderBy; protected Set joins; public CriteriaQueryImpl(Metamodel metamodel, ResultType queryResult, Class result, CriteriaBuilderImpl queryBuilder) { super(metamodel, queryResult, queryBuilder, result); } /** * Specify the item that is to be returned in the query result. Replaces the * previously specified selection, if any. * * @param selection * selection specifying the item that is to be returned in the * query result * @return the modified query */ @Override public CriteriaQuery select(Selection selection) { this.selection = (SelectionImpl) selection; this.selection.findRootAndParameters(this); if (selection.isCompoundSelection()) { //bug 366386: validate that aliases are not reused if (this.selection.isCompoundSelection() && ((CompoundSelectionImpl)this.selection).getDuplicateAliasNames() != null) { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("jpa_criteriaapi_alias_reused", new Object[] { ((CompoundSelectionImpl)this.selection).getDuplicateAliasNames() })); } if (selection.getJavaType().equals(Tuple.class)) { this.queryResult = ResultType.TUPLE; this.queryType = (Class) Tuple.class; } else if (((InternalSelection) selection).isConstructor()) { Selection[] selectArray = selection.getCompoundSelectionItems().toArray(new Selection[selection.getCompoundSelectionItems().size()]); populateAndSetConstructorSelection((ConstructorSelectionImpl)selection, this.selection.getJavaType(), selectArray); this.queryType = (Class) selection.getJavaType(); } else { this.queryResult = ResultType.OBJECT_ARRAY; this.queryType = (Class) ClassConstants.AOBJECT; } } else { // Update query type only when it's not null in selection argument. Class queryType = selection.getJavaType(); if (queryType != null) { this.queryType = (Class) queryType; } TypeImpl type = ((MetamodelImpl)this.metamodel).getType(this.queryType); if (type != null && type.getPersistenceType().equals(PersistenceType.ENTITY)) { this.queryResult = ResultType.ENTITY; // this will be a selection item in a report query } else { this.queryResult = ResultType.OTHER; } } return this; } /** * Specify the items that are to be returned in the query result. Replaces * the previously specified selection(s), if any. * * The type of the result of the query execution depends on the * specification of the criteria query object as well as the arguments to * the multiselect method as follows: * * If the type of the criteria query is CriteriaQuery<Tuple>, a Tuple object * corresponding to the arguments of the multiselect method will be * instantiated and returned for each row that results from the query * execution. * * If the type of the criteria query is CriteriaQuery<X> for some * user-defined class X, then the arguments to the multiselect method will * be passed to the X constructor and an instance of type X will be returned * for each row. The IllegalStateException will be thrown if a constructor * for the given argument types does not exist. * * If the type of the criteria query is CriteriaQuery<X[]> for some class X, * an instance of type X[] will be returned for each row. The elements of * the array will correspond to the arguments of the multiselect method. The * IllegalStateException will be thrown if the arguments to the multiselect * method are not of type X. * * If the type of the criteria query is CriteriaQuery<Object>, and only a * single argument is passed to the multiselect method, an instance of type * Object will be returned for each row. * * If the type of the criteria query is CriteriaQuery<Object>, and more than * one argument is passed to the multiselect method, an instance of type * Object[] will be instantiated and returned for each row. The elements of * the array will correspond to the arguments to the multiselect method. * * @param selections * expressions specifying the items that are to be returned in * the query result * @return the modified query */ @Override public CriteriaQuery multiselect(Selection... selections) { if (selections == null || selections.length == 0) { this.selection = null; return this; } for (Selection select : selections) { ((SelectionImpl)select).findRootAndParameters(this); } if (this.queryResult == ResultType.CONSTRUCTOR) { populateAndSetConstructorSelection(null, this.queryType, selections); } else if (this.queryResult.equals(ResultType.ENTITY)) { if (selections.length == 1 && selections[0].getJavaType().equals(this.queryType)) { this.selection = (SelectionImpl) selections[0]; } else { try { populateAndSetConstructorSelection(null, this.queryType, selections);//throws IllegalArgumentException if it doesn't exist } catch(IllegalArgumentException constructorDoesNotExist){ this.queryResult = ResultType.PARTIAL; this.selection = new CompoundSelectionImpl(this.queryType, selections); } } } else if (this.queryResult.equals(ResultType.TUPLE)) { this.selection = new CompoundSelectionImpl(this.queryType, selections); } else if (this.queryResult.equals(ResultType.OTHER)) { if (selections.length == 1 && selections[0].getJavaType().equals(this.queryType)) { this.selection = (SelectionImpl) selections[0]; } else { if (!BasicTypeHelperImpl.getInstance().isDateClass(this.queryType)) { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("MULTIPLE_SELECTIONS_PASSED_TO_QUERY_WITH_PRIMITIVE_RESULT")); } populateAndSetConstructorSelection(null, this.queryType, selections); } } else { // unknown this.selection = new CompoundSelectionImpl(this.queryType, selections); } //bug 366386: validate that aliases are not reused if (this.selection.isCompoundSelection() && ((CompoundSelectionImpl)this.selection).getDuplicateAliasNames() != null) { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("jpa_criteriaapi_alias_reused", new Object[] { ((CompoundSelectionImpl)this.selection).getDuplicateAliasNames() })); } return this; } /** * Specify the items that are to be returned in the query result. Replaces * the previously specified selection(s), if any. * * The type of the result of the query execution depends on the * specification of the criteria query object as well as the arguments to * the multiselect method as follows: * * If the type of the criteria query is CriteriaQuery<Tuple>, a Tuple object * corresponding to the items in the selection list passed to the * multiselect method will be instantiated and returned for each row that * results from the query execution. * * If the type of the criteria query is CriteriaQuery<X> for some * user-defined class X, then the items in the selection list passed to the * multiselect method will be passed to the X constructor and an instance of * type X will be returned for each row. The IllegalStateException will be * thrown if a constructor for the given argument types does not exist. * * If the type of the criteria query is CriteriaQuery<X[]> for some class X, * an instance of type X[] will be returned for each row. The elements of * the array will correspond to the items in the selection list passed to * the multiselect method. The IllegalStateException will be thrown if the * elements in the selection list passed to the multiselect method are not * of type X. * * If the type of the criteria query is CriteriaQuery<Object>, and the * selection list passed to the multiselect method contains only a single * item, an instance of type Object will be returned for each row. * * If the type of the criteria query is CriteriaQuery<Object>, and the * selection list passed to the multiselect method contains more than one * item, an instance of type Object[] will be instantiated and returned for * each row. The elements of the array will correspond to the items in the * selection list passed to the multiselect method. * * @param selectionList * list of expressions specifying the items that to be are * returned in the query result * @return the modified query */ @Override public CriteriaQuery multiselect(List> selectionList) { if (selectionList == null) { this.selection = null; return this; } return this.multiselect(selectionList.toArray(new Selection[selectionList.size()])); } // override the return type only: /** * Modify the query to restrict the query result according to the specified * boolean expression. Replaces the previously added restriction(s), if any. * This method only overrides the return type of the corresponding * AbstractQuery method. * * @param restriction * a simple or compound boolean expression * @return the modified query */ @Override public CriteriaQuery where(Expression restriction) { return (CriteriaQuery) super.where(restriction); } /** * Modify the query to restrict the query result according to the * conjunction of the specified restriction predicates. Replaces the * previously added restriction(s), if any. If no restrictions are * specified, any previously added restrictions are simply removed. This * method only overrides the return type of the corresponding AbstractQuery * method. * * @param restrictions * zero or more restriction predicates * @return the modified query */ @Override public CriteriaQuery where(Predicate... restrictions) { return (CriteriaQuery) super.where(restrictions); } /** * Specify the expressions that are used to form groups over the query * results. Replaces the previous specified grouping expressions, if any. If * no grouping expressions are specified, any previously added grouping * expressions are simply removed. This method only overrides the return * type of the corresponding AbstractQuery method. * * @param grouping * zero or more grouping expressions * @return the modified query */ @Override public CriteriaQuery groupBy(Expression... grouping) { super.groupBy(grouping); return this; } /** * Specify the expressions that are used to form groups over the query * results. Replaces the previous specified grouping expressions, if any. If * no grouping expressions are specified, any previously added grouping * expressions are simply removed. This method only overrides the return * type of the corresponding AbstractQuery method. * * @param grouping * list of zero or more grouping expressions * @return the modified query */ @Override public CriteriaQuery groupBy(List> grouping) { super.groupBy(grouping); return this; } /** * Specify a restriction over the groups of the query. Replaces the previous * having restriction(s), if any. This method only overrides the return type * of the corresponding AbstractQuery method. * * @param restriction * a simple or compound boolean expression * @return the modified query */ @Override public CriteriaQuery having(Expression restriction) { super.having(restriction); return this; } /** * Specify restrictions over the groups of the query according the * conjunction of the specified restriction predicates. Replaces the * previously added restriction(s), if any. If no restrictions are * specified, any previously added restrictions are simply removed. This * method only overrides the return type of the corresponding AbstractQuery * method. * * @param restrictions * zero or more restriction predicates * @return the modified query */ @Override public CriteriaQuery having(Predicate... restrictions) { super.having(restrictions); return this; } /** * Specify the ordering expressions that are used to order the query * results. Replaces the previous ordering expressions, if any. If no * ordering expressions are specified, the previous ordering, if any, is * simply removed, and results will be returned in no particular order. The * left-to-right sequence of the ordering expressions determines the * precedence, whereby the leftmost has highest precedence. * * @param o * zero or more ordering expressions * @return the modified query. */ @Override public CriteriaQuery orderBy(Order... o) { this.orderBy = new ArrayList<>(); for (Order order : o) { findRootAndParameters(order); this.orderBy.add(order); } return this; } /** * Specify the ordering expressions that are used to order the query * results. Replaces the previous ordering expressions, if any. If no * ordering expressions are specified, the previous ordering, if any, is * simply removed, and results will be returned in no particular order. The * order of the ordering expressions in the list determines the precedence, * whereby the first element in the list has highest precedence. * * @param o * list of zero or more ordering expressions * @return the modified query. */ @Override public CriteriaQuery orderBy(List o) { for (Order order : o) { findRootAndParameters(order); } this.orderBy = o; return this; } /** * This method will set this queryImpl's selection to a ConstructorSelectionImpl, creating a new * instance or populating the one passed in as necessary. * Throws IllegalArgumentException if a constructor taking arguments represented * by the selections array doesn't exist for the given class. * * Also sets the query result to ResultType.CONSTRUCTOR * */ public void populateAndSetConstructorSelection(ConstructorSelectionImpl constructorSelection, Class class1, Selection... selections) throws IllegalArgumentException{ Class[] constructorArgs = new Class[selections.length]; int count = 0; for (Selection select : selections) { if(select instanceof ConstructorSelectionImpl) { ConstructorSelectionImpl constructorSelect = (ConstructorSelectionImpl)select; Selection[] selectArray = constructorSelect.getCompoundSelectionItems().toArray(new Selection[constructorSelect.getCompoundSelectionItems().size()]); populateAndSetConstructorSelection(constructorSelect, constructorSelect.getJavaType(), selectArray); } constructorArgs[count++] = select.getJavaType(); } Constructor constructor = null; try { if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) { constructor = AccessController.doPrivileged(new PrivilegedGetConstructorFor<>(class1, constructorArgs, false)); } else { constructor = PrivilegedAccessHelper.getConstructorFor(class1, constructorArgs, false); } if (constructorSelection == null){ constructorSelection = new ConstructorSelectionImpl(class1, selections); } this.queryResult = ResultType.CONSTRUCTOR; constructorSelection.setConstructor(constructor); constructorSelection.setConstructorArgTypes(constructorArgs); this.selection = constructorSelection; } catch (Exception e){ //PrivilegedActionException and NoSuchMethodException are possible Object[] params = new Object[1]; params[0] = this.queryType; throw new IllegalArgumentException(ExceptionLocalization.buildMessage("criteria_no_constructor_found", params), e); } } /** * Specify whether duplicate query results will be eliminated. A true value * will cause duplicates to be eliminated. A false value will cause * duplicates to be retained. If distinct has not been specified, duplicate * results must be retained. This method only overrides the return type of * the corresponding AbstractQuery method. * * @param distinct * boolean value specifying whether duplicate results must be * eliminated from the query result or whether they must be * retained * @return the modified query. */ @Override public CriteriaQuery distinct(boolean distinct) { super.distinct(distinct); return this; } @Override public void addJoin(FromImpl from) { if (this.joins == null) { this.joins = new LinkedHashSet(); } this.joins.add(from); } @Override protected DatabaseQuery getDatabaseQuery() { ObjectLevelReadQuery query = null; if (this.selection == null || !this.selection.isCompoundSelection()) { query = createSimpleQuery(); } else { query = createCompoundQuery(); } return query; } /** * Return the ordering expressions in order of precedence. * * @return the list of ordering expressions */ @Override public List getOrderList() { return this.orderBy; } /** * Return the selection item of the query. This will correspond to the query * type. * * @return the selection item of the query */ @Override public Selection getSelection() { return (Selection) this.selection; } /** * Translates from the criteria query to a EclipseLink Database Query. */ @SuppressWarnings("deprecation") protected ObjectLevelReadQuery createCompoundQuery() { ObjectLevelReadQuery query = null; if (this.queryResult == ResultType.UNKNOWN) { if (this.selection.isConstructor()) { this.queryResult = ResultType.CONSTRUCTOR; } else if (this.selection.getJavaType().equals(Tuple.class)) { this.queryResult = ResultType.TUPLE; } else { this.queryResult = ResultType.OBJECT_ARRAY; } } if (this.queryResult.equals(ResultType.PARTIAL)) { ReadAllQuery raq = new ReadAllQuery(this.queryType); for (Selection selection : this.selection.getCompoundSelectionItems()) { raq.addPartialAttribute(((SelectionImpl) selection).currentNode); } raq.setExpressionBuilder(((InternalSelection) this.selection.getCompoundSelectionItems().get(0)).getCurrentNode().getBuilder()); query = raq; } else { ReportQuery reportQuery = null; if (this.queryResult.equals(ResultType.CONSTRUCTOR) || this.queryResult.equals(ResultType.OTHER)) { // other is also a constructor type if multi-select was called. // with a type other than the query type. reportQuery = new ReportQuery(); reportQuery.addConstructorReportItem(((ConstructorSelectionImpl) this.selection).translate()); reportQuery.setShouldReturnSingleAttribute(true); } else { if (this.queryResult.equals(ResultType.TUPLE)) { reportQuery = new TupleQuery(this.selection == null ? new ArrayList<>() : this.selection.getCompoundSelectionItems()); } else { reportQuery = new ReportQuery(); reportQuery.setShouldReturnWithoutReportQueryResult(true); } reportQuery.setExpressionBuilder(((InternalSelection) this.selection.getCompoundSelectionItems().get(0)).getCurrentNode().getBuilder()); for (Selection nested : this.selection.getCompoundSelectionItems()) { if (((SelectionImpl) nested).isConstructor()) { reportQuery.addConstructorReportItem(((ConstructorSelectionImpl) nested).translate()); } else if (nested.isCompoundSelection()) { throw new IllegalStateException(ExceptionLocalization.buildMessage("NESTED_COMPOUND_SELECTION_OTHER_THAN_CONSTRUCTOR_NOT_SUPPORTED")); } else { if (((InternalSelection) nested).isFrom()) { reportQuery.addItem(nested.getAlias(), ((SelectionImpl) nested).getCurrentNode(), ((FromImpl) nested).findJoinFetches()); } else if (((InternalExpression) nested).isCompoundExpression() && ((FunctionExpressionImpl) nested).getOperation() == CriteriaBuilderImpl.SIZE) { //selecting size not all databases support subselect in select clause so convert to count/groupby PathImpl collectionExpression = (PathImpl) ((FunctionExpressionImpl) nested).getChildExpressions().get(0); ExpressionImpl fromExpression = (ExpressionImpl) collectionExpression.getParentPath(); reportQuery.addAttribute(nested.getAlias(), collectionExpression.getCurrentNode().count(), ClassConstants.INTEGER); reportQuery.addGrouping(fromExpression.getCurrentNode()); } else { reportQuery.addAttribute(nested.getAlias(), ((SelectionImpl) nested).getCurrentNode(), nested.getJavaType()); } } } } ExpressionBuilder builder = null; Class queryClazz = null; // First check the WHERE clause if(this.where != null && ((InternalSelection) this.where).getCurrentNode() != null) { builder = ((InternalSelection) this.where).getCurrentNode().getBuilder(); queryClazz = builder.getQueryClass(); } // Check all the SELECTION items next if(queryClazz == null && this.selection != null) { for(Selection s : this.selection.getCompoundSelectionItems()) { if(((InternalSelection) s).getCurrentNode() != null ) { builder = ((InternalSelection) s).getCurrentNode().getBuilder(); queryClazz = builder.getQueryClass(); if(queryClazz != null) { break; } } } } // Fallback on the root if(queryClazz == null && this.roots != null) { for(Root r : this.roots) { if(((RootImpl) r).getCurrentNode() != null ) { builder = ((RootImpl) r).getCurrentNode().getBuilder(); queryClazz = builder.getQueryClass(); if(queryClazz != null) { break; } } } } reportQuery.setExpressionBuilder(builder); reportQuery.setReferenceClass(queryClazz); query = reportQuery; if (this.groupBy != null && !this.groupBy.isEmpty()) { for (Expression exp : this.groupBy) { reportQuery.addGrouping(((InternalSelection) exp).getCurrentNode()); } } if (this.havingClause != null) { reportQuery.setHavingExpression(((InternalSelection) this.havingClause).getCurrentNode()); } } return query; } protected ObjectLevelReadQuery createSimpleQuery() { ObjectLevelReadQuery query = null; if (this.queryResult == ResultType.UNKNOWN) { // unknown type so let's figure this out. if (selection == null) { if (this.roots != null && !this.roots.isEmpty()) { this.selection = (SelectionImpl) this.roots.iterator().next(); query = new ReadAllQuery(((FromImpl) this.selection).getJavaType()); List list = ((FromImpl) this.roots.iterator().next()).findJoinFetches(); for (org.eclipse.persistence.expressions.Expression fetch : list) { query.addJoinedAttribute(fetch); } if (!list.isEmpty()) { query.setExpressionBuilder(list.get(0).getBuilder()); } } else if (this.roots == null || this.roots.isEmpty()) { throw new IllegalArgumentException(ExceptionLocalization.buildMessage("CRITERIA_NO_ROOT_FOR_COMPOUND_QUERY")); } } else { // Selection is not null set type to selection TypeImpl type = ((MetamodelImpl)this.metamodel).getType(selection.getJavaType()); if (type != null && type.getPersistenceType().equals(PersistenceType.ENTITY)) { query = new ReadAllQuery(type.getJavaType()); List list = ((FromImpl) this.roots.iterator().next()).findJoinFetches(); for (org.eclipse.persistence.expressions.Expression fetch : list) { query.addJoinedAttribute(fetch); } query.setExpressionBuilder(((InternalSelection)selection).getCurrentNode().getBuilder()); } else { query = new ReportQuery(); query.setReferenceClass(this.selection.getCurrentNode().getBuilder().getQueryClass()); if (!this.selection.isCompoundSelection() && ((InternalExpression) this.selection).isCompoundExpression()) { if (((FunctionExpressionImpl) this.selection).getOperation() == CriteriaBuilderImpl.SIZE) { //selecting size not all databases support subselect in select clause so convert to count/groupby PathImpl collectionExpression = (PathImpl) ((FunctionExpressionImpl) this.selection).getChildExpressions().get(0); ExpressionImpl fromExpression = (ExpressionImpl) collectionExpression.getParentPath(); ((ReportQuery) query).addAttribute(this.selection.getAlias(), collectionExpression.getCurrentNode().count(), ClassConstants.INTEGER); ((ReportQuery) query).addGrouping(fromExpression.getCurrentNode()); } ((ReportQuery) query).addAttribute(this.selection.getAlias(), this.selection.getCurrentNode(), this.selection.getJavaType()); } else { ((ReportQuery) query).addItem(this.selection.getAlias(), this.selection.getCurrentNode()); ((ReportQuery) query).setShouldReturnSingleAttribute(true); } } } } else if (this.queryResult.equals(ResultType.ENTITY)) { if (this.selection != null && (!((InternalSelection) this.selection).isRoot())) { query = new ReportQuery(); query.setReferenceClass(this.queryType); ((ReportQuery) query).addItem(this.selection.getAlias(), this.selection.getCurrentNode(), ((FromImpl) this.selection).findJoinFetches()); ((ReportQuery) query).setShouldReturnSingleAttribute(true); } else { query = new ReadAllQuery(this.queryType); if (this.roots != null && !this.roots.isEmpty()) { List list = ((FromImpl) this.roots.iterator().next()).findJoinFetches(); if (!list.isEmpty()) { query.setExpressionBuilder(list.get(0).getBuilder()); // set the builder to one of the fetches bases. } for (org.eclipse.persistence.expressions.Expression fetch : list) { query.addJoinedAttribute(fetch); } } if (selection != null) { query.setExpressionBuilder(this.selection.currentNode.getBuilder()); } } } else { ReportQuery reportQuery = null; if (this.queryResult.equals(ResultType.TUPLE)) { List list = new ArrayList<>(); list.add(this.selection); reportQuery = new TupleQuery(list); } else { reportQuery = new ReportQuery(); reportQuery.setShouldReturnWithoutReportQueryResult(true); } if (this.selection != null) { if (!this.selection.isCompoundSelection() && ((InternalExpression)this.selection).isCompoundExpression()){ if(((FunctionExpressionImpl)this.selection).getOperation() == CriteriaBuilderImpl.SIZE){ //selecting size not all databases support subselect in select clause so convert to count/groupby PathImpl collectionExpression = (PathImpl) ((FunctionExpressionImpl)this.selection).getChildExpressions().get(0); ExpressionImpl fromExpression = (ExpressionImpl) collectionExpression.getParentPath(); reportQuery.addAttribute(this.selection.getAlias(), collectionExpression.getCurrentNode().count(), ClassConstants.INTEGER); reportQuery.addGrouping(fromExpression.getCurrentNode()); }else{ reportQuery.addAttribute(this.selection.getAlias(), this.selection.getCurrentNode(), this.selection.getJavaType()); }}else{ if (((InternalSelection) selection).isFrom()) { reportQuery.addItem(selection.getAlias(), selection.getCurrentNode(), ((FromImpl) selection).findJoinFetches()); } else { reportQuery.addAttribute(selection.getAlias(), selection.getCurrentNode(), selection.getJavaType()); }} reportQuery.setReferenceClass(((InternalSelection) this.selection).getCurrentNode().getBuilder().getQueryClass()); reportQuery.setExpressionBuilder(((InternalSelection) this.selection).getCurrentNode().getBuilder()); } query = reportQuery; if (this.groupBy != null && !this.groupBy.isEmpty()) { for (Expression exp : this.groupBy) { reportQuery.addGrouping(((InternalSelection) exp).getCurrentNode()); } } if (this.havingClause != null) { reportQuery.setHavingExpression(((InternalSelection) this.havingClause).getCurrentNode()); } } if (query.getReferenceClass() == null){ if (this.where != null && ((InternalSelection) this.where).getCurrentNode() != null && ((InternalSelection) this.where).getCurrentNode().getBuilder() != null && ((InternalSelection) this.where).getCurrentNode().getBuilder().getQueryClass() != null) { query.setReferenceClass(((InternalSelection) this.where).getCurrentNode().getBuilder().getQueryClass()); } else if (roots != null && ! roots.isEmpty()){ Root root = this.getRoots().iterator().next(); query.setReferenceClass(root.getJavaType()); } } if (selection == null) { //the builder in the where clause may not be the correct builder for this query. Search for a root that matches the query type. if (roots != null && ! roots.isEmpty()){ for (Root root : this.getRoots()){ if (root.getJavaType().equals(this.queryType)){ query.setExpressionBuilder(((RootImpl) root).getCurrentNode().getBuilder()); break; } } } } return query; } /** * Translates from the criteria query to a EclipseLink Database Query. */ @Override public DatabaseQuery translate() { ObjectLevelReadQuery query = (ObjectLevelReadQuery)super.translate(); for (Iterator> iterator = this.getRoots().iterator(); iterator.hasNext();) { findJoins((FromImpl) iterator.next()); } if (this.joins != null && !joins.isEmpty()) { for (FromImpl join : this.joins) { query.addNonFetchJoinedAttribute(((InternalSelection) join).getCurrentNode()); } } if (this.distinct) { query.setDistinctState(ObjectLevelReadQuery.USE_DISTINCT); } else { query.setDistinctState(ObjectLevelReadQuery.DONT_USE_DISTINCT); if (query.hasJoining()) { query.setShouldFilterDuplicates(false); } } if (this.orderBy != null && !this.orderBy.isEmpty()) { for (Order order : this.orderBy) { OrderImpl orderImpl = (OrderImpl) order; org.eclipse.persistence.expressions.Expression orderExp = ((ExpressionImpl) orderImpl.getExpression()).getCurrentNode(); if (orderImpl.isAscending()) { orderExp = orderExp.ascending(); } else { orderExp = orderExp.descending(); } query.addOrdering(orderExp); } } return query; } }