ParamNameResolver 源码解析

  • Author: HuiFer
  • Description: 该文介绍 mybatis @Param 注解和ParamNameResolver
  • 源码阅读工程: SourceHot-Mybatis

源码

  • org.apache.ibatis.reflection.ParamNameResolver
  1. /**
  2. * {@link Param} 注解的扫描工具和处理工具
  3. */
  4. public class ParamNameResolver {
  5. public static final String GENERIC_NAME_PREFIX = "param";
  6. /**
  7. * <p>
  8. * The key is the index and the value is the name of the parameter.<br />
  9. * The name is obtained from {@link Param} if specified. When {@link Param} is not specified,
  10. * the parameter index is used. Note that this index could be different from the actual index
  11. * when the method has special parameters (i.e. {@link RowBounds} or {@link ResultHandler}).
  12. * </p>
  13. *
  14. * {@link ParamNameResolver#ParamNameResolver(org.apache.ibatis.session.Configuration, java.lang.reflect.Method)} 中的map 变量值转换而得
  15. * {参数索引: 参数名称(arg0,Param注解的value)}
  16. *
  17. */
  18. private final SortedMap<Integer, String> names;
  19. private boolean hasParamAnnotation;
  20. public ParamNameResolver(Configuration config, Method method) {
  21. // 方法参数类型
  22. final Class<?>[] paramTypes = method.getParameterTypes();
  23. // 参数上的注解
  24. final Annotation[][] paramAnnotations = method.getParameterAnnotations();
  25. // 参数索引和参数名称
  26. // {参数索引:参数名称}
  27. final SortedMap<Integer, String> map = new TreeMap<>();
  28. int paramCount = paramAnnotations.length;
  29. // get names from @Param annotations
  30. for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
  31. if (isSpecialParameter(paramTypes[paramIndex])) {
  32. // skip special parameters
  33. // 如果是特殊类型跳过
  34. continue;
  35. }
  36. String name = null;
  37. // 注解扫描@Param
  38. for (Annotation annotation : paramAnnotations[paramIndex]) {
  39. // 是否为 Param 注解的下级
  40. if (annotation instanceof Param) {
  41. hasParamAnnotation = true;
  42. // 获取 value 属性值
  43. name = ((Param) annotation).value();
  44. break;
  45. }
  46. }
  47. if (name == null) {
  48. // 如果没有写 @param 处理方式如下
  49. // @Param was not specified.
  50. if (config.isUseActualParamName()) {
  51. name = getActualParamName(method, paramIndex);
  52. }
  53. if (name == null) {
  54. // use the parameter index as the name ("0", "1", ...)
  55. // gcode issue #71
  56. name = String.valueOf(map.size());
  57. }
  58. }
  59. // 循环参数列表 放入map 对象
  60. map.put(paramIndex, name);
  61. }
  62. names = Collections.unmodifiableSortedMap(map);
  63. }
  64. /**
  65. * 是否为特殊参数 , 依据 是否是 {@link RowBounds} 或者 {@link ResultHandler}
  66. * @param clazz
  67. * @return
  68. */
  69. private static boolean isSpecialParameter(Class<?> clazz) {
  70. return RowBounds.class.isAssignableFrom(clazz) || ResultHandler.class.isAssignableFrom(clazz);
  71. }
  72. /**
  73. * 返回方法名 参数索引
  74. * @param method
  75. * @param paramIndex
  76. * @return
  77. */
  78. private String getActualParamName(Method method, int paramIndex) {
  79. return ParamNameUtil.getParamNames(method).get(paramIndex);
  80. }
  81. /**
  82. * Returns parameter names referenced by SQL providers.
  83. */
  84. public String[] getNames() {
  85. return names.values().toArray(new String[0]);
  86. }
  87. /**
  88. * <p>
  89. * A single non-special parameter is returned without a name.
  90. * Multiple parameters are named using the naming rule.
  91. * In addition to the default names, this method also adds the generic names (param1, param2,
  92. * ...).
  93. * </p>
  94. * <p>
  95. * 通常参数异常在这个地方抛出 param ... 异常
  96. * 获取参数名称,和参数传递的真实数据
  97. */
  98. public Object getNamedParams(Object[] args) {
  99. final int paramCount = names.size();
  100. if (args == null || paramCount == 0) {
  101. // 是否有参数
  102. return null;
  103. } else if (!hasParamAnnotation && paramCount == 1) {
  104. // 没有使用 @param 注解 参数只有一个
  105. return args[names.firstKey()];
  106. } else {
  107. // 根据索引创建
  108. final Map<String, Object> param = new ParamMap<>();
  109. int i = 0;
  110. for (Map.Entry<Integer, String> entry : names.entrySet()) {
  111. param.put(entry.getValue(), args[entry.getKey()]);
  112. // add generic param names (param1, param2, ...)
  113. // param + 当前索引位置
  114. final String genericParamName = GENERIC_NAME_PREFIX + (i + 1);
  115. // ensure not to overwrite parameter named with @Param
  116. if (!names.containsValue(genericParamName)) {
  117. param.put(genericParamName, args[entry.getKey()]);
  118. }
  119. i++;
  120. }
  121. return param;
  122. }
  123. }
  124. }

debug 阶段

  • 测试用例为同一个 , 每次修改 mapper 方法参数来进行 debug
  1. @Test
  2. void testXmlConfigurationLoad() throws IOException {
  3. Reader reader = Resources.getResourceAsReader("mybatis-config-demo.xml");
  4. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
  5. Configuration configuration = factory.getConfiguration();
  6. SqlSession sqlSession = factory.openSession();
  7. HsSellMapper mapper = sqlSession.getMapper(HsSellMapper.class);
  8. List<HsSell> list = mapper.list(2);
  9. List<Object> objects = sqlSession.selectList("com.huifer.mybatis.mapper.HsSellMapper.list");
  10. assertEquals(list.size(), objects.size());
  11. }
  1. List<HsSell> list( Integer id);

如果不写@Param称则返回 image-20191219083223084

  1. List<HsSell> list(@Param("ID") Integer id);
  • @Param返回

image-20191219083344439

image-20191219083354873

  • org.apache.ibatis.reflection.ParamNameResolver#getNamedParams

    1. List<HsSell> list( Integer id);

image-20191219084455292

  1. List<HsSell> list(@Param("ID") Integer id);

​ 写上@Param

image-20191219084943102

image-20191219085131167