Package org.springframework.data.repository.query

Source Code of org.springframework.data.repository.query.Parameters

/*
* Copyright 2008-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.repository.query;

import static java.lang.String.*;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.Assert;

/**
* Abstracts method parameters that have to be bound to query parameters or applied to the query independently.
*
* @author Oliver Gierke
*/
public abstract class Parameters<S extends Parameters<S, T>, T extends Parameter> implements Iterable<T> {

  public static final List<Class<?>> TYPES = Arrays.asList(Pageable.class, Sort.class);

  private static final String PARAM_ON_SPECIAL = format("You must not user @%s on a parameter typed %s or %s",
      Param.class.getSimpleName(), Pageable.class.getSimpleName(), Sort.class.getSimpleName());
  private static final String ALL_OR_NOTHING = String.format("Either use @%s "
      + "on all parameters except %s and %s typed once, or none at all!", Param.class.getSimpleName(),
      Pageable.class.getSimpleName(), Sort.class.getSimpleName());
  private static final ParameterNameDiscoverer PARAMETER_DISCOVERER = new DefaultParameterNameDiscoverer();

  private final int pageableIndex;
  private final int sortIndex;
  private final List<T> parameters;

  /**
   * Creates a new instance of {@link Parameters}.
   *
   * @param method
   */
  public Parameters(Method method) {

    Assert.notNull(method);

    this.parameters = new ArrayList<T>();

    List<Class<?>> types = Arrays.asList(method.getParameterTypes());

    for (int i = 0; i < types.size(); i++) {

      MethodParameter methodParameter = new MethodParameter(method, i);
      methodParameter.initParameterNameDiscovery(PARAMETER_DISCOVERER);

      T parameter = createParameter(methodParameter);

      if (parameter.isSpecialParameter() && parameter.isNamedParameter()) {
        throw new IllegalArgumentException(PARAM_ON_SPECIAL);
      }

      parameters.add(parameter);
    }

    this.pageableIndex = types.indexOf(Pageable.class);
    this.sortIndex = types.indexOf(Sort.class);

    assertEitherAllParamAnnotatedOrNone();
  }

  /**
   * Creates a new {@link Parameters} instance with the given {@link Parameter}s put into new context.
   *
   * @param originals
   */
  protected Parameters(List<T> originals) {

    this.parameters = new ArrayList<T>();

    int pageableIndexTemp = -1;
    int sortIndexTemp = -1;

    for (int i = 0; i < originals.size(); i++) {

      T original = originals.get(i);
      this.parameters.add(original);

      pageableIndexTemp = original.isPageable() ? i : -1;
      sortIndexTemp = original.isSort() ? i : -1;
    }

    this.pageableIndex = pageableIndexTemp;
    this.sortIndex = sortIndexTemp;
  }

  /**
   * Creates a {@link Parameter} instance for the given {@link MethodParameter}.
   *
   * @param parameter will never be {@literal null}.
   * @return
   */
  protected abstract T createParameter(MethodParameter parameter);

  /**
   * Returns whether the method the {@link Parameters} was created for contains a {@link Pageable} argument.
   *
   * @return
   */
  public boolean hasPageableParameter() {
    return pageableIndex != -1;
  }

  /**
   * Returns the index of the {@link Pageable} {@link Method} parameter if available. Will return {@literal -1} if there
   * is no {@link Pageable} argument in the {@link Method}'s parameter list.
   *
   * @return the pageableIndex
   */
  public int getPageableIndex() {
    return pageableIndex;
  }

  /**
   * Returns the index of the {@link Sort} {@link Method} parameter if available. Will return {@literal -1} if there is
   * no {@link Sort} argument in the {@link Method}'s parameter list.
   *
   * @return
   */
  public int getSortIndex() {
    return sortIndex;
  }

  /**
   * Returns whether the method the {@link Parameters} was created for contains a {@link Sort} argument.
   *
   * @return
   */
  public boolean hasSortParameter() {
    return sortIndex != -1;
  }

  /**
   * Returns whether we potentially find a {@link Sort} parameter in the parameters.
   *
   * @return
   */
  public boolean potentiallySortsDynamically() {
    return hasSortParameter() || hasPageableParameter();
  }

  /**
   * Returns the parameter with the given index.
   *
   * @param index
   * @return
   */
  public T getParameter(int index) {

    try {
      return parameters.get(index);
    } catch (IndexOutOfBoundsException e) {
      throw new ParameterOutOfBoundsException(
          "Invalid parameter index! You seem to have declare too little query method parameters!", e);
    }
  }

  /**
   * Returns whether we have a parameter at the given position.
   *
   * @param position
   * @return
   */
  public boolean hasParameterAt(int position) {

    try {
      return null != getParameter(position);
    } catch (ParameterOutOfBoundsException e) {
      return false;
    }
  }

  /**
   * Returns whether the method signature contains one of the special parameters ({@link Pageable}, {@link Sort}).
   *
   * @return
   */
  public boolean hasSpecialParameter() {
    return hasSortParameter() || hasPageableParameter();
  }

  /**
   * Returns the number of parameters.
   *
   * @return
   */
  public int getNumberOfParameters() {
    return parameters.size();
  }

  /**
   * Returns a {@link Parameters} instance with effectively all special parameters removed.
   *
   * @return
   * @see Parameter#TYPES
   * @see Parameter#isSpecialParameter()
   */
  public S getBindableParameters() {

    List<T> bindables = new ArrayList<T>();

    for (T candidate : this) {

      if (candidate.isBindable()) {
        bindables.add(candidate);
      }
    }

    return createFrom(bindables);
  }

  protected abstract S createFrom(List<T> parameters);

  /**
   * Returns a bindable parameter with the given index. So for a method with a signature of
   * {@code (Pageable pageable, String name)} a call to {@code #getBindableParameter(0)} will return the {@link String}
   * parameter.
   *
   * @param bindableIndex
   * @return
   */
  public T getBindableParameter(int bindableIndex) {
    return getBindableParameters().getParameter(bindableIndex);
  }

  /**
   * Asserts that either all of the non special parameters ({@link Pageable}, {@link Sort}) are annotated with
   * {@link Param} or none of them is.
   *
   * @param method
   */
  private void assertEitherAllParamAnnotatedOrNone() {

    boolean nameFound = false;
    int index = 0;

    for (T parameter : this.getBindableParameters()) {

      if (parameter.isNamedParameter()) {
        Assert.isTrue(nameFound || index == 0, ALL_OR_NOTHING);
        nameFound = true;
      } else {
        Assert.isTrue(!nameFound, ALL_OR_NOTHING);
      }

      index++;
    }
  }

  /**
   * Returns whether the given type is a bindable parameter.
   *
   * @param type
   * @return
   */
  public static boolean isBindable(Class<?> type) {
    return !TYPES.contains(type);
  }

  /*
   * (non-Javadoc)
   * @see java.lang.Iterable#iterator()
   */
  public Iterator<T> iterator() {
    return parameters.iterator();
  }
}
TOP

Related Classes of org.springframework.data.repository.query.Parameters

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.