Skip to content

Instantly share code, notes, and snippets.

@deeTEEcee
Created February 10, 2020 03:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save deeTEEcee/e01e915665adef484ec9388d36d37b47 to your computer and use it in GitHub Desktop.
Save deeTEEcee/e01e915665adef484ec9388d36d37b47 to your computer and use it in GitHub Desktop.
Doclet for filtering public classes from JavaDoc
package com.sightmachine.doclet;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import com.sun.javadoc.Doc;
import com.sun.javadoc.DocErrorReporter;
import com.sun.javadoc.ProgramElementDoc;
import com.sun.javadoc.RootDoc;
import com.sun.tools.doclets.standard.Standard;
import com.sun.tools.javadoc.Main;
import com.sun.javadoc.Doclet;
import com.sun.javadoc.LanguageVersion;
/**
To debug, run the doclet directly on the main method. That method is not used when
javadocs is run.
CustomDoclet builds on top of the standard doclet interface (com.sun.javadoc.Doclet) which requires
implementing a few methods. The actual standard doclet was copied from example code and is hacky to say the least.
New features:
*"@hide" which can be applied directly in the code to classes, interfaces, methods, and class members.
**/
public class CustomDoclet extends Doclet {
public static boolean validOptions(String[][] options, DocErrorReporter reporter) {
return Standard.validOptions(options, reporter);
}
public static LanguageVersion languageVersion() {
return LanguageVersion.JAVA_1_5;
}
public static int optionLength(String option) {
return Standard.optionLength(option);
}
public static boolean start(RootDoc root) {
return Standard.start((RootDoc) process(root, RootDoc.class));
}
private static boolean exclude(Doc doc) {
if (doc.name().contains("UnitTest")) {
return true;
} else if (doc.tags("@hide").length > 0) {
return true;
} else if (doc instanceof ProgramElementDoc) {
if (((ProgramElementDoc) doc).containingPackage().tags("@hide").length > 0)
return true;
}
// nothing above found a reason to exclude
return false;
}
private static Object process(Object obj, Class expect) {
if (obj == null)
return null;
Class cls = obj.getClass();
if (cls.getName().startsWith("com.sun.")) {
return Proxy
.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), new ExcludeHandler(obj));
} else if (obj instanceof Object[]) {
Class componentType = expect.getComponentType();
if (componentType == null) { // Without this, processing the annotation in 'FieldName.java' breaks.
return null;
}
Object[] array = (Object[]) obj;
List list = new ArrayList(array.length);
for (int i = 0; i < array.length; i++) {
Object entry = array[i];
if ((entry instanceof Doc) && exclude((Doc) entry))
continue;
list.add(process(entry, componentType));
}
return list.toArray((Object[]) Array.newInstance(componentType, list.size()));
} else {
return obj;
}
}
private static class ExcludeHandler implements InvocationHandler {
private Object target;
public ExcludeHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (args != null) {
String methodName = method.getName();
if (methodName.equals("compareTo") || methodName.equals("equals") || methodName
.equals("overrides") || methodName.equals("subclassOf")) {
args[0] = unwrap(args[0]);
}
}
try {
return process(method.invoke(target, args), method.getReturnType());
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
private Object unwrap(Object proxy) {
if (proxy instanceof Proxy)
return ((ExcludeHandler) Proxy.getInvocationHandler(proxy)).target;
return proxy;
}
}
public static void main(String[] args) {
// Use this for testing and debugging the doclet. Add all arguments as java program arguments.
String name = CustomDoclet.class.getName();
Main.execute(name, name, args);
}
}
@deeTEEcee
Copy link
Author

deeTEEcee commented Feb 10, 2020

Originally copied from: https://gist.github.com/benjchristensen/1410681 . Compared to the original source, I made some small modifications to fix things that were broken (e.g: some classes with annotations would break)

Hopefully, this helps anyone who needs javadocs to add this feature and are constrained for any reason.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment