The craftsman may be late, but he is never absent. Finally, he decided to share his cloud notes
The reason
You’ve probably used the Javadoc command or IDE wrapper command to generate Java API doc documents, but have you ever thought about how the Javadoc command parses file generation? Javadoc is actually just an executable in the JDK directory, but the executable is a wrapper based on the JDK’s Tools.jar, which means that javadoc is implemented in Tools.jar.
Many times we may have some bizarre requirements, such as obtaining Java document comments for processing. How do we parse Java files to obtain these comment information? You may have initially thought about using regular matching, but there are compatibility issues with this scheme. Or, you might consider using third-party libraries to parse Java source files, but many of these libraries are for The Java source, not the comments in the source code. So a great solution is to customize the Doclet and use Javadoc operations.
Program verification
Since this solution relies on Javadoc and Doclet, let’s take a look at the documentation for a technical evaluation. For details, see the Oracle documentation:
- javadoc doclet
- javadoc tools
We can find that, in fact, we only need to customize a Doclet class. As for how to define the Doclet class, the document has been written in detail, and the specific code fragment is given, we can directly move over for verification, the code is as follows:
public class CustomerDoclet extends Doclet {
public static boolean start(RootDoc root) {
ClassDoc[] classes = root.classes();
// Annotate the document information, you can parse the organization as you like, depending on your needs
return true; }}public static void main(String[] args) {
String[] docArgs =
new String[] {
"-doclet", CustomerDoclet.class.getName(), "/home/yan/test/cn/test/JavaSource.java"
};
com.sun.tools.javadoc.Main.execute(docArgs);
}
Copy the code
Simply run the above code snippet to customize the Javadoc output parsing. Run around and find it’s okay, so let’s get started.
Implement a Gradle plug-in for javadoc customization
For the sake of simplicity and simplicity, we are going to implement a plugin that checks whether the Android, androidLibrary, Java, and javaLibrary code source files contain Javadoc@author. Gradle-javadoc-checker. For details, see github.com/yanbober/gr… To obtain.
Note: This section requires you to be familiar with Gradle plugin development, so it is recommended that you read this section first.
Add the dependent
dependencies {
compile gradleApi()
compile 'com. Android. Tools. Build: gradle: 3.1.0'
/ / tools. The dependence on the jar
compile files(org.gradle.internal.jvm.Jvm.current().toolsJar)
}
Copy the code
Write a custom Javadoc judge @author tool
public class JavaDocReader {
private static RootDoc root;
// Customize the doclet
public static class CustomerDoclet {
public static boolean start(RootDoc root) {
JavaDocReader.root = root;
return true; }}// Javadoc encapsulation in tools.jar
public static RootDoc process(String[] extraArges) {
List<String> argsOrderList = new ArrayList<>();
argsOrderList.add("-doclet");
argsOrderList.add(CustomerDoclet.class.getName());
argsOrderList.addAll(Arrays.asList(extraArges));
String[] args = argsOrderList.toArray(new String[argsOrderList.size()]);
System.out.println(args);
Main.execute(args);
return root;
}
// Javadoc encapsulation in tools.jar
public static void process(List
sourcePaths, List
javapackages, List
excludePackages, String outputDir)
throws Exception {
String paths = list2formatString(sourcePaths, ";");
String includes = list2formatString(javapackages, ":");
String excludes = list2formatString(excludePackages, ":");
List<String> argsOrderList = new ArrayList<>();
argsOrderList.add("-doclet");
argsOrderList.add(CustomerDoclet.class.getName());
if(paths ! =null && paths.length() > 0) {
argsOrderList.add("-sourcepath");
argsOrderList.add(paths);
}
argsOrderList.add("-encoding");
argsOrderList.add("utf-8");
argsOrderList.add("-verbose");
if(includes ! =null && includes.length() > 0) {
argsOrderList.add("-subpackages");
argsOrderList.add(includes);
}
if(excludes ! =null && excludes.length() > 0) {
argsOrderList.add("-exclude");
argsOrderList.add(excludes);
}
String[] args = argsOrderList.toArray(new String[argsOrderList.size()]);
System.out.println(Arrays.toString(args));
// Run the javadoc command in tools.jar
Main.execute(args);
File file = new File(outputDir);
if(! file.exists()) { file.mkdirs(); } file =new File(file, new Date().toString() + ".txt");
FileOutputStream outputStream = new FileOutputStream(file);
// Determine if each top-level Java class has an @author writer, and write a file record if it does not
ClassDoc[] classes = root.classes();
if(classes ! =null) {
for (int i = 0; i < classes.length; ++i) {
if (classes[i].containingClass() == null && classes[i].isPublic()) {
Tag[] authorTags = classes[i].tags("author");
if (authorTags == null || authorTags.length == 0) {
String filename = classes[i].position().file().getAbsolutePath();
outputStream.write((filename+"\r\n").getBytes());
}
}
}
}
root = null;
outputStream.flush();
outputStream.close();
}
private static String list2formatString(List<String> srcs, String div) {
StringBuilder stringBuilder = new StringBuilder();
for (int index=0; index<srcs.size(); index++) {
if (index > 0) {
stringBuilder.append(div);
}
stringBuilder.append(srcs.get(index));
}
returnstringBuilder.toString(); }}Copy the code
With the Javadoc custom utility classes in place, you can write gradle custom Tasks.
Write a custom Gradle Task to check
/ / groovy
class JavaDocCheckerTask extends DefaultTask {
// Customize input for task
@Input
List<String> includePackages
@Input
List<String> excludePackages
@Input
List<String> sourcePaths
// Customize the output of the task
@OutputDirectory
String outputDir
// Customize the execution logic of the task
@TaskAction
void checker() {
if (sourcePaths == null || sourcePaths.size() == 0) {
throw new GradleScriptException("JavaDocCheckerTask sourcePaths params can't be null or empty!")}if (outputDir == null || outputDir.length() == 0) {
throw new GradleScriptException("JavaDocCheckerTask outputDir params can't be null or empty!")}//task Executes javadoc command operations based on output parameters
JavaDocReader.process(sourcePaths, includePackages, excludePackages, outputDir)
}
}
Copy the code
With a custom Gradle Task for Javadoc operations, it’s time to plug in the plug-in.
Add custom tasks to the build project
Define the extension parameters for the plug-in:
class CheckerExtension {
public static final String NAME = "javadocChecker"
List<String> includePackages
List<String> excludePackages
List<String> sourcePaths
String outputDirectory
}
Copy the code
Combine extended parameters with task:
class JavaDocCheckerPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
// Add a custom extension
project.extensions.create(CheckerExtension.NAME, CheckerExtension)
// Add custom tasks to project
project.tasks.create("javaDocChecker", JavaDocCheckerTask)
// Apply to Java, AndroidLibrary and AndroidApplication
JavaPluginConvention java = null
BaseExtension android = null
if (project.plugins.hasPlugin(AppPlugin)) {
android = project.extensions.getByType(AppExtension)
} else if(project.plugins.hasPlugin(LibraryPlugin)) {
android = project.extensions.getByType(LibraryExtension)
} else if (project.plugins.hasPlugin(JavaPlugin)) {
java = project.convention.getPlugin(JavaPluginConvention)
}
if (java == null && android == null) {
throw new GradleException("it's a not support plugin type!")
}
project.afterEvaluate {
afterEvaluateInner(project, java, android)
}
}
private void afterEvaluateInner(Project project, JavaPluginConvention java, BaseExtension android) {
if(java ! =null) {
// The Java plug-in does the Java sourceSets processing
processJava(project, java)
} else if(android ! =null) {
// The Android plugin does the Android sourceSets processing
processAndroid(project, android)
}
}
private void processJava(Project project, JavaPluginConvention java) {
List<String> sources = new ArrayList<>()
// Get the SRC of Java sourceSets mainSourceSet mainSourceSet = java.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) mainSourceSet.allJava.srcDirs.each { sources.add(it.absolutePath) } assignedTask(project, sources) }private void processAndroid(Project project, BaseExtension android) {
List<String> sources = new ArrayList<>()
// Check the android sourceSets main SRC
AndroidSourceSet mainSourceSet = android.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME)
mainSourceSet.java.srcDirs.each {
sources.add(it.absolutePath)
}
assignedTask(project, sources)
}
// Assign the custom attributes of the plug-in extension to the input and output of the custom task
private void assignedTask(Project project, List<String> sources) {
def checker = project[CheckerExtension.NAME]
if (checker == null) {
return
}
project.getTasksByName("javaDocChecker".false).each {
it.configure {
includePackages = checker.includePackages == null ? [] : checker.includePackages
excludePackages = checker.excludePackages == null ? [] : checker.excludePackages
sourcePaths = sources
outputDir = checker.outputDirectory
}
}
}
}
Copy the code
The core body of this plug-in is developed and ready to use. This is a complete small project to solve practical problems through custom Javadoc output. You can access the project source code for research or customize your own operations. The full plugin source can be found at github.com/yanbober/gr… To obtain.
conclusion
This article gives an implementation idea, you can find that Doclet is simply a giant, for the Java Doc document operation only you can think of, nothing he can not do. I hope it inspires you.
Artisans if the water without permission is strictly prohibited to be reproduced, please respect the author’s work.