`
Mysun
  • 浏览: 273567 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Sun的apt工具及Mirrors包学习

阅读更多
  最近看来一些有关Java Annotation的东西,主要是翻了一下Thinking in Java这本书。算是对Java的Annotation有了一个大致的了解。在看Thinking in Java的时候,书里面有一段代码,专门介绍如何利用Java 1.5之后自带的apt(Annotation Processing Tool)工具来处理Annotation的。代码如下:
//: annotations/database/TableCreationProcessorFactory.java 
// The database example using Visitor. 
// {Exec: apt -factory 
// annotations.database.TableCreationProcessorFactory 
// database/Member.java -s database} 
package annotations.database; 
import com.sun.mirror.apt.*; 
import com.sun.mirror.declaration.*; 
import com.sun.mirror.util.*; 
import java.util.*; 
import static com.sun.mirror.util.DeclarationVisitors.*; 
 
public class TableCreationProcessorFactory 
  implements AnnotationProcessorFactory { 
  public AnnotationProcessor getProcessorFor( 
    Set<AnnotationTypeDeclaration> atds, 
    AnnotationProcessorEnvironment env) { 
    return new TableCreationProcessor(env); 
  } 
  public Collection<String> supportedAnnotationTypes() { 
    return Arrays.asList( 
      "annotations.database.DBTable", 
      "annotations.database.Constraints", 
      "annotations.database.SQLString", 
      "annotations.database.SQLInteger"); 
  } 
  public Collection<String> supportedOptions() { 
    return Collections.emptySet(); 
  } 
  private static class TableCreationProcessor 
    implements AnnotationProcessor { 
    private final AnnotationProcessorEnvironment env; 
    private String sql = ""; 
    public TableCreationProcessor( 
      AnnotationProcessorEnvironment env) { 
      this.env = env; 
    } 
    public void process() { 
      for(TypeDeclaration typeDecl : 
        env.getSpecifiedTypeDeclarations()) { 
        typeDecl.accept(getDeclarationScanner( 
          new TableCreationVisitor(), NO_OP)); 
        sql = sql.substring(0, sql.length() - 1) + ");"; 
        System.out.println("creation SQL is :\n" + sql); 
        sql = ""; 
      } 
    } 
    private class TableCreationVisitor 
      extends SimpleDeclarationVisitor { 
      public void visitClassDeclaration( 
        ClassDeclaration d) { 
        DBTable dbTable = d.getAnnotation(DBTable.class);
        if(dbTable != null) { 
          sql += "CREATE TABLE "; 
          sql += (dbTable.name().length() < 1) 
            ? d.getSimpleName().toUpperCase() 
            : dbTable.name(); 
          sql += " ("; 
        } 
      } 
      public void visitFieldDeclaration( 
        FieldDeclaration d) { 
        String columnName = ""; 
        if(d.getAnnotation(SQLInteger.class) != null) { 
          SQLInteger sInt = d.getAnnotation( 
              SQLInteger.class); 
          // Use field name if name not specified 
          if(sInt.name().length() < 1) 
            columnName = d.getSimpleName().toUpperCase(); 
          else 
            columnName = sInt.name(); 
          sql += "\n    " + columnName + " INT" + 
            getConstraints(sInt.constraints()) + ","; 
        } 
        if(d.getAnnotation(SQLString.class) != null) { 
          SQLString sString = d.getAnnotation( 
              SQLString.class); 
          // Use field name if name not specified. 
          if(sString.name().length() < 1) 
            columnName = d.getSimpleName().toUpperCase(); 
          else 
            columnName = sString.name(); 
          sql += "\n    " + columnName + " VARCHAR(" + 
            sString.value() + ")" + 
            getConstraints(sString.constraints()) + ","; 
        } 
      } 
      private String getConstraints(Constraints con) { 
        String constraints = ""; 
        if(!con.allowNull()) 
          constraints += " NOT NULL"; 
        if(con.primaryKey()) 
          constraints += " PRIMARY KEY"; 
        if(con.unique()) 
          constraints += " UNIQUE"; 
        return constraints; 
      } 
    } 
  } 
} ///:~ 

  这段代码做的事情是利用Java mirrors包提供的Visitor模式来处理Java源代码中的Annotation,然后生成一个创建数据库表的SQL语句。至于那些个Annotation怎么定义的大家参看Thinking in Java第四版的相关章节,这里不再累述了。
  在这里我要将的主要有两个方面,一个是关于apt的,一个是关于上面代码中的Visitor模式的。
   一,关于apt
   apt是Sun从JDK 1.5(包括1.5)之后开始提供的处理源代码级别Annotation的工具,主要目标是根据源代码生成新的代码或者其他的一些文件,例如对象关系映射文件等。apt在处理源代码中的Annotation的时候,会调用特定的AnnotationProcessor,这些AnnotationProcessor是需要开发人员去实现的,一个Processor可以对应一个自定义的Annotation或者多个自定义的Annotation。
   但是apt不是直接调用AnnotationProcessor的,而是要通过AnnotationProcessorFactory来获得处理具体Annotation的。而AnnotationProcessorFactory是一个接口,所以为了使用apt,我们除了要实现AnnotationProcessor之外,还要实现AnnotationProcessorFactory。具体的方法见Thinking in Java第四版。
   apt的实现是在com.sun.tools.apt及其子包中,这个包实现了com.sun.mirror及其相关子包中的接口,用来处理源代码级别的Annotation。mirror包是Sun提供的专门用来获取源代码中的类型信息的工具包,而reflect包则是用来获取运行时类型信息的工具包。Sun建议在处理Java代码文件时,使用mirror包。
   为了降低处理源码中Annotation的代码复杂度,mirror中的关于类型的所有接口(xxxDeclaration)实现了Visitor模式,每个Declaration接口的子类都有一个accept方法,用来接收一个DeclarationVisitor接口的实现类,并调用该接口中的相应方法。具体可以参看Sun的相关API文档。
   我通过上面的代码看了一下mirror包里面相关类的源代码,从源代码以及上面代码的写法来看,apt是在扫描了全部的Java源文件之后,才去调用Processor的。也就是说AnnotationProcessorFactory接口的getProcessorFor方法是在apt分析了所有的源代码之后才被调用的,之后apt就会调用getProcessorFor方法返回的AnnotationProcessor接口实现类的process()方法,来处理Annotation。apt在扫描源代码的时候会将相关的Annotation信息保存在AnnotationProcessorEnvironment对象中,这样在AnnotationProcessor中就可以拿到所有Annotation信息了。至于那些Annotation的信息会被保存下来,这是在AnnotationProcessorFactory接口的supportedAnnotationTypes()方法中规定的。
   关于apt大概就是这些了。
   二,关于Visitor模式
   在Sun的com.sun.mirror.declaration包里面定义了很多的Declaration接口,用来对应源代码中的不同层次的元素,包括类型,构造函数,成员变量,方法参数等等。但是在mirror包里面没有提供实现类。具体的实现类是在com.sun.tools.apt.mirror.declaration包里面定义的。因为apt工具需要使用这些信息。
   在每个Declaration中都有个accept方法,该方法接收一个DeclarationVisitor接口的实现类,并调用DeclarationVisitor接口的实现类相应方法。在DeclarationVisitor定义了正对不同Declaration接口的方法,具体可以参看Sun的相关API文档。
   在最开始的代码里面,TableCreationProcessor的process方法是这样写的:
  
   public void process() { 
      for(TypeDeclaration typeDecl : 
        env.getSpecifiedTypeDeclarations()) { 
        typeDecl.accept(getDeclarationScanner( 
          new TableCreationVisitor(), NO_OP)); 
        sql = sql.substring(0, sql.length() - 1) + ");"; 
        System.out.println("creation SQL is :\n" + sql); 
        sql = ""; 
      }
   }
   

   其中的for循环遍历所有的TypeDeclaration,并调用每个TypeDeclaration的accept方法。在调用accept方法的时候并不是直接初始化一个DeclarationVisitor接口的实现类,而是调用的com.sun.mirror.util.DeclarationVisitors静态类的getDeclarationScanner静态方法。这个方法的作用看一下API的说明就知道了,是用来包装DeclarationVisitor的。官方的说明如下:
  
引用

   Return a DeclarationVisitor that will scan the declaration structure, visiting declarations contained in another declaration. For example, when visiting a class, the fields, methods, constructors, etc. of the class are also visited. The order in which the contained declarations are scanned is not specified.

The pre and post DeclarationVisitor parameters specify, respectively, the processing the scanner will do before or after visiting the contained declarations. If only one of pre and post processing is needed, use DeclarationVisitors.NO_OP for the other parameter.
  

   大概意思就是这个方法包装出来的DeclarationScanner类实现了DeclarationVisitor接口,同时在Visit一个Declaration的时候,会同时Visit这个Declaration下的所有子Declaration,比如在Visit一个ClassDeclaration的时候,就会同时Visit这个Class中的TypeParameterDeclaration,FieldDeclaration,MethodDeclaration,TypeDeclaration(因为Type可能会有嵌套),ConstructorDeclaration等。
   这样的话就节省了开发人员的代码量了,要不然我们自己还是要写同样的代码去处理这些个东西,而且还容易出错。

   要写的主要问题大概就这么一些,其他的感觉都是比较好理解的,看下书应该就知道了。
分享到:
评论
1 楼 xjw1987524 2011-03-16  
想问下你怎么调用呢,我也看到这里,不过很是郁闷啊,不知道怎么运行它,命令行编译也没有main函数啊。。。

相关推荐

    搭建APT代理服务器.pdf

    ### 搭建APT代理服务器知识点详解 #### 一、APT代理服务器概述 APT代理服务器是一种专门为局域网内多台Ubuntu Linux系统提供软件包安装与更新服务的解决方案。通过集中下载并缓存软件包,它能显著提高局域网内...

    openstack工具MirantisOpenStack-9.0 mirrors bootstraps VirtualBox等

    openstack工具,fuel一键安装镜像光盘MirantisOpenStack-9.0 上传本地源mirrors bootstraps 虚拟机VirtualBox等

    mirrors-Nacos-master.zip

    Nacos 是一个由阿里巴巴开源的、轻量级的分布式服务治理和配置中心,它主要服务于微服务架构,提供服务发现、配置管理、健康检查等...通过学习和研究这些源码,你可以更好地理解和利用 Nacos,提升你的微服务治理能力。

    Ubuntu18.04sudoaptupdate无法解析域名的解决方案.docx

    Ubuntu18.04sudoaptupdate无法解析域名的解决方案.docx

    maven-阿里云-mirrors.txt.zip

    Maven是Java开发中的一款项目管理和集成工具,它简化了构建、依赖管理以及项目的生命周期过程。在Maven中,`mirrors`配置是一个重要的部分,它关乎到Maven如何高效地下载依赖。`maven-阿里云-mirrors.txt.zip`这个...

    ubuntu deb包及依赖库下载地址打包2011年

    在 Ubuntu 中,`dpkg` 工具用于处理这些包,包括安装、删除和验证等操作。 #### 依赖管理 当安装一个软件包时,可能需要其他软件包的支持,这些被称作依赖包。依赖关系确保了软件包能够正常运行。例如,一个应用...

    apt-smart:apt-smart:为Debian,Ubuntu和Linux Mint提供智能,自动化,健壮的apt-get镜像选择

    `apt-get` 是 Advanced Package Tool(高级包工具)的一部分,用于管理和升级 Linux 系统中的软件包。它允许用户安装、升级、卸载和搜索软件包。然而,`apt-get` 默认依赖于配置文件中设定的软件源,这些源可能位于...

    docker-apt-mirror:使用 Nginx 提供 apt 镜像

    如果您想使用自己的 mirrors.list 文件,请通过将 /etc/apt/mirror.list 挂载为主机卷来覆盖默认值。 nginx 设置为在尽可能少的干扰下通过端口 80 炸掉整个 apt 镜像。 再一次,通过将 /etc/nginx/sites-enabled/...

    ros源,sudo apt-get update ,ubtunt源,详细实测,有用更新方法

    对于基于Debian的发行版,如Ubuntu,通常会使用`apt`命令来进行软件包的安装、更新等操作。本文将详细介绍如何配置Ubuntu系统的软件和更新选项,以及如何正确地设置ROS源,以确保能够顺利地获取最新的ROS相关软件包...

    Linux包管理速查表

    APT是Debian及其衍生版(如Ubuntu)中的包管理工具。它提供了强大而灵活的功能,用于安装、更新和删除软件包。 - **安装包**:`apt-get install &lt;pkg&gt;` - **移除包**:`apt-get remove &lt;pkg&gt;` - **更新包列表**:`...

    Ethreal抓包工具简介

    【Ethereal抓包工具简介】 Ethereal是一款强大的网络封包分析软件,广泛应用于网络故障排查、网络安全分析和性能优化。它能够捕获并显示网络上的数据包,帮助用户理解网络通信过程,深入分析网络流量。 **Ethereal...

    python-apt-mirror-updater:用于Debian和Ubuntu的自动,健壮的apt-get镜像选择

    在 Debian 和 Ubuntu 的包管理中,`apt` 和 `apt-get` 是两个紧密相关的命令行工具。`apt` 提供了一个更高级、用户友好的接口,而 `apt-get` 是其底层工作引擎,执行实际的包安装、升级和管理任务。因此,优化 `apt-...

    树莓派换源,附:国内源地址

    sudo nano /etc/apt/sources.list deb http://mirrors.ustc.edu.cn/raspbian/raspbian/ buster main contrib non-free rpi 2.更改系统更新源 sudo nano /etc/apt/sources.list.d/raspi.list deb ...

    mirrors-YApi-master.zip

    "mirrors-YApi-master.zip"这个压缩包文件,正是YApi的一个版本,虽然它提示仅供学习使用,但我们仍能从中获取丰富的知识。 YApi是由HappyDigger团队开发的,它的设计目标是提供一个高效率、易用的API管理平台,...

    ubuntu18.04换源 - 更换清华源

    在Ubuntu 18.04操作系统中,"换源"是指更换系统软件包的下载源,目的是为了提高软件更新和安装的速度以及稳定性。通常,Ubuntu官方的软件源可能因为地理位置和网络条件的原因,在某些地区访问速度较慢。在这种情况下...

    mirrors-fzf-master_java_

    标题中的"mirrors-fzf-master_java_"表明这是一个与fzf工具相关的项目,可能是该工具的一个镜像或特定版本,特别是针对Java平台优化的。fzf是"Fast Filter"的缩写,是一个广受欢迎的开源命令行工具,由Junegunn Choi...

    mirrors-opencv_contrib-4.5.0.zip

    OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉库,被广泛应用于图像处理、机器学习和深度学习领域。它提供了丰富的函数和模块,使得开发者能够轻松地进行图像分析和处理任务。在OpenCV的...

    Debian,Ubuntu,opensuse,Fedora,Arch等发行版包管理命令速查表

    - 移除包:`apt-get remove` - 更新包列表:`apt-get update` - 更新系统:`apt-get upgrade` - 列出源:`cat /etc/apt/sources.list` - 添加源:编辑`/etc/apt/sources.list` - 移除源:编辑`/etc/apt/...

    mirrors-x64dbg-master.zip

    对于想要学习Android结构的初学者来说,x64dbg虽然不是直接针对Android的调试工具,但其强大的反汇编和内存分析能力也可以在一定程度上帮助理解Android应用的运行机制。通过调试Dalvik VM或ART(Android RunTime)的...

Global site tag (gtag.js) - Google Analytics