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

org.apache.ibatis.reflection.ParamNameResolver Maven / Gradle / Ivy

There is a newer version: 3.5.16_1
Show newest version
/*
 *    Copyright 2009-2021 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.apache.ibatis.reflection;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

public class ParamNameResolver {

  public static final String GENERIC_NAME_PREFIX = "param";

  private final boolean useActualParamName;

  /**
   * 

* The key is the index and the value is the name of the parameter.
* The name is obtained from {@link Param} if specified. When {@link Param} is not specified, * the parameter index is used. Note that this index could be different from the actual index * when the method has special parameters (i.e. {@link RowBounds} or {@link ResultHandler}). *

*
    *
  • aMethod(@Param("M") int a, @Param("N") int b) -> {{0, "M"}, {1, "N"}}
  • *
  • aMethod(int a, int b) -> {{0, "0"}, {1, "1"}}
  • *
  • aMethod(int a, RowBounds rb, int b) -> {{0, "0"}, {2, "1"}}
  • *
*/ private final SortedMap names; private boolean hasParamAnnotation; public ParamNameResolver(Configuration config, Method method) { this.useActualParamName = config.isUseActualParamName(); final Class[] paramTypes = method.getParameterTypes(); final Annotation[][] paramAnnotations = method.getParameterAnnotations(); final SortedMap map = new TreeMap<>(); int paramCount = paramAnnotations.length; // get names from @Param annotations for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) { if (isSpecialParameter(paramTypes[paramIndex])) { // skip special parameters continue; } String name = null; for (Annotation annotation : paramAnnotations[paramIndex]) { if (annotation instanceof Param) { hasParamAnnotation = true; name = ((Param) annotation).value(); break; } } if (name == null) { // @Param was not specified. if (useActualParamName) { name = getActualParamName(method, paramIndex); } if (name == null) { // use the parameter index as the name ("0", "1", ...) // gcode issue #71 name = String.valueOf(map.size()); } } map.put(paramIndex, name); } names = Collections.unmodifiableSortedMap(map); } private String getActualParamName(Method method, int paramIndex) { return ParamNameUtil.getParamNames(method).get(paramIndex); } private static boolean isSpecialParameter(Class clazz) { return RowBounds.class.isAssignableFrom(clazz) || ResultHandler.class.isAssignableFrom(clazz); } /** * Returns parameter names referenced by SQL providers. * * @return the names */ public String[] getNames() { return names.values().toArray(new String[0]); } /** *

* A single non-special parameter is returned without a name. * Multiple parameters are named using the naming rule. * In addition to the default names, this method also adds the generic names (param1, param2, * ...). *

* * @param args * the args * @return the named params */ public Object getNamedParams(Object[] args) { final int paramCount = names.size(); if (args == null || paramCount == 0) { return null; } else if (!hasParamAnnotation && paramCount == 1) { Object value = args[names.firstKey()]; return wrapToMapIfCollection(value, useActualParamName ? names.get(0) : null); } else { final Map param = new ParamMap<>(); int i = 0; for (Map.Entry entry : names.entrySet()) { param.put(entry.getValue(), args[entry.getKey()]); // add generic param names (param1, param2, ...) final String genericParamName = GENERIC_NAME_PREFIX + (i + 1); // ensure not to overwrite parameter named with @Param if (!names.containsValue(genericParamName)) { param.put(genericParamName, args[entry.getKey()]); } i++; } return param; } } /** * Wrap to a {@link ParamMap} if object is {@link Collection} or array. * * @param object a parameter object * @param actualParamName an actual parameter name * (If specify a name, set an object to {@link ParamMap} with specified name) * @return a {@link ParamMap} * @since 3.5.5 */ public static Object wrapToMapIfCollection(Object object, String actualParamName) { if (object instanceof Collection) { ParamMap map = new ParamMap<>(); map.put("collection", object); if (object instanceof List) { map.put("list", object); } Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object)); return map; } else if (object != null && object.getClass().isArray()) { ParamMap map = new ParamMap<>(); map.put("array", object); Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object)); return map; } return object; } }