Lombok简介

Lombok(https://projectlombok.org/)  提供了以注解的形式为java对象增加属性和方法,这使得原来冗长的java源文件变的简洁(不需要再使用ide去生成getter和setter方法,不过ide需要插件支持才能识别lombok自动添加的getter/setter方法,因为真正的代码其实是在编译阶段添加到子节码文件中的),一些固定模板的代码也可以自动添加,例如生成Logger。详细的原理有很多分析贴,此处不再赘述,有需要可以参见附录中的链接:http://notatube.blogspot.com/2010/11/project-lombok-trick-explained.html

Lombok中自带的注解几乎涵盖了所有冗余的,但总是会有一些需要我们自己定制的需求。

研究内容

最近遇到一个情景,一些JAVA对象都需要一个映射到数据库自增ID的字段,为了避免代码冗余,让他们继承自同一个包含同一个id字段的父类似乎就可以解决问题,不同的主键还有可能是不同的数据类型,较常见的是Long,Integer和String(uuid),所以这个父类需要写成一个模板类,并且要求所有包含主键的类都要继承这个泛型父类,其实我们只是想要的只是这个类增加一个id字段,并且生成对应的getter和setter 方法就好了,与其搞成继承关系,倒不如让效法lombok,使用annotation来生成这个字段和方法。

本文探讨的内容包括:

  1. 新增一个PrimaryKey注解,接受keyName和keyType两个参数,凡是有PrimaryKey注解的类,都会自动生成一个类型是${keyType}、字段名为${keyName}的字段,并为这个字段生成getter和setter方法。

  2. 让intellij的lombok插件能够识别新的注解,可以自动提示主键字段和它的getter/setter方法,而不报编译错误

自定义注解

不仅要新建自定义注解,还要新建对应的Handler,以便编译阶段正确处理包含自定义注解的源文件。

开发环境设置

首先checkout最新的lombok代码,https://github.com/rzwitserloot/lombok.git

lombok项目目前只有基于Eclipse的debug环境配置脚本,如果是Intellij,需要自己配置一下lombok的环境,稍后会介绍。

工程中有基于ant的自动构建脚本,先运行"compile" 任务,这时会自动触发"ensureBuildDeps"这个任务,它会下载一些依赖的Jar包。Tips:中间会去下一个对应jdk版本的rt.jar文件,由于这个文件比较大,国内下载速度非常慢,建议自行翻|墙下载,放到lib目录对应java版本的文件夹下面即可。

编译成功之后,就可以跑一下"test"任务了,它会先执行"dist",在dist目录下面生成lombok的jar文件,然后执行自动测试。

新建自定义注解

注解类代码如下:

package lombok;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
 * 默认以Long作为主键类型
 * Created by hoyt on 15/9/22.
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface PrimaryKey {
    Class keyType() default Long.class;
    String keyName() default "id";
}

新建HandlePrimaryKey

handler需要继承自JavacAnnotationHandler,并实现其handle方法,简述一下handle方法里的操作

  1. 判断目标注解(这里就是PrimaryKey)是否满足正确性验证

  2. 验证通过时,为被注解的类动态添加字段,字段的名称和类型都是PrimaryKey注解中的值

  3. 为新添加的字段创建getter和setter方法

handle方法的声明如下:

public void handle(AnnotationValues<PrimaryKey> annotation, JCTree.JCAnnotation ast, JavacNode annotationNode){

}

其中,annotation是lombok自定义的类型,包含了自定义的注解信息,通过如下代码,就可以获得注解中设置的具体值

        String keyName = annotation.getInstance().keyName();
        Class pk = annotation.getInstance().keyType();

在新建字段、创建getter/setter方法时,都可以直接复用lombok已有的方法和类,非常方便,贴出部分关键代码。

        JCTree.JCExpression keyType = chainDotsString(typeNode, type);
        
        JCTree.JCVariableDecl field = maker.VarDef(
                maker.Modifiers(Flags.PRIVATE),
                typeNode.toName(keyName), keyType, null);
        
        JCTree.JCVariableDecl fieldDecl = recursiveSetGeneratedBy(field, source, typeNode.getContext());         JavacNode fieldNode = injectFieldAndMarkGenerated(typeNode, fieldDecl);         new HandleGetter().generateGetterForField(fieldNode, source.pos(),  AccessLevel.PUBLIC, false);
        new HandleSetter().generateSetterForField(fieldNode, typeNode,  AccessLevel.PUBLIC);
        return true;

*如果要支持Eclipse自带的编译器,需要另外写一个handler

测试Handle

幸好lombok已经包含了测试/调试环境配置(只针对eclipse,Intellij需要自行配置)。直接运行"setupJavaOracle8TestEnvironment",就会自动配置好基于junit的测试/调试环境。这时打开"Run Configurations",就会发现Junit的测试里多了一种"RunLombokTest"...如下图所示:

实际上没有必要跑全部的junit测试,只要跑TestWithDelombok即可

lombok的单元测试是这样的:在test/transform/resource目录里,有三个文件夹,before,after-delombok和after-ejc,before中是所有测试用的java文件,而after-delombok目录中包含的则是lombok.jar参与编译后生成的java源文件,单元测试时,会将after-delombok中的文件作为expected value去同生成的代码做比较,如果一致就认为通过测试。因此单元测试时,在before目录中创建一个class,并为之加上自定义注解,同时在after-lombok中新建一个同名类,把预期的字段和方法写进去即可。after-ejc用于测试eclipse的java编译器结果。注:lombok在处理字段和方法时,会加上额外的标注注解。

至于Intellij,做调试相对就麻烦一点,需要打开一个intellij的新实例,新建一个项目,在这个项目中引入修改后的lombok,然后加上自定义的注解,这时会触发原来那个intellij中lombok的代码运行,此时断点就会被触发。

Intellij-lombok插件

自定义的注解已经完成,在javac时指定javaagent为新打包出来的lombok.jar即可,不过蛋疼的是,ide此时尚不能识别自定义的注解,为了能够让集成开发环境与新添加的自定义注解合作无间,还需要对Intellij的lombok插件做一番改造。

今天相关的代码见:https://git.oschina.net/hoyt/lombok.git,明天继续补完Intellij插件的工作。

最新文章

  1. 【C#】 异常处理
  2. [JAVA] 面向对象编程OOP Note
  3. FreeBSD Opera Flash问题
  4. oracle修改字段长度
  5. SQL SERVER 和ACCESS的数据导入导出
  6. Solr5.0配置中文分词包
  7. 6.Mybatis中的动态Sql和Sql片段(Mybatis的一个核心)
  8. 自动扫描FTP文件工具类 ScanFtp.java
  9. 深入浅出Java并发包—锁机制(三)
  10. SQL Server查询性能优化——覆盖索引(一)
  11. 贴片方式COB COF COG
  12. (sqlite3.OperationalError) no such table: users [SQL: &#39;SELECT users.id AS users_id, users.email AS users_email, users.username AS users_username, users.role_id AS users_role_id, users.password_hash A
  13. arcgis api 4.x for js 离线部署
  14. 【原创】大数据基础之Logstash(5)监控
  15. ECMA Script 6_解构赋值_模式匹配
  16. NetBus —— 让你的 App 内部随处感知网络的变化
  17. linux下objdump应用
  18. sed 收集
  19. 201621123075 Week02-Java基本语法与类库
  20. 2.Django|简介与静态文件| URL控制器

热门文章

  1. JQuery.validate 错误信息对话框
  2. 20.Mysql锁机制
  3. SqlServer添加触发器死锁的原因
  4. 引爆你的Javascript代码进化
  5. Xstream将XML转换为javabean的问题
  6. maven下载的jar相应pom文件下载不完整问题。
  7. 【Go】 Go 语言环境安装
  8. 【WebService】WebService基础知识(一)
  9. Java课堂测试01及感想
  10. 2019.01.14 bzoj2648: SJY摆棋子(kd-tree)