Package org.eclipse.persistence.jpa.internal.jpql

Source Code of org.eclipse.persistence.jpa.internal.jpql.ParameterTypeVisitor

/*******************************************************************************
* Copyright (c) 2006, 2011 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
*     Oracle - initial API and implementation
*
******************************************************************************/
package org.eclipse.persistence.jpa.internal.jpql;

import java.util.Collection;
import org.eclipse.persistence.jpa.internal.jpql.parser.AbsExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.AbstractTraverseParentVisitor;
import org.eclipse.persistence.jpa.internal.jpql.parser.AdditionExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.AndExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.AvgFunction;
import org.eclipse.persistence.jpa.internal.jpql.parser.BetweenExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.CollectionValuedPathExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.ComparisonExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.CompoundExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.ConcatExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.CountFunction;
import org.eclipse.persistence.jpa.internal.jpql.parser.DivisionExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.EmptyCollectionComparisonExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.ExistsExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.Expression;
import org.eclipse.persistence.jpa.internal.jpql.parser.IdentificationVariable;
import org.eclipse.persistence.jpa.internal.jpql.parser.InExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.InputParameter;
import org.eclipse.persistence.jpa.internal.jpql.parser.LengthExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.LikeExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.LowerExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.MaxFunction;
import org.eclipse.persistence.jpa.internal.jpql.parser.MinFunction;
import org.eclipse.persistence.jpa.internal.jpql.parser.ModExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.MultiplicationExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.NullComparisonExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.NumericLiteral;
import org.eclipse.persistence.jpa.internal.jpql.parser.OrExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.SizeExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.SqrtExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.StateFieldPathExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.SubstringExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.SubtractionExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.SumFunction;
import org.eclipse.persistence.jpa.internal.jpql.parser.TrimExpression;
import org.eclipse.persistence.jpa.internal.jpql.parser.UpdateItem;
import org.eclipse.persistence.jpa.jpql.spi.IType;

/**
* This visitor's responsibility is to find the type of an input parameter.
*
* @version 2.3
* @since 2.3
* @author Pascal Filion
*/
final class ParameterTypeVisitor extends AbstractTraverseParentVisitor {

  /**
   * This is used to prevent an infinite loop between input parameters. Example: ":arg1 = :arg2".
   */
  private Expression currentExpression;

  /**
   * The {@link Expression} that will help to determine the type of the input parameter.
   */
  private Expression expression;

  /**
   * Used to ignore the type when calculating it. If <b>Object.class</b> was used, then it could
   * incorrectly calculate the type. Example: ":arg = 'JPQL' AND :arg IS NULL", the second :arg
   * should be ignored.
   */
  private boolean ignoreType;

  /**
   * The {@link InputParameter} for which its type will be searched by visiting the query.
   */
  private InputParameter inputParameter;

  /**
   * The context used to query information about the query.
   */
  private final JPQLQueryContext queryContext;

  /**
   * The well defined type, which does not have to be calculated.
   */
  private Class<?> type;

  /**
   * Creates a new <code>ParameterTypeVisitor</code>.
   *
   * @param query The external form representing the JPQL query
   */
  ParameterTypeVisitor(JPQLQueryContext queryContext) {
    super();
    this.queryContext = queryContext;
  }

  /**
   * Disposes this visitor.
   */
  void dispose() {
    type              = null;
    expression        = null;
    ignoreType        = false;
    inputParameter    = null;
    currentExpression = null;
  }

