最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Lombok實(shí)現(xiàn)方式JSR-269

 更新時(shí)間:2021年06月03日 08:46:44   作者:ingxx  
Lombok的出現(xiàn)幫助開(kāi)發(fā)人員在開(kāi)發(fā)工程中消除了大部分冗余代碼:繁瑣的get、set方法甚至建造者模式,今天通過(guò)本文給大家分享Lombok實(shí)現(xiàn)方式JSR-269的相關(guān)知識(shí),感興趣的朋友一起看看吧

前言

簡(jiǎn)介

Lombok是一款好用順手的工具,就像Google Guava一樣,在此予以強(qiáng)烈推薦,每一個(gè)Java工程師都應(yīng)該使用它。Lombok是一種Java™實(shí)用工具,可用來(lái)幫助開(kāi)發(fā)人員消除Java的冗長(zhǎng)代碼,尤其是對(duì)于簡(jiǎn)單的Java對(duì)象(POJO)。它通過(guò)注釋實(shí)現(xiàn)這一目的。通過(guò)在開(kāi)發(fā)環(huán)境中實(shí)現(xiàn)Lombok,開(kāi)發(fā)人員可以節(jié)省構(gòu)建諸如hashCode()和equals()這樣的方法以及以往用來(lái)分類各種accessor和mutator的大量時(shí)間。

Lombok的實(shí)現(xiàn)方式是什么呢?
新建一個(gè)測(cè)試類使用Lombok的Getter和Setter注解,通過(guò)IDEA進(jìn)行編譯

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class UserInfo {
    private String userId;

    private String userName;
}

打開(kāi)編譯后生成的UserInfo.class文件

發(fā)現(xiàn)已經(jīng)生成了get、set方法,由此可以推斷出Lombok是在編譯期為代碼進(jìn)行了增強(qiáng),那么在編譯期進(jìn)行增強(qiáng)是如何實(shí)現(xiàn)的?

編譯階段

在JDK6提出并通過(guò)了JSR-269提案,提案通過(guò)了一組被稱為“插入式注解處理器”的標(biāo)準(zhǔn)API,可以提前至編譯期對(duì)代碼中的特定注解進(jìn)行處理, 從而影響到編譯器的工作過(guò)程。
對(duì)于底層的一些實(shí)現(xiàn),普遍會(huì)認(rèn)為實(shí)現(xiàn)是像虛擬機(jī)一樣使用C++實(shí)現(xiàn),對(duì)于Java程序員來(lái)說(shuō)并不是特別友好。但是Javac編譯器是使用Java實(shí)現(xiàn)的更容易上手。
Javac的編譯過(guò)程大致分為幾步

  1. 準(zhǔn)備過(guò)程:初始化插入式注解處理器
  2. 解析與填充符號(hào)表過(guò)程 詞法、語(yǔ)法分析構(gòu)建抽象語(yǔ)法樹(shù)(AST)
  3. 插入式注解處理器的注解處理過(guò)程
  4. 分析與字節(jié)碼生成過(guò)程
  5. 語(yǔ)法樹(shù)變動(dòng)后會(huì)再次解析與填充符號(hào)表,語(yǔ)法樹(shù)沒(méi)有變動(dòng)時(shí)編譯器就不會(huì)再對(duì)源碼字符流操作,而是基于抽象語(yǔ)法樹(shù)

綜上所述想實(shí)現(xiàn)Lombok的效果只需要遵守JSR-269在編譯期對(duì)AST進(jìn)行操作即可實(shí)現(xiàn)
當(dāng)然不止有Lombok通過(guò)這種方式實(shí)現(xiàn),例如FindBug、MapStruct等也通過(guò)這種方式實(shí)現(xiàn)

實(shí)現(xiàn)

JCTree

JCTree是AST元素的基類,想實(shí)現(xiàn)效果只需要添加JCTree節(jié)點(diǎn)即可
JCTree是一個(gè)抽象類部分實(shí)現(xiàn)

