All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.thoughtworks.qdox.JavaDocBuilder Maven / Gradle / Ivy

The newest version!
package com.thoughtworks.qdox;

import com.thoughtworks.qdox.directorywalker.DirectoryScanner;
import com.thoughtworks.qdox.directorywalker.FileVisitor;
import com.thoughtworks.qdox.directorywalker.SuffixFilter;
import com.thoughtworks.qdox.model.ClassLibrary;
import com.thoughtworks.qdox.model.DefaultDocletTagFactory;
import com.thoughtworks.qdox.model.DocletTagFactory;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaClassCache;
import com.thoughtworks.qdox.model.JavaSource;
import com.thoughtworks.qdox.model.ModelBuilder;
import com.thoughtworks.qdox.parser.Lexer;
import com.thoughtworks.qdox.parser.ParseException;
import com.thoughtworks.qdox.parser.impl.JFlexLexer;
import com.thoughtworks.qdox.parser.impl.Parser;
import com.thoughtworks.qdox.parser.structs.ClassDef;
import com.thoughtworks.qdox.parser.structs.FieldDef;
import com.thoughtworks.qdox.parser.structs.MethodDef;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Reader;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

/**
 * Simple facade to QDox allowing a source tree to be parsed and the resulting object model navigated.
 *
 * 

Example

*

 * // -- Create JavaDocBuilder
 *
 * JavaDocBuilder builder = new JavaDocBuilder();
 *
 * // -- Add some files
 *
 * // Reading a single source file.
 * builder.addSource(new FileReader("MyFile.java"));
 *
 * // Reading from another kind of input stream.
 * builder.addSource(new StringReader("package test; public class Hello {}"));
 *
 * // Adding all .java files in a source tree (recursively).
 * builder.addSourceTree(new File("mysrcdir"));
 *
 * // -- Retrieve source files
 *
 * JavaSource[] source = builder.getSources();
 *
 * 
* * @author Joe Walnes * @author Aslak Hellesøy */ public class JavaDocBuilder implements Serializable, JavaClassCache { private Map classes = new HashMap(); private ClassLibrary classLibrary; private List sources = new ArrayList(); private DocletTagFactory docletTagFactory; private String encoding = System.getProperty("file.encoding"); private boolean debugLexer; private boolean debugParser; public JavaDocBuilder() { this(new DefaultDocletTagFactory()); } public JavaDocBuilder(DocletTagFactory docletTagFactory) { this.docletTagFactory = docletTagFactory; classLibrary = new ClassLibrary(this); classLibrary.addDefaultLoader(); } private void addClasses(JavaSource source) { Set resultSet = new HashSet(); addClassesRecursive(source, resultSet); JavaClass[] javaClasses = (JavaClass[]) resultSet.toArray(new JavaClass[resultSet.size()]); for (int classIndex = 0; classIndex < javaClasses.length; classIndex++) { JavaClass cls = javaClasses[classIndex]; addClass(cls); } } private void addClass(JavaClass cls) { classes.put(cls.getFullyQualifiedName(), cls); cls.setJavaClassCache(this); } public JavaClass getClassByName(String name) { if (name == null) { return null; } JavaClass result = (JavaClass) classes.get(name); if (result == null) { // Try to make a binary class out of it result = createBinaryClass(name); if (result != null) { addClass(result); } else { result = createUnknownClass(name); } } return result; } private JavaClass createUnknownClass(String name) { ModelBuilder unknownBuilder = new ModelBuilder(classLibrary, docletTagFactory); ClassDef classDef = new ClassDef(); classDef.name = name; unknownBuilder.beginClass(classDef); unknownBuilder.endClass(); JavaSource unknownSource = unknownBuilder.getSource(); JavaClass result = unknownSource.getClasses()[0]; return result; } private JavaClass createBinaryClass(String name) { // First see if the class exists at all. Class clazz = classLibrary.getClass(name); if (clazz == null) { return null; } else { // Create a new builder and mimic the behaviour of the parser. // We're getting all the information we need via reflection instead. ModelBuilder binaryBuilder = new ModelBuilder(classLibrary, docletTagFactory); // Set the package name and class name String packageName = getPackageName(name); binaryBuilder.addPackage(packageName); ClassDef classDef = new ClassDef(); classDef.name = getClassName(name); // Set the extended class and interfaces. Class[] interfaces = clazz.getInterfaces(); if (clazz.isInterface()) { // It's an interface classDef.type = ClassDef.INTERFACE; for (int i = 0; i < interfaces.length; i++) { Class anInterface = interfaces[i]; classDef.extendz.add(anInterface.getName()); } } else { // It's a class for (int i = 0; i < interfaces.length; i++) { Class anInterface = interfaces[i]; classDef.implementz.add(anInterface.getName()); } Class superclass = clazz.getSuperclass(); if (superclass != null) { classDef.extendz.add(superclass.getName()); } } addModifiers(classDef.modifiers, clazz.getModifiers()); binaryBuilder.beginClass(classDef); // add the constructors Constructor[] constructors = clazz.getConstructors(); for (int i = 0; i < constructors.length; i++) { addMethodOrConstructor(constructors[i], binaryBuilder); } // add the methods Method[] methods = clazz.getMethods(); for (int i = 0; i < methods.length; i++) { // Ignore methods defined in superclasses if (methods[i].getDeclaringClass() == clazz) { addMethodOrConstructor(methods[i], binaryBuilder); } } Field[] fields = clazz.getFields(); for (int i = 0; i < fields.length; i++) { if (fields[i].getDeclaringClass() == clazz) { addField(fields[i], binaryBuilder); } } binaryBuilder.endClass(); JavaSource binarySource = binaryBuilder.getSource(); // There is always only one class in a "binary" source. JavaClass result = binarySource.getClasses()[0]; return result; } } private void addModifiers(Set set, int modifier) { String modifierString = Modifier.toString(modifier); for (StringTokenizer stringTokenizer = new StringTokenizer(modifierString); stringTokenizer.hasMoreTokens();) { set.add(stringTokenizer.nextToken()); } } private void addField(Field field, ModelBuilder binaryBuilder) { FieldDef fieldDef = new FieldDef(); Class fieldType = field.getType(); fieldDef.name = field.getName(); fieldDef.type = getTypeName(fieldType); fieldDef.dimensions = getDimension(fieldType); binaryBuilder.addField(fieldDef); } private void addMethodOrConstructor(Member member, ModelBuilder binaryBuilder) { MethodDef methodDef = new MethodDef(); // The name of constructors are qualified. Need to strip it. // This will work for regular methods too, since -1 + 1 = 0 int lastDot = member.getName().lastIndexOf('.'); methodDef.name = member.getName().substring(lastDot + 1); addModifiers(methodDef.modifiers, member.getModifiers()); Class[] exceptions; Class[] parameterTypes; if (member instanceof Method) { methodDef.constructor = false; // For some stupid reason, these methods are not defined in Member, // but in both Method and Construcotr. exceptions = ((Method) member).getExceptionTypes(); parameterTypes = ((Method) member).getParameterTypes(); Class returnType = ((Method) member).getReturnType(); methodDef.returns = getTypeName(returnType); methodDef.dimensions = getDimension(returnType); } else { methodDef.constructor = true; exceptions = ((Constructor) member).getExceptionTypes(); parameterTypes = ((Constructor) member).getParameterTypes(); } for (int j = 0; j < exceptions.length; j++) { Class exception = exceptions[j]; methodDef.exceptions.add(exception.getName()); } for (int j = 0; j < parameterTypes.length; j++) { FieldDef param = new FieldDef(); Class parameterType = parameterTypes[j]; param.name = "p" + j; param.type = getTypeName(parameterType); param.dimensions = getDimension(parameterType); methodDef.params.add(param); } binaryBuilder.addMethod(methodDef); } private static final int getDimension(Class c) { return c.getName().lastIndexOf('[') + 1; } private static String getTypeName(Class c) { return c.getComponentType() != null ? c.getComponentType().getName() : c.getName(); } private String getPackageName(String fullClassName) { int lastDot = fullClassName.lastIndexOf('.'); return lastDot == -1 ? "" : fullClassName.substring(0, lastDot); } private String getClassName(String fullClassName) { int lastDot = fullClassName.lastIndexOf('.'); return lastDot == -1 ? fullClassName : fullClassName.substring(lastDot + 1); } public JavaSource addSource(Reader reader) { return addSource(reader, "UNKNOWN SOURCE"); } public JavaSource addSource(Reader reader, String sourceInfo) { ModelBuilder builder = new ModelBuilder(classLibrary, docletTagFactory); Lexer lexer = new JFlexLexer(reader); Parser parser = new Parser(lexer, builder); parser.setDebugLexer(debugLexer); parser.setDebugParser(debugParser); try { parser.parse(); } catch (ParseException e) { e.setSourceInfo(sourceInfo); throw e; } JavaSource source = builder.getSource(); sources.add(source); addClasses(source); return source; } public JavaSource addSource(File file) throws IOException, FileNotFoundException { return addSource(file.toURL()); } public JavaSource addSource(URL url) throws IOException, FileNotFoundException { JavaSource source = addSource(new InputStreamReader(url.openStream(),encoding), url.toExternalForm()); source.setURL(url); return source; } public JavaSource[] getSources() { return (JavaSource[]) sources.toArray(new JavaSource[sources.size()]); } /** * Returns all the classes found in all the sources, including inner classes * and "extra" classes (multiple outer classes defined in the same source file). * * @return all the classes found in all the sources. * @since 1.3 */ public JavaClass[] getClasses() { Set resultSet = new HashSet(); JavaSource[] javaSources = getSources(); for (int i = 0; i < javaSources.length; i++) { JavaSource javaSource = javaSources[i]; addClassesRecursive(javaSource, resultSet); } JavaClass[] result = (JavaClass[]) resultSet.toArray(new JavaClass[resultSet.size()]); return result; } private void addClassesRecursive(JavaSource javaSource, Set resultSet) { JavaClass[] classes = javaSource.getClasses(); for (int j = 0; j < classes.length; j++) { JavaClass javaClass = classes[j]; addClassesRecursive(javaClass, resultSet); } } private void addClassesRecursive(JavaClass javaClass, Set set) { // Add the class... set.add(javaClass); // And recursively all of its inner classes JavaClass[] innerClasses = javaClass.getNestedClasses(); for (int i = 0; i < innerClasses.length; i++) { JavaClass innerClass = innerClasses[i]; addClassesRecursive(innerClass, set); } } public void addSourceTree(File file) { DirectoryScanner scanner = new DirectoryScanner(file); scanner.addFilter(new SuffixFilter(".java")); scanner.scan(new FileVisitor() { public void visitFile(File currentFile) { try { addSource(currentFile); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Unsupported encoding : " + encoding); } catch (IOException e) { throw new RuntimeException("Cannot read file : " + currentFile.getName()); } } }); } public List search(Searcher searcher) { List results = new LinkedList(); for (Iterator iterator = classLibrary.all().iterator(); iterator.hasNext();) { String clsName = (String) iterator.next(); JavaClass cls = getClassByName(clsName); if (searcher.eval(cls)) { results.add(cls); } } return results; } public ClassLibrary getClassLibrary() { return classLibrary; } public void save(File file) throws IOException { FileOutputStream fos = new FileOutputStream(file); ObjectOutputStream out = new ObjectOutputStream(fos); try { out.writeObject(this); } finally { out.close(); fos.close(); } } /** * Note that after loading JavaDocBuilder classloaders need to be re-added. */ public static JavaDocBuilder load(File file) throws IOException { FileInputStream fis = new FileInputStream(file); ObjectInputStream in = new ObjectInputStream(fis); JavaDocBuilder builder = null; try { builder = (JavaDocBuilder) in.readObject(); } catch (ClassNotFoundException e) { throw new Error("Couldn't load class : " + e.getMessage()); } finally { in.close(); fis.close(); } return builder; } public void setEncoding(String encoding) { this.encoding = encoding; } /** * Forces QDox to dump tokens returned from lexer to System.err. */ public void setDebugLexer(boolean debugLexer) { this.debugLexer = debugLexer; } /** * Forces QDox to dump parser states to System.out. */ public void setDebugParser(boolean debugParser) { this.debugParser = debugParser; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy