Mybatis 可以用反射设置值吗?

Tod*_*day 1 mybatis

Mybatis 可以用反射设置值吗?我有一个类,它有一个属性,它的 setter 是 protected 。所以我必须使用反射来设置这个值?Mybatis 可以工作吗?

Per*_*sia 5

是的,mybatis 使用reflect 来设置值。在 Reflator.java(mybatis 3.3.0) 中,mybatis 会配置 set 方法。

private void addSetMethods(Class<?> cls) {
    Map<String, List<Method>> conflictingSetters = new HashMap<String, List<Method>>();
    Method[] methods = getClassMethods(cls);
    for (Method method : methods) {
      String name = method.getName();
      if (name.startsWith("set") && name.length() > 3) {
        if (method.getParameterTypes().length == 1) {
          name = PropertyNamer.methodToProperty(name);
          addMethodConflict(conflictingSetters, name, method);
        }
      }
    }
    resolveSetterConflicts(conflictingSetters);
  }
Run Code Online (Sandbox Code Playgroud)

如果您的类没有 set 方法,则在 addSetFields 时,它将为该字段添加新的 SetInvoker:

private void addSetField(Field field) {
    if (isValidPropertyName(field.getName())) {
      setMethods.put(field.getName(), new SetFieldInvoker(field));
      setTypes.put(field.getName(), field.getType());
    }
  }
Run Code Online (Sandbox Code Playgroud)

而 SetFieldInvoker 是这样的:

/**
 * @author Clinton Begin
 */
public class SetFieldInvoker implements Invoker {
  private Field field;

  public SetFieldInvoker(Field field) {
    this.field = field;
  }

  @Override
  public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
    field.set(target, args[0]);
    return null;
  }

  @Override
  public Class<?> getType() {
    return field.getType();
  }
}
Run Code Online (Sandbox Code Playgroud)

DefaultResultSetHandler 调用 BeanWrapper 的 setBeanProperty 方法会调用 getSetInvoker

private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {
    try {
      Invoker method = metaClass.getSetInvoker(prop.getName());
      Object[] params = {value};
      try {
        method.invoke(object, params);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    } catch (Throwable t) {
      throw new ReflectionException("Could not set property '" + prop.getName() + "' of '" + object.getClass() + "' with value '" + value + "' Cause: " + t.toString(), t);
    }
  } 
Run Code Online (Sandbox Code Playgroud)

整个调用链可能是这样的: DefaultSqlSession##selectList -->SimpleExecutor##doQuery --> SimpleStatementHandler##query --> DefaultResultSetHandler##handleResultSets