【qdox】Java 代码解析利器 QDox
前言
最近在写 maven 插件,涉及到了 java 代码解析这块内容。需要解析 java 源码,然后对于类中的不同部分进行处理。发现手写还是很难的,找了一圈发现了两个不错的工具可以使用,一个是 javaparser,另一个是 qdox 。个人感觉 javaparser 强大一些,更新与维护也比较勤,但是相对来说上手难一点,从他的使用文档独立成书在买,可见一斑,而 qdox 比较小巧,上手很快,功能也满足大部分需求,最终还是选择了 qdox。
什么是 QDox
官方的介绍是:
QDox - full extractor of Java class/interface/method definitions (including annotations, parameters, param names)
大概意思是一款完整的 java 类、接口、方法定义的提取器,包括了注释、参数及参数名称。其实核心功能就是我输入一个 java 类的源码,他可以把这个 java 类解析成一个对象,我们通过这个对象可以获取很方便的获取解析的类的不同组成,比如我可以获得这个类有哪些方法,这个方法的参数是什么,返回值又是什么,他们的类型又分别是什么?还有这个方法上有哪些注释、哪些 tag。也能获取类中有哪些的 field。。。总之把这个类庖丁解牛般解析好,使得调用者很方便的获取到自己感兴趣的信息。
为什么使用 QDox
除了上面说的 QDox 上手比较快外,他的运行速度及占用空间都十分优秀。
另外不得不说的是这个项目可以说是一个上古时期的项目了,看了 github 上的提交记录,最早的一条提交记录是 2002 年的时候,因为这个项目之前使用的是 svn,所以具体时间可能更早。一个开源项目维护了快 20 年也是一件挺令人钦佩的事。不过到目前为止,这个项目在 github 上只有 151 个 star,如果这个项目对你有所帮助,希望大家可以给作者一个 star。github 上有太多类似的项目默默无闻的出现,又默默无闻的消逝。
扯远了,虽然项目关注的人比较少,但是使用它的项目还是比较多的。maven 的官方 javadoc 插件 maven-javadoc-plugin 就是使用它来解析代码中的 doc tags 的。所以可能你没有直接使用它,但是它其中已经在你本地的 maven 仓库内躺着了。有官方背书,对于它的使用就比较放心了。
什么情况下适合使用 QDox
这个就比较多了,通常只要我们需要解析源码的内容就可以使用,比如我想获得指定类文件中的全部方法。就可以使用。可能有些人感到不解了,为什么不通过反射拿到这些内容,这样不是更方便吗?首先,反射的前提是你能拿到这个类的实例,或者你项目中就有这个类。即使这些条件都满足,但是一个很常见的需求反射没法满足,比如说拿到方法的注释及 tags 等,这类在编译时就被抹除了。这种情况就不得不用源码解析的方法了。
另外它不只是能解析,他同时可以生成 java 类文件,所以你可以动态的生成一些 java 类。
无论是解析还是生成,在写插件的时候肯定需要会有这样的场景,比如我想通过代码里的 javadoc 这些 tags 生成一个接口文档给前端,这样就不用我一个一个手写了。再比如我想通过数据表的信息,自动生成 model 类,service 类。。。使用场景的限制主要是个人的想象力。
如何使用 QDox
创建 java 项目 builder 对象
// 创建 java 项目 builder 对象
JavaProjectBuilder javaProjectBuilder = new JavaProjectBuilder();
添加 java 源文件
// 添加 java 源文件
javaProjectBuilder.addSource(new File("/Users/kiwi/study/code/study-example/study-qdox-example/src/main/java/cn/coder4j/study/example/qdox/Demo.java"));
demo 示例是通过文件添加的,其实支持很多种类型,比如 URL、Reader 甚至直接添加一个目录,框架会自己扫描目录下的所有 java 文件
获得解析后的 JavaClass 对象
经过上面两步,准备工作就已经结束了,可以直接获得解析后的 JavaClass 对象了,有两种方式获取,一种是直接获得解析后的类集合,为什么是集合呢?因为上面也说了是可以添加目录的,而且 addSource 可以多次调用,添加多个文件。另一种是在知道类名称的情况下直接使用 getClassByName 获得
// 获得解析后的类
Collection<JavaClass> classes = javaProjectBuilder.getClasses();
for (JavaClass javaClass : classes) {
}
JavaClass 接口定义
package com.thoughtworks.qdox.model;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.util.List;
import com.thoughtworks.qdox.library.ClassLibrary;
/**
* Equivalent of {@link java.lang.Class}, providing the most important methods.
* Where the original Class is using an Array, this model is using a List.
*
* @author Robert Scholte
*/
public interface JavaClass extends JavaModel, JavaType, JavaAnnotat