  /**
   * Returns the type, if it can be determined, of the input parameter.
   *
   * @param typeVisitor The visitor used to calculate the type of the {@link Expression} that was
   * found to have the closest type of the input parameter
   * @return Either the closed type or {@link Object} if it can't be determined
   */
  IType getType() {

    // The type should be ignored, use the special constant
    if (ignoreType) {
      return queryContext.getTypeHelper().unknownType();
    }

    // The calculation couldn't find an expression with a type
    if (expression == null) {
      if (type == null) {
        type = Object.class;
      }
      return queryContext.getType(type);
    }

    return queryContext.getType(expression);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(AbsExpression expression) {
    // The absolute function always have a return type
    this.expression = expression;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(AdditionExpression expression) {
    visitCompoundExpression(expression);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(AndExpression expression) {
    visitCompoundExpression(expression);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(AvgFunction expression) {
    // The average function always have a return type
    this.expression = expression;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(BetweenExpression expression) {
    expression.getExpression().accept(this);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(CollectionValuedPathExpression expression) {
    // A collection-valued path expression always have a return type
    this.expression = expression;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(ComparisonExpression expression) {
    visitCompoundExpression(expression);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(ConcatExpression expression) {
    if (expression.getExpression().isAncestor(inputParameter)) {
      this.expression = expression;
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(CountFunction expression) {
    // The count function always have a return type
    this.expression = expression;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(DivisionExpression expression) {
    visitCompoundExpression(expression);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(EmptyCollectionComparisonExpression expression) {

    // Can't determine the type
    if (expression.getExpression() == inputParameter) {
      ignoreType = true;
    }
    else {
      super.visit(expression);
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(ExistsExpression expression) {
    // The exist function always have a return type
    this.expression = expression;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(IdentificationVariable expression) {
    // The identification variable always have a return type
    this.expression = expression;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(InExpression expression) {

    // BNF: ... IN collection_valued_input_parameter
    if (expression.getInItems() == inputParameter) {
      type = Collection.class;
    }
    else if (expression.getInItems().isAncestor(inputParameter)) {
      expression.getExpression().accept(this);
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(InputParameter expression) {
    this.inputParameter = expression;
    expression.getParent().accept(this);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(LengthExpression expression) {

    // LENGTH takes a string as argument
    if (expression.isAncestor(inputParameter)) {
      type = String.class;
    }
    // LENGTH returns an integer value
    else {
      type = Integer.class;
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(LikeExpression expression) {

    Expression patternValue     = expression.getPatternValue();
    Expression stringExpression = expression.getStringExpression();
    Expression escapeCharacter  = expression.getEscapeCharacter();

    if (escapeCharacter == inputParameter) {
      this.type = Character.class;
    }
    else if (patternValue.isAncestor(inputParameter)) {
      this.expression = expression.getStringExpression();
    }
    else if (stringExpression.isAncestor(inputParameter)) {
      this.expression = expression;
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(LowerExpression expression) {
    // The lower function always have a return type
    this.expression = expression;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(MaxFunction expression) {
    // The maximum function always have a return type
    this.expression = expression;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(MinFunction expression) {
    // The minimum function always have a return type
    this.expression = expression;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(ModExpression expression) {
    // The modulo function always have a return type
    this.expression = expression;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(MultiplicationExpression expression) {
    visitCompoundExpression(expression);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(NullComparisonExpression expression) {

    // Can't determine the type
    if (expression.getExpression() == inputParameter) {
      ignoreType = true;
    }
    // A singled valued path expression always have a return type
    else {
      expression.getExpression().accept(this);
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(NumericLiteral expression) {
    // A numerical expression always have a return type
    this.expression = expression;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(OrExpression expression) {
    visitCompoundExpression(expression);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(SizeExpression expression) {
    // The modulo function always have a return type
    this.expression = expression;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(SqrtExpression expression) {
    if (expression.isAncestor(inputParameter)) {
      super.visit(expression);
    }
    else {
      this.expression = expression;
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(StateFieldPathExpression expression) {
    // A state field path expression always have a return type
    this.expression = expression;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(SubstringExpression expression) {

    // The string primary is always a string
    if (expression.getFirstExpression().isAncestor(inputParameter)) {
      type = String.class;
    }
    // The first or second arithmetic expression is always an integer
    else if (expression.getSecondExpression().isAncestor(inputParameter) ||
             expression.getThirdExpression() .isAncestor(inputParameter)) {

      type = Integer.class;
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(SubtractionExpression expression) {
    visitCompoundExpression(expression);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(SumFunction expression) {
    // The sum function always have a return type
    this.expression = expression;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(TrimExpression expression) {

    if (expression.getTrimCharacter() == inputParameter) {
      type = Character.class;
    }
    else if (expression.getExpression() == inputParameter) {
      type = String.class;
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void visit(UpdateItem expression) {
    expression.getStateFieldPathExpression().accept(this);
  }

  private void visitCompoundExpression(CompoundExpression expression) {

    Expression leftExpression  = expression.getLeftExpression();
    Expression rightExpression = expression.getRightExpression();

    // Now traverse the other side to find its return type
    if (leftExpression.isAncestor(inputParameter)) {
      if (currentExpression == null) {
        currentExpression = expression;
        rightExpression.accept(this);
        currentExpression = null;
      }
      else {
        type = null;
        ignoreType = true;
        expression = null;
      }
    }
    // Now traverse the other side to find its return type
    else if (rightExpression.isAncestor(inputParameter)) {
      if (currentExpression == null) {
        currentExpression = expression;
        leftExpression.accept(this);
        currentExpression = null;
      }
      else {
        type = null;
        ignoreType = true;
        expression = null;
      }
    }
    // Otherwise continue up
    else {
      super.visit(expression);
    }
  }
}
TOP

Related Classes of org.eclipse.persistence.jpa.internal.jpql.ParameterTypeVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.