blob: a40aef115495bb5ba3759ae22631e59218638659 [file] [log] [blame]
/*
* Copyright (c) 2011, 2021 Oracle and/or its affiliates. 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:
// Oracle - initial API and implementation
//
package org.eclipse.persistence.jpa.jpql.tools.model.query;
import org.eclipse.persistence.jpa.jpql.parser.CollectionValuedPathExpression;
import org.eclipse.persistence.jpa.jpql.tools.TypeHelper;
import org.eclipse.persistence.jpa.jpql.tools.spi.IManagedType;
import org.eclipse.persistence.jpa.jpql.tools.spi.IMapping;
import org.eclipse.persistence.jpa.jpql.tools.spi.IType;
import org.eclipse.persistence.jpa.jpql.tools.spi.ITypeDeclaration;
/**
* A collection-valued field is designated by the name of an association field in a one-to-many or a
* many-to-many relationship or by the name of an element collection field. The type of a
* collection-valued field is a collection of values of the abstract schema type of the related
* entity or element type.
*
* <div><p><b>BNF:</b> <code>collection_valued_path_expression ::= general_identification_variable.{single_valued_object_field.}*collection_valued_field</code></p></div>
*
* @see CollectionValuedPathExpression
*
* @version 2.4
* @since 2.4
* @author Pascal Filion
*/
public class CollectionValuedPathExpressionStateObject extends AbstractPathExpressionStateObject {
/**
* Creates a new <code>CollectionValuedPathExpressionStateObject</code>.
*
* @param parent The parent of this state object, which cannot be <code>null</code>
* @exception NullPointerException The given parent cannot be <code>null</code>
*/
public CollectionValuedPathExpressionStateObject(StateObject parent) {
super(parent);
}
/**
* Creates a new <code>CollectionValuedPathExpressionStateObject</code>.
*
* @param parent The parent of this state object, which cannot be <code>null</code>
* @param path The collection-valued path expression
* @exception NullPointerException The given parent cannot be <code>null</code>
*/
public CollectionValuedPathExpressionStateObject(StateObject parent, String path) {
super(parent, path);
}
@Override
public void accept(StateObjectVisitor visitor) {
visitor.visit(this);
}
@Override
public CollectionValuedPathExpression getExpression() {
return (CollectionValuedPathExpression) super.getExpression();
}
@Override
protected IManagedType resolveManagedType() {
IMapping mapping = getMapping();
if (mapping == null) {
return null;
}
TypeHelper typeHelper = getTypeHelper();
ITypeDeclaration typeDeclaration = mapping.getTypeDeclaration();
IType type = typeDeclaration.getType();
// Collection type cannot be traversed
// Example: SELECT e.employees. FROM Employee e where employees is a collection,
// it cannot be traversed
if (typeHelper.isCollectionType(type)) {
return null;
}
// Primitive types cannot have a managed type
if (typeHelper.isPrimitiveType(type)) {
return null;
}
// Retrieve the corresponding managed type for the mapping's type
return getManagedTypeProvider().getManagedType(type);
}
@Override
protected IType resolveType() {
TypeHelper typeHelper = getTypeHelper();
ITypeDeclaration typeDeclaration = getTypeDeclaration();
IType type = typeDeclaration.getType();
// For a collection type, return the first type parameter
if (typeHelper.isCollectionType(type)) {
ITypeDeclaration[] typeParameters = typeDeclaration.getTypeParameters();
if (typeParameters.length > 0) {
type = typeParameters[0].getType();
}
}
// For a map type, by default the value is the actual type to return
else if (typeHelper.isMapType(type)) {
ITypeDeclaration[] typeParameters = typeDeclaration.getTypeParameters();
if (typeParameters.length == 2) {
type = typeParameters[1].getType();
}
}
// A collection-valued path expression should not reference a primitive,
// however, in an invalid query, this could potentially happen and the API
// only deals with the primitive wrapper type
return typeHelper.convertPrimitive(type);
}
/**
* Keeps a reference of the {@link CollectionValuedPathExpression parsed object} object, which
* should only be done when this object is instantiated during the conversion of a parsed JPQL
* query into {@link StateObject StateObjects}.
*
* @param expression The {@link CollectionValuedPathExpression parsed object} representing a
* collection-valued path expression
*/
public void setExpression(CollectionValuedPathExpression expression) {
super.setExpression(expression);
}
}