广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >Lombok实现方式JSR-269
  • 876
分享到

Lombok实现方式JSR-269

2024-04-02 19:04:59 876人浏览 薄情痞子
摘要

前言 简介 Lombok是一款好用顺手的工具,就像Google Guava一样,在此予以强烈推荐,每一个Java工程师都应该使用它。Lombok是一种Java™实用工具

前言

简介

Lombok是一款好用顺手的工具,就像Google Guava一样,在此予以强烈推荐,每一个Java工程师都应该使用它。Lombok是一种Java™实用工具,可用来帮助开发人员消除Java的冗长代码,尤其是对于简单的Java对象(POJO)。它通过注释实现这一目的。通过在开发环境中实现Lombok,开发人员可以节省构建诸如hashCode()和equals()这样的方法以及以往用来分类各种accessor和mutator的大量时间。

Lombok的实现方式是什么呢?
新建一个测试类使用Lombok的Getter和Setter注解,通过idea进行编译


import lombok.Getter;
import lombok.Setter;

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

    private String userName;
}

打开编译后生成的UserInfo.class文件

发现已经生成了get、set方法,由此可以推断出Lombok是在编译期为代码进行了增强,那么在编译期进行增强是如何实现的?

编译阶段

jdk6提出并通过了jsR-269提案,提案通过了一组被称为“插入式注解处理器”的标准api,可以提前至编译期对代码中的特定注解进行处理, 从而影响到编译器的工作过程。
对于底层的一些实现,普遍会认为实现是像虚拟机一样使用c++实现,对于Java程序员来说并不是特别友好。但是Javac编译器是使用Java实现的更容易上手。
Javac的编译过程大致分为几步

  1. 准备过程:初始化插入式注解处理器
  2. 解析与填充符号表过程 词法、语法分析构建抽象语法树(AST)
  3. 插入式注解处理器的注解处理过程
  4. 分析与字节码生成过程
  5. 语法树变动后会再次解析与填充符号表,语法树没有变动时编译器就不会再对源码字符流操作,而是基于抽象语法树

综上所述想实现Lombok的效果只需要遵守JSR-269在编译期对AST进行操作即可实现
当然不止有Lombok通过这种方式实现,例如FindBug、MapStruct等也通过这种方式实现

实现

JCTree

JCTree是AST元素的基类,想实现效果只需要添加JCTree节点即可
JCTree是一个抽象类部分实现

从类名可以猜到是什么节点使用的这里挑几个常用的解释
JCStatement 声明语法树节点
JCBlock 语法块
JCReturn:return语句语法树节点
JCClassDecl:类定义语法树节点
JCVariableDecl:字段/变量定义语法树节点
JCMethodDecl:方法定义语法树节点
JCModifiers:访问标志语法树节点
JCExpression:表达式语法树节点,常见的子类如下
JCAssign:赋值语句语法树节点
JCIdent:标识符语法树节点 例如this

TreeMaker

主要用于生成语法树节点

代码

首先需要注解类,标明作用的范围和作用的时期,两个类分别对应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 {
    //语法树
    protected JavacTrees trees;

    //构建语法树节点
    protected TreeMaker treeMaker;

    //创建标识符的对象
    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) {
        //获取注解标识的类
        Set<? extends Element> set = roundEnv.getElementsAnnotatedWith(getAnnotation());
        //拿到语法树
        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;
    }

    
    public abstract JCTree.JCMethodDecl makeMethodDecl(JCTree.JCVariableDecl jcVariableDecl);

    
    public abstract Class<? extends Annotation> getAnnotation();
}

用于处理Setter注解 继承MyAbstractProcessor


@SupportedAnnotationTypes("com.ingxx.processor.Setter") //注解处理器作用于哪个注解 也可以重写getSupportedAnnotationTypes
@SupportedSourceVersion(SourceVersion.RELEASE_8) //可以处理什么版本 也可以重写getSupportedSourceVersion
public class SetterProcessor extends MyAbstractProcessor {

    @Override
    public JCTree.JCMethodDecl makeMethodDecl(JCTree.JCVariableDecl jcVariableDecl) {
        ListBuffer<JCTree.JCStatement> statements = new ListBuffer<>();
        //生成函数体 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), //访问标志
                getNewMethodName(jcVariableDecl.getName()), //名字
                treeMaker.TypeIdent(TypeTag.VOID), //返回类型
                List.nil(), //泛型形参列表
                List.of(getParameters(jcVariableDecl)), //参数列表
                List.nil(), //异常列表
                body, //方法体
                null //默认方法(可能是interface中的那个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), //访问标志
                prototypeJCVariable.name, //名字
                prototypeJCVariable.vartype, //类型
                null //初始化语句
        );
    }
}

用于处理Getter注解 继承MyAbstractProcessor


@SupportedAnnotationTypes("com.ingxx.processor.Getter") //注解处理器作用于哪个注解 也可以重写getSupportedAnnotationTypes
@SupportedSourceVersion(SourceVersion.RELEASE_8) //可以处理什么版本 也可以重写getSupportedSourceVersion
public class GetterProcessor extends MyAbstractProcessor {

    @Override
    public JCTree.JCMethodDecl makeMethodDecl(JCTree.JCVariableDecl jcVariableDecl) {
        ListBuffer<JCTree.JCStatement> statements = new ListBuffer<>();
        //生成函数体 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()));
    }
}

编译现有类


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

新建一个测试类 IDEA中由于找不到get set方法会报错,可以忽略


@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());
    }
}

接着编译


//多个处理器用逗号分隔
javac -processor com.ingxx.processor.GetterProcessor,com.ingxx.processor.SetterProcessor UserInfo.java -d .

查看编译后的文件发现已经生成了get、set方法

