zoukankan      html  css  js  c++  java
  • Lombok自定义annotation扩展含Intellij插件

    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"...如下图所示:

    Lombok自定义annotation扩展含Intellij插件

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

    Lombok自定义annotation扩展含Intellij插件

    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在处理字段和方法时,会加上额外的标注注解。

    Lombok自定义annotation扩展含Intellij插件

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

    Intellij-lombok插件

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

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

  • 相关阅读:
    谷歌、火狐浏览器下实现JS跨域iframe高度自适应的完美解决方法,跨域调用JS不再是难题!
    23种设计模式大全(适合新手阅读)
    职责链模式-设计模式系列
    策略模式-设计模式系列
    状态模式-设计模式系列
    解释器模式-设计模式系列
    备忘录模式
    中介者模式
    SQL-Server collation, what is it and how to change db/column collation
    [SimHash] the Hash-based Similarity Detection Algorithm
  • 原文地址:https://www.cnblogs.com/zhaoxinshanwei/p/8430990.html
Copyright © 2011-2022 走看看