可能大家看了我上一篇注解的文章,還是不知所云。這很正常,概念性的東西,不容易讓大家有感性的認識。我認為最高效的學習方法,就是在實踐中運用。我們拿@NotNull注解來舉例。
比如說,你寫了一個后臺系統,接收用戶的請求,經過運算后返回結果,很通用的一個實現方案。假定所有的方法都需要校驗參數是否為空,不然就可能有NullPointerException,如果系統有N個接口,每個接口參數有M個,你需要寫N * M個if判斷語句。如
if (StringUtils.isBlank(request.getA())) {
throw new IllegalArgumentException("A is blank");
}
這么寫下來,肯定代碼是很丑的。那怎么辦呢?記得我們之前說過的編碼理念,Don't repeat yourself,就派上用場了。
Java中已經定義了@NotNull
的注解,可以用來做這件事。(我們也可以自定義注解,見上一篇文章)在我們這個場景,我們的需求是:
- 在請求類中,所有不能為空的屬性上,需要標記為
@NotNull
- 寫一個通用的validation方法,獲取請求中的參數,檢查如果有標記
@NotNull
,且參數的值為null,則拋出異常。
代碼實現,
public class QueryUserRequest extends BaseRequest {
@NotNull
private String name;
@NotNull
private Integer age;
private Boolean gender;
// 省略getter, setter方法
}
為了使校驗參數的方法得到最大的通用性,我們把它放到BaseRequest中,讓所有的request都繼承這個父類。
public class BaseRequest {
public void nullFieldValidate() throws IllegalAccessException, InvocationTargetException {
Field[] fields = this.getClass().getDeclaredFields();
for (Field field : fields) {
String fieldName = field.getName();
Object fieldValue = runGetter(field, this);
boolean isAnnotationNotNull = field.isAnnotationPresent(NotNull.class);
if (isAnnotationNotNull && fieldValue == null) {
System.out.println(fieldName + " can't be null");
}
}
}
// 由于所有子類的屬性都是private的,所以必須要找到屬性的getter方法
// 以下代碼借鑒[stackoverflow的文章](https://stackoverflow.com/questions/13400075/reflection-generic-get-field-value)
public Object runGetter(Field field, Object instance) {
// MZ: Find the correct method
for (Method method : instance.getClass().getDeclaredMethods()) {
if ((method.getName().startsWith("get")) && (method.getName().length() == (field.getName().length() + 3))) {
if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase())) {
// MZ: Method found, run it
try {
return method.invoke(instance);
} catch (IllegalAccessException | InvocationTargetException e) {
System.out.println("Could not determine method: " + method.getName());
}
}
}
}
return null;
}
}
對于獲取類屬性上的注解有3種方法,如果有其他的方法也可以告知
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
// 方法1
Annotation[] annotations = field.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof NotNull && fieldValue == null) {
System.out.println(field.getName() + " can't be null");
}
}
// 方法2
Annotation annotation = field.getAnnotation(NotNull.class);
if (annotation != null && fieldValue == null) {
System.out.println(field.getName() + " can't be null");
}
// 方法3
boolean isAnnotationNotNull = field.isAnnotationPresent(NotNull.class);
if (isAnnotationNotNull && fieldValue == null) {
System.out.println(field.getName() + " can't be null");
}
}