一、前言
这里啰嗦一下,实例方法就是没有static关键字的对象行为方法,有static关键字的就是静态方法可直接通过类名调用,构造方法就是与类名相同的方法,
上一篇文章《关于Java变量的类型权限选择与变量变更途径》我也提了链式调用,今天再次来聊聊这个链式调用。我们都知道类实例方法的调用,一般你得通过new获取对象实例,才能调用实例方法;同时我们也知道this关键字可表示对象实例。理解这些内容很关键的哦!!!
当你读懂这些代码,某一天派上用场时,项目大佬肯定在心里暗暗惊叹,哎哟这小子不错哦!
二、ResultMapping的成员变量
/**
* @author Clinton Begin
*/
public class ResultMapping {
private Configuration configuration;
private String property;
private String column;
private Class<?> javaType;
private JdbcType jdbcType;
private TypeHandler<?> typeHandler;
private String nestedResultMapId;
private String nestedQueryId;
private Set<String> notNullColumns;
private String columnPrefix;
private List<ResultFlag> flags;
private List<ResultMapping> composites;
private String resultSet;
private String foreignColumn;
private boolean lazy;
ResultMapping() {
}
}
你会发现ResultMapping有15个成员变量,我们多见的也就5个左右。如果一个构造方法10多个入参,而且入参可能还得经过加工,那么这个构造方法就是魔鬼方法了,读也读不懂!!
三、链式调用
链式调用的好处:即使入参太多也方便处理,可读性强,不必知道入参的顺序,尤其在多处调用这种逻辑时优势很明显。
1)MapperBuilderAssistant的buildResultMapping方法
这里调用了ResultMapping的构造方法,当然是把ResultMapping构造过程封装起来了。
public ResultMapping buildResultMapping(
Class<?> resultType,
String property,
String column,
Class<?> javaType,
JdbcType jdbcType,
String nestedSelect,
String nestedResultMap,
String notNullColumn,
String columnPrefix,
Class<? extends TypeHandler<?>> typeHandler,
List<ResultFlag> flags,
String resultSet,
String foreignColumn,
boolean lazy) {
Class<?> javaTypeClass = resolveResultJavaType(resultType, property, javaType);
TypeHandler<?> typeHandlerInstance = resolveTypeHandler(javaTypeClass, typeHandler);
List<ResultMapping> composites;
if ((nestedSelect == null || nestedSelect.isEmpty()) && (foreignColumn == null || foreignColumn.isEmpty())) {
composites = Collections.emptyList();
} else {
composites = parseCompositeColumnName(column);
}
return new ResultMapping.Builder(configuration, property, column, javaTypeClass)
.jdbcType(jdbcType)
.nestedQueryId(applyCurrentNamespace(nestedSelect, true))
.nestedResultMapId(applyCurrentNamespace(nestedResultMap, true))
.resultSet(resultSet)
.typeHandler(typeHandlerInstance)
.flags(flags == null ? new ArrayList<>() : flags)
.composites(composites)
.notNullColumns(parseMultipleColumnNames(notNullColumn))
.columnPrefix(columnPrefix)
.foreignColumn(foreignColumn)
.lazy(lazy)
.build();
}
2)MapperAnnotationBuilder的applyResults
MapperAnnotationBuilder的applyResults方法又把MapperBuilderAssistant封装起来了。
private void applyResults(Result[] results,
Class<?> resultType,
List<ResultMapping> resultMappings) {
for (Result result : results) {
List<ResultFlag> flags = new ArrayList<>();
if (result.id()) {
flags.add(ResultFlag.ID);
}
@SuppressWarnings("unchecked")
Class<? extends TypeHandler<?>> typeHandler = (Class<? extends TypeHandler<?>>)
((result.typeHandler() == UnknownTypeHandler.class)
? null : result.typeHandler());
boolean hasNestedResultMap = hasNestedResultMap(result);
ResultMapping resultMapping = assistant.buildResultMapping(
resultType,
nullOrEmpty(result.property()),
nullOrEmpty(result.column()),
result.javaType() == void.class ? null : result.javaType(),
result.jdbcType() == JdbcType.UNDEFINED ? null : result.jdbcType(),
hasNestedSelect(result) ? nestedSelectId(result) : null,
hasNestedResultMap ? nestedResultMapId(result) : null,
null,
hasNestedResultMap ? findColumnPrefix(result) : null,
typeHandler,
flags,
null,
null,
isLazy(result));
resultMappings.add(resultMapping);
}
}
3)MapperAnnotationBuilder的applyConstructorArgs
private void applyConstructorArgs(Arg[] args,
Class<?> resultType,
List<ResultMapping> resultMappings) {
for (Arg arg : args) {
List<ResultFlag> flags = new ArrayList<>();
flags.add(ResultFlag.CONSTRUCTOR);
if (arg.id()) {
flags.add(ResultFlag.ID);
}
@SuppressWarnings("unchecked")
Class<? extends TypeHandler<?>> typeHandler = (Class<? extends TypeHandler<?>>)
(arg.typeHandler() == UnknownTypeHandler.class ? null : arg.typeHandler());
ResultMapping resultMapping = assistant.buildResultMapping(
resultType,
nullOrEmpty(arg.name()),
nullOrEmpty(arg.column()),
arg.javaType() == void.class ? null : arg.javaType(),
arg.jdbcType() == JdbcType.UNDEFINED ? null : arg.jdbcType(),
nullOrEmpty(arg.select()),
nullOrEmpty(arg.resultMap()),
null,
nullOrEmpty(arg.columnPrefix()),
typeHandler,
flags,
null,
null,
false);
resultMappings.add(resultMapping);
}
}
四、ResultMapping完整源码
不看一下源码,还是感觉怪怪的,
/**
* @author Clinton Begin
*/
public class ResultMapping {
private Configuration configuration;
private String property;
private String column;
private Class<?> javaType;
private JdbcType jdbcType;
private TypeHandler<?> typeHandler;
private String nestedResultMapId;
private String nestedQueryId;
private Set<String> notNullColumns;
private String columnPrefix;
private List<ResultFlag> flags;
private List<ResultMapping> composites;
private String resultSet;
private String foreignColumn;
private boolean lazy;
ResultMapping() {
}
public static class Builder {
private ResultMapping resultMapping = new ResultMapping();
/**------------------- 公有构造方法 START -----------------------*/
// 1、公有构造方法,下面提供重载
public Builder(Configuration configuration,
String property,
String column,
TypeHandler<?> typeHandler) {
this(configuration, property);
resultMapping.column = column;
resultMapping.typeHandler = typeHandler;
}
// 2、公有构造方法
public Builder(Configuration configuration,
String property,
String column,
Class<?> javaType) {
this(configuration, property);
resultMapping.column = column;
resultMapping.javaType = javaType;
}
// 3、公有构造方法
public Builder(Configuration configuration, String property) {
resultMapping.configuration = configuration;
resultMapping.property = property;
resultMapping.flags = new ArrayList<>();
resultMapping.composites = new ArrayList<>();
resultMapping.lazy = configuration.isLazyLoadingEnabled();
}
/**>>>>>>>>>>>>>>>>>>>> 公有构造方法 END -----------------------*/
/**------------------- 设置属性方法 START -----------------------*/
public Builder javaType(Class<?> javaType) {
resultMapping.javaType = javaType;
return this;
}
public Builder jdbcType(JdbcType jdbcType) {
resultMapping.jdbcType = jdbcType;
return this;
}
public Builder nestedResultMapId(String nestedResultMapId) {
resultMapping.nestedResultMapId = nestedResultMapId;
return this;
}
public Builder nestedQueryId(String nestedQueryId) {
resultMapping.nestedQueryId = nestedQueryId;
return this;
}
public Builder resultSet(String resultSet) {
resultMapping.resultSet = resultSet;
return this;
}
public Builder foreignColumn(String foreignColumn) {
resultMapping.foreignColumn = foreignColumn;
return this;
}
public Builder notNullColumns(Set<String> notNullColumns) {
resultMapping.notNullColumns = notNullColumns;
return this;
}
public Builder columnPrefix(String columnPrefix) {
resultMapping.columnPrefix = columnPrefix;
return this;
}
public Builder flags(List<ResultFlag> flags) {
resultMapping.flags = flags;
return this;
}
public Builder typeHandler(TypeHandler<?> typeHandler) {
resultMapping.typeHandler = typeHandler;
return this;
}
public Builder composites(List<ResultMapping> composites) {
resultMapping.composites = composites;
return this;
}
public Builder lazy(boolean lazy) {
resultMapping.lazy = lazy;
return this;
}
/**>>>>>>>>>>>>>>>>> 设置属性方法 END -----------------------*/
/**--- 建造方法 ------------------------*/
public ResultMapping build() {
// lock down collections
resultMapping.flags = Collections.unmodifiableList(resultMapping.flags);
resultMapping.composites = Collections.unmodifiableList(resultMapping.composites);
resolveTypeHandler();
validate();
return resultMapping;
}
//一些验证逻辑,验证result map有没有写错
private void validate() {
// Issue #697: cannot define both nestedQueryId and nestedResultMapId
if (resultMapping.nestedQueryId != null && resultMapping.nestedResultMapId != null) {
throw new IllegalStateException("Cannot define both nestedQueryId " +
"and nestedResultMapId in property " + resultMapping.property);
}
// Issue #5: there should be no mappings without typehandler
if (resultMapping.nestedQueryId == null
&& resultMapping.nestedResultMapId == null && resultMapping.typeHandler == null) {
throw new IllegalStateException("No typehandler found for property "
+ resultMapping.property);
}
// Issue #4 and GH #39: column is optional only in nested resultmaps but not in the rest
if (resultMapping.nestedResultMapId == null
&& resultMapping.column == null && resultMapping.composites.isEmpty()) {
throw new IllegalStateException("Mapping is missing column attribute for property "
+ resultMapping.property);
}
if (resultMapping.getResultSet() != null) {
int numColumns = 0;
if (resultMapping.column != null) {
numColumns = resultMapping.column.split(",").length;
}
int numForeignColumns = 0;
if (resultMapping.foreignColumn != null) {
numForeignColumns = resultMapping.foreignColumn.split(",").length;
}
if (numColumns != numForeignColumns) {
throw new IllegalStateException("There should be the same number of columns " +
"and foreignColumns in property " + resultMapping.property);
}
}
}
private void resolveTypeHandler() {
if (resultMapping.typeHandler == null && resultMapping.javaType != null) {
Configuration configuration = resultMapping.configuration;
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
resultMapping.typeHandler = typeHandlerRegistry
.getTypeHandler(resultMapping.javaType, resultMapping.jdbcType);
}
}
public Builder column(String column) {
resultMapping.column = column;
return this;
}
}
public String getProperty() {
return property;
}
public String getColumn() {
return column;
}
public Class<?> getJavaType() {
return javaType;
}
public JdbcType getJdbcType() {
return jdbcType;
}
public TypeHandler<?> getTypeHandler() {
return typeHandler;
}
public String getNestedResultMapId() {
return nestedResultMapId;
}
public String getNestedQueryId() {
return nestedQueryId;
}
public Set<String> getNotNullColumns() {
return notNullColumns;
}
public String getColumnPrefix() {
return columnPrefix;
}
public List<ResultFlag> getFlags() {
return flags;
}
public List<ResultMapping> getComposites() {
return composites;
}
public boolean isCompositeResult() {
return this.composites != null && !this.composites.isEmpty();
}
public String getResultSet() {
return this.resultSet;
}
public String getForeignColumn() {
return foreignColumn;
}
public void setForeignColumn(String foreignColumn) {
this.foreignColumn = foreignColumn;
}
public boolean isLazy() {
return lazy;
}
public void setLazy(boolean lazy) {
this.lazy = lazy;
}
public boolean isSimple() {
return this.nestedResultMapId == null && this.nestedQueryId == null && this.resultSet == null;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ResultMapping that = (ResultMapping) o;
return property != null && property.equals(that.property);
}
@Override
public int hashCode() {
if (property != null) {
return property.hashCode();
} else if (column != null) {
return column.hashCode();
} else {
return 0;
}
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("ResultMapping{");
//sb.append("configuration=").append(configuration); // configuration doesn't have a useful .toString()
sb.append("property='").append(property).append('\'');
sb.append(", column='").append(column).append('\'');
sb.append(", javaType=").append(javaType);
sb.append(", jdbcType=").append(jdbcType);
//sb.append(", typeHandler=").append(typeHandler); // typeHandler also doesn't have a useful .toString()
sb.append(", nestedResultMapId='").append(nestedResultMapId).append('\'');
sb.append(", nestedQueryId='").append(nestedQueryId).append('\'');
sb.append(", notNullColumns=").append(notNullColumns);
sb.append(", columnPrefix='").append(columnPrefix).append('\'');
sb.append(", flags=").append(flags);
sb.append(", composites=").append(composites);
sb.append(", resultSet='").append(resultSet).append('\'');
sb.append(", foreignColumn='").append(foreignColumn).append('\'');
sb.append(", lazy=").append(lazy);
sb.append('}');
return sb.toString();
}
}
总结:关于链式调用在MyBatis的源码里面还可以找到很多,如:MappedStatement、ParameterMapping等等。