從類名可以猜到是什么節(jié)點(diǎn)使用的這里挑幾個(gè)常用的解釋
JCStatement 聲明語(yǔ)法樹(shù)節(jié)點(diǎn)
JCBlock 語(yǔ)法塊
JCReturn:return語(yǔ)句語(yǔ)法樹(shù)節(jié)點(diǎn)
JCClassDecl:類定義語(yǔ)法樹(shù)節(jié)點(diǎn)
JCVariableDecl:字段/變量定義語(yǔ)法樹(shù)節(jié)點(diǎn)
JCMethodDecl:方法定義語(yǔ)法樹(shù)節(jié)點(diǎn)
JCModifiers:訪問(wèn)標(biāo)志語(yǔ)法樹(shù)節(jié)點(diǎn)
JCExpression:表達(dá)式語(yǔ)法樹(shù)節(jié)點(diǎn),常見(jiàn)的子類如下
JCAssign:賦值語(yǔ)句語(yǔ)法樹(shù)節(jié)點(diǎn)
JCIdent:標(biāo)識(shí)符語(yǔ)法樹(shù)節(jié)點(diǎn) 例如this

TreeMaker

主要用于生成語(yǔ)法樹(shù)節(jié)點(diǎn)

代碼

首先需要注解類,標(biāo)明作用的范圍和作用的時(shí)期,兩個(gè)類分別對(duì)應(yīng)Lombok的Getter、Setter

@Target({ElementType.TYPE}) //加在類上的注解
@Retention(RetentionPolicy.SOURCE) //作用于編譯期
public @interface Getter {
}
@Target({ElementType.TYPE}) //加在類上的注解
@Retention(RetentionPolicy.SOURCE) //作用于編譯期
public @interface Setter {
}

新建抽象注解處理器需要繼承AbstractProcessor,這里使用模板方法模式

public abstract class MyAbstractProcessor extends AbstractProcessor {
    //語(yǔ)法樹(shù)
    protected JavacTrees trees;

    //構(gòu)建語(yǔ)法樹(shù)節(jié)點(diǎn)
    protected TreeMaker treeMaker;

    //創(chuàng)建標(biāo)識(shí)符的對(duì)象
    protected Names names;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        this.trees = JavacTrees.instance(processingEnv);
        Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
        this.treeMaker = TreeMaker.instance(context);
        this.names = Names.instance(context);
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        //獲取注解標(biāo)識(shí)的類
        Set<? extends Element> set = roundEnv.getElementsAnnotatedWith(getAnnotation());
        //拿到語(yǔ)法樹(shù)
        set.stream().map(element -> trees.getTree(element)).forEach(jcTree -> jcTree.accept(new TreeTranslator() {
            //拿到類定義
            @Override
            public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
                List<JCTree.JCVariableDecl> jcVariableDeclList = List.nil();
                //拿到所有成員變量
                for (JCTree tree : jcClassDecl.defs) {
                    if (tree.getKind().equals(Tree.Kind.VARIABLE)) {
                        JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) tree;
                        jcVariableDeclList = jcVariableDeclList.append(jcVariableDecl);
                    }
                }

                jcVariableDeclList.forEach(jcVariableDecl -> {
                    jcClassDecl.defs = jcClassDecl.defs.prepend(makeMethodDecl(jcVariableDecl));
                });
                super.visitClassDef(jcClassDecl);
            }
        }));
        return true;
    }

    /**
     * 創(chuàng)建方法
     * @param jcVariableDecl
     * @return
     */
    public abstract JCTree.JCMethodDecl makeMethodDecl(JCTree.JCVariableDecl jcVariableDecl);

    /**
     * 獲取何種注解
     * @return
     */
    public abstract Class<? extends Annotation> getAnnotation();
}

用于處理Setter注解 繼承MyAbstractProcessor

@SupportedAnnotationTypes("com.ingxx.processor.Setter") //注解處理器作用于哪個(gè)注解 也可以重寫(xiě)getSupportedAnnotationTypes
@SupportedSourceVersion(SourceVersion.RELEASE_8) //可以處理什么版本 也可以重寫(xiě)getSupportedSourceVersion
public class SetterProcessor extends MyAbstractProcessor {

