Skip to content

Instantly share code, notes, and snippets.

@benjchristensen
Created November 30, 2011 20:29
Show Gist options
  • Save benjchristensen/1410681 to your computer and use it in GitHub Desktop.
Save benjchristensen/1410681 to your computer and use it in GitHub Desktop.
Doclet for filtering public classes from Javadoc
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;
/**
* Used to decide what gets included/excluded in the Javadoc
* <p>
* <li>It filters out all inner classes with "UnitTest" in their name.</li>
* <li>It filters out classes with @ExcludeFromJavadoc in the javadoc comment</li>
*/
public class JavadocFilter {
public static void main(String[] args) {
String name = JavadocFilter.class.getName();
Main.execute(name, name, args);
}
public static boolean validOptions(String[][] options, DocErrorReporter reporter) throws java.io.IOException {
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) throws java.io.IOException {
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("@ExcludeFromJavadoc").length > 0) {
return true;
} else if (doc instanceof ProgramElementDoc) {
if (((ProgramElementDoc) doc).containingPackage().tags("@ExcludeFromJavadoc").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();
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;
}
}
}
@benjchristensen
Copy link
Author

@benjchristensen
Copy link
Author

Pass the path to this class into the javadoc tool:

In an ant task it is like this:
doclet="com.netflix.api.endpoint.ServiceLayerJavadoclet"

Using javadoc from command line it is this argument:
-doclet Generate output via alternate doclet

@deeTEEcee
Copy link

thanks, this is super helpful. Using JDK 1.8, I was using doclava for this but they fail to provide 3rd party links which I wanted. Also tried out ydoc but it's broken.

@deeTEEcee
Copy link

fyi, this breaks with annotation files.

@bishtjagmohan
Copy link

Do we still need something like this in JDK11 or jdk11 has inbuilt APIs for similar feature?

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