zoukankan      html  css  js  c++  java
  • mybatis结果的组装(springboot)

    文主要解答一个问题,即如果bean没有setter,而且属性不是public的,mybatis的自动组装是否可以赋值成功的问题。

    查询调用过程

    DefaultSqlSession.selectList -->SimpleExecutor.doQuery --> SimpleStatementHandler.query --> DefaultResultSetHandler.handleResultSets --> BeanWrapper.setBeanProperty --> MetaClass.getSetInvoker --> Reflector.getSetInvoker

    关键方法

    SimpleStatementHandler.query

    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        String sql = boundSql.getSql();
        statement.execute(sql);
        return resultSetHandler.<E>handleResultSets(statement);
      }

    DefaultResultSetHandler.handleResultSets

    @Override
      public List<Object> handleResultSets(Statement stmt) throws SQLException {
        ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
     
        final List<Object> multipleResults = new ArrayList<Object>();
     
        int resultSetCount = 0;
        ResultSetWrapper rsw = getFirstResultSet(stmt);
     
        List<ResultMap> resultMaps = mappedStatement.getResultMaps();
        int resultMapCount = resultMaps.size();
        validateResultMapsCount(rsw, resultMapCount);
        while (rsw != null && resultMapCount > resultSetCount) {
          ResultMap resultMap = resultMaps.get(resultSetCount);
          handleResultSet(rsw, resultMap, multipleResults, null);
          rsw = getNextResultSet(stmt);
          cleanUpAfterHandlingResultSet();
          resultSetCount++;
        }
     
        String[] resultSets = mappedStatement.getResulSets();
        if (resultSets != null) {
          while (rsw != null && resultSetCount < resultSets.length) {
            ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
            if (parentMapping != null) {
              String nestedResultMapId = parentMapping.getNestedResultMapId();
              ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
              handleResultSet(rsw, resultMap, null, parentMapping);
            }
            rsw = getNextResultSet(stmt);
            cleanUpAfterHandlingResultSet();
            resultSetCount++;
          }
        }
     
        return collapseSingleResultList(multipleResults);
      }

    DefaultResultSetHandler.handleResultSets

    private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
        try {
          if (parentMapping != null) {
            handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
          } else {
            if (resultHandler == null) {
              DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
              handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
              multipleResults.add(defaultResultHandler.getResultList());
            } else {
              handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
            }
          }
        } finally {
          // issue #228 (close resultsets)
          closeResultSet(rsw.getResultSet());
        }
      }

    DefaultResultSetHandler.handleRowValues

    private void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
        if (resultMap.hasNestedResultMaps()) {
          ensureNoRowBounds();
          checkResultHandler();
          handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
        } else {
          handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
        }
      }

    DefaultResultSetHandler.handleRowValuesForSimpleResultMap

    private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
          throws SQLException {
        DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
        skipRows(rsw.getResultSet(), rowBounds);
        while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
          ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
          Object rowValue = getRowValue(rsw, discriminatedResultMap);
          storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
        }
      }

    DefaultResultSetHandler.getRowValue

    private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
        final ResultLoaderMap lazyLoader = new ResultLoaderMap();
        Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null);
        if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
          final MetaObject metaObject = configuration.newMetaObject(resultObject);
          boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();
          if (shouldApplyAutomaticMappings(resultMap, false)) {
            foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
          }
          foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
          foundValues = lazyLoader.size() > 0 || foundValues;
          resultObject = foundValues ? resultObject : null;
          return resultObject;
        }
        return resultObject;
      }

    DefaultResultSetHandler.applyPropertyMappings

    private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
          throws SQLException {
        final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
        boolean foundValues = false;
        final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
        for (ResultMapping propertyMapping : propertyMappings) {
          String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
          if (propertyMapping.getNestedResultMapId() != null) {
            // the user added a column attribute to a nested result map, ignore it
            column = null;
          }
          if (propertyMapping.isCompositeResult()
              || (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
              || propertyMapping.getResultSet() != null) {
            Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
            // issue #541 make property optional
            final String property = propertyMapping.getProperty();
            // issue #377, call setter on nulls
            if (value != DEFERED
                && property != null
                && (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive()))) {
              metaObject.setValue(property, value);
            }
            if (value != null || value == DEFERED) {
              foundValues = true;
            }
          }
        }
        return foundValues;
      }

    MetaObject.setValue

    public void setValue(String name, Object value) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
          MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
          if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
            if (value == null && prop.getChildren() != null) {
              // don't instantiate child path if value is null
              return;
            } else {
              metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
            }
          }
          metaValue.setValue(prop.getChildren(), value);
        } else {
          objectWrapper.set(prop, value);
        }
      }

    BeanWrapper.set

    @Override
      public void set(PropertyTokenizer prop, Object value) {
        if (prop.getIndex() != null) {
          Object collection = resolveCollection(prop, object);
          setCollectionValue(prop, collection, value);
        } else {
          setBeanProperty(prop, object, value);
        }
      }

    BeanWrapper.setBeanProperty

    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);
        }
      }

    MetaClass.getSetInovker

    public Invoker getSetInvoker(String name) {
        return reflector.getSetInvoker(name);
      }

    Reflector.getSetInvoker

    public Invoker getSetInvoker(String propertyName) {
        Invoker method = setMethods.get(propertyName);
        if (method == null) {
          throw new ReflectionException("There is no setter for property named '" + propertyName + "' in '" + type + "'");
        }
        return method;
      }

    setMethods的修改

    有setter的话,走Reflector. resolveSetterConflicts

    private void resolveSetterConflicts(Map<String, List<Method>> conflictingSetters) {
        for (String propName : conflictingSetters.keySet()) {
          List<Method> setters = conflictingSetters.get(propName);
          Method firstMethod = setters.get(0);
          if (setters.size() == 1) {
            addSetMethod(propName, firstMethod);
          } else {
            Class<?> expectedType = getTypes.get(propName);
            if (expectedType == null) {
              throw new ReflectionException("Illegal overloaded setter method with ambiguous type for property "
                  + propName + " in class " + firstMethod.getDeclaringClass() + ".  This breaks the JavaBeans " +
                  "specification and can cause unpredicatble results.");
            } else {
              Iterator<Method> methods = setters.iterator();
              Method setter = null;
              while (methods.hasNext()) {
                Method method = methods.next();
                if (method.getParameterTypes().length == 1
                    && expectedType.equals(method.getParameterTypes()[0])) {
                  setter = method;
                  break;
                }
              }
              if (setter == null) {
                throw new ReflectionException("Illegal overloaded setter method with ambiguous type for property "
                    + propName + " in class " + firstMethod.getDeclaringClass() + ".  This breaks the JavaBeans " +
                    "specification and can cause unpredicatble results.");
              }
              addSetMethod(propName, setter);
            }
          }
        }
      }
    
    private void addSetMethod(String name, Method method) {
        if (isValidPropertyName(name)) {
          setMethods.put(name, new MethodInvoker(method));
          setTypes.put(name, method.getParameterTypes()[0]);
        }
      }

    没有setter的话,走Reflector. addSetField

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

    小结

    即使bean的属性是私有的,没有setter,mybatis也会通过反射去设置值。

  • 相关阅读:
    2单表CRUD综合样例开发教程
    1代码表样例开发教程
    ProcessOn
    UniEAP Platform V5.0 Unable to compile class for JSP
    Message Unable to compile class for JSP
    UniEAP Platform V5.0建库
    UML_2_浅谈UML的概念和模型之UML九种图
    PPT鼠绘必须掌握的PPT绘图三大核心功能
    PPT添加节
    remap.config文件配置模板
  • 原文地址:https://www.cnblogs.com/austinspark-jessylu/p/8065355.html
Copyright © 2011-2022 走看看