    @Override
    public JCTree.JCMethodDecl makeMethodDecl(JCTree.JCVariableDecl jcVariableDecl) {
        ListBuffer<JCTree.JCStatement> statements = new ListBuffer<>();
        //生成函數(shù)體 this.name = name;
        statements.append(treeMaker.Exec(treeMaker.Assign(treeMaker.Select(treeMaker.Ident(names.fromString("this")), jcVariableDecl.getName()),treeMaker.Ident(jcVariableDecl.getName()))));
        JCTree.JCBlock body = treeMaker.Block(0, statements.toList());
        //生成方法
        return treeMaker.MethodDef(
                treeMaker.Modifiers(Flags.PUBLIC), //訪問(wèn)標(biāo)志
                getNewMethodName(jcVariableDecl.getName()), //名字
                treeMaker.TypeIdent(TypeTag.VOID), //返回類型
                List.nil(), //泛型形參列表
                List.of(getParameters(jcVariableDecl)), //參數(shù)列表
                List.nil(), //異常列表
                body, //方法體
                null //默認(rèn)方法(可能是interface中的那個(gè)default)
        );
    }

    @Override
    public Class<? extends Annotation> getAnnotation() {
        return Setter.class;
    }

    private Name getNewMethodName(Name name) {
        String fieldName = name.toString();
        return names.fromString("set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1, name.length()));
    }

    private JCTree.JCVariableDecl getParameters(JCTree.JCVariableDecl prototypeJCVariable) {
        return treeMaker.VarDef(
                treeMaker.Modifiers(Flags.PARAMETER), //訪問(wèn)標(biāo)志
                prototypeJCVariable.name, //名字
                prototypeJCVariable.vartype, //類型
                null //初始化語(yǔ)句
        );
    }
}

用于處理Getter注解 繼承MyAbstractProcessor

@SupportedAnnotationTypes("com.ingxx.processor.Getter") //注解處理器作用于哪個(gè)注解 也可以重寫(xiě)getSupportedAnnotationTypes
@SupportedSourceVersion(SourceVersion.RELEASE_8) //可以處理什么版本 也可以重寫(xiě)getSupportedSourceVersion
public class GetterProcessor extends MyAbstractProcessor {

    @Override
    public JCTree.JCMethodDecl makeMethodDecl(JCTree.JCVariableDecl jcVariableDecl) {
        ListBuffer<JCTree.JCStatement> statements = new ListBuffer<>();
        //生成函數(shù)體 return this.字段名
        statements.append(treeMaker.Return(treeMaker.Select(treeMaker.Ident(names.fromString("this")), jcVariableDecl.getName())));
        JCTree.JCBlock body = treeMaker.Block(0, statements.toList());
        //生成方法
        return treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC), getNewMethodName(jcVariableDecl.getName()), jcVariableDecl.vartype, List.nil(), List.nil(), List.nil(), body, null);
    }

    @Override
    public Class<? extends Annotation> getAnnotation() {
        return Getter.class;
    }

    private Name getNewMethodName(Name name) {
        String fieldName = name.toString();
        return names.fromString("get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1, name.length()));
    }
}

編譯現(xiàn)有類

javac -cp $JAVA_HOME/lib/tools.jar *.java -d . 

新建一個(gè)測(cè)試類 IDEA中由于找不到get set方法會(huì)報(bào)錯(cuò),可以忽略

@Getter
@Setter
public class UserInfo {
    private String userId;

    private String userName;

    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId("001");
        userInfo.setUserName("得物");
        System.out.println("id = "+userInfo.getUserId()+" name = "+userInfo.getUserName());
    }
}

接著編譯

//多個(gè)處理器用逗號(hào)分隔
javac -processor com.ingxx.processor.GetterProcessor,com.ingxx.processor.SetterProcessor UserInfo.java -d .

查看編譯后的文件發(fā)現(xiàn)已經(jīng)生成了get、set方法