以上就是从Lombok到JSR-269的详细内容,更多关于JS 反射机制的资料请关注编程网其它相关文章!

--结束END--

本文标题: Lombok实现方式JSR-269

本文链接: https://www.lsjlt.com/news/127457.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Lombok实现方式JSR-269
    前言 简介 Lombok是一款好用顺手的工具,就像Google Guava一样,在此予以强烈推荐,每一个Java工程师都应该使用它。Lombok是一种Java™实用工具...
    99+
    2022-11-12
  • Spring 校验(validator,JSR-303)简单实现方式
    目录Spring 校验(validator,JSR-303)实现什么是JSR-303规范与Spring MVC结合实体类添加验证注解控制器验证注解添加Java Hibernate V...
    99+
    2022-11-12
  • MyBatisPlus+Lombok实现分页功能的方法详解
    目录一、Lombok1、添加Lombok依赖2、安装Lombok插件3、模型类上添加注解二、分页功能1、调用方法传入参数获取返回值2、设置分页拦截器3、运行测试程序一、Lombok ...
    99+
    2022-11-13
  • python3cmp实现方式
    目录python3 cmp实现PY3__cmp__ mixin类cmp()函数实现的注解python3 使用cmp函数报错使用operator模块python3 cmp实现 pyth...
    99+
    2022-11-13
  • PVPlayer的实现方式
    PVPlayer的实现方式可以是通过以下几种方式之一:1. 使用现有的音视频播放器库:PVPlayer可以使用现有的音视频播放器库,...
    99+
    2023-09-20
    PVPlayer
  • rpm包方式实现LNMP
    rpm包 lnmp nginx-主机 : 172.16.40.99php-fpm-主机 : 172.16.40.11mariadb-主机  : 172.16.40.88一.安装,配置ng...
    99+
    2022-10-18
  • Java中Elasticsearch实现分页方式(三种方式)
    目录ES 简介ES 的特点:一、from + size 浅分页二、scroll 深分页scroll删除三、search_after 深分页ES 简介 Elasticsearch 是一...
    99+
    2022-11-13
  • Redis分布式锁的实现方式
    目录一、分布式锁是什么1、获取锁2、释放锁二、代码实例上面代码存在锁误删问题:三、基于SETNX实现的分布式锁存在下面几个问题1、不可重入2、不可重试3、超时释放4、主从一致性四、Redisson实现分布式锁1、pom2...
    99+
    2023-04-03
    Java Redis分布式锁实现方式 实现Redis分布式锁 Redis分布式锁实现
  • ZooKeeper分布式锁的实现方式
    本篇内容介绍了“ZooKeeper分布式锁的实现方式”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!目录一、分布式锁方案比较二、ZooKeep...
    99+
    2023-06-20
  • Shell四种运行方式(启动方式)的实现
    Shell 是一个应用程序,它的一端连接着 linux 内核,另一端连接着用户。Shell 是用户和 Linux 系统沟通的桥梁,我们都是通过 Shell 来管理 Linux 系统。 我们可以直接使用 Shell,也可以...
    99+
    2022-06-04
    Shell 运行方式 Shell 启动方式
  • mybatis实现mapper代理模式的方式
    今晚继续复习mybtis 以根据id值查询单条数据为例 编写SqlMapConfig.xml文件 <configuration> <!-- 使用mybatis...
    99+
    2022-11-12
  • Zookeeper的分布式锁的实现方式
    这篇文章主要讲解了“Zookeeper的分布式锁的实现方式”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Zookeeper的分布式锁的实现方式”吧!1. 背景最近在学习 Zookeeper,...
    99+
    2023-06-05
  • C++种string的实现方式
    这篇文章主要讲解了“C++种string的实现方式”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++种string的实现方式”吧!常见的string实现方式有两种,一种是深拷贝的方式,一种...
    99+
    2023-06-16
  • Java切面的实现方式
    Java 切面(Aspect)是指在软件开发中,将某些横跨多个组件的功能,如日志记录、性能监控、权限控制等,抽象出来形成一个独立的模块,称之为切面。切面可以被应用到多个模块中,提供相同的功能。Java中实现切面的技术有多种,下面分别介绍...
    99+
    2023-09-05
    java spring 开发语言
  • 线程池的实现方式
    线程池有以下几种实现方式:Executors目前提供了5种不同的线程池创建配置:1、newCachedThreadPool()它是用来处理大量短时间工作任务的线程池,具有几个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的...
    99+
    2018-03-19
    java入门 线程池
  • redis中list的实现方式
    了解redis中list的实现方式?这个问题可能是我们日常学习或工作经常见到的。希望通过这个问题能让你收获颇深。下面是小编给大家带来的参考内容,让我们一起来看看吧!Redis 列表(list)是简单的字符串...
    99+
    2022-10-18
  • MongoDB主从的实现方式
    这篇文章主要介绍“MongoDB主从的实现方式”,在日常操作中,相信很多人在MongoDB主从的实现方式问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”MongoDB主从的实现...
    99+
    2022-10-18
  • CSS3动画的实现方式
    这篇文章主要讲解了“CSS3动画的实现方式”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“CSS3动画的实现方式”吧!任务我们最近在SeatGeek更新了我们...
    99+
    2022-10-19
  • 有哪些LFU实现方式
    本篇内容主要讲解“有哪些LFU实现方式”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“有哪些LFU实现方式”吧!LFU实现力扣原题描述如下:请你为 最不...
    99+
    2022-10-19
  • Springboot集成swagger实现方式
    Swagger 提供了一个全新的维护 API 文档的方式,有4大优点: 自动生成文档:只需要少量的注解,Swagger 就可以根据代码自动生成 API 文档,很好的保证了文...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作