--- a/langtools/make/build.properties Thu Dec 17 14:10:44 2009 -0800
+++ b/langtools/make/build.properties Sat Dec 19 10:26:47 2009 -0800
@@ -149,11 +149,26 @@
#
# The following files require the import JDK to be available
-require.import.jdk.files =
+require.import.jdk.files = \
+ com/sun/tools/javac/nio/*.java
# The following files in the import jdk source directory are required
# in order to compile the files defined in ${require.import.jdk.files}
-import.jdk.stub.files =
+#
+# For NIO, the list of stub files is defined by the contents of the primary
+# API packages, together with such types that may be required in order to
+# compile the stubs. Some of these dependencies would go away if the stub
+# generator were to be improved -- e.g. by removing unnecessary imports.
+#
+import.jdk.stub.files = \
+ java/io/File.java \
+ java/nio/file/**.java \
+ java/nio/file/attribute/**.java \
+ java/nio/file/spi/**.java \
+ java/nio/channels/AsynchronousChannel.java \
+ java/nio/channels/AsynchronousFileChannel.java \
+ java/nio/channels/CompletionHandler.java \
+ java/nio/channels/SeekableByteChannel.java
# The following value is used by the main jtreg target.
# An empty value means all tests
--- a/langtools/make/build.xml Thu Dec 17 14:10:44 2009 -0800
+++ b/langtools/make/build.xml Sat Dec 19 10:26:47 2009 -0800
@@ -98,7 +98,7 @@
import.jdk should be unset, or set to jdk home (to use rt.jar)
or to jdk repo (to use src/share/classes).
Based on the value, if any, set up default values for javac's sourcepath,
- classpath and bootclasspath. Note: the default values are overridden
+ classpath and bootclasspath. Note: the default values are overridden
in the build-bootstrap-classes macro. -->
<available property="import.jdk.src.dir" value="${import.jdk}/src/share/classes"
@@ -552,8 +552,8 @@
<compilerarg line="${javac.version.opt}"/>
<compilerarg line="${javac.lint.opts}"/>
</javac>
- <copy todir="@{classes.dir}">
- <fileset dir="${src.classes.dir}" includes="@{includes}">
+ <copy todir="@{classes.dir}" includeemptydirs="false">
+ <fileset dir="${src.classes.dir}" includes="@{includes}" excludes="@{excludes}">
<exclude name="**/*.java"/>
<exclude name="**/*.properties"/>
<exclude name="**/*-template"/>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,718 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.tools.classfile;
+
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import com.sun.tools.classfile.Dependency.Finder;
+import com.sun.tools.classfile.Dependency.Filter;
+import com.sun.tools.classfile.Dependency.Location;
+import com.sun.tools.classfile.Type.ArrayType;
+import com.sun.tools.classfile.Type.ClassSigType;
+import com.sun.tools.classfile.Type.ClassType;
+import com.sun.tools.classfile.Type.MethodType;
+import com.sun.tools.classfile.Type.SimpleType;
+import com.sun.tools.classfile.Type.TypeParamType;
+import com.sun.tools.classfile.Type.WildcardType;
+
+import static com.sun.tools.classfile.ConstantPool.*;
+
+/**
+ * A framework for determining {@link Dependency dependencies} between class files.
+ *
+ * A {@link Dependency.Finder finder} is used to identify the dependencies of
+ * individual classes. Some finders may return subtypes of {@code Dependency} to
+ * further characterize the type of dependency, such as a dependency on a
+ * method within a class.
+ *
+ * A {@link Dependency.Filter filter} may be used to restrict the set of
+ * dependencies found by a finder.
+ *
+ * Dependencies that are found may be passed to a {@link Dependencies.Recorder
+ * recorder} so that the dependencies can be stored in a custom data structure.
+ */
+public class Dependencies {
+ /**
+ * Thrown when a class file cannot be found.
+ */
+ public static class ClassFileNotFoundException extends Exception {
+ private static final long serialVersionUID = 3632265927794475048L;
+
+ public ClassFileNotFoundException(String className) {
+ super(className);
+ this.className = className;
+ }
+
+ public ClassFileNotFoundException(String className, Throwable cause) {
+ this(className);
+ initCause(cause);
+ }
+
+ public final String className;
+ }
+
+ /**
+ * Thrown when an exception is found processing a class file.
+ */
+ public static class ClassFileError extends Error {
+ private static final long serialVersionUID = 4111110813961313203L;
+
+ public ClassFileError(Throwable cause) {
+ initCause(cause);
+ }
+ }
+
+ /**
+ * Service provider interface to locate and read class files.
+ */
+ public interface ClassFileReader {
+ /**
+ * Get the ClassFile object for a specified class.
+ * @param className the name of the class to be returned.
+ * @return the ClassFile for the given class
+ * @throws Dependencies#ClassFileNotFoundException if the classfile cannot be
+ * found
+ */
+ public ClassFile getClassFile(String className)
+ throws ClassFileNotFoundException;
+ }
+
+ /**
+ * Service provide interface to handle results.
+ */
+ public interface Recorder {
+ /**
+ * Record a dependency that has been found.
+ * @param d
+ */
+ public void addDependency(Dependency d);
+ }
+
+ /**
+ * Get the default finder used to locate the dependencies for a class.
+ * @return the default finder
+ */
+ public static Finder getDefaultFinder() {
+ return new APIDependencyFinder(AccessFlags.ACC_PRIVATE);
+ }
+
+ /**
+ * Get a finder used to locate the API dependencies for a class.
+ * These include the superclass, superinterfaces, and classes referenced in
+ * the declarations of fields and methods. The fields and methods that
+ * are checked can be limited according to a specified access.
+ * The access parameter must be one of {@link AccessFlags#ACC_PUBLIC ACC_PUBLIC},
+ * {@link AccessFlags#ACC_PRIVATE ACC_PRIVATE},
+ * {@link AccessFlags#ACC_PROTECTED ACC_PROTECTED}, or 0 for
+ * package private access. Members with greater than or equal accessibility
+ * to that specified will be searched for dependencies.
+ * @param access the access of members to be checked
+ * @return an API finder
+ */
+ public static Finder getAPIFinder(int access) {
+ return new APIDependencyFinder(access);
+ }
+
+ /**
+ * Get the finder used to locate the dependencies for a class.
+ * @return the finder
+ */
+ public Finder getFinder() {
+ if (finder == null)
+ finder = getDefaultFinder();
+ return finder;
+ }
+
+ /**
+ * Set the finder used to locate the dependencies for a class.
+ * @param f the finder
+ */
+ public void setFinder(Finder f) {
+ f.getClass(); // null check
+ finder = f;
+ }
+
+ /**
+ * Get the default filter used to determine included when searching
+ * the transitive closure of all the dependencies.
+ * Unless overridden, the default filter accepts all dependencies.
+ * @return the default filter.
+ */
+ public static Filter getDefaultFilter() {
+ return DefaultFilter.instance();
+ }
+
+ /**
+ * Get a filter which uses a regular expression on the target's class name
+ * to determine if a dependency is of interest.
+ * @param pattern the pattern used to match the target's class name
+ * @return a filter for matching the target class name with a regular expression
+ */
+ public static Filter getRegexFilter(Pattern pattern) {
+ return new TargetRegexFilter(pattern);
+ }
+
+ /**
+ * Get a filter which checks the package of a target's class name
+ * to determine if a dependency is of interest. The filter checks if the
+ * package of the target's class matches any of a set of given package
+ * names. The match may optionally match subpackages of the given names as well.
+ * @param packageNames the package names used to match the target's class name
+ * @param matchSubpackages whether or not to match subpackages as well
+ * @return a filter for checking the target package name against a list of package names
+ */
+ public static Filter getPackageFilter(Set<String> packageNames, boolean matchSubpackages) {
+ return new TargetPackageFilter(packageNames, matchSubpackages);
+ }
+
+ /**
+ * Get the filter used to determine the dependencies included when searching
+ * the transitive closure of all the dependencies.
+ * Unless overridden, the default filter accepts all dependencies.
+ * @return the filter
+ */
+ public Filter getFilter() {
+ if (filter == null)
+ filter = getDefaultFilter();
+ return filter;
+ }
+
+ /**
+ * Set the filter used to determine the dependencies included when searching
+ * the transitive closure of all the dependencies.
+ * @param f the filter
+ */
+ public void setFilter(Filter f) {
+ f.getClass(); // null check
+ filter = f;
+ }
+
+ /**
+ * Find the dependencies of a class, using the current
+ * {@link Dependencies#getFinder finder} and
+ * {@link Dependencies#getFilter filter}.
+ * The search may optionally include the transitive closure of all the
+ * filtered dependencies, by also searching in the classes named in those
+ * dependencies.
+ * @param classFinder a finder to locate class files
+ * @param rootClassNames the names of the root classes from which to begin
+ * searching
+ * @param transitiveClosure whether or not to also search those classes
+ * named in any filtered dependencies that are found.
+ * @return the set of dependencies that were found
+ * @throws ClassFileNotFoundException if a required class file cannot be found
+ * @throws ClassFileError if an error occurs while processing a class file,
+ * such as an error in the internal class file structure.
+ */
+ public Set<Dependency> findAllDependencies(
+ ClassFileReader classFinder, Set<String> rootClassNames,
+ boolean transitiveClosure)
+ throws ClassFileNotFoundException {
+ final Set<Dependency> results = new HashSet<Dependency>();
+ Recorder r = new Recorder() {
+ public void addDependency(Dependency d) {
+ results.add(d);
+ }
+ };
+ findAllDependencies(classFinder, rootClassNames, transitiveClosure, r);
+ return results;
+ }
+
+
+
+ /**
+ * Find the dependencies of a class, using the current
+ * {@link Dependencies#getFinder finder} and
+ * {@link Dependencies#getFilter filter}.
+ * The search may optionally include the transitive closure of all the
+ * filtered dependencies, by also searching in the classes named in those
+ * dependencies.
+ * @param classFinder a finder to locate class files
+ * @param rootClassNames the names of the root classes from which to begin
+ * searching
+ * @param transitiveClosure whether or not to also search those classes
+ * named in any filtered dependencies that are found.
+ * @param recorder a recorder for handling the results
+ * @throws ClassFileNotFoundException if a required class file cannot be found
+ * @throws ClassFileError if an error occurs while processing a class file,
+ * such as an error in the internal class file structure.
+ */
+ public void findAllDependencies(
+ ClassFileReader classFinder, Set<String> rootClassNames,
+ boolean transitiveClosure, Recorder recorder)
+ throws ClassFileNotFoundException {
+ Set<String> doneClasses = new HashSet<String>();
+
+ getFinder(); // ensure initialized
+ getFilter(); // ensure initialized
+
+ // Work queue of names of classfiles to be searched.
+ // Entries will be unique, and for classes that do not yet have
+ // dependencies in the results map.
+ Deque<String> deque = new LinkedList<String>(rootClassNames);
+
+ String className;
+ while ((className = deque.poll()) != null) {
+ assert (!doneClasses.contains(className));
+ doneClasses.add(className);
+
+ ClassFile cf = classFinder.getClassFile(className);
+
+ // The following code just applies the filter to the dependencies
+ // followed for the transitive closure.
+ for (Dependency d: finder.findDependencies(cf)) {
+ recorder.addDependency(d);
+ if (transitiveClosure && filter.accepts(d)) {
+ String cn = d.getTarget().getClassName();
+ if (!doneClasses.contains(cn))
+ deque.add(cn);
+ }
+ }
+ }
+ }
+
+ private Filter filter;
+ private Finder finder;
+
+ /**
+ * A location identifying a class.
+ */
+ static class SimpleLocation implements Location {
+ public SimpleLocation(String className) {
+ this.className = className;
+ }
+
+ /**
+ * Get the name of the class being depended on. This name will be used to
+ * locate the class file for transitive dependency analysis.
+ * @return the name of the class being depended on
+ */
+ public String getClassName() {
+ return className;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other)
+ return true;
+ if (!(other instanceof SimpleLocation))
+ return false;
+ return (className.equals(((SimpleLocation) other).className));
+ }
+
+ @Override
+ public int hashCode() {
+ return className.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return className;
+ }
+
+ private String className;
+ }
+
+ /**
+ * A dependency of one class on another.
+ */
+ static class SimpleDependency implements Dependency {
+ public SimpleDependency(Location origin, Location target) {
+ this.origin = origin;
+ this.target = target;
+ }
+
+ public Location getOrigin() {
+ return origin;
+ }
+
+ public Location getTarget() {
+ return target;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other)
+ return true;
+ if (!(other instanceof SimpleDependency))
+ return false;
+ SimpleDependency o = (SimpleDependency) other;
+ return (origin.equals(o.origin) && target.equals(o.target));
+ }
+
+ @Override
+ public int hashCode() {
+ return origin.hashCode() * 31 + target.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return origin + ":" + target;
+ }
+
+ private Location origin;
+ private Location target;
+ }
+
+
+ /**
+ * This class accepts all dependencies.
+ */
+ static class DefaultFilter implements Filter {
+ private static DefaultFilter instance;
+
+ static DefaultFilter instance() {
+ if (instance == null)
+ instance = new DefaultFilter();
+ return instance;
+ }
+
+ public boolean accepts(Dependency dependency) {
+ return true;
+ }
+ }
+
+ /**
+ * This class accepts those dependencies whose target's class name matches a
+ * regular expression.
+ */
+ static class TargetRegexFilter implements Filter {
+ TargetRegexFilter(Pattern pattern) {
+ this.pattern = pattern;
+ }
+
+ public boolean accepts(Dependency dependency) {
+ return pattern.matcher(dependency.getTarget().getClassName()).matches();
+ }
+
+ private final Pattern pattern;
+ }
+
+ /**
+ * This class accepts those dependencies whose class name is in a given
+ * package.
+ */
+ static class TargetPackageFilter implements Filter {
+ TargetPackageFilter(Set<String> packageNames, boolean matchSubpackages) {
+ for (String pn: packageNames) {
+ if (pn.length() == 0) // implies null check as well
+ throw new IllegalArgumentException();
+ }
+ this.packageNames = packageNames;
+ this.matchSubpackages = matchSubpackages;
+ }
+
+ public boolean accepts(Dependency dependency) {
+ String cn = dependency.getTarget().getClassName();
+ int lastSep = cn.lastIndexOf("/");
+ String pn = (lastSep == -1 ? "" : cn.substring(0, lastSep));
+ if (packageNames.contains(pn))
+ return true;
+
+ if (matchSubpackages) {
+ for (String n: packageNames) {
+ if (pn.startsWith(n + "."))
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private final Set<String> packageNames;
+ private final boolean matchSubpackages;
+ }
+
+
+
+ /**
+ * This class identifies class names directly or indirectly in the constant pool.
+ */
+ static class ClassDependencyFinder extends BasicDependencyFinder {
+ public Iterable<? extends Dependency> findDependencies(ClassFile classfile) {
+ Visitor v = new Visitor(classfile);
+ for (CPInfo cpInfo: classfile.constant_pool.entries()) {
+ v.scan(cpInfo);
+ }
+ return v.deps;
+ }
+ }
+
+ /**
+ * This class identifies class names in the signatures of classes, fields,
+ * and methods in a class.
+ */
+ static class APIDependencyFinder extends BasicDependencyFinder {
+ APIDependencyFinder(int access) {
+ switch (access) {
+ case AccessFlags.ACC_PUBLIC:
+ case AccessFlags.ACC_PROTECTED:
+ case AccessFlags.ACC_PRIVATE:
+ case 0:
+ showAccess = access;
+ break;
+ default:
+ throw new IllegalArgumentException("invalid access 0x"
+ + Integer.toHexString(access));
+ }
+ }
+
+ public Iterable<? extends Dependency> findDependencies(ClassFile classfile) {
+ try {
+ Visitor v = new Visitor(classfile);
+ v.addClass(classfile.super_class);
+ v.addClasses(classfile.interfaces);
+ // inner classes?
+ for (Field f : classfile.fields) {
+ if (checkAccess(f.access_flags))
+ v.scan(f.descriptor, f.attributes);
+ }
+ for (Method m : classfile.methods) {
+ if (checkAccess(m.access_flags)) {
+ v.scan(m.descriptor, m.attributes);
+ Exceptions_attribute e =
+ (Exceptions_attribute) m.attributes.get(Attribute.Exceptions);
+ if (e != null)
+ v.addClasses(e.exception_index_table);
+ }
+ }
+ return v.deps;
+ } catch (ConstantPoolException e) {
+ throw new ClassFileError(e);
+ }
+ }
+
+ boolean checkAccess(AccessFlags flags) {
+ // code copied from javap.Options.checkAccess
+ boolean isPublic = flags.is(AccessFlags.ACC_PUBLIC);
+ boolean isProtected = flags.is(AccessFlags.ACC_PROTECTED);
+ boolean isPrivate = flags.is(AccessFlags.ACC_PRIVATE);
+ boolean isPackage = !(isPublic || isProtected || isPrivate);
+
+ if ((showAccess == AccessFlags.ACC_PUBLIC) && (isProtected || isPrivate || isPackage))
+ return false;
+ else if ((showAccess == AccessFlags.ACC_PROTECTED) && (isPrivate || isPackage))
+ return false;
+ else if ((showAccess == 0) && (isPrivate))
+ return false;
+ else
+ return true;
+ }
+
+ private int showAccess;
+ }
+
+ static abstract class BasicDependencyFinder implements Finder {
+ private Map<String,Location> locations = new HashMap<String,Location>();
+
+ Location getLocation(String className) {
+ Location l = locations.get(className);
+ if (l == null)
+ locations.put(className, l = new SimpleLocation(className));
+ return l;
+ }
+
+ class Visitor implements ConstantPool.Visitor<Void,Void>, Type.Visitor<Void, Void> {
+ private ConstantPool constant_pool;
+ private Location origin;
+ Set<Dependency> deps;
+
+ Visitor(ClassFile classFile) {
+ try {
+ constant_pool = classFile.constant_pool;
+ origin = getLocation(classFile.getName());
+ deps = new HashSet<Dependency>();
+ } catch (ConstantPoolException e) {
+ throw new ClassFileError(e);
+ }
+ }
+
+ void scan(Descriptor d, Attributes attrs) {
+ try {
+ scan(new Signature(d.index).getType(constant_pool));
+ Signature_attribute sa = (Signature_attribute) attrs.get(Attribute.Signature);
+ if (sa != null)
+ scan(new Signature(sa.signature_index).getType(constant_pool));
+ } catch (ConstantPoolException e) {
+ throw new ClassFileError(e);
+ }
+ }
+
+ void scan(CPInfo cpInfo) {
+ cpInfo.accept(this, null);
+ }
+
+ void scan(Type t) {
+ t.accept(this, null);
+ }
+
+ void addClass(int index) throws ConstantPoolException {
+ if (index != 0) {
+ String name = constant_pool.getClassInfo(index).getBaseName();
+ if (name != null)
+ addDependency(name);
+ }
+ }
+
+ void addClasses(int[] indices) throws ConstantPoolException {
+ for (int i: indices)
+ addClass(i);
+ }
+
+ private void addDependency(String name) {
+ deps.add(new SimpleDependency(origin, getLocation(name)));
+ }
+
+ // ConstantPool.Visitor methods
+
+ public Void visitClass(CONSTANT_Class_info info, Void p) {
+ try {
+ if (info.getName().startsWith("["))
+ new Signature(info.name_index).getType(constant_pool).accept(this, null);
+ else
+ addDependency(info.getBaseName());
+ return null;
+ } catch (ConstantPoolException e) {
+ throw new ClassFileError(e);
+ }
+ }
+
+ public Void visitDouble(CONSTANT_Double_info info, Void p) {
+ return null;
+ }
+
+ public Void visitFieldref(CONSTANT_Fieldref_info info, Void p) {
+ return visitRef(info, p);
+ }
+
+ public Void visitFloat(CONSTANT_Float_info info, Void p) {
+ return null;
+ }
+
+ public Void visitInteger(CONSTANT_Integer_info info, Void p) {
+ return null;
+ }
+
+ public Void visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) {
+ return visitRef(info, p);
+ }
+
+ public Void visitLong(CONSTANT_Long_info info, Void p) {
+ return null;
+ }
+
+ public Void visitNameAndType(CONSTANT_NameAndType_info info, Void p) {
+ try {
+ new Signature(info.type_index).getType(constant_pool).accept(this, null);
+ return null;
+ } catch (ConstantPoolException e) {
+ throw new ClassFileError(e);
+ }
+ }
+
+ public Void visitMethodref(CONSTANT_Methodref_info info, Void p) {
+ return visitRef(info, p);
+ }
+
+ public Void visitString(CONSTANT_String_info info, Void p) {
+ return null;
+ }
+
+ public Void visitUtf8(CONSTANT_Utf8_info info, Void p) {
+ return null;
+ }
+
+ private Void visitRef(CPRefInfo info, Void p) {
+ try {
+ visitClass(info.getClassInfo(), p);
+ return null;
+ } catch (ConstantPoolException e) {
+ throw new ClassFileError(e);
+ }
+ }
+
+ // Type.Visitor methods
+
+ private void findDependencies(Type t) {
+ if (t != null)
+ t.accept(this, null);
+ }
+
+ private void findDependencies(List<? extends Type> ts) {
+ if (ts != null) {
+ for (Type t: ts)
+ t.accept(this, null);
+ }
+ }
+
+ public Void visitSimpleType(SimpleType type, Void p) {
+ return null;
+ }
+
+ public Void visitArrayType(ArrayType type, Void p) {
+ findDependencies(type.elemType);
+ return null;
+ }
+
+ public Void visitMethodType(MethodType type, Void p) {
+ findDependencies(type.paramTypes);
+ findDependencies(type.returnType);
+ findDependencies(type.throwsTypes);
+ return null;
+ }
+
+ public Void visitClassSigType(ClassSigType type, Void p) {
+ findDependencies(type.superclassType);
+ findDependencies(type.superinterfaceTypes);
+ return null;
+ }
+
+ public Void visitClassType(ClassType type, Void p) {
+ findDependencies(type.outerType);
+ addDependency(type.name);
+ findDependencies(type.typeArgs);
+ return null;
+ }
+
+ public Void visitTypeParamType(TypeParamType type, Void p) {
+ findDependencies(type.classBound);
+ findDependencies(type.interfaceBounds);
+ return null;
+ }
+
+ public Void visitWildcardType(WildcardType type, Void p) {
+ findDependencies(type.boundType);
+ return null;
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/classfile/Dependency.java Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.classfile;
+
+
+/**
+ * A directed relationship between two {@link Dependency.Location Location}s.
+ * Subtypes of {@code Dependency} may provide additional detail about the dependency.
+ *
+ * @see Dependency.Finder
+ * @see Dependency.Filter
+ * @see Dependencies
+ */
+public interface Dependency {
+ /**
+ * A filter used to select dependencies of interest, and to discard others.
+ */
+ public interface Filter {
+ /**
+ * Return true if the dependency is of interest.
+ * @param dependency the dependency to be considered
+ * @return true if and only if the dependency is of interest.
+ */
+ boolean accepts(Dependency dependency);
+ }
+
+ /**
+ * An interface for finding the immediate dependencies of a given class file.
+ */
+ public interface Finder {
+ /**
+ * Find the immediate dependencies of a given class file.
+ * @param classfile the class file to be examined
+ * @return the dependencies located in the given class file.
+ */
+ public Iterable<? extends Dependency> findDependencies(ClassFile classfile);
+ }
+
+
+ /**
+ * A location somewhere within a class. Subtypes of {@code Location}
+ * may be used to provide additional detail about the location.
+ */
+ public interface Location {
+ /**
+ * Get the name of the class containing the location.
+ * This name will be used to locate the class file for transitive
+ * dependency analysis.
+ * @return the name of the class containing the location.
+ */
+ String getClassName();
+ }
+
+
+ /**
+ * Get the location that has the dependency.
+ * @return the location that has the dependency.
+ */
+ Location getOrigin();
+
+ /**
+ * Get the location that is being depended upon.
+ * @return the location that is being depended upon.
+ */
+ Location getTarget();
+}
+
--- a/langtools/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java Thu Dec 17 14:10:44 2009 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java Sat Dec 19 10:26:47 2009 -0800
@@ -39,6 +39,8 @@
import static javax.tools.JavaFileObject.Kind.*;
+import com.sun.tools.javac.util.BaseFileManager;
+
/**
* <p><b>This is NOT part of any API supported by Sun Microsystems.
* If you write code that depends on this, you do so at your own risk.
@@ -74,14 +76,7 @@
protected abstract String inferBinaryName(Iterable<? extends File> path);
protected static JavaFileObject.Kind getKind(String filename) {
- if (filename.endsWith(CLASS.extension))
- return CLASS;
- else if (filename.endsWith(SOURCE.extension))
- return SOURCE;
- else if (filename.endsWith(HTML.extension))
- return HTML;
- else
- return OTHER;
+ return BaseFileManager.getKind(filename);
}
protected static String removeExtension(String fileName) {
--- a/langtools/src/share/classes/com/sun/tools/javac/file/CloseableURLClassLoader.java Thu Dec 17 14:10:44 2009 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-/*
- * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package com.sun.tools.javac.file;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.jar.JarFile;
-
-/**
- * A URLClassLoader that also implements Closeable.
- * Reflection is used to access internal data structures in the URLClassLoader,
- * since no public API exists for this purpose. Therefore this code is somewhat
- * fragile. Caveat emptor.
- * @throws Error if the internal data structures are not as expected.
- *
- * <p><b>This is NOT part of any API supported by Sun Microsystems. 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>
- */
-class CloseableURLClassLoader
- extends URLClassLoader implements Closeable {
- CloseableURLClassLoader(URL[] urls, ClassLoader parent) throws Error {
- super(urls, parent);
- try {
- getLoaders(); //proactive check that URLClassLoader is as expected
- } catch (Throwable t) {
- throw new Error("cannot create CloseableURLClassLoader", t);
- }
- }
-
- /**
- * Close any jar files that may have been opened by the class loader.
- * Reflection is used to access the jar files in the URLClassLoader's
- * internal data structures.
- * @throws java.io.IOException if the jar files cannot be found for any
- * reson, or if closing the jar file itself causes an IOException.
- */
- public void close() throws IOException {
- try {
- for (Object l: getLoaders()) {
- if (l.getClass().getName().equals("sun.misc.URLClassPath$JarLoader")) {
- Field jarField = l.getClass().getDeclaredField("jar");
- JarFile jar = (JarFile) getField(l, jarField);
- if (jar != null) {
- //System.err.println("CloseableURLClassLoader: closing " + jar);
- jar.close();
- }
- }
- }
- } catch (Throwable t) {
- IOException e = new IOException("cannot close class loader");
- e.initCause(t);
- throw e;
- }
- }
-
- private ArrayList<?> getLoaders()
- throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException
- {
- Field ucpField = URLClassLoader.class.getDeclaredField("ucp");
- Object urlClassPath = getField(this, ucpField);
- if (urlClassPath == null)
- throw new AssertionError("urlClassPath not set in URLClassLoader");
- Field loadersField = urlClassPath.getClass().getDeclaredField("loaders");
- return (ArrayList<?>) getField(urlClassPath, loadersField);
- }
-
- private Object getField(Object o, Field f)
- throws IllegalArgumentException, IllegalAccessException {
- boolean prev = f.isAccessible();
- try {
- f.setAccessible(true);
- return f.get(o);
- } finally {
- f.setAccessible(prev);
- }
- }
-
-}
--- a/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java Thu Dec 17 14:10:44 2009 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java Sat Dec 19 10:26:47 2009 -0800
@@ -26,29 +26,16 @@
package com.sun.tools.javac.file;
import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
import java.io.File;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.io.InputStream;
import java.io.OutputStreamWriter;
-import java.lang.ref.SoftReference;
-import java.lang.reflect.Constructor;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
-import java.net.URLClassLoader;
-import java.nio.ByteBuffer;
import java.nio.CharBuffer;
-import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CoderResult;
-import java.nio.charset.CodingErrorAction;
-import java.nio.charset.IllegalCharsetNameException;
-import java.nio.charset.UnsupportedCharsetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -66,18 +53,13 @@
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
-import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.file.RelativePath.RelativeFile;
import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
-import com.sun.tools.javac.main.JavacOption;
import com.sun.tools.javac.main.OptionName;
-import com.sun.tools.javac.main.RecognizedOptions;
+import com.sun.tools.javac.util.BaseFileManager;
import com.sun.tools.javac.util.Context;
-import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
-import com.sun.tools.javac.util.Log;
-import com.sun.tools.javac.util.Options;
import static javax.tools.StandardLocation.*;
import static com.sun.tools.javac.main.OptionName.*;
@@ -91,7 +73,7 @@
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
-public class JavacFileManager implements StandardJavaFileManager {
+public class JavacFileManager extends BaseFileManager implements StandardJavaFileManager {
boolean useZipFileIndex;
@@ -102,17 +84,10 @@
return buffer.toString().toCharArray();
}
- /**
- * The log to be used for error reporting.
- */
- protected Log log;
-
/** Encapsulates knowledge of paths
*/
private Paths paths;
- private Options options;
-
private FSInfo fsInfo;
private final File uninited = new File("U N I N I T E D");
@@ -134,12 +109,6 @@
protected boolean mmappedIO;
protected boolean ignoreSymbolFile;
- protected String classLoaderClass;
-
- /**
- * User provided charset (through javax.tools).
- */
- protected Charset charset;
/**
* Register a Context.Factory to create a JavacFileManager.
@@ -157,18 +126,18 @@
* it as the JavaFileManager for that context.
*/
public JavacFileManager(Context context, boolean register, Charset charset) {
+ super(charset);
if (register)
context.put(JavaFileManager.class, this);
- byteBufferCache = new ByteBufferCache();
- this.charset = charset;
setContext(context);
}
/**
* Set the context for JavacFileManager.
*/
+ @Override
public void setContext(Context context) {
- log = Log.instance(context);
+ super.setContext(context);
if (paths == null) {
paths = Paths.instance(context);
} else {
@@ -177,14 +146,12 @@
paths.setContext(context);
}
- options = Options.instance(context);
fsInfo = FSInfo.instance(context);
useZipFileIndex = System.getProperty("useJavaUtilZip") == null;// TODO: options.get("useJavaUtilZip") == null;
mmappedIO = options.get("mmappedIO") != null;
ignoreSymbolFile = options.get("ignore.symbol.file") != null;
- classLoaderClass = options.get("procloader");
}
public JavaFileObject getFileForInput(String name) {
@@ -214,17 +181,6 @@
return getJavaFileObjectsFromStrings(Arrays.asList(nullCheck(names)));
}
- protected JavaFileObject.Kind getKind(String extension) {
- if (extension.equals(JavaFileObject.Kind.CLASS.extension))
- return JavaFileObject.Kind.CLASS;
- else if (extension.equals(JavaFileObject.Kind.SOURCE.extension))
- return JavaFileObject.Kind.SOURCE;
- else if (extension.equals(JavaFileObject.Kind.HTML.extension))
- return JavaFileObject.Kind.HTML;
- else
- return JavaFileObject.Kind.OTHER;
- }
-
private static boolean isValidName(String name) {
// Arguably, isValidName should reject keywords (such as in SourceVersion.isName() ),
// but the set of keywords depends on the source level, and we don't want
@@ -359,9 +315,7 @@
}
private boolean isValidFile(String s, Set<JavaFileObject.Kind> fileKinds) {
- int lastDot = s.lastIndexOf(".");
- String extn = (lastDot == -1 ? s : s.substring(lastDot));
- JavaFileObject.Kind kind = getKind(extn);
+ JavaFileObject.Kind kind = getKind(s);
return fileKinds.contains(kind);
}
@@ -564,18 +518,6 @@
}
}
- CharBuffer getCachedContent(JavaFileObject file) {
- SoftReference<CharBuffer> r = contentCache.get(file);
- return (r == null ? null : r.get());
- }
-
- void cache(JavaFileObject file, CharBuffer cb) {
- contentCache.put(file, new SoftReference<CharBuffer>(cb));
- }
-
- private final Map<JavaFileObject, SoftReference<CharBuffer>> contentCache
- = new HashMap<JavaFileObject, SoftReference<CharBuffer>>();
-
private String defaultEncodingName;
private String getDefaultEncodingName() {
if (defaultEncodingName == null) {
@@ -585,161 +527,6 @@
return defaultEncodingName;
}
- protected String getEncodingName() {
- String encName = options.get(OptionName.ENCODING);
- if (encName == null)
- return getDefaultEncodingName();
- else
- return encName;
- }
-
- protected Source getSource() {
- String sourceName = options.get(OptionName.SOURCE);
- Source source = null;
- if (sourceName != null)
- source = Source.lookup(sourceName);
- return (source != null ? source : Source.DEFAULT);
- }
-
- /**
- * Make a byte buffer from an input stream.
- */
- ByteBuffer makeByteBuffer(InputStream in)
- throws IOException {
- int limit = in.available();
- if (mmappedIO && in instanceof FileInputStream) {
- // Experimental memory mapped I/O
- FileInputStream fin = (FileInputStream)in;
- return fin.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, limit);
- }
- if (limit < 1024) limit = 1024;
- ByteBuffer result = byteBufferCache.get(limit);
- int position = 0;
- while (in.available() != 0) {
- if (position >= limit)
- // expand buffer
- result = ByteBuffer.
- allocate(limit <<= 1).
- put((ByteBuffer)result.flip());
- int count = in.read(result.array(),
- position,
- limit - position);
- if (count < 0) break;
- result.position(position += count);
- }
- return (ByteBuffer)result.flip();
- }
-
- void recycleByteBuffer(ByteBuffer bb) {
- byteBufferCache.put(bb);
- }
-
- /**
- * A single-element cache of direct byte buffers.
- */
- private static class ByteBufferCache {
- private ByteBuffer cached;
- ByteBuffer get(int capacity) {
- if (capacity < 20480) capacity = 20480;
- ByteBuffer result =
- (cached != null && cached.capacity() >= capacity)
- ? (ByteBuffer)cached.clear()
- : ByteBuffer.allocate(capacity + capacity>>1);
- cached = null;
- return result;
- }
- void put(ByteBuffer x) {
- cached = x;
- }
- }
-
- private final ByteBufferCache byteBufferCache;
-
- CharsetDecoder getDecoder(String encodingName, boolean ignoreEncodingErrors) {
- Charset cs = (this.charset == null)
- ? Charset.forName(encodingName)
- : this.charset;
- CharsetDecoder decoder = cs.newDecoder();
-
- CodingErrorAction action;
- if (ignoreEncodingErrors)
- action = CodingErrorAction.REPLACE;
- else
- action = CodingErrorAction.REPORT;
-
- return decoder
- .onMalformedInput(action)
- .onUnmappableCharacter(action);
- }
-
- /**
- * Decode a ByteBuffer into a CharBuffer.
- */
- CharBuffer decode(ByteBuffer inbuf, boolean ignoreEncodingErrors) {
- String encodingName = getEncodingName();
- CharsetDecoder decoder;
- try {
- decoder = getDecoder(encodingName, ignoreEncodingErrors);
- } catch (IllegalCharsetNameException e) {
- log.error("unsupported.encoding", encodingName);
- return (CharBuffer)CharBuffer.allocate(1).flip();
- } catch (UnsupportedCharsetException e) {
- log.error("unsupported.encoding", encodingName);
- return (CharBuffer)CharBuffer.allocate(1).flip();
- }
-
- // slightly overestimate the buffer size to avoid reallocation.
- float factor =
- decoder.averageCharsPerByte() * 0.8f +
- decoder.maxCharsPerByte() * 0.2f;
- CharBuffer dest = CharBuffer.
- allocate(10 + (int)(inbuf.remaining()*factor));
-
- while (true) {
- CoderResult result = decoder.decode(inbuf, dest, true);
- dest.flip();
-
- if (result.isUnderflow()) { // done reading
- // make sure there is at least one extra character
- if (dest.limit() == dest.capacity()) {
- dest = CharBuffer.allocate(dest.capacity()+1).put(dest);
- dest.flip();
- }
- return dest;
- } else if (result.isOverflow()) { // buffer too small; expand
- int newCapacity =
- 10 + dest.capacity() +
- (int)(inbuf.remaining()*decoder.maxCharsPerByte());
- dest = CharBuffer.allocate(newCapacity).put(dest);
- } else if (result.isMalformed() || result.isUnmappable()) {
- // bad character in input
-
- // report coding error (warn only pre 1.5)
- if (!getSource().allowEncodingErrors()) {
- log.error(new SimpleDiagnosticPosition(dest.limit()),
- "illegal.char.for.encoding",
- charset == null ? encodingName : charset.name());
- } else {
- log.warning(new SimpleDiagnosticPosition(dest.limit()),
- "illegal.char.for.encoding",
- charset == null ? encodingName : charset.name());
- }
-
- // skip past the coding error
- inbuf.position(inbuf.position() + result.length());
-
- // undo the flip() to prepare the output buffer
- // for more translation
- dest.position(dest.limit());
- dest.limit(dest.capacity());
- dest.put((char)0xfffd); // backward compatible
- } else {
- throw new AssertionError(result);
- }
- }
- // unreached
- }
-
public ClassLoader getClassLoader(Location location) {
nullCheck(location);
Iterable<? extends File> path = getLocation(location);
@@ -754,39 +541,7 @@
}
}
- URL[] urls = lb.toArray(new URL[lb.size()]);
- ClassLoader thisClassLoader = getClass().getClassLoader();
-
- // Bug: 6558476
- // Ideally, ClassLoader should be Closeable, but before JDK7 it is not.
- // On older versions, try the following, to get a closeable classloader.
-
- // 1: Allow client to specify the class to use via hidden option
- if (classLoaderClass != null) {
- try {
- Class<? extends ClassLoader> loader =
- Class.forName(classLoaderClass).asSubclass(ClassLoader.class);
- Class<?>[] constrArgTypes = { URL[].class, ClassLoader.class };
- Constructor<? extends ClassLoader> constr = loader.getConstructor(constrArgTypes);
- return constr.newInstance(new Object[] { urls, thisClassLoader });
- } catch (Throwable t) {
- // ignore errors loading user-provided class loader, fall through
- }
- }
-
- // 2: If URLClassLoader implements Closeable, use that.
- if (Closeable.class.isAssignableFrom(URLClassLoader.class))
- return new URLClassLoader(urls, thisClassLoader);
-
- // 3: Try using private reflection-based CloseableURLClassLoader
- try {
- return new CloseableURLClassLoader(urls, thisClassLoader);
- } catch (Throwable t) {
- // ignore errors loading workaround class loader, fall through
- }
-
- // 4: If all else fails, use plain old standard URLClassLoader
- return new URLClassLoader(urls, thisClassLoader);
+ return getClassLoader(lb.toArray(new URL[lb.size()]));
}
public Iterable<JavaFileObject> list(Location location,
@@ -836,38 +591,6 @@
return a.equals(b);
}
- public boolean handleOption(String current, Iterator<String> remaining) {
- for (JavacOption o: javacFileManagerOptions) {
- if (o.matches(current)) {
- if (o.hasArg()) {
- if (remaining.hasNext()) {
- if (!o.process(options, current, remaining.next()))
- return true;
- }
- } else {
- if (!o.process(options, current))
- return true;
- }
- // operand missing, or process returned false
- throw new IllegalArgumentException(current);
- }
- }
-
- return false;
- }
- // where
- private static JavacOption[] javacFileManagerOptions =
- RecognizedOptions.getJavacFileManagerOptions(
- new RecognizedOptions.GrumpyHelper());
-
- public int isSupportedOption(String option) {
- for (JavacOption o : javacFileManagerOptions) {
- if (o.matches(option))
- return o.hasArg() ? 1 : 0;
- }
- return -1;
- }
-
public boolean hasLocation(Location location) {
return getLocation(location) != null;
}
@@ -1115,15 +838,4 @@
}
throw new IllegalArgumentException("Invalid relative path: " + file);
}
-
- private static <T> T nullCheck(T o) {
- o.getClass(); // null check
- return o;
- }
-
- private static <T> Iterable<T> nullCheck(Iterable<T> it) {
- for (T t : it)
- t.getClass(); // null check
- return it;
- }
}
--- a/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java Thu Dec 17 14:10:44 2009 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java Sat Dec 19 10:26:47 2009 -0800
@@ -66,7 +66,7 @@
* @param context the context
* @return the Paths instance for this context
*/
- static Paths instance(Context context) {
+ public static Paths instance(Context context) {
Paths instance = context.get(pathsKey);
if (instance == null)
instance = new Paths(context);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,543 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.nio;
+
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitOption;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.Attributes;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import javax.lang.model.SourceVersion;
+import javax.tools.FileObject;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.StandardLocation;
+
+import static java.nio.file.FileVisitOption.*;
+import static javax.tools.StandardLocation.*;
+
+import com.sun.tools.javac.file.Paths;
+import com.sun.tools.javac.util.BaseFileManager;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+
+import static com.sun.tools.javac.main.OptionName.*;
+
+
+// NOTE the imports carefully for this compilation unit.
+//
+// Path: java.nio.file.Path -- the new NIO type for which this file manager exists
+//
+// Paths: com.sun.tools.javac.file.Paths -- legacy javac type for handling path options
+// The other Paths (java.nio.file.Paths) is not used
+
+// NOTE this and related classes depend on new API in JDK 7.
+// This requires special handling while bootstrapping the JDK build,
+// when these classes might not yet have been compiled. To workaround
+// this, the build arranges to make stubs of these classes available
+// when compiling this and related classes. The set of stub files
+// is specified in make/build.properties.
+
+/**
+ * Implementation of PathFileManager: a JavaFileManager based on the use
+ * of java.nio.file.Path.
+ *
+ * <p>Just as a Path is somewhat analagous to a File, so too is this
+ * JavacPathFileManager analogous to JavacFileManager, as it relates to the
+ * support of FileObjects based on File objects (i.e. just RegularFileObject,
+ * not ZipFileObject and its variants.)
+ *
+ * <p>The default values for the standard locations supported by this file
+ * manager are the same as the default values provided by JavacFileManager --
+ * i.e. as determined by the javac.file.Paths class. To override these values,
+ * call {@link #setLocation}.
+ *
+ * <p>To reduce confusion with Path objects, the locations such as "class path",
+ * "source path", etc, are generically referred to here as "search paths".
+ *
+ * <p><b>This is NOT part of any API supported by Sun Microsystems. 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>
+ */
+public class JavacPathFileManager extends BaseFileManager implements PathFileManager {
+ protected FileSystem defaultFileSystem;
+
+ /**
+ * Create a JavacPathFileManager using a given context, optionally registering
+ * it as the JavaFileManager for that context.
+ */
+ public JavacPathFileManager(Context context, boolean register, Charset charset) {
+ super(charset);
+ if (register)
+ context.put(JavaFileManager.class, this);
+ pathsForLocation = new HashMap<Location, PathsForLocation>();
+ fileSystems = new HashMap<Path,FileSystem>();
+ setContext(context);
+ }
+
+ /**
+ * Set the context for JavacPathFileManager.
+ */
+ @Override
+ protected void setContext(Context context) {
+ super.setContext(context);
+ searchPaths = Paths.instance(context);
+ }
+
+ @Override
+ public FileSystem getDefaultFileSystem() {
+ if (defaultFileSystem == null)
+ defaultFileSystem = FileSystems.getDefault();
+ return defaultFileSystem;
+ }
+
+ @Override
+ public void setDefaultFileSystem(FileSystem fs) {
+ defaultFileSystem = fs;
+ }
+
+ @Override
+ public void flush() throws IOException {
+ contentCache.clear();
+ }
+
+ @Override
+ public void close() throws IOException {
+ for (FileSystem fs: fileSystems.values())
+ fs.close();
+ }
+
+ @Override
+ public ClassLoader getClassLoader(Location location) {
+ nullCheck(location);
+ Iterable<? extends Path> path = getLocation(location);
+ if (path == null)
+ return null;
+ ListBuffer<URL> lb = new ListBuffer<URL>();
+ for (Path p: path) {
+ try {
+ lb.append(p.toUri().toURL());
+ } catch (MalformedURLException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ return getClassLoader(lb.toArray(new URL[lb.size()]));
+ }
+
+ // <editor-fold defaultstate="collapsed" desc="Location handling">
+
+ public boolean hasLocation(Location location) {
+ return (getLocation(location) != null);
+ }
+
+ public Iterable<? extends Path> getLocation(Location location) {
+ nullCheck(location);
+ lazyInitSearchPaths();
+ PathsForLocation path = pathsForLocation.get(location);
+ if (path == null && !pathsForLocation.containsKey(location)) {
+ setDefaultForLocation(location);
+ path = pathsForLocation.get(location);
+ }
+ return path;
+ }
+
+ private Path getOutputLocation(Location location) {
+ Iterable<? extends Path> paths = getLocation(location);
+ return (paths == null ? null : paths.iterator().next());
+ }
+
+ public void setLocation(Location location, Iterable<? extends Path> searchPath)
+ throws IOException
+ {
+ nullCheck(location);
+ lazyInitSearchPaths();
+ if (searchPath == null) {
+ setDefaultForLocation(location);
+ } else {
+ if (location.isOutputLocation())
+ checkOutputPath(searchPath);
+ PathsForLocation pl = new PathsForLocation();
+ for (Path p: searchPath)
+ pl.add(p); // TODO -Xlint:path warn if path not found
+ pathsForLocation.put(location, pl);
+ }
+ }
+
+ private void checkOutputPath(Iterable<? extends Path> searchPath) throws IOException {
+ Iterator<? extends Path> pathIter = searchPath.iterator();
+ if (!pathIter.hasNext())
+ throw new IllegalArgumentException("empty path for directory");
+ Path path = pathIter.next();
+ if (pathIter.hasNext())
+ throw new IllegalArgumentException("path too long for directory");
+ if (!path.exists())
+ throw new FileNotFoundException(path + ": does not exist");
+ else if (!isDirectory(path))
+ throw new IOException(path + ": not a directory");
+ }
+
+ private void setDefaultForLocation(Location locn) {
+ Collection<File> files = null;
+ if (locn instanceof StandardLocation) {
+ switch ((StandardLocation) locn) {
+ case CLASS_PATH:
+ files = searchPaths.userClassPath();
+ break;
+ case PLATFORM_CLASS_PATH:
+ files = searchPaths.bootClassPath();
+ break;
+ case SOURCE_PATH:
+ files = searchPaths.sourcePath();
+ break;
+ case CLASS_OUTPUT: {
+ String arg = options.get(D);
+ files = (arg == null ? null : Collections.singleton(new File(arg)));
+ break;
+ }
+ case SOURCE_OUTPUT: {
+ String arg = options.get(S);
+ files = (arg == null ? null : Collections.singleton(new File(arg)));
+ break;
+ }
+ }
+ }
+
+ PathsForLocation pl = new PathsForLocation();
+ if (files != null) {
+ for (File f: files)
+ pl.add(f.toPath());
+ }
+ pathsForLocation.put(locn, pl);
+ }
+
+ private void lazyInitSearchPaths() {
+ if (!inited) {
+ setDefaultForLocation(PLATFORM_CLASS_PATH);
+ setDefaultForLocation(CLASS_PATH);
+ setDefaultForLocation(SOURCE_PATH);
+ inited = true;
+ }
+ }
+ // where
+ private boolean inited = false;
+
+ private Map<Location, PathsForLocation> pathsForLocation;
+ private Paths searchPaths;
+
+ private static class PathsForLocation extends LinkedHashSet<Path> {
+ private static final long serialVersionUID = 6788510222394486733L;
+ }
+
+ // </editor-fold>
+
+ // <editor-fold defaultstate="collapsed" desc="FileObject handling">
+
+ @Override
+ public Path getPath(FileObject fo) {
+ nullCheck(fo);
+ if (!(fo instanceof PathFileObject))
+ throw new IllegalArgumentException();
+ return ((PathFileObject) fo).getPath();
+ }
+
+ @Override
+ public boolean isSameFile(FileObject a, FileObject b) {
+ nullCheck(a);
+ nullCheck(b);
+ if (!(a instanceof PathFileObject))
+ throw new IllegalArgumentException("Not supported: " + a);
+ if (!(b instanceof PathFileObject))
+ throw new IllegalArgumentException("Not supported: " + b);
+ return ((PathFileObject) a).isSameFile((PathFileObject) b);
+ }
+
+ @Override
+ public Iterable<JavaFileObject> list(Location location,
+ String packageName, Set<Kind> kinds, boolean recurse)
+ throws IOException {
+ // validatePackageName(packageName);
+ nullCheck(packageName);
+ nullCheck(kinds);
+
+ Iterable<? extends Path> paths = getLocation(location);
+ if (paths == null)
+ return List.nil();
+ ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
+
+ for (Path path : paths)
+ list(path, packageName, kinds, recurse, results);
+
+ return results.toList();
+ }
+
+ private void list(Path path, String packageName, final Set<Kind> kinds,
+ boolean recurse, final ListBuffer<JavaFileObject> results)
+ throws IOException {
+ if (!path.exists())
+ return;
+
+ final Path pathDir;
+ if (isDirectory(path))
+ pathDir = path;
+ else {
+ FileSystem fs = getFileSystem(path);
+ if (fs == null)
+ return;
+ pathDir = fs.getRootDirectories().iterator().next();
+ }
+ String sep = path.getFileSystem().getSeparator();
+ Path packageDir = packageName.isEmpty() ? pathDir
+ : pathDir.resolve(packageName.replace(".", sep));
+ if (!packageDir.exists())
+ return;
+
+/* Alternate impl of list, superceded by use of Files.walkFileTree */
+// Deque<Path> queue = new LinkedList<Path>();
+// queue.add(packageDir);
+//
+// Path dir;
+// while ((dir = queue.poll()) != null) {
+// DirectoryStream<Path> ds = dir.newDirectoryStream();
+// try {
+// for (Path p: ds) {
+// String name = p.getName().toString();
+// if (isDirectory(p)) {
+// if (recurse && SourceVersion.isIdentifier(name)) {
+// queue.add(p);
+// }
+// } else {
+// if (kinds.contains(getKind(name))) {
+// JavaFileObject fe =
+// PathFileObject.createDirectoryPathFileObject(this, p, pathDir);
+// results.append(fe);
+// }
+// }
+// }
+// } finally {
+// ds.close();
+// }
+// }
+ int maxDepth = (recurse ? Integer.MAX_VALUE : 1);
+ Set<FileVisitOption> opts = EnumSet.of(DETECT_CYCLES, FOLLOW_LINKS);
+ Files.walkFileTree(packageDir, opts, maxDepth,
+ new SimpleFileVisitor<Path>() {
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir) {
+ if (SourceVersion.isIdentifier(dir.getName().toString())) // JSR 292?
+ return FileVisitResult.CONTINUE;
+ else
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ if (attrs.isRegularFile() && kinds.contains(getKind(file.getName().toString()))) {
+ JavaFileObject fe =
+ PathFileObject.createDirectoryPathFileObject(
+ JavacPathFileManager.this, file, pathDir);
+ results.append(fe);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ }
+
+ @Override
+ public Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths(
+ Iterable<? extends Path> paths) {
+ ArrayList<PathFileObject> result;
+ if (paths instanceof Collection<?>)
+ result = new ArrayList<PathFileObject>(((Collection<?>)paths).size());
+ else
+ result = new ArrayList<PathFileObject>();
+ for (Path p: paths)
+ result.add(PathFileObject.createSimplePathFileObject(this, nullCheck(p)));
+ return result;
+ }
+
+ @Override
+ public Iterable<? extends JavaFileObject> getJavaFileObjects(Path... paths) {
+ return getJavaFileObjectsFromPaths(Arrays.asList(nullCheck(paths)));
+ }
+
+ @Override
+ public JavaFileObject getJavaFileForInput(Location location,
+ String className, Kind kind) throws IOException {
+ return getFileForInput(location, getRelativePath(className, kind));
+ }
+
+ @Override
+ public FileObject getFileForInput(Location location,
+ String packageName, String relativeName) throws IOException {
+ return getFileForInput(location, getRelativePath(packageName, relativeName));
+ }
+
+ private JavaFileObject getFileForInput(Location location, String relativePath)
+ throws IOException {
+ for (Path p: getLocation(location)) {
+ if (isDirectory(p)) {
+ Path f = resolve(p, relativePath);
+ if (f.exists())
+ return PathFileObject.createDirectoryPathFileObject(this, f, p);
+ } else {
+ FileSystem fs = getFileSystem(p);
+ if (fs != null) {
+ Path file = getPath(fs, relativePath);
+ if (file.exists())
+ return PathFileObject.createJarPathFileObject(this, file);
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public JavaFileObject getJavaFileForOutput(Location location,
+ String className, Kind kind, FileObject sibling) throws IOException {
+ return getFileForOutput(location, getRelativePath(className, kind), sibling);
+ }
+
+ @Override
+ public FileObject getFileForOutput(Location location, String packageName,
+ String relativeName, FileObject sibling)
+ throws IOException {
+ return getFileForOutput(location, getRelativePath(packageName, relativeName), sibling);
+ }
+
+ private JavaFileObject getFileForOutput(Location location,
+ String relativePath, FileObject sibling) {
+ Path dir = getOutputLocation(location);
+ if (dir == null) {
+ if (location == CLASS_OUTPUT) {
+ Path siblingDir = null;
+ if (sibling != null && sibling instanceof PathFileObject) {
+ siblingDir = ((PathFileObject) sibling).getPath().getParent();
+ }
+ return PathFileObject.createSiblingPathFileObject(this,
+ siblingDir.resolve(getBaseName(relativePath)),
+ relativePath);
+ } else if (location == SOURCE_OUTPUT) {
+ dir = getOutputLocation(CLASS_OUTPUT);
+ }
+ }
+
+ Path file;
+ if (dir != null) {
+ file = resolve(dir, relativePath);
+ return PathFileObject.createDirectoryPathFileObject(this, file, dir);
+ } else {
+ file = getPath(getDefaultFileSystem(), relativePath);
+ return PathFileObject.createSimplePathFileObject(this, file);
+ }
+
+ }
+
+ @Override
+ public String inferBinaryName(Location location, JavaFileObject fo) {
+ nullCheck(fo);
+ // Need to match the path semantics of list(location, ...)
+ Iterable<? extends Path> paths = getLocation(location);
+ if (paths == null) {
+ return null;
+ }
+
+ if (!(fo instanceof PathFileObject))
+ throw new IllegalArgumentException(fo.getClass().getName());
+
+ return ((PathFileObject) fo).inferBinaryName(paths);
+ }
+
+ private FileSystem getFileSystem(Path p) throws IOException {
+ FileSystem fs = fileSystems.get(p);
+ if (fs == null) {
+ fs = FileSystems.newFileSystem(p, Collections.<String,Void>emptyMap(), null);
+ fileSystems.put(p, fs);
+ }
+ return fs;
+ }
+
+ private Map<Path,FileSystem> fileSystems;
+
+ // </editor-fold>
+
+ // <editor-fold defaultstate="collapsed" desc="Utility methods">
+
+ private static String getRelativePath(String className, Kind kind) {
+ return className.replace(".", "/") + kind.extension;
+ }
+
+ private static String getRelativePath(String packageName, String relativeName) {
+ return packageName.replace(".", "/") + relativeName;
+ }
+
+ private static String getBaseName(String relativePath) {
+ int lastSep = relativePath.lastIndexOf("/");
+ return relativePath.substring(lastSep + 1); // safe if "/" not found
+ }
+
+ private static boolean isDirectory(Path path) throws IOException {
+ BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path);
+ return attrs.isDirectory();
+ }
+
+ private static Path getPath(FileSystem fs, String relativePath) {
+ return fs.getPath(relativePath.replace("/", fs.getSeparator()));
+ }
+
+ private static Path resolve(Path base, String relativePath) {
+ FileSystem fs = base.getFileSystem();
+ Path rp = fs.getPath(relativePath.replace("/", fs.getSeparator()));
+ return base.resolve(rp);
+ }
+
+ // </editor-fold>
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/nio/PathFileManager.java Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.nio;
+
+import java.io.IOException;
+import java.nio.file.FileSystem;
+import java.nio.file.Path;
+import javax.tools.FileObject;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+
+/**
+ * File manager based on {@linkplain File java.nio.file.Path}.
+ *
+ * Eventually, this should be moved to javax.tools.
+ * Also, JavaCompiler might reasonably provide a method getPathFileManager,
+ * similar to {@link javax.tools.JavaCompiler#getStandardFileManager
+ * getStandardFileManager}. However, would need to be handled carefully
+ * as another forward reference from langtools to jdk.
+ *
+ * <p><b>This is NOT part of any API supported by Sun Microsystems. 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>
+ */
+public interface PathFileManager extends JavaFileManager {
+ /**
+ * Get the default file system used to create paths. If no value has been
+ * set, the default file system is {@link FileSystems#getDefault}.
+ */
+ FileSystem getDefaultFileSystem();
+
+ /**
+ * Set the default file system used to create paths.
+ * @param fs the default file system used to create any new paths.
+ */
+ void setDefaultFileSystem(FileSystem fs);
+
+ /**
+ * Get file objects representing the given files.
+ *
+ * @param paths a list of paths
+ * @return a list of file objects
+ * @throws IllegalArgumentException if the list of paths includes
+ * a directory
+ */
+ Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths(
+ Iterable<? extends Path> paths);
+
+ /**
+ * Get file objects representing the given paths.
+ * Convenience method equivalent to:
+ *
+ * <pre>
+ * getJavaFileObjectsFromPaths({@linkplain java.util.Arrays#asList Arrays.asList}(paths))
+ * </pre>
+ *
+ * @param paths an array of paths
+ * @return a list of file objects
+ * @throws IllegalArgumentException if the array of files includes
+ * a directory
+ * @throws NullPointerException if the given array contains null
+ * elements
+ */
+ Iterable<? extends JavaFileObject> getJavaFileObjects(Path... paths);
+
+ /**
+ * Return the Path for a file object that has been obtained from this
+ * file manager.
+ *
+ * @param fo A file object that has been obtained from this file manager.
+ * @return The underlying Path object.
+ * @throws IllegalArgumentException is the file object was not obtained from
+ * from this file manager.
+ */
+ Path getPath(FileObject fo);
+
+ /**
+ * Get the search path associated with the given location.
+ *
+ * @param location a location
+ * @return a list of paths or {@code null} if this location has no
+ * associated search path
+ * @see #setLocation
+ */
+ Iterable<? extends Path> getLocation(Location location);
+
+ /**
+ * Associate the given search path with the given location. Any
+ * previous value will be discarded.
+ *
+ * @param location a location
+ * @param searchPath a list of files, if {@code null} use the default
+ * search path for this location
+ * @see #getLocation
+ * @throws IllegalArgumentException if location is an output
+ * location and searchpath does not contain exactly one element
+ * @throws IOException if location is an output location and searchpath
+ * does not represent an existing directory
+ */
+ void setLocation(Location location, Iterable<? extends Path> searchPath) throws IOException;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/nio/PathFileObject.java Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.nio;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharsetDecoder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.Attributes;
+import java.nio.file.attribute.BasicFileAttributes;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.NestingKind;
+import javax.tools.JavaFileObject;
+
+import com.sun.tools.javac.util.BaseFileManager;
+
+
+/**
+ * Implementation of JavaFileObject using java.nio.file API.
+ *
+ * <p>PathFileObjects are, for the most part, straightforward wrappers around
+ * Path objects. The primary complexity is the support for "inferBinaryName".
+ * This is left as an abstract method, implemented by each of a number of
+ * different factory methods, which compute the binary name based on
+ * information available at the time the file object is created.
+ *
+ * <p><b>This is NOT part of any API supported by Sun Microsystems. 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>
+ */
+abstract class PathFileObject implements JavaFileObject {
+ private JavacPathFileManager fileManager;
+ private Path path;
+
+ /**
+ * Create a PathFileObject within a directory, such that the binary name
+ * can be inferred from the relationship to the parent directory.
+ */
+ static PathFileObject createDirectoryPathFileObject(JavacPathFileManager fileManager,
+ final Path path, final Path dir) {
+ return new PathFileObject(fileManager, path) {
+ @Override
+ String inferBinaryName(Iterable<? extends Path> paths) {
+ return toBinaryName(dir.relativize(path));
+ }
+ };
+ }
+
+ /**
+ * Create a PathFileObject in a file system such as a jar file, such that
+ * the binary name can be inferred from its position within the filesystem.
+ */
+ static PathFileObject createJarPathFileObject(JavacPathFileManager fileManager,
+ final Path path) {
+ return new PathFileObject(fileManager, path) {
+ @Override
+ String inferBinaryName(Iterable<? extends Path> paths) {
+ return toBinaryName(path);
+ }
+ };
+ }
+
+ /**
+ * Create a PathFileObject whose binary name can be inferred from the
+ * relative path to a sibling.
+ */
+ static PathFileObject createSiblingPathFileObject(JavacPathFileManager fileManager,
+ final Path path, final String relativePath) {
+ return new PathFileObject(fileManager, path) {
+ @Override
+ String inferBinaryName(Iterable<? extends Path> paths) {
+ return toBinaryName(relativePath, "/");
+ }
+ };
+ }
+
+ /**
+ * Create a PathFileObject whose binary name might be inferred from its
+ * position on a search path.
+ */
+ static PathFileObject createSimplePathFileObject(JavacPathFileManager fileManager,
+ final Path path) {
+ return new PathFileObject(fileManager, path) {
+ @Override
+ String inferBinaryName(Iterable<? extends Path> paths) {
+ Path absPath = path.toAbsolutePath();
+ for (Path p: paths) {
+ Path ap = p.toAbsolutePath();
+ if (absPath.startsWith(ap)) {
+ try {
+ Path rp = ap.relativize(absPath);
+ if (rp != null) // maybe null if absPath same as ap
+ return toBinaryName(rp);
+ } catch (IllegalArgumentException e) {
+ // ignore this p if cannot relativize path to p
+ }
+ }
+ }
+ return null;
+ }
+ };
+ }
+
+ protected PathFileObject(JavacPathFileManager fileManager, Path path) {
+ fileManager.getClass(); // null check
+ path.getClass(); // null check
+ this.fileManager = fileManager;
+ this.path = path;
+ }
+
+ abstract String inferBinaryName(Iterable<? extends Path> paths);
+
+ /**
+ * Return the Path for this object.
+ * @return the Path for this object.
+ */
+ Path getPath() {
+ return path;
+ }
+
+ @Override
+ public Kind getKind() {
+ return BaseFileManager.getKind(path.getName().toString());
+ }
+
+ @Override
+ public boolean isNameCompatible(String simpleName, Kind kind) {
+ simpleName.getClass();
+ // null check
+ if (kind == Kind.OTHER && getKind() != kind) {
+ return false;
+ }
+ String sn = simpleName + kind.extension;
+ String pn = path.getName().toString();
+ if (pn.equals(sn)) {
+ return true;
+ }
+ if (pn.equalsIgnoreCase(sn)) {
+ try {
+ // allow for Windows
+ return path.toRealPath(false).getName().toString().equals(sn);
+ } catch (IOException e) {
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public NestingKind getNestingKind() {
+ return null;
+ }
+
+ @Override
+ public Modifier getAccessLevel() {
+ return null;
+ }
+
+ @Override
+ public URI toUri() {
+ return path.toUri();
+ }
+
+ @Override
+ public String getName() {
+ return path.toString();
+ }
+
+ @Override
+ public InputStream openInputStream() throws IOException {
+ return path.newInputStream();
+ }
+
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ ensureParentDirectoriesExist();
+ return path.newOutputStream();
+ }
+
+ @Override
+ public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
+ CharsetDecoder decoder = fileManager.getDecoder(fileManager.getEncodingName(), ignoreEncodingErrors);
+ return new InputStreamReader(openInputStream(), decoder);
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ CharBuffer cb = fileManager.getCachedContent(this);
+ if (cb == null) {
+ InputStream in = openInputStream();
+ try {
+ ByteBuffer bb = fileManager.makeByteBuffer(in);
+ JavaFileObject prev = fileManager.log.useSource(this);
+ try {
+ cb = fileManager.decode(bb, ignoreEncodingErrors);
+ } finally {
+ fileManager.log.useSource(prev);
+ }
+ fileManager.recycleByteBuffer(bb);
+ if (!ignoreEncodingErrors) {
+ fileManager.cache(this, cb);
+ }
+ } finally {
+ in.close();
+ }
+ }
+ return cb;
+ }
+
+ @Override
+ public Writer openWriter() throws IOException {
+ ensureParentDirectoriesExist();
+ return new OutputStreamWriter(path.newOutputStream(), fileManager.getEncodingName());
+ }
+
+ @Override
+ public long getLastModified() {
+ try {
+ BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path);
+ return attrs.lastModifiedTime().toMillis();
+ } catch (IOException e) {
+ return -1;
+ }
+ }
+
+ @Override
+ public boolean delete() {
+ try {
+ path.delete();
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ public boolean isSameFile(PathFileObject other) {
+ try {
+ return path.isSameFile(other.path);
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return (other instanceof PathFileObject && path.equals(((PathFileObject) other).path));
+ }
+
+ @Override
+ public int hashCode() {
+ return path.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[" + path + "]";
+ }
+
+ private void ensureParentDirectoriesExist() throws IOException {
+ Path parent = path.getParent();
+ if (parent != null)
+ Files.createDirectories(parent);
+ }
+
+ private long size() {
+ try {
+ BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path);
+ return attrs.size();
+ } catch (IOException e) {
+ return -1;
+ }
+ }
+
+ protected static String toBinaryName(Path relativePath) {
+ return toBinaryName(relativePath.toString(),
+ relativePath.getFileSystem().getSeparator());
+ }
+
+ protected static String toBinaryName(String relativePath, String sep) {
+ return removeExtension(relativePath).replaceAll(sep, ".");
+ }
+
+ protected static String removeExtension(String fileName) {
+ int lastDot = fileName.lastIndexOf(".");
+ return (lastDot == -1 ? fileName : fileName.substring(0, lastDot));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.util;
+
+import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.main.JavacOption;
+import com.sun.tools.javac.main.OptionName;
+import com.sun.tools.javac.main.RecognizedOptions;
+import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.lang.ref.SoftReference;
+import java.lang.reflect.Constructor;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+
+/**
+ * Utility methods for building a filemanager.
+ * There are no references here to file-system specific objects such as
+ * java.io.File or java.nio.file.Path.
+ */
+public class BaseFileManager {
+ protected BaseFileManager(Charset charset) {
+ this.charset = charset;
+ byteBufferCache = new ByteBufferCache();
+ }
+
+ /**
+ * Set the context for JavacPathFileManager.
+ */
+ protected void setContext(Context context) {
+ log = Log.instance(context);
+ options = Options.instance(context);
+ classLoaderClass = options.get("procloader");
+ }
+
+ /**
+ * The log to be used for error reporting.
+ */
+ public Log log;
+
+ /**
+ * User provided charset (through javax.tools).
+ */
+ protected Charset charset;
+
+ protected Options options;
+
+ protected String classLoaderClass;
+
+ protected Source getSource() {
+ String sourceName = options.get(OptionName.SOURCE);
+ Source source = null;
+ if (sourceName != null)
+ source = Source.lookup(sourceName);
+ return (source != null ? source : Source.DEFAULT);
+ }
+
+ protected ClassLoader getClassLoader(URL[] urls) {
+ ClassLoader thisClassLoader = getClass().getClassLoader();
+
+ // Bug: 6558476
+ // Ideally, ClassLoader should be Closeable, but before JDK7 it is not.
+ // On older versions, try the following, to get a closeable classloader.
+
+ // 1: Allow client to specify the class to use via hidden option
+ if (classLoaderClass != null) {
+ try {
+ Class<? extends ClassLoader> loader =
+ Class.forName(classLoaderClass).asSubclass(ClassLoader.class);
+ Class<?>[] constrArgTypes = { URL[].class, ClassLoader.class };
+ Constructor<? extends ClassLoader> constr = loader.getConstructor(constrArgTypes);
+ return constr.newInstance(new Object[] { urls, thisClassLoader });
+ } catch (Throwable t) {
+ // ignore errors loading user-provided class loader, fall through
+ }
+ }
+
+ // 2: If URLClassLoader implements Closeable, use that.
+ if (Closeable.class.isAssignableFrom(URLClassLoader.class))
+ return new URLClassLoader(urls, thisClassLoader);
+
+ // 3: Try using private reflection-based CloseableURLClassLoader
+ try {
+ return new CloseableURLClassLoader(urls, thisClassLoader);
+ } catch (Throwable t) {
+ // ignore errors loading workaround class loader, fall through
+ }
+
+ // 4: If all else fails, use plain old standard URLClassLoader
+ return new URLClassLoader(urls, thisClassLoader);
+ }
+
+ // <editor-fold defaultstate="collapsed" desc="Option handling">
+ public boolean handleOption(String current, Iterator<String> remaining) {
+ for (JavacOption o: javacFileManagerOptions) {
+ if (o.matches(current)) {
+ if (o.hasArg()) {
+ if (remaining.hasNext()) {
+ if (!o.process(options, current, remaining.next()))
+ return true;
+ }
+ } else {
+ if (!o.process(options, current))
+ return true;
+ }
+ // operand missing, or process returned false
+ throw new IllegalArgumentException(current);
+ }
+ }
+
+ return false;
+ }
+ // where
+ private static JavacOption[] javacFileManagerOptions =
+ RecognizedOptions.getJavacFileManagerOptions(
+ new RecognizedOptions.GrumpyHelper());
+
+ public int isSupportedOption(String option) {
+ for (JavacOption o : javacFileManagerOptions) {
+ if (o.matches(option))
+ return o.hasArg() ? 1 : 0;
+ }
+ return -1;
+ }
+ // </editor-fold>
+
+ // <editor-fold defaultstate="collapsed" desc="Encoding">
+ private String defaultEncodingName;
+ private String getDefaultEncodingName() {
+ if (defaultEncodingName == null) {
+ defaultEncodingName =
+ new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding();
+ }
+ return defaultEncodingName;
+ }
+
+ public String getEncodingName() {
+ String encName = options.get(OptionName.ENCODING);
+ if (encName == null)
+ return getDefaultEncodingName();
+ else
+ return encName;
+ }
+
+ public CharBuffer decode(ByteBuffer inbuf, boolean ignoreEncodingErrors) {
+ String encodingName = getEncodingName();
+ CharsetDecoder decoder;
+ try {
+ decoder = getDecoder(encodingName, ignoreEncodingErrors);
+ } catch (IllegalCharsetNameException e) {
+ log.error("unsupported.encoding", encodingName);
+ return (CharBuffer)CharBuffer.allocate(1).flip();
+ } catch (UnsupportedCharsetException e) {
+ log.error("unsupported.encoding", encodingName);
+ return (CharBuffer)CharBuffer.allocate(1).flip();
+ }
+
+ // slightly overestimate the buffer size to avoid reallocation.
+ float factor =
+ decoder.averageCharsPerByte() * 0.8f +
+ decoder.maxCharsPerByte() * 0.2f;
+ CharBuffer dest = CharBuffer.
+ allocate(10 + (int)(inbuf.remaining()*factor));
+
+ while (true) {
+ CoderResult result = decoder.decode(inbuf, dest, true);
+ dest.flip();
+
+ if (result.isUnderflow()) { // done reading
+ // make sure there is at least one extra character
+ if (dest.limit() == dest.capacity()) {
+ dest = CharBuffer.allocate(dest.capacity()+1).put(dest);
+ dest.flip();
+ }
+ return dest;
+ } else if (result.isOverflow()) { // buffer too small; expand
+ int newCapacity =
+ 10 + dest.capacity() +
+ (int)(inbuf.remaining()*decoder.maxCharsPerByte());
+ dest = CharBuffer.allocate(newCapacity).put(dest);
+ } else if (result.isMalformed() || result.isUnmappable()) {
+ // bad character in input
+
+ // report coding error (warn only pre 1.5)
+ if (!getSource().allowEncodingErrors()) {
+ log.error(new SimpleDiagnosticPosition(dest.limit()),
+ "illegal.char.for.encoding",
+ charset == null ? encodingName : charset.name());
+ } else {
+ log.warning(new SimpleDiagnosticPosition(dest.limit()),
+ "illegal.char.for.encoding",
+ charset == null ? encodingName : charset.name());
+ }
+
+ // skip past the coding error
+ inbuf.position(inbuf.position() + result.length());
+
+ // undo the flip() to prepare the output buffer
+ // for more translation
+ dest.position(dest.limit());
+ dest.limit(dest.capacity());
+ dest.put((char)0xfffd); // backward compatible
+ } else {
+ throw new AssertionError(result);
+ }
+ }
+ // unreached
+ }
+
+ public CharsetDecoder getDecoder(String encodingName, boolean ignoreEncodingErrors) {
+ Charset cs = (this.charset == null)
+ ? Charset.forName(encodingName)
+ : this.charset;
+ CharsetDecoder decoder = cs.newDecoder();
+
+ CodingErrorAction action;
+ if (ignoreEncodingErrors)
+ action = CodingErrorAction.REPLACE;
+ else
+ action = CodingErrorAction.REPORT;
+
+ return decoder
+ .onMalformedInput(action)
+ .onUnmappableCharacter(action);
+ }
+ // </editor-fold>
+
+ // <editor-fold defaultstate="collapsed" desc="ByteBuffers">
+ /**
+ * Make a byte buffer from an input stream.
+ */
+ public ByteBuffer makeByteBuffer(InputStream in)
+ throws IOException {
+ int limit = in.available();
+ if (limit < 1024) limit = 1024;
+ ByteBuffer result = byteBufferCache.get(limit);
+ int position = 0;
+ while (in.available() != 0) {
+ if (position >= limit)
+ // expand buffer
+ result = ByteBuffer.
+ allocate(limit <<= 1).
+ put((ByteBuffer)result.flip());
+ int count = in.read(result.array(),
+ position,
+ limit - position);
+ if (count < 0) break;
+ result.position(position += count);
+ }
+ return (ByteBuffer)result.flip();
+ }
+
+ public void recycleByteBuffer(ByteBuffer bb) {
+ byteBufferCache.put(bb);
+ }
+
+ /**
+ * A single-element cache of direct byte buffers.
+ */
+ private static class ByteBufferCache {
+ private ByteBuffer cached;
+ ByteBuffer get(int capacity) {
+ if (capacity < 20480) capacity = 20480;
+ ByteBuffer result =
+ (cached != null && cached.capacity() >= capacity)
+ ? (ByteBuffer)cached.clear()
+ : ByteBuffer.allocate(capacity + capacity>>1);
+ cached = null;
+ return result;
+ }
+ void put(ByteBuffer x) {
+ cached = x;
+ }
+ }
+
+ private final ByteBufferCache byteBufferCache;
+ // </editor-fold>
+
+ // <editor-fold defaultstate="collapsed" desc="Content cache">
+ public CharBuffer getCachedContent(JavaFileObject file) {
+ SoftReference<CharBuffer> r = contentCache.get(file);
+ return (r == null ? null : r.get());
+ }
+
+ public void cache(JavaFileObject file, CharBuffer cb) {
+ contentCache.put(file, new SoftReference<CharBuffer>(cb));
+ }
+
+ protected final Map<JavaFileObject, SoftReference<CharBuffer>> contentCache
+ = new HashMap<JavaFileObject, SoftReference<CharBuffer>>();
+ // </editor-fold>
+
+ public static Kind getKind(String name) {
+ if (name.endsWith(Kind.CLASS.extension))
+ return Kind.CLASS;
+ else if (name.endsWith(Kind.SOURCE.extension))
+ return Kind.SOURCE;
+ else if (name.endsWith(Kind.HTML.extension))
+ return Kind.HTML;
+ else
+ return Kind.OTHER;
+ }
+
+ protected static <T> T nullCheck(T o) {
+ o.getClass(); // null check
+ return o;
+ }
+
+ protected static <T> Collection<T> nullCheck(Collection<T> it) {
+ for (T t : it)
+ t.getClass(); // null check
+ return it;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/CloseableURLClassLoader.java Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.util;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.jar.JarFile;
+
+/**
+ * A URLClassLoader that also implements Closeable.
+ * Reflection is used to access internal data structures in the URLClassLoader,
+ * since no public API exists for this purpose. Therefore this code is somewhat
+ * fragile. Caveat emptor.
+ * @throws Error if the internal data structures are not as expected.
+ *
+ * <p><b>This is NOT part of any API supported by Sun Microsystems. 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>
+ */
+public class CloseableURLClassLoader
+ extends URLClassLoader implements Closeable {
+ public CloseableURLClassLoader(URL[] urls, ClassLoader parent) throws Error {
+ super(urls, parent);
+ try {
+ getLoaders(); //proactive check that URLClassLoader is as expected
+ } catch (Throwable t) {
+ throw new Error("cannot create CloseableURLClassLoader", t);
+ }
+ }
+
+ /**
+ * Close any jar files that may have been opened by the class loader.
+ * Reflection is used to access the jar files in the URLClassLoader's
+ * internal data structures.
+ * @throws java.io.IOException if the jar files cannot be found for any
+ * reson, or if closing the jar file itself causes an IOException.
+ */
+ @Override
+ public void close() throws IOException {
+ try {
+ for (Object l: getLoaders()) {
+ if (l.getClass().getName().equals("sun.misc.URLClassPath$JarLoader")) {
+ Field jarField = l.getClass().getDeclaredField("jar");
+ JarFile jar = (JarFile) getField(l, jarField);
+ if (jar != null) {
+ //System.err.println("CloseableURLClassLoader: closing " + jar);
+ jar.close();
+ }
+ }
+ }
+ } catch (Throwable t) {
+ IOException e = new IOException("cannot close class loader");
+ e.initCause(t);
+ throw e;
+ }
+ }
+
+ private ArrayList<?> getLoaders()
+ throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException
+ {
+ Field ucpField = URLClassLoader.class.getDeclaredField("ucp");
+ Object urlClassPath = getField(this, ucpField);
+ if (urlClassPath == null)
+ throw new AssertionError("urlClassPath not set in URLClassLoader");
+ Field loadersField = urlClassPath.getClass().getDeclaredField("loaders");
+ return (ArrayList<?>) getField(urlClassPath, loadersField);
+ }
+
+ private Object getField(Object o, Field f)
+ throws IllegalArgumentException, IllegalAccessException {
+ boolean prev = f.isAccessible();
+ try {
+ f.setAccessible(true);
+ return f.get(o);
+ } finally {
+ f.setAccessible(prev);
+ }
+ }
+
+}
--- a/langtools/src/share/classes/javax/lang/model/element/package-info.java Thu Dec 17 14:10:44 2009 -0800
+++ b/langtools/src/share/classes/javax/lang/model/element/package-info.java Sat Dec 19 10:26:47 2009 -0800
@@ -26,6 +26,16 @@
/**
* Interfaces used to model elements of the Java programming language.
*
+ * The term "element" in this package is used to refer to program
+ * elements, the declared entities that make up a program. Elements
+ * include classes, interfaces, methods, constructors, and fields.
+ * The interfaces in this package do not model the structure of a
+ * program inside a method body; for example there is no
+ * representation of a {@code for} loop or {@code try}-{@code finally}
+ * block. However, the interfaces can model some structures only
+ * appearing inside method bodies, such as local variables and
+ * anonymous classes.
+ *
* <p>When used in the context of annotation processing, an accurate
* model of the element being represented must be returned. As this
* is a language model, the source code provides the fiducial
--- a/langtools/src/share/classes/javax/tools/StandardJavaFileManager.java Thu Dec 17 14:10:44 2009 -0800
+++ b/langtools/src/share/classes/javax/tools/StandardJavaFileManager.java Sat Dec 19 10:26:47 2009 -0800
@@ -28,7 +28,6 @@
import java.io.File;
import java.io.IOException;
import java.util.*;
-import java.util.concurrent.*;
/**
* File manager based on {@linkplain File java.io.File}. A common way
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/nio/compileTest/CompileTest.java Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @compile HelloPathWorld.java
+ * @run main CompileTest
+ */
+
+import java.io.*;
+import java.nio.file.*;
+import java.util.*;
+import java.util.jar.*;
+import javax.tools.*;
+
+import com.sun.tools.javac.nio.*;
+import com.sun.tools.javac.util.Context;
+import java.nio.file.spi.FileSystemProvider;
+
+
+public class CompileTest {
+ public static void main(String[] args) throws Exception {
+ new CompileTest().run();
+ }
+
+ public void run() throws Exception {
+ File rtDir = new File("rt.dir");
+ File javaHome = new File(System.getProperty("java.home"));
+ if (javaHome.getName().equals("jre"))
+ javaHome = javaHome.getParentFile();
+ File rtJar = new File(new File(new File(javaHome, "jre"), "lib"), "rt.jar");
+ expand(rtJar, rtDir);
+
+ String[] rtDir_opts = {
+ "-bootclasspath", rtDir.toString(),
+ "-classpath", "",
+ "-sourcepath", "",
+ "-extdirs", ""
+ };
+ test(rtDir_opts, "HelloPathWorld");
+
+ if (isJarFileSystemAvailable()) {
+ String[] rtJar_opts = {
+ "-bootclasspath", rtJar.toString(),
+ "-classpath", "",
+ "-sourcepath", "",
+ "-extdirs", ""
+ };
+ test(rtJar_opts, "HelloPathWorld");
+
+ String[] default_opts = { };
+ test(default_opts, "HelloPathWorld");
+
+ // finally, a non-trivial program
+ test(default_opts, "CompileTest");
+ } else
+ System.err.println("jar file system not available: test skipped");
+ }
+
+ void test(String[] opts, String className) throws Exception {
+ count++;
+ System.err.println("Test " + count + " " + Arrays.asList(opts) + " " + className);
+ Path testSrcDir = Paths.get(System.getProperty("test.src"));
+ Path testClassesDir = Paths.get(System.getProperty("test.classes"));
+ Path classes = Paths.get("classes." + count);
+ classes.createDirectory();
+
+ Context ctx = new Context();
+ PathFileManager fm = new JavacPathFileManager(ctx, true, null);
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+ List<String> options = new ArrayList<String>();
+ options.addAll(Arrays.asList(opts));
+ options.addAll(Arrays.asList(
+ "-verbose", "-XDverboseCompilePolicy",
+ "-d", classes.toString()
+ ));
+ Iterable<? extends JavaFileObject> compilationUnits =
+ fm.getJavaFileObjects(testSrcDir.resolve(className + ".java"));
+ StringWriter sw = new StringWriter();
+ PrintWriter out = new PrintWriter(sw);
+ JavaCompiler.CompilationTask t =
+ compiler.getTask(out, fm, null, options, null, compilationUnits);
+ boolean ok = t.call();
+ System.err.println(sw.toString());
+ if (!ok) {
+ throw new Exception("compilation failed");
+ }
+
+ File expect = new File("classes." + count + "/" + className + ".class");
+ if (!expect.exists())
+ throw new Exception("expected file not found: " + expect);
+ long expectedSize = new File(testClassesDir.toString(), className + ".class").length();
+ long actualSize = expect.length();
+ if (expectedSize != actualSize)
+ throw new Exception("wrong size found: " + actualSize + "; expected: " + expectedSize);
+ }
+
+ boolean isJarFileSystemAvailable() {
+ boolean result = false;
+ for (FileSystemProvider fsp: FileSystemProvider.installedProviders()) {
+ String scheme = fsp.getScheme();
+ System.err.println("Provider: " + scheme + " " + fsp);
+ if (scheme.equalsIgnoreCase("jar") || scheme.equalsIgnoreCase("zip"))
+ result = true;
+ }
+ return result;
+ }
+
+ void expand(File jar, File dir) throws IOException {
+ JarFile jarFile = new JarFile(jar);
+ try {
+ Enumeration<JarEntry> entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry je = entries.nextElement();
+ if (!je.isDirectory()) {
+ copy(jarFile.getInputStream(je), new File(dir, je.getName()));
+ }
+ }
+ } finally {
+ jarFile.close();
+ }
+ }
+
+ void copy(InputStream in, File dest) throws IOException {
+ dest.getParentFile().mkdirs();
+ OutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
+ try {
+ byte[] data = new byte[8192];
+ int n;
+ while ((n = in.read(data, 0, data.length)) > 0)
+ out.write(data, 0, n);
+ } finally {
+ out.close();
+ in.close();
+ }
+ }
+
+ void error(String message) {
+ System.err.println("Error: " + message);
+ errors++;
+ }
+
+ int errors;
+ int count;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/nio/compileTest/HelloPathWorld.java Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+class HelloPathWorld {
+ public static void main(String... args) {
+ System.out.println("Hello World!");
+ }
+}
--- a/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java Thu Dec 17 14:10:44 2009 -0800
+++ b/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java Sat Dec 19 10:26:47 2009 -0800
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6397298 6400986 6425592 6449798 6453386 6508401 6498938
+ * @bug 6397298 6400986 6425592 6449798 6453386 6508401 6498938 6911854
* @summary Tests that getElementsAnnotatedWith works properly.
* @author Joseph D. Darcy
* @compile TestElementsAnnotatedWith.java
@@ -33,8 +33,8 @@
* @compile -processor TestElementsAnnotatedWith -proc:only Part1.java Part2.java
* @compile -processor TestElementsAnnotatedWith -proc:only C2.java
* @compile -processor TestElementsAnnotatedWith -proc:only Foo.java
- * @compile -XD-d=. Foo.java
- * @compile -processor TestElementsAnnotatedWith -proc:only TestElementsAnnotatedWith.java
+ * @compile Foo.java
+ * @compile/process -processor TestElementsAnnotatedWith -proc:only Foo
*/
import java.lang.annotation.Annotation;
@@ -89,7 +89,7 @@
// Verify that the annotation information is as
// expected.
- Set<String> expectedNames = new HashSet<String>(Arrays.asList(annotatedElementInfo.names()));
+ Set<String> expectedNames = new HashSet<>(Arrays.asList(annotatedElementInfo.names()));
resultsMeta =
roundEnvironment.
@@ -126,9 +126,6 @@
System.err.println("AnnotatedElementInfo: " + annotatedElementInfo);
throw new RuntimeException();
}
-
- if("TestElementsAnnotatedWith".equals(firstType.getSimpleName().toString()))
- writeClassFile(); // Start another round to test class file input
} else {
// If processing is over without an error, the specified
// elements should be empty so an empty set should be returned.
@@ -163,48 +160,14 @@
} catch(IllegalArgumentException iae) {}
try {
- Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(processingEnv.
- getElementUtils().
- getTypeElement("java.lang.Object") );
+ Set<? extends Element> elements =
+ roundEnvironment.getElementsAnnotatedWith(processingEnv.
+ getElementUtils().
+ getTypeElement("java.lang.Object") );
throw new RuntimeException("Illegal argument exception not thrown");
} catch(IllegalArgumentException iae) {}
}
- /*
- * Hack alert! The class file read below is generated by the
- * "@compile -XD-d=. Foo.java" directive above. This sneakily
- * overrides the output location to the current directory where a
- * subsequent @compile can read the file. This could be improved
- * if either a new directive like @process accepted class file
- * arguments (the javac command accepts such arguments but
- * @compile does not) or the test.src and test.classes properties
- * were set to be read with @compile jobs.
- */
- private void writeClassFile() {
- try {
- Filer filer = processingEnv.getFiler();
- JavaFileObject jfo = filer.createClassFile("Foo");
- OutputStream os = jfo.openOutputStream();
- // Copy the bytes over
- System.out.println((new File(".")).getAbsolutePath());
- InputStream io = new BufferedInputStream(new FileInputStream(new File(".", "Foo.class")));
- try {
- int datum = io.read();
- while(datum != -1) {
- os.write(datum);
- datum = io.read();
- }
- } finally {
- io.close();
- }
- os.close();
- } catch (IOException ioe) {
- throw new RuntimeException(ioe);
- }
-
-
- }
-
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javap/classfile/deps/GetDeps.java Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.Pattern;
+import javax.tools.*;
+
+import com.sun.tools.classfile.*;
+import com.sun.tools.classfile.Dependencies.*;
+import com.sun.tools.classfile.Dependency.Location;
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.util.Context;
+
+/**
+ * Demo utility for using the classfile dependency analysis API framework.
+ *
+ * Usage:
+ * getdeps [options] classes
+ * where options include:
+ * -classpath path where to find classes to analyze
+ * -p package-name restrict analysis to classes in this package
+ * (may be given multiple times)
+ * -r regex restrict analysis to packages matching pattern
+ * (-p and -r are exclusive)
+ * -rev invert the dependencies in the output
+ * -t transitive closure of dependencies
+ */
+public class GetDeps {
+ public static void main(String... args) throws Exception {
+ new GetDeps().run(args);
+ }
+
+ void run(String... args) throws IOException, ClassFileNotFoundException {
+ PrintWriter pw = new PrintWriter(System.out);
+ try {
+ run(pw, args);
+ } finally {
+ pw.flush();
+ }
+ }
+
+ void run(PrintWriter out, String... args) throws IOException, ClassFileNotFoundException {
+ decodeArgs(args);
+
+ final StandardJavaFileManager fm = new JavacFileManager(new Context(), false, null);
+ if (classpath != null)
+ fm.setLocation(StandardLocation.CLASS_PATH, classpath);
+
+ ClassFileReader reader = new ClassFileReader(fm);
+
+ Dependencies d = new Dependencies();
+
+ if (regex != null)
+ d.setFilter(Dependencies.getRegexFilter(Pattern.compile(regex)));
+
+ if (packageNames.size() > 0)
+ d.setFilter(Dependencies.getPackageFilter(packageNames, false));
+
+ SortedRecorder r = new SortedRecorder(reverse);
+
+ d.findAllDependencies(reader, rootClassNames, transitiveClosure, r);
+
+ SortedMap<Location,SortedSet<Dependency>> deps = r.getMap();
+ for (Map.Entry<Location, SortedSet<Dependency>> e: deps.entrySet()) {
+ out.println(e.getKey());
+ for (Dependency dep: e.getValue()) {
+ out.println(" " + dep.getTarget());
+ }
+ }
+ }
+
+ void decodeArgs(String... args) {
+ rootClassNames = new TreeSet<String>();
+ packageNames = new TreeSet<String>();
+
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i];
+ if (arg.equals("-classpath") && (i + 1 < args.length))
+ classpath = getPathFiles(args[++i]);
+ else if (arg.equals("-p") && (i + 1 < args.length))
+ packageNames.add(args[++i]);
+ else if (arg.equals("-r") && (i + 1 < args.length))
+ regex = args[++i];
+ else if (arg.equals("-rev"))
+ reverse = true;
+ else if (arg.equals("-t"))
+ transitiveClosure = true;
+ else if (arg.startsWith("-"))
+ throw new Error(arg);
+ else {
+ for ( ; i < args.length; i++)
+ rootClassNames.add(args[i]);
+ }
+ }
+ }
+
+ List<File> getPathFiles(String path) {
+ List<File> files = new ArrayList<File>();
+ for (String p: path.split(File.pathSeparator)) {
+ if (p.length() > 0)
+ files.add(new File(p));
+ }
+ return files;
+ }
+
+ boolean transitiveClosure;
+ List<File> classpath;
+ Set<String> rootClassNames;
+ Set<String> packageNames;
+ String regex;
+ boolean reverse;
+
+
+ static class ClassFileReader implements Dependencies.ClassFileReader {
+ private JavaFileManager fm;
+
+ ClassFileReader(JavaFileManager fm) {
+ this.fm = fm;
+ }
+
+ @Override
+ public ClassFile getClassFile(String className) throws ClassFileNotFoundException {
+ try {
+ JavaFileObject fo = fm.getJavaFileForInput(
+ StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS);
+ if (fo == null)
+ fo = fm.getJavaFileForInput(
+ StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS);
+ if (fo == null)
+ throw new ClassFileNotFoundException(className);
+ InputStream in = fo.openInputStream();
+ try {
+ return ClassFile.read(in);
+ } finally {
+ in.close();
+ }
+ } catch (ConstantPoolException e) {
+ throw new ClassFileNotFoundException(className, e);
+ } catch (IOException e) {
+ throw new ClassFileNotFoundException(className, e);
+ }
+ }
+ };
+
+ static class SortedRecorder implements Recorder {
+ public SortedRecorder(boolean reverse) {
+ this.reverse = reverse;
+ }
+
+ public void addDependency(Dependency d) {
+ Location o = (reverse ? d.getTarget() : d.getOrigin());
+ SortedSet<Dependency> odeps = map.get(o);
+ if (odeps == null) {
+ Comparator<Dependency> c = (reverse ? originComparator : targetComparator);
+ map.put(o, odeps = new TreeSet<Dependency>(c));
+ }
+ odeps.add(d);
+ }
+
+ public SortedMap<Location, SortedSet<Dependency>> getMap() {
+ return map;
+ }
+
+ private Comparator<Dependency> originComparator = new Comparator<Dependency>() {
+ public int compare(Dependency o1, Dependency o2) {
+ return o1.getOrigin().toString().compareTo(o2.getOrigin().toString());
+ }
+ };
+
+ private Comparator<Dependency> targetComparator = new Comparator<Dependency>() {
+ public int compare(Dependency o1, Dependency o2) {
+ return o1.getTarget().toString().compareTo(o2.getTarget().toString());
+ }
+ };
+
+ private Comparator<Location> locationComparator = new Comparator<Location>() {
+ public int compare(Location o1, Location o2) {
+ return o1.toString().compareTo(o2.toString());
+ }
+ };
+
+ private final SortedMap<Location, SortedSet<Dependency>> map =
+ new TreeMap<Location, SortedSet<Dependency>>(locationComparator);
+
+ boolean reverse;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javap/classfile/deps/T6907575.java Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6907575
+ * @build GetDeps p.C1
+ * @run main T6907575
+ */
+
+import java.io.*;
+
+public class T6907575 {
+ public static void main(String... args) throws Exception {
+ new T6907575().run();
+ }
+
+ void run() throws Exception {
+ String testSrc = System.getProperty("test.src");
+ String testClasses = System.getProperty("test.classes");
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ GetDeps gd = new GetDeps();
+ gd.run(pw, "-classpath", testClasses, "-t", "-p", "p", "p/C1");
+ pw.close();
+ System.out.println(sw);
+
+ String ref = readFile(new File(testSrc, "T6907575.out"));
+ diff(sw.toString().replaceAll("[\r\n]+", "\n"), ref);
+ }
+
+ void diff(String actual, String ref) throws Exception {
+ System.out.println("EXPECT:>>>" + ref + "<<<");
+ System.out.println("ACTUAL:>>>" + actual + "<<<");
+ if (!actual.equals(ref))
+ throw new Exception("output not as expected");
+ }
+
+ String readFile(File f) throws IOException {
+ Reader r = new FileReader(f);
+ char[] buf = new char[(int) f.length()];
+ int offset = 0;
+ int n;
+ while (offset < buf.length && (n = r.read(buf, offset, buf.length - offset)) != -1)
+ offset += n;
+ return new String(buf, 0, offset);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javap/classfile/deps/T6907575.out Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,8 @@
+p/C1
+ java/lang/Object
+ p/C2
+p/C2
+ java/lang/Object
+ p/C3
+p/C3
+ java/lang/Object
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javap/classfile/deps/p/C1.java Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package p;
+
+public class C1 {
+ C2 c2;
+}
+
+class C2 {
+ C3 c3;
+}
+
+class C3 {
+}