blob: 57e528b2d04a6fa4525d6d4a8172445a0d343b29 [file] [log] [blame]
/*
* Copyright (c) 1998, 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 from Oracle TopLink
package org.eclipse.persistence.internal.jpa.parsing;
// Java imports
import java.util.*;
import org.eclipse.persistence.exceptions.JPQLException;
import org.eclipse.persistence.queries.ObjectLevelReadQuery;
import org.eclipse.persistence.queries.ReportQuery;
/**
* INTERNAL
* <p><b>Purpose</b>: Represent a constructor node (NEW)
* <p><b>Responsibilities</b>:<ul>
* <li> Generate the correct expression for a constructor
* </ul>
*/
public class ConstructorNode extends Node implements AliasableNode {
/** The name of the constructor class. */
private String className = null;
/** The list of constructor call argument nodes */
public List<Node> constructorItems = new ArrayList<>();
/**
* Return a new ConstructorNode
*/
public ConstructorNode(String className) {
this.className = className;
}
/**
* INTERNAL
* Apply this node to the passed query
*/
@Override
public void applyToQuery(ObjectLevelReadQuery theQuery, GenerationContext context) {
if (theQuery instanceof ReportQuery) {
SelectGenerationContext selectContext = (SelectGenerationContext)context;
ReportQuery reportQuery = (ReportQuery)theQuery;
reportQuery.beginAddingConstructorArguments(
getConstructorClass(context.getParseTreeContext()));
for (Iterator<Node> i = constructorItems.iterator(); i.hasNext();) {
Node node = i.next();
if (selectingRelationshipField(node, context)) {
selectContext.useOuterJoins();
}
node.applyToQuery(reportQuery, context);
selectContext.dontUseOuterJoins();
}
reportQuery.endAddingToConstructorItem();
}
}
/**
* INTERNAL
* Validate node and calculate its type.
*/
@Override
public void validate(ParseTreeContext context) {
for (Iterator<Node> i = constructorItems.iterator(); i.hasNext();) {
Node item = i.next();
item.validate(context);
}
// Resolve constructor class
TypeHelper typeHelper = context.getTypeHelper();
Object type = typeHelper.resolveTypeName(className);
if (type == null) {
String name = className;
// check for inner classes
int index = name.lastIndexOf('.');
if (index != -1) {
name = name.substring(0, index) + '$' + name.substring(index+1);
type = typeHelper.resolveTypeName(name);
}
}
setType(type);
}
/**
* INTERNAL
* Is this node a ConstructorNode
*/
@Override
public boolean isConstructorNode() {
return true;
}
/**
* INTERNAL
* Add an Order By Item to this node
*/
public void addConstructorItem(Node theNode) {
constructorItems.add(theNode);
}
/**
* INTERNAL
* Set the list of constructor items of this node.
*/
public void setConstructorItems(List<Node> items) {
this.constructorItems = items;
}
/**
* INTERNAL
* Get the list of constructor items of this node.
*/
public List<Node> getConstructorItems() {
return this.constructorItems;
}
/**
* Check the specific constructor class and return its class instance.
* @exception JPQLException if the specified constructor class could not
* be found.
*/
private Class<?> getConstructorClass(ParseTreeContext context) {
Object type = getType();
if (type == null) {
throw JPQLException.constructorClassNotFound(
context.getQueryInfo(), getLine(), getColumn(), className);
}
return (Class<?>)type;
}
/**
* INTERNAL
*/
private boolean selectingRelationshipField(Node node, GenerationContext context) {
if ((node == null) || !node.isDotNode()) {
return false;
}
TypeHelper typeHelper = context.getParseTreeContext().getTypeHelper();
Node path = node.getLeft();
AttributeNode attribute = (AttributeNode)node.getRight();
return typeHelper.isRelationship(path.getType(),
attribute.getAttributeName());
}
/**
* INTERNAL
* Get the string representation of this node.
*/
@Override
public String getAsString() {
StringBuilder repr = new StringBuilder();
repr.append("NEW ").append(className);
repr.append("(");
for (Iterator<Node> i = constructorItems.iterator(); i.hasNext();) {
Node node = i.next();
repr.append(node.getAsString());
if (i.hasNext()) {
repr.append(", ");
}
}
repr.append(")");
return repr.toString();
}
@Override
public boolean isAliasableNode(){
return true;
}
}