MyBatis 源码分析 - 配置文件解析过程 (7)

到此关于 setter 方法的解析过程就说完了。我在前面说过 MetaClass 的hasSetter最终调用了 Refactor 的hasSetter方法,那么现在是时候分析 Refactor 的hasSetter方法了。代码如下如下:

public boolean hasSetter(String propertyName) { return setMethods.keySet().contains(propertyName); }

代码如上,就两行,很简单,就不多说了。

2.3.2.3 PropertyTokenizer 源码分析

对于较为复杂的属性,需要进行进一步解析才能使用。那什么样的属性是复杂属性呢?来看个测试代码就知道了。

public class MetaClassTest { private class Author { private Integer id; private String name; private Integer age; /** 一个作者对应多篇文章 */ private Article[] articles; // 省略 getter/setter } private class Article { private Integer id; private String title; private String content; /** 一篇文章对应一个作者 */ private Author author; // 省略 getter/setter } @Test public void testHasSetter() { // 为 Author 创建元信息对象 MetaClass authorMeta = MetaClass.forClass(Author.class, new DefaultReflectorFactory()); System.out.println("------------☆ Author ☆------------"); System.out.println("id -> " + authorMeta.hasSetter("id")); System.out.println("name -> " + authorMeta.hasSetter("name")); System.out.println("age -> " + authorMeta.hasSetter("age")); // 检测 Author 中是否包含 Article[] 的 setter System.out.println("articles -> " + authorMeta.hasSetter("articles")); System.out.println("articles[] -> " + authorMeta.hasSetter("articles[]")); System.out.println("title -> " + authorMeta.hasSetter("title")); // 为 Article 创建元信息对象 MetaClass articleMeta = MetaClass.forClass(Article.class, new DefaultReflectorFactory()); System.out.println("\n------------☆ Article ☆------------"); System.out.println("id -> " + articleMeta.hasSetter("id")); System.out.println("title -> " + articleMeta.hasSetter("title")); System.out.println("content -> " + articleMeta.hasSetter("content")); // 下面两个均为复杂属性,分别检测 Article 类中的 Author 类是否包含 id 和 name 的 setter 方法 System.out.println("author.id -> " + articleMeta.hasSetter("author.id")); System.out.println("author.name -> " + articleMeta.hasSetter("author.name")); } }

如上,Article类中包含了一个Author引用。然后我们调用 articleMeta 的 hasSetter 检测author.id和author.name属性是否存在,我们的期望结果为 true。测试结果如下:

MyBatis 源码分析 - 配置文件解析过程

如上,标记⑤处的输出均为 true,我们的预期达到了。标记②处检测 Article 数组的是否存在 setter 方法,结果也均为 true。这说明 PropertyTokenizer 对数组和复合属性均进行了处理。那它是如何处理的呢?答案如下:

public class PropertyTokenizer implements Iterator<PropertyTokenizer> { private String name; private final String indexedName; private String index; private final String children; public PropertyTokenizer(String fullname) { // 检测传入的参数中是否包含字符 '.' int delim = fullname.indexOf('.'); if (delim > -1) { /* * 以点位为界,进行分割。比如: * fullname = * * 以第一个点为分界符: * name = www * children = coolblog.xyz */ name = fullname.substring(0, delim); children = fullname.substring(delim + 1); } else { // fullname 中不存在字符 '.' name = fullname; children = null; } indexedName = name; // 检测传入的参数中是否包含字符 '[' delim = name.indexOf('['); if (delim > -1) { /* * 获取中括号里的内容,比如: * 1. 对于数组或List集合:[] 中的内容为数组下标, * 比如 fullname = articles[1],index = 1 * 2. 对于Map:[] 中的内容为键, * 比如 fullname = xxxMap[keyName],index = keyName * * 关于 index 属性的用法,可以参考 BaseWrapper 的 getCollectionValue 方法 */ index = name.substring(delim + 1, name.length() - 1); // 获取分解符前面的内容,比如 fullname = articles[1],name = articles name = name.substring(0, delim); } } // 省略 getter @Override public boolean hasNext() { return children != null; } @Override public PropertyTokenizer next() { // 对 children 进行再次切分,用于解析多重复合属性 return new PropertyTokenizer(children); } // 省略部分方法 }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyzyxw.html