以上就是從Lombok到JSR-269的詳細(xì)內(nèi)容,更多關(guān)于JS 反射機(jī)制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 微信小程序?qū)崿F(xiàn)收縮式菜單

    微信小程序?qū)崿F(xiàn)收縮式菜單

    這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)收縮式菜單,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • Webpack的dll功能使用

    Webpack的dll功能使用

    這篇文章主要介紹了Webpack的dll功能使用,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • JavaScript代碼輕松實(shí)現(xiàn)網(wǎng)頁(yè)內(nèi)容禁止復(fù)制(代碼簡(jiǎn)單)

    JavaScript代碼輕松實(shí)現(xiàn)網(wǎng)頁(yè)內(nèi)容禁止復(fù)制(代碼簡(jiǎn)單)

    有些時(shí)候我們寫(xiě)的內(nèi)容不想被別人復(fù)制,在代碼中怎么實(shí)現(xiàn)的呢?下面小編給大家介紹javascript代碼輕松實(shí)現(xiàn)網(wǎng)頁(yè)內(nèi)容禁止復(fù)制,感興趣的童鞋一起看看吧
    2015-10-10
  • Javascript無(wú)阻塞加載具體方式

    Javascript無(wú)阻塞加載具體方式

    這篇文章介紹了JS無(wú)阻塞加載,有需要的朋友可以參考一下
    2013-06-06
  • JavaScript中常見(jiàn)的繼承方式總結(jié)

    JavaScript中常見(jiàn)的繼承方式總結(jié)

    這篇文章主要和大家詳細(xì)介紹了JavaScript中常見(jiàn)的幾種繼承方式,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)JavaScript有一定幫助,需要的小伙伴可以參考下面文章詳細(xì)內(nèi)容
    2022-11-11
  • js判斷文件是否為utf-8編碼的方法

    js判斷文件是否為utf-8編碼的方法

    使用FileReader以u(píng)tf-8格式讀取文件,根據(jù)文件內(nèi)容是否包含亂碼字符,來(lái)判斷文件是否為utf-8,本文就詳細(xì)的介紹一下使用,感興趣的小伙伴們可以參考一下
    2021-06-06
  • 如何在js中引入less的變量

    如何在js中引入less的變量

    這篇文章主要介紹了如何在js中引入less的變量,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07
  • JavaScript?中傳遞參數(shù)的方式示例詳解

    JavaScript?中傳遞參數(shù)的方式示例詳解

    JavaScript中參數(shù)傳遞方式包括按值傳遞、按引用傳遞、參數(shù)解構(gòu)傳遞、Rest參數(shù)傳遞、回調(diào)函數(shù)傳遞、閉包傳遞、模板字符串傳遞和高階函數(shù)傳遞,每種方式都有其特點(diǎn)和適用場(chǎng)景,選擇合適的傳遞方式可以提高代碼的可讀性、可維護(hù)性和靈活性,感興趣的朋友一起看看吧
    2025-01-01
  • JavaScript實(shí)現(xiàn)點(diǎn)擊復(fù)制功能具體代碼(JS訪問(wèn)剪貼板相關(guān))

    JavaScript實(shí)現(xiàn)點(diǎn)擊復(fù)制功能具體代碼(JS訪問(wèn)剪貼板相關(guān))

    這篇文章主要給大家介紹了關(guān)于JavaScript實(shí)現(xiàn)點(diǎn)擊復(fù)制功能(JS訪問(wèn)剪貼板相關(guān))的相關(guān)資料,復(fù)制功能指的是將一個(gè)文本或者圖片等資源從一個(gè)位置通過(guò)復(fù)制的方式再次拷貝到另一個(gè)位置,需要的朋友可以參考下
    2023-10-10
  • js實(shí)現(xiàn)的修改div里img標(biāo)簽的src屬性

    js實(shí)現(xiàn)的修改div里img標(biāo)簽的src屬性

    js實(shí)現(xiàn)的修改div里img標(biāo)簽的src屬性...
    2007-09-09

最新評(píng)論

安塞县| 北安市| 屯门区| 清河县| 肃宁县| 平顶山市| 永嘉县| 桃园市| 金溪县| 杂多县| 兴山县| 沂南县| 马公市| 霸州市| 大洼县| 富锦市| 黄浦区| 丰县| 常山县| 无棣县| 开远市| 阳东县| 同仁县| 荆门市| 阿拉善右旗| 日土县| 英德市| 周口市| 鹤壁市| 六安市| 巴楚县| 花莲县| 洛川县| 大田县| 鹿泉市| 工布江达县| 莲花县| 垣曲县| 玉溪市| 阳曲县| 资源县|