註解提高篇:自定義註解處理器(APT)
## 0x01 繼承AbstractProcessor抽象類
當定義好Annotation註解後,接下來就需要一個註解處理器來處理我們的自定義註解了。實現Java Annotation一般需要繼承AbstractProcessor抽象類,並且重寫其四個方法來實現提取,解析並處理自定義註解的邏輯如下:
class WondertwoProcessor extends AbstractProcessor { //返回註解處理器可處理的註解操作 @Override public Set<String> getSupportedOptions() { return super.getSupportedOptions(); } //得到註解處理器可以支援的註解型別 @Override public Set<String> getSupportedAnnotationTypes() { return super.getSupportedAnnotationTypes(); } //執行一些初始化邏輯 @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); } //核心方法,掃描,解析並處理自定義註解,生成***.java檔案 @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { return false; } }
## 0x02 重寫核心方法process()
由上可知process()方法才是掃描,解析,處理註解的核心方法,動手實戰一下寫一個簡單的WondertwoProcessor來提取自定義註解@CustomizeInterface
,然後藉助JavaPoet生成Java介面檔案。
/** * 自定義註解處理器,將類中public方法提取為介面方法(不含static方法) * { * Exec: apt -factory annotation3.WondertwoFactory * ProvinceDefiner.java -s ../annotaion3 * } * Created by wondertwo on 2016/10/18. */ class WondertwoProcessor extends AbstractProcessor { private ProcessingEnvironment envir; public WondertwoProcessor(ProcessingEnvironment env) { this.envir = env; } @Override public Set<String> getSupportedOptions() { return super.getSupportedOptions(); } @Override public Set<String> getSupportedAnnotationTypes() { return super.getSupportedAnnotationTypes(); } @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { for (TypeElement typeEle : annotations) { WondertwoInterface wondertwoInterface = typeEle.getAnnotation(WondertwoInterface.class); if (wondertwoInterface == null) break; Class clazz = typeEle.getClass(); if (clazz.getDeclaredMethods().length > 0) { try { if (typeEle.getModifiers().contains(Modifier.PUBLIC) && !typeEle.getModifiers().contains(Modifier.STATIC)) { PrintWriter writer = (PrintWriter) envir.getFiler() .createSourceFile(wondertwoInterface.value()); writer.println("package " + clazz.getPackage().getName() + ";"); writer.println("public interface " + wondertwoInterface.value() + " {"); for (Method method : clazz.getDeclaredMethods()) { writer.print(" public "); writer.print(method.getReturnType() + " "); writer.print(method.getName() + " ("); int i = 0; for (TypeParameterElement parameter : typeEle.getTypeParameters()) { writer.print(parameter.asType() + " " + parameter.getSimpleName()); if (++i < typeEle.getTypeParameters().size()) writer.print(", "); } writer.println(");"); } writer.println("}"); writer.close(); } } catch (IOException e) { throw new RuntimeException(e); } } } return true; } }
看過《Java程式設計思想》的同學肯定對上面的例項非常眼熟,書中對應的例項也是提取非靜態公有方法生成介面原始檔,但由於是JDK6.0標準已經有很多API發生了很大的變化,本例基於JDK8!
可以看到我們只在process()方法中加入了處理註解,生成.java檔案的邏輯,這裡是的邏輯是根據自定義註解提取對應類的非靜態public方法,然後將抽取的非靜態共有方法拼接成對應的介面!
## 0x03 例項探究:Android依賴註解庫ButterKnife
不會偷懶的程式設計師不是一個好程式設計師,Android開發者對ButterKnife依賴註解庫一定耳熟能詳,當我們UI佈局中控制元件很多的時候ButterKnife無疑顯著提高了開發效率。
作為一個註解庫其實現的原理依然是Java Annotation的方式,我們在Github翻出ButterKnife原始碼檔案,找到其核心類——註解處理類ButterKnifeProcessor.java,原始碼較長刪減後如下:
public final class ButterKnifeProcessor extends AbstractProcessor {
@Override public synchronized void init(ProcessingEnvironment env) {
super.init(env);
elementUtils = env.getElementUtils();
typeUtils = env.getTypeUtils();
filer = env.getFiler();
}
@Override public Set<String> getSupportedAnnotationTypes() {
Set<String> types = new LinkedHashSet<String>();
types.add(Bind.class.getCanonicalName());
for (Class<? extends Annotation> listener : LISTENERS) {
types.add(listener.getCanonicalName());
}
types.add(BindBool.class.getCanonicalName());
types.add(BindColor.class.getCanonicalName());
types.add(BindDimen.class.getCanonicalName());
types.add(BindDrawable.class.getCanonicalName());
types.add(BindInt.class.getCanonicalName());
types.add(BindString.class.getCanonicalName());
return types;
}
@Override public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env) {
Map<TypeElement, BindingClass> targetClassMap = findAndParseTargets(env);
for (Map.Entry<TypeElement, BindingClass> entry : targetClassMap.entrySet()) {
TypeElement typeElement = entry.getKey();
BindingClass bindingClass = entry.getValue();
try {
JavaFileObject jfo = filer.createSourceFile(bindingClass.getFqcn(), typeElement);
Writer writer = jfo.openWriter();
writer.write(bindingClass.brewJava());
writer.flush();
writer.close();
} catch (IOException e) {
error(typeElement, "Unable to write view binder for type %s: %s", typeElement,
e.getMessage());
}
}
return true;
}
@Override public Set<String> getSupportedOptions() {
return Collections.singleton(OPTION_SDK_INT);
}
}
如果想要進一步瞭解ButteKnife掃描,解析,處理註解,生成Java程式碼的每一部細節,可以參考文章:淺析ButterKnife
相關推薦
註解提高篇:自定義註解處理器(APT)
## 0x01 繼承AbstractProcessor抽象類 當定義好Annotation註解後,接下來就需要一個註解處理器來處理我們的自定義註解了。實現Java Annotation一般需要繼承AbstractProcessor抽象類,並且重寫其四個方法來實現提取,解析並處理自定義註解的邏輯如下: cla
註解基礎篇:自定義Java Annotation
## 寫在前面 JDK5增加了對Annotation(註解)的支援,Annotation是程式碼裡的特殊標記,這些標記可以在編譯,類載入和執行時被讀取讀取出來,並執行相應的處理和操作!比如在不改變程式邏輯的情況下,開發人員可以在程式碼中嵌入一些補充資訊,程式碼分析和開發部署工具APT(AnnotationP
Android自定義控制元件系列二:自定義開關按鈕(一)
這一次我們將會實現一個完整純粹的自定義控制元件,而不是像之前的組合控制元件一樣,拿系統的控制元件來實現;計劃分為三部分:自定義控制元件的基本部分,和自定義控制元件的自定義屬性; 下面就開始第一部分的編寫,本次以一個定義的開關按鈕為例,下面就開始吧: 先看看效果,一個點選開
Android註解:自定義註解之原始碼註解
首先如果你對註解沒有太多瞭解,建議先看一下我之前的兩篇部落格 Android註解:Java註解 Android註解:Android 常用註解 這兩篇部落格都詳細介紹了關於Android註解的一些基礎知識。這是Android自定義註解的第一篇,原始碼註解。A
2 手寫實現SpringMVC,第二節:自定義註解及反射賦值
還是回到最終要實現的效果。 可以發現,這裡面使用了大量的自定義註解,並且還有autuwire的屬性也需要被賦值(Spring的IOC功能)。 先來建立自定義註解 注意,根據不同的註解使用的範圍來定義@Target,譬如Controller,Service能註解到類,R
Java註解:自定義註解示例,利用反射進行解析
Java註解能夠提供程式碼的相關資訊,同時對於所註解的程式碼結構又沒有直接影響。在這篇教程中,我們將學習Java註解,如何編寫自定義註解,註解的使用,以及如何使用反射解析註解。 註解是Java 1.5引入的,目前已被廣泛應用於各種Java框
2:自定義註解日誌脫敏(半原創)
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import j
Android進階必學:自定義註解之動態代理
自定義註解是Android進階的必學知識,從現在起我講為大家帶來四篇文章,讓大家徹底學會自定義註解 靜態代理大家都明白,就是相當於包裝了一次,在包裝這一次的時候可以加一些業務邏輯。同樣靜態代理的特點是一個介面對應一個代理類,當然委託類可以多個。 靜態
Spring Boot自定義註解掃描器 Spring Boot自定義註解掃描器
原 Spring Boot自定義註解掃描器 2018年08月15日 14:37:52 Dongguabai 閱讀數:502
【java自定義註解2】java自定義註解結合Spring AOP
承接上一篇,註解應用於屬性,本篇定義了一個用於方法的註解,結合Spring AOP 實現 切面程式設計。 以下demo演示使用了SpringBoot,與SSM中使用方式大致相同,效果如下: 1、自定義註解(用
【java自定義註解1】java自定義註解-屬性
關於自定義註解,以前專案種應用的不多,最近看新專案過程中發現了挺多自定義註解相關內容,使用起來比較巧妙,於是 總結了兩種方式,記錄如下: 第一種:結合反射進行屬性注入,程式碼如下:
精通Spring Boot——第十八篇:自定義認證流程
前兩篇簡單介紹了一下使用Spring Security 使用Http Basic登入,以及Spring Security如何自定義登入邏輯。這篇文章主要介紹如何使用handler來定義認證相關的流程。 先做一些自定義的操作,如配置自定義登入頁,配置登入請求URL等。 當我們使用Spring Security時
java註解詳解和自定義註解
本文首先介紹了註解的基本概念和JDK內建的標準註解,然後介紹瞭如何自定義註解,最後給出了自定義註解的例子。 一、註解的基本概念 Java 註解就像修飾符一樣,可以用於從java程式碼中抽取文件、跟蹤程式碼中的依賴性或者在編譯時做檢查。註解可以被應用在包、類、
Spring註解的原理與自定義註解的實現
本文只是用於記錄個人在學習annotation過程中的心德,所以知識面不太完善。 1、註解的基本概念 Java 的annotation提供的是一種類似於註釋的機制,註解本身不做任何事,好比一個配置或者說一個標記。用於包、型別、構造方法、方法、成員變數、引數及本地變數
MySQL 第八篇:自定義函式、儲存過程、遊標
本篇內容由猿道教育的課程內容整理而來。 我把MySQL的內容整理成9篇部落格,學完這9篇部落格雖不能說能成為大神,但是應付一般中小企業的開發已經足夠了,有疑問或建議的歡迎留言討論。 自定義函式 一、函式的概念與定義 1、理解函式 函式可以看作是
Java註解詳解,自定義註解,利用反射解析註解
概要 這篇文章將會帶領你瞭解Java註解,註解的使用,註解的解析,利用反射解析執行時註解,相信有一定Java基礎的小夥伴一定會接觸大量的註解,Spring , Hibernate , MyBatis等著名的框架也有很多關於註解方面的應用,對於註解的使用小夥伴們
java註解簡單講解以及自定義註解例子
註解(Annotation) jdk5定義了4個標準的元註解。除了元註解,還有其它幫我們定義好的註解如@SuppressWarnings 當然我們也可以自定義註解 @Target, @Retention, @Documented, @Inherited @Retent
Spring AOP 基於註解實現日誌記錄+自定義註解
一、寫一個自定義註解 註解中包括配置方法所在模組名稱,以及功能名稱,當然我們在註解裡可以自定義。import java.lang.annotation.Documented; import java.lang.annotation.ElementType; im
Android特效第三篇:自定義Gallery實戰(仿網易) .
Android系統提供了一個Gallery畫廊控制元件,在專案很多時候都會用到Gallery,比如新浪首頁的廣告,網易看客戶端首頁等隨處可見,今天我自己定義了一個仿網易的Gallery與大家共享。 首先請看效果圖:
Web開發之-JSP學習總結-第四篇:自定義標籤總結
一、自定義標籤開發步驟—以高仿<c:if test=""></c:if>標籤為例 1、編寫一個普通的java類,繼承SimpleTagSupport類,叫標籤處理器類。並且覆蓋doTag方法 /** * 標籤處理器類 * 1)繼承