Mybatis技術內幕(2.3.5):反射模組-Property工具類

失控的阿甘發表於2019-03-19

基於Mybatis-3.5.0版本

1.0 property包

org.apache.ibatis.reflection.property包下主要有三個工具類,如下:

Mybatis技術內幕(2.3.5):反射模組-Property工具類

2.0 PropertyCopier 屬性複製器

org.apache.ibatis.reflection.property.PropertyCopier屬性複製器,主要用於同一型別兩個物件屬性複製。程式碼如下:

/**
 * 屬性複製器
 * 
 * @author Clinton Begin
 */
public final class PropertyCopier {

	private PropertyCopier() {
		// Prevent Instantiation of Static Class
	}

	/**
     * 將 sourceBean 的屬性,複製到 destinationBean 中
     * @param type 指定類
     * @param sourceBean 來源 Bean 物件
     * @param destinationBean 目標 Bean 物件
     */
	public static void copyBeanProperties(Class<?> type, Object sourceBean, Object destinationBean) {
		Class<?> parent = type;
		// 迴圈,從當前類開始,不斷複製到父類,直到父類不存在
		while (parent != null) {
			// 獲得當前 parent 類定義的屬性
			final Field[] fields = parent.getDeclaredFields();
			for (Field field : fields) {
				try {
					try {
						// 從 sourceBean 中,複製到 destinationBean 去
						field.set(destinationBean, field.get(sourceBean));
					} catch (IllegalAccessException e) {
						// 設定屬性可訪問
						if (Reflector.canControlMemberAccessible()) {
							field.setAccessible(true);
							field.set(destinationBean, field.get(sourceBean));
						} else {
							throw e;
						}
					}
				} catch (Exception e) {
					// Nothing useful to do, will only fail on final fields, which will be ignored.
				}
			}
			parent = parent.getSuperclass();
		}
	}
}
複製程式碼

2.1 PropertyNamer 屬性名工具類

org.apache.ibatis.reflection.property.PropertyNamer屬性名工具類,主要用來處理getter和setter方法。程式碼如下:

/**
 * 屬性名工具類,主要用來處理getter和setter方法
 * @author Clinton Begin
 */
public final class PropertyNamer {

	private PropertyNamer() {
		// Prevent Instantiation of Static Class
	}

	/**
	 * 根據getter或setter方法獲取屬性名
	 * 規則:
	 * 1.java bean getter/setter 方法命名規範擷取屬性名
	 * 2.根據駝峰命名法 將第一個字元小寫
	 * @param name
	 * @return
	 */
	public static String methodToProperty(String name) {
		if (name.startsWith("is")) {
			name = name.substring(2);
		} else if (name.startsWith("get") || name.startsWith("set")) {
			name = name.substring(3);
		} else {
			throw new ReflectionException("Error parsing property name '" + name + "'.  Didn't start with 'is', 'get' or 'set'.");
		}

		/**
		 * 如果擷取的屬性名長度為1或長度大於1且第2位字元是小寫
		 * 例如:
		 * getA -> A -> a
		 * getAA -> AA -> AA
		 */
		if (name.length() == 1 || (name.length() > 1 && !Character.isUpperCase(name.charAt(1)))) {
			name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
		}

		return name;
	}

	/**
	 * 判斷是否為is、get、set方法
	 * @param name 方法名
	 * @return
	 */
	public static boolean isProperty(String name) {
		return name.startsWith("get") || name.startsWith("set") || name.startsWith("is");
	}

	/**
	 * 判斷是否為 is、get方法
	 * @param name 方法名
	 * @return
	 */
	public static boolean isGetter(String name) {
		return name.startsWith("get") || name.startsWith("is");
	}

	/**
	 * 判斷是否為set方法
	 * @param name 方法名
	 * @return
	 */
	public static boolean isSetter(String name) {
		return name.startsWith("set");
	}
}
複製程式碼

2.2 PropertyTokenizer 屬性分詞器

org.apache.ibatis.reflection.property.PropertyTokenizer實現Iterator介面,屬性分詞器,支援迭代器的訪問方式。示例和程式碼如下:

/**
 * 實現 Iterator 介面,屬性分詞器,支援迭代器的訪問方式
 * 
 * @author Clinton Begin
 */
public class PropertyTokenizer implements Iterator<PropertyTokenizer> {
	// 當前表示式的名稱
	private String name;
	// 當前表示式的索引名
	private final String indexedName;
	// 索引下標
	private String index;
	// 子表示式
	private final String children;

	/**
	 * 對傳入的表示式,並初始化上面的成員變數 
	 * 例: orders[0].item[0].name 
	 * name = orders 
	 * indexedName =
	 * orders[0] 
	 * children = item[0].name 
	 * index = 0
	 * 
	 * @param fullname 待解析的表示式
	 */
	public PropertyTokenizer(String fullname) {
		// 初始化 name、children 字串,使用 '.'作為分隔
		int delim = fullname.indexOf('.');
		if (delim > -1) {
			name = fullname.substring(0, delim);
			children = fullname.substring(delim + 1);
		} else {
			name = fullname;
			children = null;
		}
		indexedName = name;
		// 若存在 '[' ,則獲得 index ,並修改 name 。
		delim = name.indexOf('[');
		if (delim > -1) {
			// 擷取'['與']'中間的字串
			index = name.substring(delim + 1, name.length() - 1);
			// 擷取'['之前的字串
			name = name.substring(0, delim);
		}
	}

	public String getName() {
		return name;
	}

	public String getIndex() {
		return index;
	}

	public String getIndexedName() {
		return indexedName;
	}

	public String getChildren() {
		return children;
	}

	@Override
	public boolean hasNext() {
		return children != null;
	}

	/**
	 * 迭代方法 建立一個以children為表示式的PropertyTokenizer物件
	 */
	@Override
	public PropertyTokenizer next() {
		return new PropertyTokenizer(children);
	}

	@Override
	public void remove() {
		throw new UnsupportedOperationException(
				"Remove is not supported, as it has no meaning in the context of properties.");
	}
}
複製程式碼

3.0 總結

這一節的內容比較簡單,不過這個PropertyTokenizer屬性分詞器的實現還是很有意思的。大家在實際的開發中如果有類似的業務場景,也可以考慮這樣設計

失控的阿甘,樂於分享,記錄點滴

相關文章