package org.hamcrest.generator;

import com.thoughtworks.qdox.model.DocletTag;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaMethod;
import com.thoughtworks.qdox.model.JavaParameter;
import com.thoughtworks.qdox.model.Type;

import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

Wraps an existing sequence of FactoryMethods, and attempts to pull in parameter names and JavaDoc (which aren't available using reflection) using QDox.
Author:Joe Walnes
See Also:
/** * Wraps an existing sequence of FactoryMethods, and attempts to pull in * parameter names and JavaDoc (which aren't available using reflection) using * QDox. * * @see <a href="http://qdox.codehaus.org/">QDox</a> * @author Joe Walnes */
public class QDoxFactoryReader implements Iterable<FactoryMethod> { private final Iterable<FactoryMethod> wrapped; private final JavaClass classSource; private static final Pattern GENERIC_REGEX = Pattern.compile("<.*>"); private static final Pattern VARARGS_REGEX = Pattern.compile("...", Pattern.LITERAL); public QDoxFactoryReader(Iterable<FactoryMethod> wrapped, QDox qdox, String className) { this.wrapped = wrapped; this.classSource = qdox.getClassByName(className); } @Override public Iterator<FactoryMethod> iterator() { final Iterator<FactoryMethod> iterator = wrapped.iterator(); return new Iterator<FactoryMethod>() { @Override public boolean hasNext() { return iterator.hasNext(); } @Override public FactoryMethod next() { return enhance(iterator.next()); } @Override public void remove() { iterator.remove(); } }; } private FactoryMethod enhance(FactoryMethod factoryMethod) { JavaMethod methodSource = findMethodInSource(factoryMethod); if (methodSource != null) { factoryMethod.setJavaDoc(createJavaDocComment(methodSource)); JavaParameter[] parametersFromSource = methodSource.getParameters(); List<FactoryMethod.Parameter> parametersFromReflection = factoryMethod.getParameters(); if (parametersFromReflection.size() == parametersFromSource.length) { for (int i = 0; i < parametersFromSource.length; i++) { parametersFromReflection.get(i).setName( parametersFromSource[i].getName()); } } } return factoryMethod; }
Attempts to locate the source code for a specific method, by cross-referencing the signature returned by reflection with the list of methods parsed by QDox.
/** * Attempts to locate the source code for a specific method, by cross-referencing * the signature returned by reflection with the list of methods parsed by QDox. */
private JavaMethod findMethodInSource(FactoryMethod factoryMethod) { // Note, this doesn't always work - it struggles with some kinds of generics. // This seems to cover most cases though. List<FactoryMethod.Parameter> params = factoryMethod.getParameters(); Type[] types = new Type[params.size()]; boolean varArgs = false; for (int i = 0; i < types.length; i++) { String type = params.get(i).getType(); varArgs = VARARGS_REGEX.matcher(type).find(); // QDox ignores varargs and generics, so we strip them out to help QDox. type = GENERIC_REGEX.matcher(type).replaceAll(""); type = VARARGS_REGEX.matcher(type).replaceAll(""); types[i] = new Type(type); } JavaMethod[] methods = classSource.getMethodsBySignature(factoryMethod.getName(), types, false, varArgs); return methods.length == 1 ? methods[0] : null; }
Reconstructs the JavaDoc as a string for a particular method.
/** * Reconstructs the JavaDoc as a string for a particular method. */
private static String createJavaDocComment(JavaMethod methodSource) { String comment = methodSource.getComment(); DocletTag[] tags = methodSource.getTags(); if ((comment == null || comment.trim().length() == 0) && tags.length == 0) { return null; } StringBuilder result = new StringBuilder(); result.append(comment); result.append("\n\n"); for (DocletTag tag : tags) { result.append('@').append(tag.getName()) .append(' ').append(tag.getValue()) .append('\n'); } return result.toString(); } }