alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (JavadocTool.java)

This example Java source code file (JavadocTool.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

hashmap, ioexception, iterable, javadoctool, javafileobject, jccompilationunit, list, listbuffer, map, messager, rootdocimpl, standardjavafilemanager, standardlocation, string, util

The JavadocTool.java Java example source code

/*
 * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.tools.javadoc;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.tools.JavaFileManager.Location;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;

import com.sun.tools.javac.code.Symbol.CompletionFailure;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.util.Abort;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Position;


/**
 *  This class could be the main entry point for Javadoc when Javadoc is used as a
 *  component in a larger software system. It provides operations to
 *  construct a new javadoc processor, and to run it on a set of source
 *  files.
 *
 *  <p>This is NOT part of any supported API.
 *  If you write code that depends on this, you do so at your own risk.
 *  This code and its internal interfaces are subject to change or
 *  deletion without notice.</b>
 *
 *  @author Neal Gafter
 */
public class JavadocTool extends com.sun.tools.javac.main.JavaCompiler {
    DocEnv docenv;

    final Messager messager;
    final JavadocClassReader javadocReader;
    final JavadocEnter javadocEnter;

    /**
     * Construct a new JavaCompiler processor, using appropriately
     * extended phases of the underlying compiler.
     */
    protected JavadocTool(Context context) {
        super(context);
        messager = Messager.instance0(context);
        javadocReader = JavadocClassReader.instance0(context);
        javadocEnter = JavadocEnter.instance0(context);
    }

    /**
     * For javadoc, the parser needs to keep comments. Overrides method from JavaCompiler.
     */
    protected boolean keepComments() {
        return true;
    }

    /**
     *  Construct a new javadoc tool.
     */
    public static JavadocTool make0(Context context) {
        Messager messager = null;
        try {
            // force the use of Javadoc's class reader
            JavadocClassReader.preRegister(context);

            // force the use of Javadoc's own enter phase
            JavadocEnter.preRegister(context);

            // force the use of Javadoc's own member enter phase
            JavadocMemberEnter.preRegister(context);

            // force the use of Javadoc's own todo phase
            JavadocTodo.preRegister(context);

            // force the use of Messager as a Log
            messager = Messager.instance0(context);

            return new JavadocTool(context);
        } catch (CompletionFailure ex) {
            messager.error(Position.NOPOS, ex.getMessage());
            return null;
        }
    }

    public RootDocImpl getRootDocImpl(String doclocale,
                                      String encoding,
                                      ModifierFilter filter,
                                      List<String> javaNames,
                                      List<String[]> options,
                                      Iterable<? extends JavaFileObject> fileObjects,
                                      boolean breakiterator,
                                      List<String> subPackages,
                                      List<String> excludedPackages,
                                      boolean docClasses,
                                      boolean legacyDoclet,
                      boolean quiet) throws IOException {
        docenv = DocEnv.instance(context);
        docenv.showAccess = filter;
        docenv.quiet = quiet;
        docenv.breakiterator = breakiterator;
        docenv.setLocale(doclocale);
        docenv.setEncoding(encoding);
        docenv.docClasses = docClasses;
        docenv.legacyDoclet = legacyDoclet;
        javadocReader.sourceCompleter = docClasses ? null : thisCompleter;

        ListBuffer<String> names = new ListBuffer();
        ListBuffer<JCCompilationUnit> classTrees = new ListBuffer();
        ListBuffer<JCCompilationUnit> packTrees = new ListBuffer();

        try {
            StandardJavaFileManager fm = docenv.fileManager instanceof StandardJavaFileManager
                    ? (StandardJavaFileManager) docenv.fileManager : null;
            for (List<String> it = javaNames; it.nonEmpty(); it = it.tail) {
                String name = it.head;
                if (!docClasses && fm != null && name.endsWith(".java") && new File(name).exists()) {
                    JavaFileObject fo = fm.getJavaFileObjects(name).iterator().next();
                    docenv.notice("main.Loading_source_file", name);
                    JCCompilationUnit tree = parse(fo);
                    classTrees.append(tree);
                } else if (isValidPackageName(name)) {
                    names = names.append(name);
                } else if (name.endsWith(".java")) {
                    if (fm == null)
                        throw new IllegalArgumentException();
                    else
                        docenv.error(null, "main.file_not_found", name);
                } else {
                    docenv.error(null, "main.illegal_package_name", name);
                }
            }
            for (JavaFileObject fo: fileObjects) {
                docenv.notice("main.Loading_source_file", fo.getName());
                JCCompilationUnit tree = parse(fo);
                classTrees.append(tree);
            }

            if (!docClasses) {
                // Recursively search given subpackages.  If any packages
                //are found, add them to the list.
                Map<String,List packageFiles =
                        searchSubPackages(subPackages, names, excludedPackages);

                // Parse the packages
                for (List<String> packs = names.toList(); packs.nonEmpty(); packs = packs.tail) {
                    // Parse sources ostensibly belonging to package.
                    String packageName = packs.head;
                    parsePackageClasses(packageName, packageFiles.get(packageName), packTrees, excludedPackages);
                }

                if (messager.nerrors() != 0) return null;

                // Enter symbols for all files
                docenv.notice("main.Building_tree");
                javadocEnter.main(classTrees.toList().appendList(packTrees.toList()));
            }
        } catch (Abort ex) {}

        if (messager.nerrors() != 0)
            return null;

        if (docClasses)
            return new RootDocImpl(docenv, javaNames, options);
        else
            return new RootDocImpl(docenv, listClasses(classTrees.toList()), names.toList(), options);
    }

    /** Is the given string a valid package name? */
    boolean isValidPackageName(String s) {
        int index;
        while ((index = s.indexOf('.')) != -1) {
            if (!isValidClassName(s.substring(0, index))) return false;
            s = s.substring(index+1);
        }
        return isValidClassName(s);
    }

    /**
     * search all directories in path for subdirectory name. Add all
     * .java files found in such a directory to args.
     */
    private void parsePackageClasses(String name,
            Iterable<JavaFileObject> files,
            ListBuffer<JCCompilationUnit> trees,
            List<String> excludedPackages)
            throws IOException {
        if (excludedPackages.contains(name)) {
            return;
        }

        boolean hasFiles = false;
        docenv.notice("main.Loading_source_files_for_package", name);

        if (files == null) {
            Location location = docenv.fileManager.hasLocation(StandardLocation.SOURCE_PATH)
                    ? StandardLocation.SOURCE_PATH : StandardLocation.CLASS_PATH;
            ListBuffer<JavaFileObject> lb = new ListBuffer();
            for (JavaFileObject fo: docenv.fileManager.list(
                    location, name, EnumSet.of(JavaFileObject.Kind.SOURCE), false)) {
                String binaryName = docenv.fileManager.inferBinaryName(location, fo);
                String simpleName = getSimpleName(binaryName);
                if (isValidClassName(simpleName)) {
                    lb.append(fo);
                }
            }
            files = lb.toList();
        }

        for (JavaFileObject fo : files) {
            // messager.notice("main.Loading_source_file", fn);
            trees.append(parse(fo));
            hasFiles = true;
        }

        if (!hasFiles) {
            messager.warning(Messager.NOPOS, "main.no_source_files_for_package",
                    name.replace(File.separatorChar, '.'));
        }
    }

    /**
     * Recursively search all directories in path for subdirectory name.
     * Add all packages found in such a directory to packages list.
     */
    private Map<String,List searchSubPackages(
            List<String> subPackages,
            ListBuffer<String> packages,
            List<String> excludedPackages)
            throws IOException {
        Map<String,List packageFiles =
                new HashMap<String,List();

        Map<String,Boolean> includedPackages = new HashMap();
        includedPackages.put("", true);
        for (String p: excludedPackages)
            includedPackages.put(p, false);

        StandardLocation path = docenv.fileManager.hasLocation(StandardLocation.SOURCE_PATH)
                ? StandardLocation.SOURCE_PATH : StandardLocation.CLASS_PATH;

        searchSubPackages(subPackages,
                includedPackages,
                packages, packageFiles,
                path,
                EnumSet.of(JavaFileObject.Kind.SOURCE));

        return packageFiles;
    }

    private void searchSubPackages(List<String> subPackages,
            Map<String,Boolean> includedPackages,
            ListBuffer<String> packages,
            Map<String, List packageFiles,
            StandardLocation location, Set<JavaFileObject.Kind> kinds)
            throws IOException {
        for (String subPackage: subPackages) {
            if (!isIncluded(subPackage, includedPackages))
                continue;

            for (JavaFileObject fo: docenv.fileManager.list(location, subPackage, kinds, true)) {
                String binaryName = docenv.fileManager.inferBinaryName(location, fo);
                String packageName = getPackageName(binaryName);
                String simpleName = getSimpleName(binaryName);
                if (isIncluded(packageName, includedPackages) && isValidClassName(simpleName)) {
                    List<JavaFileObject> list = packageFiles.get(packageName);
                    list = (list == null ? List.of(fo) : list.prepend(fo));
                    packageFiles.put(packageName, list);
                    if (!packages.contains(packageName))
                        packages.add(packageName);
                }
            }
        }
    }

    private String getPackageName(String name) {
        int lastDot = name.lastIndexOf(".");
        return (lastDot == -1 ? "" : name.substring(0, lastDot));
    }

    private String getSimpleName(String name) {
        int lastDot = name.lastIndexOf(".");
        return (lastDot == -1 ? name : name.substring(lastDot + 1));
    }

    private boolean isIncluded(String packageName, Map<String,Boolean> includedPackages) {
        Boolean b = includedPackages.get(packageName);
        if (b == null) {
            b = isIncluded(getPackageName(packageName), includedPackages);
            includedPackages.put(packageName, b);
        }
        return b;
    }

    /**
     * Recursively search all directories in path for subdirectory name.
     * Add all packages found in such a directory to packages list.
     */
    private void searchSubPackage(String packageName,
                                  ListBuffer<String> packages,
                                  List<String> excludedPackages,
                                  Collection<File> pathnames) {
        if (excludedPackages.contains(packageName))
            return;

        String packageFilename = packageName.replace('.', File.separatorChar);
        boolean addedPackage = false;
        for (File pathname : pathnames) {
            File f = new File(pathname, packageFilename);
            String filenames[] = f.list();
            // if filenames not null, then found directory
            if (filenames != null) {
                for (String filename : filenames) {
                    if (!addedPackage
                            && (isValidJavaSourceFile(filename) ||
                                isValidJavaClassFile(filename))
                            && !packages.contains(packageName)) {
                        packages.append(packageName);
                        addedPackage = true;
                    } else if (isValidClassName(filename) &&
                               (new File(f, filename)).isDirectory()) {
                        searchSubPackage(packageName + "." + filename,
                                         packages, excludedPackages, pathnames);
                    }
                }
            }
        }
    }

    /**
     * Return true if given file name is a valid class file name.
     * @param file the name of the file to check.
     * @return true if given file name is a valid class file name
     * and false otherwise.
     */
    private static boolean isValidJavaClassFile(String file) {
        if (!file.endsWith(".class")) return false;
        String clazzName = file.substring(0, file.length() - ".class".length());
        return isValidClassName(clazzName);
    }

    /**
     * Return true if given file name is a valid Java source file name.
     * @param file the name of the file to check.
     * @return true if given file name is a valid Java source file name
     * and false otherwise.
     */
    private static boolean isValidJavaSourceFile(String file) {
        if (!file.endsWith(".java")) return false;
        String clazzName = file.substring(0, file.length() - ".java".length());
        return isValidClassName(clazzName);
    }

    /** Are surrogates supported?
     */
    final static boolean surrogatesSupported = surrogatesSupported();
    private static boolean surrogatesSupported() {
        try {
            boolean b = Character.isHighSurrogate('a');
            return true;
        } catch (NoSuchMethodError ex) {
            return false;
        }
    }

    /**
     * Return true if given file name is a valid class name
     * (including "package-info").
     * @param s the name of the class to check.
     * @return true if given class name is a valid class name
     * and false otherwise.
     */
    public static boolean isValidClassName(String s) {
        if (s.length() < 1) return false;
        if (s.equals("package-info")) return true;
        if (surrogatesSupported) {
            int cp = s.codePointAt(0);
            if (!Character.isJavaIdentifierStart(cp))
                return false;
            for (int j=Character.charCount(cp); j<s.length(); j+=Character.charCount(cp)) {
                cp = s.codePointAt(j);
                if (!Character.isJavaIdentifierPart(cp))
                    return false;
            }
        } else {
            if (!Character.isJavaIdentifierStart(s.charAt(0)))
                return false;
            for (int j=1; j<s.length(); j++)
                if (!Character.isJavaIdentifierPart(s.charAt(j)))
                    return false;
        }
        return true;
    }

    /**
     * From a list of top level trees, return the list of contained class definitions
     */
    List<JCClassDecl> listClasses(List trees) {
        ListBuffer<JCClassDecl> result = new ListBuffer();
        for (JCCompilationUnit t : trees) {
            for (JCTree def : t.defs) {
                if (def.hasTag(JCTree.Tag.CLASSDEF))
                    result.append((JCClassDecl)def);
            }
        }
        return result.toList();
    }

}

Other Java examples (source code examples)

Here is a short list of links related to this Java JavadocTool.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.