7026941: 199: path options ignored when reusing filemanager across tasks

Reviewed-by: jlahoda, jfranck
This commit is contained in:
Jonathan Gibbons 2014-06-08 15:02:34 -07:00
parent 8aa391d4c9
commit 15853aca13
17 changed files with 1008 additions and 278 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -202,9 +202,6 @@ public class ClientCodeWrapper {
// <editor-fold defaultstate="collapsed" desc="Wrapper classes">
// FIXME: all these classes should be converted to use multi-catch when
// that is available in the bootstrap compiler.
protected class WrappedJavaFileManager implements JavaFileManager {
protected JavaFileManager clientJavaFileManager;
WrappedJavaFileManager(JavaFileManager clientJavaFileManager) {

View File

@ -161,6 +161,15 @@ public class JavacTaskImpl extends BasicJavacTask {
compilerMain.log = Log.instance(context);
compilerMain.setOptions(Options.instance(context));
compilerMain.filenames = new LinkedHashSet<>();
compilerMain.deferredFileManagerOptions = new LinkedHashMap<>();
// The following line is conceptually wrong. It should not refer to args
// which may include inappropriate file manager options.
// (Ideally, args should not even be passed into JavacTaskImpl at all.)
// The "no filenames in args" check should have been handled by the use of
// the GrumpyHelper in JavacTool.getTask, but processArgs also has some
// additional checking, which should be factored out and called separately.
// If we fix this, then filenames and deferredFileManagerOptions in Main
// can revert to being protected or private, not public.
Collection<File> filenames = compilerMain.processArgs(CommandLine.parse(args), classNames);
if (filenames != null && !filenames.isEmpty())
throw new IllegalArgumentException("Malformed arguments " + toString(filenames, " "));

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -158,11 +158,6 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
symbolFileEnabled = b;
}
@Override
public boolean isDefaultBootClassPath() {
return locations.isDefaultBootClassPath();
}
public JavaFileObject getFileForInput(String name) {
return getRegularFile(new File(name));
}
@ -579,15 +574,6 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
}
}
private String defaultEncodingName;
private String getDefaultEncodingName() {
if (defaultEncodingName == null) {
defaultEncodingName =
new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding();
}
return defaultEncodingName;
}
public ClassLoader getClassLoader(Location location) {
nullCheck(location);
Iterable<? extends File> path = getLocation(location);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -22,12 +22,10 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.file;
import java.io.FileNotFoundException;
import java.util.Iterator;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
@ -38,64 +36,72 @@ import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.zip.ZipFile;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileManager.Location;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import com.sun.tools.javac.code.Lint;
import com.sun.tools.javac.main.Option;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Options;
import com.sun.tools.javac.util.StringUtils;
import javax.tools.JavaFileManager;
import javax.tools.StandardJavaFileManager;
import static javax.tools.StandardLocation.*;
import static com.sun.tools.javac.main.Option.*;
import static javax.tools.StandardLocation.CLASS_PATH;
import static javax.tools.StandardLocation.PLATFORM_CLASS_PATH;
import static javax.tools.StandardLocation.SOURCE_PATH;
/** This class converts command line arguments, environment variables
* and system properties (in File.pathSeparator-separated String form)
* into a boot class path, user class path, and source path (in
* {@code Collection<String>} form).
import static com.sun.tools.javac.main.Option.BOOTCLASSPATH;
import static com.sun.tools.javac.main.Option.DJAVA_ENDORSED_DIRS;
import static com.sun.tools.javac.main.Option.DJAVA_EXT_DIRS;
import static com.sun.tools.javac.main.Option.ENDORSEDDIRS;
import static com.sun.tools.javac.main.Option.EXTDIRS;
import static com.sun.tools.javac.main.Option.XBOOTCLASSPATH;
import static com.sun.tools.javac.main.Option.XBOOTCLASSPATH_APPEND;
import static com.sun.tools.javac.main.Option.XBOOTCLASSPATH_PREPEND;
/**
* This class converts command line arguments, environment variables and system properties (in
* File.pathSeparator-separated String form) into a boot class path, user class path, and source
* path (in {@code Collection<String>} form).
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
* <p>
* <b>This is NOT part of any supported API. If you write code that depends on this, you do so at
* your own risk. This code and its internal interfaces are subject to change or deletion without
* notice.</b>
*/
public class Locations {
/** The log to use for warning output */
/**
* The log to use for warning output
*/
private Log log;
/** Collection of command-line options */
private Options options;
/** Handler for -Xlint options */
private Lint lint;
/** Access to (possibly cached) file info */
/**
* Access to (possibly cached) file info
*/
private FSInfo fsInfo;
/** Whether to warn about non-existent path elements */
/**
* Whether to warn about non-existent path elements
*/
private boolean warn;
// TODO: remove need for this
private boolean inited = false; // TODO? caching bad?
public Locations() {
initHandlers();
}
public void update(Log log, Options options, Lint lint, FSInfo fsInfo) {
// could replace Lint by "boolean warn"
public void update(Log log, Lint lint, FSInfo fsInfo) {
this.log = log;
this.options = options;
this.lint = lint;
warn = lint.isEnabled(Lint.LintCategory.PATH);
this.fsInfo = fsInfo;
}
@ -104,14 +110,14 @@ public class Locations {
}
public boolean isDefaultBootClassPath() {
BootClassPathLocationHandler h =
(BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH);
BootClassPathLocationHandler h
= (BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH);
return h.isDefault();
}
boolean isDefaultBootClassPathRtJar(File file) {
BootClassPathLocationHandler h =
(BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH);
BootClassPathLocationHandler h
= (BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH);
return h.isDefaultRtJar(file);
}
@ -127,6 +133,7 @@ public class Locations {
/**
* Split a path into its elements. Empty path elements will be ignored.
*
* @param path The path to be split
* @return The elements of the path
*/
@ -135,12 +142,13 @@ public class Locations {
}
/**
* Split a path into its elements. If emptyPathDefault is not null, all
* empty elements in the path, including empty elements at either end of
* the path, will be replaced with the value of emptyPathDefault.
* Split a path into its elements. If emptyPathDefault is not null, all empty elements in the
* path, including empty elements at either end of the path, will be replaced with the value of
* emptyPathDefault.
*
* @param path The path to be split
* @param emptyPathDefault The value to substitute for empty path elements,
* or null, to ignore empty path elements
* @param emptyPathDefault The value to substitute for empty path elements, or null, to ignore
* empty path elements
* @return The elements of the path
*/
private static Iterable<File> getPathEntries(String path, File emptyPathDefault) {
@ -148,33 +156,38 @@ public class Locations {
int start = 0;
while (start <= path.length()) {
int sep = path.indexOf(File.pathSeparatorChar, start);
if (sep == -1)
if (sep == -1) {
sep = path.length();
if (start < sep)
}
if (start < sep) {
entries.add(new File(path.substring(start, sep)));
else if (emptyPathDefault != null)
} else if (emptyPathDefault != null) {
entries.add(emptyPathDefault);
}
start = sep + 1;
}
return entries;
}
/**
* Utility class to help evaluate a path option.
* Duplicate entries are ignored, jar class paths can be expanded.
* Utility class to help evaluate a path option. Duplicate entries are ignored, jar class paths
* can be expanded.
*/
private class Path extends LinkedHashSet<File> {
private static final long serialVersionUID = 0;
private boolean expandJarClassPaths = false;
private Set<File> canonicalValues = new HashSet<>();
private final Set<File> canonicalValues = new HashSet<>();
public Path expandJarClassPaths(boolean x) {
expandJarClassPaths = x;
return this;
}
/** What to use when path element is the empty string */
/**
* What to use when path element is the empty string
*/
private File emptyPathDefault = null;
public Path emptyPathDefault(File x) {
@ -182,15 +195,15 @@ public class Locations {
return this;
}
public Path() { super(); }
public Path addDirectories(String dirs, boolean warn) {
boolean prev = expandJarClassPaths;
expandJarClassPaths = true;
try {
if (dirs != null)
for (File dir : getPathEntries(dirs))
if (dirs != null) {
for (File dir : getPathEntries(dirs)) {
addDirectory(dir, warn);
}
}
return this;
} finally {
expandJarClassPaths = prev;
@ -203,19 +216,22 @@ public class Locations {
private void addDirectory(File dir, boolean warn) {
if (!dir.isDirectory()) {
if (warn)
if (warn) {
log.warning(Lint.LintCategory.PATH,
"dir.path.element.not.found", dir);
}
return;
}
File[] files = dir.listFiles();
if (files == null)
if (files == null) {
return;
}
for (File direntry : files) {
if (isArchive(direntry))
if (isArchive(direntry)) {
addFile(direntry, warn);
}
}
}
@ -232,8 +248,9 @@ public class Locations {
public Path addFiles(Iterable<? extends File> files, boolean warn) {
if (files != null) {
for (File file: files)
for (File file : files) {
addFile(file, warn);
}
}
return this;
}
@ -248,7 +265,7 @@ public class Locations {
return;
}
if (! fsInfo.exists(file)) {
if (!fsInfo.exists(file)) {
/* No such file or directory exists */
if (warn) {
log.warning(Lint.LintCategory.PATH,
@ -288,12 +305,13 @@ public class Locations {
}
/* Now what we have left is either a directory or a file name
conforming to archive naming convention */
conforming to archive naming convention */
super.add(file);
canonicalValues.add(canonFile);
if (expandJarClassPaths && fsInfo.isFile(file))
if (expandJarClassPaths && fsInfo.isFile(file)) {
addJarClassPath(file, warn);
}
}
// Adds referenced classpath elements from a jar's Class-Path
@ -302,7 +320,7 @@ public class Locations {
// filenames, but if we do, we should redo all path-related code.
private void addJarClassPath(File jarFile, boolean warn) {
try {
for (File f: fsInfo.getJarClassPath(jarFile)) {
for (File f : fsInfo.getJarClassPath(jarFile)) {
addFile(f, warn);
}
} catch (IOException e) {
@ -312,53 +330,56 @@ public class Locations {
}
/**
* Base class for handling support for the representation of Locations.
* Implementations are responsible for handling the interactions between
* the command line options for a location, and API access via setLocation.
* Base class for handling support for the representation of Locations. Implementations are
* responsible for handling the interactions between the command line options for a location,
* and API access via setLocation.
*
* @see #initHandlers
* @see #getHandler
*/
protected abstract class LocationHandler {
final Location location;
final Set<Option> options;
/**
* Create a handler. The location and options provide a way to map
* from a location or an option to the corresponding handler.
* Create a handler. The location and options provide a way to map from a location or an
* option to the corresponding handler.
*
* @param location the location for which this is the handler
* @param options the options affecting this location
* @see #initHandlers
*/
protected LocationHandler(Location location, Option... options) {
this.location = location;
this.options = options.length == 0 ?
EnumSet.noneOf(Option.class):
EnumSet.copyOf(Arrays.asList(options));
this.options = options.length == 0
? EnumSet.noneOf(Option.class)
: EnumSet.copyOf(Arrays.asList(options));
}
// TODO: TEMPORARY, while Options still used for command line options
void update(Options optionTable) {
for (Option o: options) {
String v = optionTable.get(o);
if (v != null) {
handleOption(o, v);
}
}
}
/** @see JavaFileManager#handleOption */
/**
* @see JavaFileManager#handleOption
*/
abstract boolean handleOption(Option option, String value);
/** @see StandardJavaFileManager#getLocation */
/**
* @see StandardJavaFileManager#getLocation
*/
abstract Collection<File> getLocation();
/** @see StandardJavaFileManager#setLocation */
/**
* @see StandardJavaFileManager#setLocation
*/
abstract void setLocation(Iterable<? extends File> files) throws IOException;
}
/**
* General purpose implementation for output locations,
* such as -d/CLASS_OUTPUT and -s/SOURCE_OUTPUT.
* All options are treated as equivalent (i.e. aliases.)
* The value is a single file, possibly null.
* General purpose implementation for output locations, such as -d/CLASS_OUTPUT and
* -s/SOURCE_OUTPUT. All options are treated as equivalent (i.e. aliases.) The value is a single
* file, possibly null.
*/
private class OutputLocationHandler extends LocationHandler {
private File outputDir;
OutputLocationHandler(Location location, Option... options) {
@ -367,14 +388,15 @@ public class Locations {
@Override
boolean handleOption(Option option, String value) {
if (!options.contains(option))
if (!options.contains(option)) {
return false;
}
// TODO: could/should validate outputDir exists and is a directory
// need to decide how best to report issue for benefit of
// direct API call on JavaFileManager.handleOption(specifies IAE)
// vs. command line decoding.
outputDir = new File(value);
outputDir = (value == null) ? null : new File(value);
return true;
}
@ -389,27 +411,30 @@ public class Locations {
outputDir = null;
} else {
Iterator<? extends File> pathIter = files.iterator();
if (!pathIter.hasNext())
if (!pathIter.hasNext()) {
throw new IllegalArgumentException("empty path for directory");
}
File dir = pathIter.next();
if (pathIter.hasNext())
if (pathIter.hasNext()) {
throw new IllegalArgumentException("path too long for directory");
if (!dir.exists())
}
if (!dir.exists()) {
throw new FileNotFoundException(dir + ": does not exist");
else if (!dir.isDirectory())
} else if (!dir.isDirectory()) {
throw new IOException(dir + ": not a directory");
}
outputDir = dir;
}
}
}
/**
* General purpose implementation for search path locations,
* such as -sourcepath/SOURCE_PATH and -processorPath/ANNOTATION_PROCESS_PATH.
* All options are treated as equivalent (i.e. aliases.)
* General purpose implementation for search path locations, such as -sourcepath/SOURCE_PATH and
* -processorPath/ANNOTATION_PROCESS_PATH. All options are treated as equivalent (i.e. aliases.)
* The value is an ordered set of files and/or directories.
*/
private class SimpleLocationHandler extends LocationHandler {
protected Collection<File> searchPath;
SimpleLocationHandler(Location location, Option... options) {
@ -418,10 +443,11 @@ public class Locations {
@Override
boolean handleOption(Option option, String value) {
if (!options.contains(option))
if (!options.contains(option)) {
return false;
searchPath = value == null ? null :
Collections.unmodifiableCollection(createPath().addFiles(value));
}
searchPath = value == null ? null
: Collections.unmodifiableCollection(createPath().addFiles(value));
return true;
}
@ -451,11 +477,11 @@ public class Locations {
}
/**
* Subtype of SimpleLocationHandler for -classpath/CLASS_PATH.
* If no value is given, a default is provided, based on system properties
* and other values.
* Subtype of SimpleLocationHandler for -classpath/CLASS_PATH. If no value is given, a default
* is provided, based on system properties and other values.
*/
private class ClassPathLocationHandler extends SimpleLocationHandler {
ClassPathLocationHandler() {
super(StandardLocation.CLASS_PATH,
Option.CLASSPATH, Option.CP);
@ -472,15 +498,20 @@ public class Locations {
String cp = value;
// CLASSPATH environment variable when run from `javac'.
if (cp == null) cp = System.getProperty("env.class.path");
if (cp == null) {
cp = System.getProperty("env.class.path");
}
// If invoked via a java VM (not the javac launcher), use the
// platform class path
if (cp == null && System.getProperty("application.home") == null)
if (cp == null && System.getProperty("application.home") == null) {
cp = System.getProperty("java.class.path");
}
// Default to current working directory.
if (cp == null) cp = ".";
if (cp == null) {
cp = ".";
}
return createPath().addFiles(cp);
}
@ -488,38 +519,37 @@ public class Locations {
@Override
protected Path createPath() {
return new Path()
.expandJarClassPaths(true) // Only search user jars for Class-Paths
.emptyPathDefault(new File(".")); // Empty path elt ==> current directory
.expandJarClassPaths(true) // Only search user jars for Class-Paths
.emptyPathDefault(new File(".")); // Empty path elt ==> current directory
}
private void lazy() {
if (searchPath == null)
if (searchPath == null) {
setLocation(null);
}
}
}
/**
* Custom subtype of LocationHandler for PLATFORM_CLASS_PATH.
* Various options are supported for different components of the
* platform class path.
* Setting a value with setLocation overrides all existing option values.
* Setting any option overrides any value set with setLocation, and reverts
* to using default values for options that have not been set.
* Setting -bootclasspath or -Xbootclasspath overrides any existing
* value for -Xbootclasspath/p: and -Xbootclasspath/a:.
* Custom subtype of LocationHandler for PLATFORM_CLASS_PATH. Various options are supported for
* different components of the platform class path. Setting a value with setLocation overrides
* all existing option values. Setting any option overrides any value set with setLocation, and
* reverts to using default values for options that have not been set. Setting -bootclasspath or
* -Xbootclasspath overrides any existing value for -Xbootclasspath/p: and -Xbootclasspath/a:.
*/
private class BootClassPathLocationHandler extends LocationHandler {
private Collection<File> searchPath;
final Map<Option, String> optionValues = new EnumMap<>(Option.class);
/**
* rt.jar as found on the default bootclasspath.
* If the user specified a bootclasspath, null is used.
* rt.jar as found on the default bootclasspath. If the user specified a bootclasspath, null
* is used.
*/
private File defaultBootClassPathRtJar = null;
/**
* Is bootclasspath the default?
* Is bootclasspath the default?
*/
private boolean isDefaultBootClassPath;
@ -544,8 +574,9 @@ public class Locations {
@Override
boolean handleOption(Option option, String value) {
if (!options.contains(option))
if (!options.contains(option)) {
return false;
}
option = canonicalize(option);
optionValues.put(option, value);
@ -557,20 +588,20 @@ public class Locations {
return true;
}
// where
// TODO: would be better if option aliasing was handled at a higher
// level
private Option canonicalize(Option option) {
switch (option) {
case XBOOTCLASSPATH:
return Option.BOOTCLASSPATH;
case DJAVA_ENDORSED_DIRS:
return Option.ENDORSEDDIRS;
case DJAVA_EXT_DIRS:
return Option.EXTDIRS;
default:
return option;
}
// TODO: would be better if option aliasing was handled at a higher
// level
private Option canonicalize(Option option) {
switch (option) {
case XBOOTCLASSPATH:
return Option.BOOTCLASSPATH;
case DJAVA_ENDORSED_DIRS:
return Option.ENDORSEDDIRS;
case DJAVA_EXT_DIRS:
return Option.EXTDIRS;
default:
return option;
}
}
@Override
Collection<File> getLocation() {
@ -602,10 +633,11 @@ public class Locations {
String xbootclasspathAppendOpt = optionValues.get(XBOOTCLASSPATH_APPEND);
path.addFiles(xbootclasspathPrependOpt);
if (endorseddirsOpt != null)
if (endorseddirsOpt != null) {
path.addDirectories(endorseddirsOpt);
else
} else {
path.addDirectories(System.getProperty("java.endorsed.dirs"), false);
}
if (bootclasspathOpt != null) {
path.addFiles(bootclasspathOpt);
@ -615,8 +647,9 @@ public class Locations {
path.addFiles(files, false);
File rt_jar = new File("rt.jar");
for (File file : getPathEntries(files)) {
if (new File(file.getName()).equals(rt_jar))
if (new File(file.getName()).equals(rt_jar)) {
defaultBootClassPathRtJar = file;
}
}
}
@ -625,22 +658,24 @@ public class Locations {
// Strictly speaking, standard extensions are not bootstrap
// classes, but we treat them identically, so we'll pretend
// that they are.
if (extdirsOpt != null)
if (extdirsOpt != null) {
path.addDirectories(extdirsOpt);
else
} else {
path.addDirectories(System.getProperty("java.ext.dirs"), false);
}
isDefaultBootClassPath =
(xbootclasspathPrependOpt == null) &&
(bootclasspathOpt == null) &&
(xbootclasspathAppendOpt == null);
isDefaultBootClassPath
= (xbootclasspathPrependOpt == null)
&& (bootclasspathOpt == null)
&& (xbootclasspathAppendOpt == null);
return path;
}
private void lazy() {
if (searchPath == null)
if (searchPath == null) {
searchPath = Collections.unmodifiableCollection(computePath());
}
}
}
@ -661,14 +696,15 @@ public class Locations {
new OutputLocationHandler((StandardLocation.NATIVE_HEADER_OUTPUT), Option.H)
};
for (LocationHandler h: handlers) {
for (LocationHandler h : handlers) {
handlersForLocation.put(h.location, h);
for (Option o: h.options)
for (Option o : h.options) {
handlersForOption.put(o, h);
}
}
}
boolean handleOption(Option option, String value) {
public boolean handleOption(Option option, String value) {
LocationHandler h = handlersForOption.get(option);
return (h == null ? false : h.handleOption(option, value));
}
@ -679,8 +715,9 @@ public class Locations {
}
File getOutputLocation(Location location) {
if (!location.isOutputLocation())
if (!location.isOutputLocation()) {
throw new IllegalArgumentException();
}
LocationHandler h = getHandler(location);
return ((OutputLocationHandler) h).outputDir;
}
@ -688,10 +725,11 @@ public class Locations {
void setLocation(Location location, Iterable<? extends File> files) throws IOException {
LocationHandler h = getHandler(location);
if (h == null) {
if (location.isOutputLocation())
if (location.isOutputLocation()) {
h = new OutputLocationHandler(location);
else
} else {
h = new SimpleLocationHandler(location);
}
handlersForLocation.put(location, h);
}
h.setLocation(files);
@ -699,33 +737,21 @@ public class Locations {
protected LocationHandler getHandler(Location location) {
location.getClass(); // null check
lazy();
return handlersForLocation.get(location);
}
// TOGO
protected void lazy() {
if (!inited) {
warn = lint.isEnabled(Lint.LintCategory.PATH);
for (LocationHandler h: handlersForLocation.values()) {
h.update(options);
}
inited = true;
}
}
/** Is this the name of an archive file? */
/**
* Is this the name of an archive file?
*/
private boolean isArchive(File file) {
String n = StringUtils.toLowerCase(file.getName());
return fsInfo.isFile(file)
&& (n.endsWith(".jar") || n.endsWith(".zip"));
&& (n.endsWith(".jar") || n.endsWith(".zip"));
}
/**
* Utility method for converting a search path string to an array
* of directory and JAR file URLs.
* Utility method for converting a search path string to an array of directory and JAR file
* URLs.
*
* Note that this method is called by apt and the DocletInvoker.
*
@ -747,8 +773,7 @@ public class Locations {
}
/**
* Returns the directory or JAR file URL corresponding to the specified
* local file name.
* Returns the directory or JAR file URL corresponding to the specified local file name.
*
* @param file the File object
* @return the resulting directory or JAR file URL, or null if unknown

View File

@ -394,6 +394,7 @@ public class JavaCompiler {
processPcks = options.isSet("process.packages");
werror = options.isSet(WERROR);
// Should this be with other option checking, in Main
if (source.compareTo(Source.DEFAULT) < 0) {
if (options.isUnset(XLINT_CUSTOM, "-" + LintCategory.OPTIONS.option)) {
if (fileManager instanceof BaseFileManager) {
@ -403,6 +404,7 @@ public class JavaCompiler {
}
}
// Should this be with other option checking, in Main
checkForObsoleteOptions(target);
verboseCompilePolicy = options.isSet("verboseCompilePolicy");
@ -434,6 +436,7 @@ public class JavaCompiler {
log.setDiagnosticFormatter(RichDiagnosticFormatter.instance(context));
}
// Should this be with other option checking, in Main
private void checkForObsoleteOptions(Target target) {
// Unless lint checking on options is disabled, check for
// obsolete source and target options.

View File

@ -33,8 +33,9 @@ import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.Processor;
@ -56,6 +57,7 @@ import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.Log.PrefixKind;
import com.sun.tools.javac.util.Log.WriterKind;
import com.sun.tools.javac.util.ServiceLoader;
import static com.sun.tools.javac.main.Option.*;
/** This class provides a command line interface to the javac compiler.
@ -120,6 +122,13 @@ public class Main {
options.put(name, value);
}
@Override
public boolean handleFileManagerOption(Option option, String value) {
options.put(option.getText(), value);
deferredFileManagerOptions.put(option, value);
return true;
}
@Override
public void remove(String name) {
options.remove(name);
@ -172,11 +181,13 @@ public class Main {
/** The list of source files to process
*/
public Set<File> filenames = null; // XXX sb protected
public Set<File> filenames = null; // XXX should be protected or private
/** List of class files names passed on the command line
*/
public ListBuffer<String> classnames = null; // XXX sb protected
protected ListBuffer<String> classnames = null;
public Map<Option, String> deferredFileManagerOptions; // XXX should be protected or private
/** Report a usage error.
*/
@ -395,6 +406,7 @@ public class Main {
filenames = new LinkedHashSet<>();
classnames = new ListBuffer<>();
deferredFileManagerOptions = new LinkedHashMap<>();
JavaCompiler comp = null;
/*
* TODO: Logic below about what is an acceptable command line
@ -446,6 +458,11 @@ public class Main {
if (batchMode)
CacheFSInfo.preRegister(context);
fileManager = context.get(JavaFileManager.class);
if (fileManager instanceof BaseFileManager) {
((BaseFileManager) fileManager).handleOptions(deferredFileManagerOptions);
}
// FIXME: this code will not be invoked if using JavacTask.parse/analyze/generate
// invoke any available plugins
String plugins = options.get(PLUGIN);
@ -511,8 +528,6 @@ public class Main {
comp.closeables = comp.closeables.prepend(log.getWriter(WriterKind.NOTICE));
}
fileManager = context.get(JavaFileManager.class);
if (!files.isEmpty()) {
// add filenames to fileObjects
comp = JavaCompiler.instance(context);

View File

@ -83,6 +83,7 @@ public enum Option {
XLINT_CUSTOM("-Xlint:", EXTENDED, BASIC, ANYOF, getXLintChoices()) {
private static final String LINT_KEY_FORMAT = " %-19s %s";
@Override
void help(Log log, OptionKind kind) {
if (this.kind != kind)
return;
@ -667,6 +668,8 @@ public enum Option {
}
}
helper.put(option, arg);
if (group == OptionGroup.FILEMANAGER)
helper.handleFileManagerOption(this, arg);
return false;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -50,6 +50,9 @@ public abstract class OptionHelper {
/** Remove any prior value for an option. */
public abstract void remove(String name);
/** Handle a file manager option. */
public abstract boolean handleFileManagerOption(Option option, String value);
/** Get access to the Log for the compilation. */
public abstract Log getLog();
@ -98,6 +101,11 @@ public abstract class OptionHelper {
throw new IllegalArgumentException();
}
@Override
public boolean handleFileManagerOption(Option option, String value) {
throw new IllegalArgumentException();
}
@Override
void error(String key, Object... args) {
throw new IllegalArgumentException(log.localize(PrefixKind.JAVAC, key, args));

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -167,11 +167,6 @@ public class JavacPathFileManager extends BaseFileManager implements PathFileMan
return getClassLoader(lb.toArray(new URL[lb.size()]));
}
@Override
public boolean isDefaultBootClassPath() {
return locations.isDefaultBootClassPath();
}
// <editor-fold defaultstate="collapsed" desc="Location handling">
public boolean hasLocation(Location location) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,7 +26,6 @@
package com.sun.tools.javac.util;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
@ -47,6 +46,8 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
@ -64,7 +65,7 @@ import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
* There are no references here to file-system specific objects such as
* java.io.File or java.nio.file.Path.
*/
public abstract class BaseFileManager {
public abstract class BaseFileManager implements JavaFileManager {
protected BaseFileManager(Charset charset) {
this.charset = charset;
byteBufferCache = new ByteBufferCache();
@ -73,12 +74,13 @@ public abstract class BaseFileManager {
/**
* Set the context for JavacPathFileManager.
* @param context the context containing items to be associated with the file manager
*/
public void setContext(Context context) {
log = Log.instance(context);
options = Options.instance(context);
classLoaderClass = options.get("procloader");
locations.update(log, options, Lint.instance(context), FSInfo.instance(context));
locations.update(log, Lint.instance(context), FSInfo.instance(context));
}
protected Locations createLocations() {
@ -123,14 +125,19 @@ public abstract class BaseFileManager {
Class<?>[] constrArgTypes = { URL[].class, ClassLoader.class };
Constructor<? extends ClassLoader> constr = loader.getConstructor(constrArgTypes);
return constr.newInstance(urls, thisClassLoader);
} catch (Throwable t) {
} catch (ReflectiveOperationException t) {
// ignore errors loading user-provided class loader, fall through
}
}
return new URLClassLoader(urls, thisClassLoader);
}
public boolean isDefaultBootClassPath() {
return locations.isDefaultBootClassPath();
}
// <editor-fold defaultstate="collapsed" desc="Option handling">
@Override
public boolean handleOption(String current, Iterator<String> remaining) {
OptionHelper helper = new GrumpyHelper(log) {
@Override
@ -147,7 +154,13 @@ public abstract class BaseFileManager {
public void remove(String name) {
options.remove(name);
}
@Override
public boolean handleFileManagerOption(Option option, String value) {
return handleOption(option, value);
}
};
for (Option o: javacFileManagerOptions) {
if (o.matches(current)) {
if (o.hasArg()) {
@ -159,7 +172,7 @@ public abstract class BaseFileManager {
if (!o.process(helper, current))
return true;
}
// operand missing, or process returned false
// operand missing, or process returned true
throw new IllegalArgumentException(current);
}
}
@ -170,6 +183,7 @@ public abstract class BaseFileManager {
private static final Set<Option> javacFileManagerOptions =
Option.getJavacFileManagerOptions();
@Override
public int isSupportedOption(String option) {
for (Option o : javacFileManagerOptions) {
if (o.matches(option))
@ -178,7 +192,27 @@ public abstract class BaseFileManager {
return -1;
}
public abstract boolean isDefaultBootClassPath();
/**
* Common back end for OptionHelper handleFileManagerOption.
* @param option the option whose value to be set
* @param value the value for the option
* @return true if successful, and false otherwise
*/
public boolean handleOption(Option option, String value) {
return locations.handleOption(option, value);
}
/**
* Call handleOption for collection of options and corresponding values.
* @param map a collection of options and corresponding values
* @return true if all the calls are successful
*/
public boolean handleOptions(Map<Option, String> map) {
boolean ok = true;
for (Map.Entry<Option, String> e: map.entrySet())
ok = ok & handleOption(e.getKey(), e.getValue());
return ok;
}
// </editor-fold>
@ -205,10 +239,7 @@ public abstract class BaseFileManager {
CharsetDecoder decoder;
try {
decoder = getDecoder(encodingName, ignoreEncodingErrors);
} catch (IllegalCharsetNameException e) {
log.error("unsupported.encoding", encodingName);
return (CharBuffer)CharBuffer.allocate(1).flip();
} catch (UnsupportedCharsetException e) {
} catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
log.error("unsupported.encoding", encodingName);
return (CharBuffer)CharBuffer.allocate(1).flip();
}
@ -286,6 +317,9 @@ public abstract class BaseFileManager {
// <editor-fold defaultstate="collapsed" desc="ByteBuffers">
/**
* Make a byte buffer from an input stream.
* @param in the stream
* @return a byte buffer containing the contents of the stream
* @throws IOException if an error occurred while reading the stream
*/
public ByteBuffer makeByteBuffer(InputStream in)
throws IOException {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -32,18 +32,23 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import com.sun.javadoc.*;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.main.CommandLine;
import com.sun.tools.javac.main.Option;
import com.sun.tools.javac.util.BaseFileManager;
import com.sun.tools.javac.util.ClientCodeException;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Options;
import static com.sun.tools.javac.code.Flags.*;
/**
@ -71,7 +76,7 @@ public class Start extends ToolOption.Helper {
private static final String standardDocletClassName =
"com.sun.tools.doclets.standard.Standard";
private long defaultFilter = PUBLIC | PROTECTED;
private final long defaultFilter = PUBLIC | PROTECTED;
private final Messager messager;
@ -324,6 +329,15 @@ public class Start extends ToolOption.Helper {
javaNames.append(arg);
}
}
if (fileManager == null) {
JavacFileManager.preRegister(context);
fileManager = context.get(JavaFileManager.class);
}
if (fileManager instanceof BaseFileManager) {
((BaseFileManager) fileManager).handleOptions(fileManagerOpts);
}
compOpts.notifyListeners();
if (javaNames.isEmpty() && subPackages.isEmpty() && isEmpty(fileObjects)) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,10 +25,14 @@
package com.sun.tools.javadoc;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.StringTokenizer;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.main.Option;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Options;
import java.util.StringTokenizer;
/**
@ -45,42 +49,42 @@ public enum ToolOption {
BOOTCLASSPATH("-bootclasspath", true) {
@Override
public void process(Helper helper, String arg) {
helper.setCompilerOpt(opt, arg);
helper.setFileManagerOpt(Option.BOOTCLASSPATH, arg);
}
},
CLASSPATH("-classpath", true) {
@Override
public void process(Helper helper, String arg) {
helper.setCompilerOpt(opt, arg);
helper.setFileManagerOpt(Option.CLASSPATH, arg);
}
},
CP("-cp", true) {
@Override
public void process(Helper helper, String arg) {
helper.setCompilerOpt(opt, arg);
helper.setFileManagerOpt(Option.CP, arg);
}
},
EXTDIRS("-extdirs", true) {
@Override
public void process(Helper helper, String arg) {
helper.setCompilerOpt(opt, arg);
helper.setFileManagerOpt(Option.EXTDIRS, arg);
}
},
SOURCEPATH("-sourcepath", true) {
@Override
public void process(Helper helper, String arg) {
helper.setCompilerOpt(opt, arg);
helper.setFileManagerOpt(Option.SOURCEPATH, arg);
}
},
SYSCLASSPATH("-sysclasspath", true) {
@Override
public void process(Helper helper, String arg) {
helper.setCompilerOpt("-bootclasspath", arg);
helper.setFileManagerOpt(Option.BOOTCLASSPATH, arg);
}
},
@ -274,6 +278,9 @@ public enum ToolOption {
/** Excluded packages, from -exclude. */
final ListBuffer<String> excludedPackages = new ListBuffer<>();
// File manager options
final Map<Option, String> fileManagerOpts = new LinkedHashMap<>();
/** javac options, set by various options. */
Options compOpts; // = Options.instance(context)
@ -306,7 +313,7 @@ public enum ToolOption {
abstract void usageError(String msg, Object... args);
protected void addToList(ListBuffer<String> list, String str){
void addToList(ListBuffer<String> list, String str){
StringTokenizer st = new StringTokenizer(str, ":");
String current;
while(st.hasMoreTokens()){
@ -315,18 +322,22 @@ public enum ToolOption {
}
}
protected void setFilter(long filterBits) {
void setFilter(long filterBits) {
if (showAccess != null) {
usageError("main.incompatible.access.flags");
}
showAccess = new ModifierFilter(filterBits);
}
private void setCompilerOpt(String opt, String arg) {
void setCompilerOpt(String opt, String arg) {
if (compOpts.get(opt) != null) {
usageError("main.option.already.seen", opt);
}
compOpts.put(opt, arg);
}
void setFileManagerOpt(Option opt, String arg) {
fileManagerOpts.put(opt, arg);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -57,12 +57,8 @@ public class T6358166 extends AbstractProcessor {
static void test(JavacFileManager fm, JavaFileObject f, String... args) throws Throwable {
Context context = new Context();
fm.setContext(context);
Main compilerMain = new Main("javac", new PrintWriter(System.err, true));
compilerMain.setOptions(Options.instance(context));
compilerMain.filenames = new LinkedHashSet<File>();
compilerMain.processArgs(args);
Main compilerMain = initCompilerMain(context, fm, args);
JavaCompiler c = JavaCompiler.instance(context);
@ -76,6 +72,19 @@ public class T6358166 extends AbstractProcessor {
throw new AssertionError("elapsed time is suspect: " + msec);
}
static Main initCompilerMain(Context context, JavacFileManager fm, String... args) {
fm.setContext(context);
context.put(JavaFileManager.class, fm);
Main compilerMain = new Main("javac", new PrintWriter(System.err, true));
compilerMain.setOptions(Options.instance(context));
compilerMain.filenames = new LinkedHashSet<File>();
compilerMain.deferredFileManagerOptions = new LinkedHashMap<>();
compilerMain.processArgs(args);
fm.handleOptions(compilerMain.deferredFileManagerOptions);
return compilerMain;
}
public boolean process(Set<? extends TypeElement> tes, RoundEnvironment renv) {
return true;
}

View File

@ -68,12 +68,9 @@ public class T6358168 extends AbstractProcessor {
static void testNoAnnotationProcessing(JavacFileManager fm, JavaFileObject f) throws Throwable {
Context context = new Context();
fm.setContext(context);
Main compilerMain = new Main("javac", new PrintWriter(System.err, true));
compilerMain.setOptions(Options.instance(context));
compilerMain.filenames = new LinkedHashSet<File>();
compilerMain.processArgs(new String[] { "-d", "." });
String[] args = { "-d", "." };
Main compilerMain = initCompilerMain(context, fm, args);
JavaCompiler compiler = JavaCompiler.instance(context);
compiler.compile(List.of(f));
@ -87,16 +84,14 @@ public class T6358168 extends AbstractProcessor {
static void testAnnotationProcessing(JavacFileManager fm, JavaFileObject f) throws Throwable {
Context context = new Context();
fm.setContext(context);
Main compilerMain = new Main("javac", new PrintWriter(System.err, true));
compilerMain.setOptions(Options.instance(context));
compilerMain.filenames = new LinkedHashSet<File>();
compilerMain.processArgs(new String[] {
"-XprintRounds",
"-processorpath", testClasses,
"-processor", self,
"-d", "."});
String[] args = {
"-XprintRounds",
"-processorpath", testClasses,
"-processor", self,
"-d", "."
};
Main compilerMain = initCompilerMain(context, fm, args);
JavaCompiler compiler = JavaCompiler.instance(context);
compiler.compile(List.of(f));
@ -108,6 +103,19 @@ public class T6358168 extends AbstractProcessor {
}
}
static Main initCompilerMain(Context context, JavacFileManager fm, String... args) {
fm.setContext(context);
context.put(JavaFileManager.class, fm);
Main compilerMain = new Main("javac", new PrintWriter(System.err, true));
compilerMain.setOptions(Options.instance(context));
compilerMain.filenames = new LinkedHashSet<File>();
compilerMain.deferredFileManagerOptions = new LinkedHashMap<>();
compilerMain.processArgs(args);
fm.handleOptions(compilerMain.deferredFileManagerOptions);
return compilerMain;
}
public boolean process(Set<? extends TypeElement> tes, RoundEnvironment renv) {
return true;
}

View File

@ -0,0 +1,632 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7026941
* @summary path options ignored when reusing filemanager across tasks
*/
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URI;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import static javax.tools.StandardLocation.*;
/**
* Test for combinations of using javac command-line options and fileManager setLocation
* calls to affect the locations available in the fileManager.
*
* Using a single Java compiler and file manager, for each of the standard locations,
* a series of operations is performed, using either compiler options or setLocation
* calls. Each operation includes a compilation, and then a check for the value of
* the standard location available in the file manager.
*
* The operations generate and use unique files to minimize the possibility of false
* positive results.
*/
public class TestSearchPaths {
public static void main(String... args) throws Exception {
TestSearchPaths t = new TestSearchPaths();
t.run();
}
void run() throws Exception {
compiler = ToolProvider.getSystemJavaCompiler();
fileManager = compiler.getStandardFileManager(null, null, null);
// basic output path
testClassOutput();
// basic search paths
testClassPath();
testSourcePath();
testPlatformClassPath();
// annotation processing
testAnnotationProcessorPath();
testSourceOutput();
// javah equivalent
testNativeHeaderOutput();
// future-proof: guard against new StandardLocations being added
if (!tested.equals(EnumSet.allOf(StandardLocation.class))) {
error("not all standard locations have been tested");
out.println("not yet tested: " + EnumSet.complementOf(tested));
}
if (errors > 0) {
throw new Exception(errors + " errors occurred");
}
}
void testClassOutput() throws IOException {
String test = "testClassOutput";
for (int i = 1; i <= 5; i++) {
File classes = createDir(test + "/" + i + "/classes");
List<String> options;
switch (i) {
default:
options = getOptions("-d", classes.getPath());
break;
case 3:
setLocation(CLASS_OUTPUT, classes);
options = null;
break;
}
List<JavaFileObject> sources = getSources("class C" + i + " { }");
callTask(options, sources);
checkPath(CLASS_OUTPUT, Mode.EQUALS, classes);
checkFile(CLASS_OUTPUT, "C" + i + ".class");
}
tested.add(CLASS_OUTPUT);
}
void testClassPath() throws IOException {
String test = "testClassPath";
for (int i = 1; i <= 5; i++) {
File classes = createDir(test + "/" + i + "/classes");
File classpath = new File("testClassOutput/" + i + "/classes");
List<String> options;
switch (i) {
default:
options = getOptions("-d", classes.getPath(), "-classpath", classpath.getPath());
break;
case 3:
setLocation(CLASS_PATH, classpath);
options = getOptions("-d", classes.getPath());
break;
case 4:
options = getOptions("-d", classes.getPath(), "-cp", classpath.getPath());
break;
}
List<JavaFileObject> sources = getSources("class D" + i + " { C" + i + " c; }");
callTask(options, sources);
checkPath(CLASS_PATH, Mode.EQUALS, classpath);
checkFile(CLASS_OUTPUT, "D" + i + ".class");
}
tested.add(CLASS_PATH);
}
void testSourcePath() throws IOException {
String test = "testSourcePath";
setLocation(CLASS_PATH); // empty
for (int i = 1; i <= 5; i++) {
File src = createDir(test + "/" + i + "/src");
writeFile(src, "C" + i + ".java", "class C" + i + "{ }");
File classes = createDir(test + "/" + i + "/classes");
File srcpath = src;
List<String> options;
switch (i) {
default:
options = getOptions("-d", classes.getPath(), "-sourcepath", srcpath.getPath());
break;
case 3:
setLocation(SOURCE_PATH, srcpath);
options = getOptions("-d", classes.getPath());
break;
}
List<JavaFileObject> sources = getSources("class D" + i + " { C" + i + " c; }");
callTask(options, sources);
checkPath(SOURCE_PATH, Mode.EQUALS, srcpath);
checkFile(CLASS_OUTPUT, "D" + i + ".class");
}
tested.add(SOURCE_PATH);
}
void testPlatformClassPath() throws IOException {
String test = "testPlatformClassPath";
List<File> defaultPath = getLocation(PLATFORM_CLASS_PATH);
StringBuilder sb = new StringBuilder();
for (File f: defaultPath) {
if (sb.length() > 0)
sb.append(File.pathSeparator);
sb.append(f);
}
String defaultPathString = sb.toString();
setLocation(CLASS_PATH); // empty
setLocation(SOURCE_PATH); // empty
for (int i = 1; i <= 10; i++) {
File classes = createDir(test + "/" + i + "/classes");
File testJars = createDir(test + "/" + i + "/testJars");
File testClasses = createDir(test + "/" + i + "/testClasses");
callTask(getOptions("-d", testClasses.getPath()), getSources("class C" + i + " { }"));
List<String> options;
Mode mode;
List<File> match;
String reference = "C" + i + " c;";
File jar;
switch (i) {
case 1:
options = getOptions("-d", classes.getPath(), "-Xbootclasspath/p:" + testClasses);
mode = Mode.STARTS_WITH;
match = Arrays.asList(testClasses);
break;
case 2:
// the default values for -extdirs and -endorseddirs come after the bootclasspath;
// so to check -Xbootclasspath/a: we specify empty values for those options.
options = getOptions("-d", classes.getPath(),
"-Xbootclasspath/a:" + testClasses,
"-extdirs", "",
"-endorseddirs", "");
mode = Mode.ENDS_WITH;
match = Arrays.asList(testClasses);
break;
case 3:
options = getOptions("-d", classes.getPath(), "-Xbootclasspath:" + defaultPathString);
mode = Mode.EQUALS;
match = defaultPath;
reference = "";
break;
case 4:
fileManager.setLocation(PLATFORM_CLASS_PATH, null);
jar = new File(testJars, "j" + i + ".jar");
writeJar(jar, testClasses, "C" + i + ".class");
options = getOptions("-d", classes.getPath(), "-endorseddirs", testJars.getPath());
mode = Mode.CONTAINS;
match = Arrays.asList(jar);
break;
case 5:
fileManager.setLocation(PLATFORM_CLASS_PATH, null);
jar = new File(testJars, "j" + i + ".jar");
writeJar(jar, testClasses, "C" + i + ".class");
options = getOptions("-d", classes.getPath(), "-Djava.endorsed.dirs=" + testJars.getPath());
mode = Mode.CONTAINS;
match = Arrays.asList(jar);
break;
case 6:
fileManager.setLocation(PLATFORM_CLASS_PATH, null);
jar = new File(testJars, "j" + i + ".jar");
writeJar(jar, testClasses, "C" + i + ".class");
options = getOptions("-d", classes.getPath(), "-extdirs", testJars.getPath());
mode = Mode.CONTAINS;
match = Arrays.asList(jar);
break;
case 7:
fileManager.setLocation(PLATFORM_CLASS_PATH, null);
jar = new File(testJars, "j" + i + ".jar");
writeJar(jar, testClasses, "C" + i + ".class");
options = getOptions("-d", classes.getPath(), "-Djava.ext.dirs=" + testJars.getPath());
mode = Mode.CONTAINS;
match = Arrays.asList(jar);
break;
case 8:
setLocation(PLATFORM_CLASS_PATH, defaultPath);
options = getOptions("-d", classes.getPath());
mode = Mode.EQUALS;
match = defaultPath;
reference = "";
break;
default:
options = getOptions("-d", classes.getPath(), "-bootclasspath", defaultPathString);
mode = Mode.EQUALS;
match = defaultPath;
reference = "";
break;
}
List<JavaFileObject> sources = getSources("class D" + i + " { " + reference + " }");
callTask(options, sources);
checkPath(PLATFORM_CLASS_PATH, mode, match);
checkFile(CLASS_OUTPUT, "D" + i + ".class");
}
tested.add(PLATFORM_CLASS_PATH);
}
void testAnnotationProcessorPath() throws IOException {
String test = "testAnnotationProcessorPath";
String template =
"import java.util.*;\n"
+ "import javax.annotation.processing.*;\n"
+ "import javax.lang.model.*;\n"
+ "import javax.lang.model.element.*;\n"
+ "@SupportedAnnotationTypes(\"*\")\n"
+ "public class A%d extends AbstractProcessor {\n"
+ " public boolean process(Set<? extends TypeElement> annos, RoundEnvironment rEnv) {\n"
+ " return true;\n"
+ " }\n"
+ " public SourceVersion getSupportedSourceVersion() {\n"
+ " return SourceVersion.latest();\n"
+ " }\n"
+ "}";
for (int i = 1; i <= 5; i++) {
File classes = createDir(test + "/" + i + "/classes");
File annodir = createDir(test + "/" + i + "/processors");
callTask(getOptions("-d", annodir.getPath()), getSources(String.format(template, i)));
File annopath = annodir;
List<String> options;
switch (i) {
default:
options = getOptions("-d", classes.getPath(),
"-processorpath", annopath.getPath(),
"-processor", "A" + i);
break;
case 3:
setLocation(ANNOTATION_PROCESSOR_PATH, annopath);
options = getOptions("-d", classes.getPath(),
"-processor", "A" + i);
break;
}
List<JavaFileObject> sources = getSources("class D" + i + " { }");
callTask(options, sources);
checkPath(ANNOTATION_PROCESSOR_PATH, Mode.EQUALS, annopath);
checkFile(CLASS_OUTPUT, "D" + i + ".class");
}
tested.add(ANNOTATION_PROCESSOR_PATH);
}
void testSourceOutput() throws IOException {
String test = "testAnnotationProcessorPath";
String source =
"import java.io.*;\n"
+ "import java.util.*;\n"
+ "import javax.annotation.processing.*;\n"
+ "import javax.lang.model.*;\n"
+ "import javax.lang.model.element.*;\n"
+ "import javax.tools.*;\n"
+ "@SupportedOptions(\"name\")\n"
+ "@SupportedAnnotationTypes(\"*\")\n"
+ "public class A extends AbstractProcessor {\n"
+ " int round = 0;\n"
+ " public boolean process(Set<? extends TypeElement> annos, RoundEnvironment rEnv) {\n"
+ " if (round++ == 0) try {\n"
+ " String name = processingEnv.getOptions().get(\"name\");\n"
+ " JavaFileObject fo = processingEnv.getFiler().createSourceFile(name);\n"
+ " try (Writer out = fo.openWriter()) {\n"
+ " out.write(\"class \" + name + \" { }\");\n"
+ " }\n"
+ " } catch (IOException e) { throw new Error(e); }\n"
+ " return true;\n"
+ " }\n"
+ " public SourceVersion getSupportedSourceVersion() {\n"
+ " return SourceVersion.latest();\n"
+ " }\n"
+ "}";
File annodir = createDir(test + "/processors");
callTask(getOptions("-d", annodir.getPath()), getSources(source));
setLocation(ANNOTATION_PROCESSOR_PATH, annodir);
for (int i = 1; i <= 5; i++) {
File classes = createDir(test + "/" + i + "/classes");
File genSrc = createDir(test + "/" + "/genSrc");
List<String> options;
switch (i) {
default:
options = getOptions("-d", classes.getPath(),
"-processor", "A", "-Aname=G" + i,
"-s", genSrc.getPath());
break;
case 3:
setLocation(SOURCE_OUTPUT, genSrc);
options = getOptions("-d", classes.getPath(),
"-processor", "A", "-Aname=G" + i);
break;
}
List<JavaFileObject> sources = getSources("class D" + i + " { }");
callTask(options, sources);
checkPath(SOURCE_OUTPUT, Mode.EQUALS, genSrc);
checkFile(CLASS_OUTPUT, "D" + i + ".class");
checkFile(CLASS_OUTPUT, "G" + i + ".class");
}
tested.add(SOURCE_OUTPUT);
}
void testNativeHeaderOutput() throws IOException {
String test = "testNativeHeaderOutput";
for (int i = 1; i <= 5; i++) {
File classes = createDir(test + "/" + i + "/classes");
File headers = createDir(test + "/" + i + "/hdrs");
List<String> options;
switch (i) {
default:
options = getOptions("-d", classes.getPath(), "-h", headers.getPath());
break;
case 3:
setLocation(NATIVE_HEADER_OUTPUT, headers);
options = getOptions("-d", classes.getPath());
break;
}
List<JavaFileObject> sources = getSources("class C" + i + " { native void m(); }");
callTask(options, sources);
checkPath(NATIVE_HEADER_OUTPUT, Mode.EQUALS, headers);
checkFile(NATIVE_HEADER_OUTPUT, "C" + i + ".h");
}
tested.add(StandardLocation.NATIVE_HEADER_OUTPUT);
}
List<String> getOptions(String... args) {
return Arrays.asList(args);
}
List<JavaFileObject> getSources(String... sources) {
List<JavaFileObject> list = new ArrayList<>();
for (String s: sources)
list.add(getSource(s));
return list;
}
JavaFileObject getSource(final String source) {
return new SimpleJavaFileObject(getURIFromSource(source), JavaFileObject.Kind.SOURCE) {
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return source;
}
};
}
void callTask(List<String> options, List<JavaFileObject> files) {
out.print("compile: ");
if (options != null) {
for (String o: options) {
if (o.length() > 64) {
o = o.substring(0, 32) + "..." + o.substring(o.length() - 32);
}
out.print(" " + o);
}
}
for (JavaFileObject f: files)
out.print(" " + f.getName());
out.println();
CompilationTask t = compiler.getTask(out, fileManager, null, options, null, files);
boolean ok = t.call();
if (!ok)
error("compilation failed");
}
enum Mode { EQUALS, CONTAINS, STARTS_WITH, ENDS_WITH };
void checkFile(StandardLocation l, String path) {
if (!l.isOutputLocation()) {
error("Not an output location: " + l);
return;
}
List<File> files = getLocation(l);
if (files == null) {
error("location is unset: " + l);
return;
}
if (files.size() != 1)
error("unexpected number of entries on " + l + ": " + files.size());
File f = new File(files.get(0), path);
if (!f.exists())
error("file not found: " + f);
}
void checkPath(StandardLocation l, Mode m, File expect) {
checkPath(l, m, Arrays.asList(expect));
}
void checkPath(StandardLocation l, Mode m, List<File> expect) {
List<File> files = getLocation(l);
if (files == null) {
error("location is unset: " + l);
return;
}
switch (m) {
case EQUALS:
if (!Objects.equals(files, expect)) {
error("location does not match the expected files: " + l);
out.println("found: " + files);
out.println("expect: " + expect);
}
break;
case CONTAINS:
int containsIndex = Collections.indexOfSubList(files, expect);
if (containsIndex == -1) {
error("location does not contain the expected files: " + l);
out.println("found: " + files);
out.println("expect: " + expect);
}
break;
case STARTS_WITH:
int startsIndex = Collections.indexOfSubList(files, expect);
if (startsIndex != 0) {
error("location does not start with the expected files: " + l);
out.println("found: " + files);
out.println("expect: " + expect);
}
break;
case ENDS_WITH:
int endsIndex = Collections.lastIndexOfSubList(files, expect);
if (endsIndex != files.size() - expect.size()) {
error("location does not end with the expected files: " + l);
out.println("found: " + files);
out.println("expect: " + expect);
}
break;
}
}
List<File> getLocation(StandardLocation l) {
Iterable<? extends File> iter = fileManager.getLocation(l);
if (iter == null)
return null;
List<File> files = new ArrayList<>();
for (File f: iter)
files.add(f);
return files;
}
void setLocation(StandardLocation l, File... files) throws IOException {
fileManager.setLocation(l, Arrays.asList(files));
}
void setLocation(StandardLocation l, List<File> files) throws IOException {
fileManager.setLocation(l, files);
}
void writeFile(File dir, String path, String body) throws IOException {
try (FileWriter w = new FileWriter(new File(dir, path))) {
w.write(body);
}
}
void writeJar(File jar, File dir, String... entries) throws IOException {
try (JarOutputStream j = new JarOutputStream(Files.newOutputStream(jar.toPath()))) {
for (String entry: entries) {
j.putNextEntry(new JarEntry(entry));
j.write(Files.readAllBytes(dir.toPath().resolve(entry)));
}
}
}
private static final Pattern packagePattern
= Pattern.compile("package\\s+(((?:\\w+\\.)*)(?:\\w+))");
private static final Pattern classPattern
= Pattern.compile("(?:public\\s+)?(?:class|enum|interface)\\s+(\\w+)");
private static URI getURIFromSource(String source) {
String packageName = null;
Matcher matcher = packagePattern.matcher(source);
if (matcher.find()) {
packageName = matcher.group(1).replace(".", "/");
}
matcher = classPattern.matcher(source);
if (matcher.find()) {
String className = matcher.group(1);
String path = ((packageName == null) ? "" : packageName + "/") + className + ".java";
return URI.create("myfo:///" + path);
} else {
throw new Error("Could not extract the java class "
+ "name from the provided source");
}
}
File createDir(String path) {
File dir = new File(path);
dir.mkdirs();
return dir;
}
JavaCompiler compiler;
StandardJavaFileManager fileManager;
/**
* Map for recording which standard locations have been tested.
*/
EnumSet<StandardLocation> tested = EnumSet.noneOf(StandardLocation.class);
/**
* Logging stream. Used directly with test and for getTask calls.
*/
final PrintWriter out = new PrintWriter(System.err, true);
/**
* Count of errors so far.
*/
int errors;
void error(String message) {
errors++;
out.println("Error: " + message);
}
}

View File

@ -105,14 +105,13 @@ class ArgTypeCompilerFactory implements Example.Compiler.Factory {
Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjectsFromFiles(files);
Context c = new Context();
ArgTypeMessages.preRegister(c);
ArgTypeJavaCompiler.preRegister(c);
Context c = initContext();
JavacTaskImpl t = (JavacTaskImpl) tool.getTask(out, fm, null, opts, null, fos, c);
return t.call();
}
}
/**
* Run the test using the standard simple entry point.
*/
@ -135,10 +134,8 @@ class ArgTypeCompilerFactory implements Example.Compiler.Factory {
args.add(f.getPath());
Main main = new Main("javac", out);
Context c = new Context();
Context c = initContext();
JavacFileManager.preRegister(c); // can't create it until Log has been set up
ArgTypeJavaCompiler.preRegister(c);
ArgTypeMessages.preRegister(c);
Main.Result result = main.compile(args.toArray(new String[args.size()]), c);
return result.isOK();
@ -161,18 +158,25 @@ class ArgTypeCompilerFactory implements Example.Compiler.Factory {
for (File f: files)
args.add(f.getPath());
Context c = new Context();
Context c = initContext();
JavacFileManager.preRegister(c); // can't create it until Log has been set up
ArgTypeJavaCompiler.preRegister(c);
ArgTypeMessages.preRegister(c);
Main m = new Main("javac", out);
Main.Result result = m.compile(args.toArray(new String[args.size()]), c);
return result.isOK();
}
}
private static Context initContext() {
Context context = new Context();
ArgTypeMessages.preRegister(context);
Options options = Options.instance(context);
options.addListener(() -> {
Log log = Log.instance(context);
log.setDiagnosticFormatter(new ArgTypeDiagnosticFormatter(options));
});
return context;
}
// <editor-fold defaultstate="collapsed" desc="Custom Javac components">
@ -227,29 +231,6 @@ class ArgTypeCompilerFactory implements Example.Compiler.Factory {
}
}
/**
* Trivial subtype of JavaCompiler to get access to the protected compilerKey field.
* The factory is used to ensure that the log is initialized with an instance of
* ArgTypeDiagnosticFormatter before we create the required JavaCompiler.
*/
static class ArgTypeJavaCompiler extends JavaCompiler {
static void preRegister(Context context) {
context.put(compilerKey, new Context.Factory<JavaCompiler>() {
public JavaCompiler make(Context c) {
Log log = Log.instance(c);
Options options = Options.instance(c);
log.setDiagnosticFormatter(new ArgTypeDiagnosticFormatter(options));
return new JavaCompiler(c);
}
});
}
// not used
private ArgTypeJavaCompiler() {
super(null);
}
}
/**
* Diagnostic formatter which "localizes" a message as a line
* containing a key, and a possibly empty set of descriptive strings for the

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -55,7 +55,7 @@ public class T6430209 {
// run annotation processor b6341534 so we can check diagnostics
// -proc:only -processor b6341534 -cp . ./src/*.java
String testSrc = System.getProperty("test.src", ".");
String testClasses = System.getProperty("test.classes") + System.getProperty("path.separator") + "../../lib";
String testClassPath = System.getProperty("test.class.path");
JavacTool tool = JavacTool.create();
MyDiagListener dl = new MyDiagListener();
StandardJavaFileManager fm = tool.getStandardFileManager(dl, null, null);
@ -64,7 +64,7 @@ public class T6430209 {
new File(testSrc, "test0.java"), new File(testSrc, "test1.java")));
Iterable<String> opts = Arrays.asList("-proc:only",
"-processor", "b6341534",
"-processorpath", testClasses);
"-processorpath", testClassPath);
StringWriter out = new StringWriter();
JavacTask task = tool.getTask(out, fm, dl, opts, null, files);
task.call();