mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-11 22:19:43 +00:00
Merge
This commit is contained in:
commit
93f097a106
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2016, 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
|
||||
@ -66,7 +66,8 @@ import java.io.IOException;
|
||||
* allow the <em>originating elements</em> to be provided as hints to
|
||||
* the tool infrastructure to better manage dependencies. The
|
||||
* originating elements are the types or packages (representing {@code
|
||||
* package-info} files) which caused an annotation processor to
|
||||
* package-info} files) or modules (representing {@code
|
||||
* module-info} files) which caused an annotation processor to
|
||||
* attempt to create a new file. For example, if an annotation
|
||||
* processor tries to create a source file, {@code
|
||||
* GeneratedFromUserSource}, in response to processing
|
||||
@ -111,10 +112,10 @@ import java.io.IOException;
|
||||
* to overwrite existing files that were not generated.
|
||||
*
|
||||
* <p> Processors can indicate a source or class file is generated by
|
||||
* including an {@link javax.annotation.Generated @Generated}
|
||||
* annotation.
|
||||
* including a {@code javax.annotation.Generated} annotation if the
|
||||
* environment is configured so that that type is accessible.
|
||||
*
|
||||
* <p> Note that some of the effect of overwriting a file can be
|
||||
* @apiNote Some of the effect of overwriting a file can be
|
||||
* achieved by using a <i>decorator</i>-style pattern. Instead of
|
||||
* modifying a class directly, the class is designed so that either
|
||||
* its superclass is generated by annotation processing or subclasses
|
||||
@ -131,18 +132,35 @@ import java.io.IOException;
|
||||
public interface Filer {
|
||||
/**
|
||||
* Creates a new source file and returns an object to allow
|
||||
* writing to it. The file's name and path (relative to the
|
||||
* {@linkplain StandardLocation#SOURCE_OUTPUT root output location
|
||||
* for source files}) are based on the type to be declared in that
|
||||
* file. If more than one type is being declared, the name of the
|
||||
* principal top-level type (the public one, for example) should
|
||||
* be used. A source file can also be created to hold information
|
||||
* about a package, including package annotations. To create a
|
||||
* source file for a named package, have {@code name} be the
|
||||
* writing to it. A source file for a type, or a package can
|
||||
* be created.
|
||||
*
|
||||
* The file's name and path (relative to the {@linkplain
|
||||
* StandardLocation#SOURCE_OUTPUT root output location for source
|
||||
* files}) are based on the name of the item to be declared in
|
||||
* that file as well as the specified module for the item (if
|
||||
* any).
|
||||
*
|
||||
* If more than one type is being declared in a single file (that
|
||||
* is, a single compilation unit), the name of the file should
|
||||
* correspond to the name of the principal top-level type (the
|
||||
* public one, for example).
|
||||
*
|
||||
* <p>A source file can also be created to hold information about
|
||||
* a package, including package annotations. To create a source
|
||||
* file for a named package, have the {@code name} argument be the
|
||||
* package's name followed by {@code ".package-info"}; to create a
|
||||
* source file for an unnamed package, use {@code "package-info"}.
|
||||
*
|
||||
* <p> Note that to use a particular {@linkplain
|
||||
* <p>The optional module name is prefixed to the type name or
|
||||
* package name and separated using a "{@code /}" character. For
|
||||
* example, to create a source file for type {@code a.B} in module
|
||||
* {@code foo}, use a {@code name} argument of {@code "foo/a.B"}.
|
||||
*
|
||||
* <p>Creating a source file in or for an unnamed package in a named
|
||||
* module is <em>not</em> supported.
|
||||
*
|
||||
* @apiNote To use a particular {@linkplain
|
||||
* java.nio.charset.Charset charset} to encode the contents of the
|
||||
* file, an {@code OutputStreamWriter} with the chosen charset can
|
||||
* be created from the {@code OutputStream} from the returned
|
||||
@ -161,37 +179,51 @@ public interface Filer {
|
||||
* @param name canonical (fully qualified) name of the principal type
|
||||
* being declared in this file or a package name followed by
|
||||
* {@code ".package-info"} for a package information file
|
||||
* @param originatingElements type or package elements causally
|
||||
* @param originatingElements type or package or module elements causally
|
||||
* associated with the creation of this file, may be elided or
|
||||
* {@code null}
|
||||
* @return a {@code JavaFileObject} to write the new source file
|
||||
* @throws FilerException if the same pathname has already been
|
||||
* created, the same type has already been created, or the name is
|
||||
* not valid for a type
|
||||
* otherwise not valid for the entity requested to being created
|
||||
* @throws IOException if the file cannot be created
|
||||
* @jls 7.3 Compilation Units
|
||||
*/
|
||||
JavaFileObject createSourceFile(CharSequence name,
|
||||
Element... originatingElements) throws IOException;
|
||||
|
||||
/**
|
||||
* Creates a new class file, and returns an object to allow
|
||||
* writing to it. The file's name and path (relative to the
|
||||
* {@linkplain StandardLocation#CLASS_OUTPUT root output location
|
||||
* for class files}) are based on the name of the type being
|
||||
* written. A class file can also be created to hold information
|
||||
* about a package, including package annotations. To create a
|
||||
* class file for a named package, have {@code name} be the
|
||||
* writing to it. A class file for a type, or a package can
|
||||
* be created.
|
||||
*
|
||||
* The file's name and path (relative to the {@linkplain
|
||||
* StandardLocation#CLASS_OUTPUT root output location for class
|
||||
* files}) are based on the name of the item to be declared as
|
||||
* well as the specified module for the item (if any).
|
||||
*
|
||||
* <p>A class file can also be created to hold information about a
|
||||
* package, including package annotations. To create a class file
|
||||
* for a named package, have the {@code name} argument be the
|
||||
* package's name followed by {@code ".package-info"}; creating a
|
||||
* class file for an unnamed package is not supported.
|
||||
*
|
||||
* <p>To avoid subsequent errors, the contents of the class file
|
||||
* should be compatible with the {@linkplain
|
||||
* ProcessingEnvironment#getSourceVersion source version} being used
|
||||
* for this run.
|
||||
* <p>The optional module name is prefixed to the type name or
|
||||
* package name and separated using a "{@code /}" character. For
|
||||
* example, to create a class file for type {@code a.B} in module
|
||||
* {@code foo}, use a {@code name} argument of {@code "foo/a.B"}.
|
||||
*
|
||||
* <p>Creating a class file in or for an unnamed package in a named
|
||||
* module is <em>not</em> supported.
|
||||
*
|
||||
* @apiNote To avoid subsequent errors, the contents of the class
|
||||
* file should be compatible with the {@linkplain
|
||||
* ProcessingEnvironment#getSourceVersion source version} being
|
||||
* used for this run.
|
||||
*
|
||||
* @param name binary name of the type being written or a package name followed by
|
||||
* {@code ".package-info"} for a package information file
|
||||
* @param originatingElements type or package elements causally
|
||||
* @param originatingElements type or package or module elements causally
|
||||
* associated with the creation of this file, may be elided or
|
||||
* {@code null}
|
||||
* @return a {@code JavaFileObject} to write the new class file
|
||||
@ -210,20 +242,27 @@ public interface Filer {
|
||||
* other supported location. The locations {@link
|
||||
* StandardLocation#CLASS_OUTPUT CLASS_OUTPUT} and {@link
|
||||
* StandardLocation#SOURCE_OUTPUT SOURCE_OUTPUT} must be
|
||||
* supported. The resource may be named relative to some package
|
||||
* (as are source and class files), and from there by a relative
|
||||
* pathname. In a loose sense, the full pathname of the new file
|
||||
* will be the concatenation of {@code location}, {@code pkg}, and
|
||||
* {@code relativeName}.
|
||||
* supported. The resource may be named relative to some module
|
||||
* and/or package (as are source and class files), and from there
|
||||
* by a relative pathname. In a loose sense, the full pathname of
|
||||
* the new file will be the concatenation of {@code location},
|
||||
* {@code moduleAndPkg}, and {@code relativeName}.
|
||||
*
|
||||
* <p>Files created via this method are not registered for
|
||||
* If {@code moduleAndPkg} contains a "{@code /}" character, the
|
||||
* prefix before the "{@code /}" character is the module name and
|
||||
* the suffix after the "{@code /}" character is the package
|
||||
* name. The package suffix may be empty. If {@code moduleAndPkg}
|
||||
* does not contain a "{@code /}" character, the entire argument
|
||||
* is interpreted as a package name.
|
||||
*
|
||||
* <p>Files created via this method are <em>not</em> registered for
|
||||
* annotation processing, even if the full pathname of the file
|
||||
* would correspond to the full pathname of a new source file
|
||||
* or new class file.
|
||||
*
|
||||
* @param location location of the new file
|
||||
* @param pkg package relative to which the file should be named,
|
||||
* or the empty string if none
|
||||
* @param moduleAndPkg module and/or package relative to which the file
|
||||
* should be named, or the empty string if none
|
||||
* @param relativeName final pathname components of the file
|
||||
* @param originatingElements type or package elements causally
|
||||
* associated with the creation of this file, may be elided or
|
||||
@ -233,10 +272,11 @@ public interface Filer {
|
||||
* @throws FilerException if the same pathname has already been
|
||||
* created
|
||||
* @throws IllegalArgumentException for an unsupported location
|
||||
* @throws IllegalArgumentException if {@code moduleAndPkg} is ill-formed
|
||||
* @throws IllegalArgumentException if {@code relativeName} is not relative
|
||||
*/
|
||||
FileObject createResource(JavaFileManager.Location location,
|
||||
CharSequence pkg,
|
||||
CharSequence moduleAndPkg,
|
||||
CharSequence relativeName,
|
||||
Element... originatingElements) throws IOException;
|
||||
|
||||
@ -246,18 +286,27 @@ public interface Filer {
|
||||
* and {@link StandardLocation#SOURCE_OUTPUT SOURCE_OUTPUT} must
|
||||
* be supported.
|
||||
*
|
||||
* <p>If {@code moduleAndPkg} contains a "{@code /}" character, the
|
||||
* prefix before the "{@code /}" character is the module name and
|
||||
* the suffix after the "{@code /}" character is the package
|
||||
* name. The package suffix may be empty; however, if a module
|
||||
* name is present, it must be nonempty. If {@code moduleAndPkg}
|
||||
* does not contain a "{@code /}" character, the entire argument
|
||||
* is interpreted as a package name.
|
||||
*
|
||||
* @param location location of the file
|
||||
* @param pkg package relative to which the file should be searched,
|
||||
* or the empty string if none
|
||||
* @param moduleAndPkg module and/or package relative to which the file
|
||||
* should be searched for, or the empty string if none
|
||||
* @param relativeName final pathname components of the file
|
||||
* @return an object to read the file
|
||||
* @throws FilerException if the same pathname has already been
|
||||
* opened for writing
|
||||
* @throws IOException if the file cannot be opened
|
||||
* @throws IllegalArgumentException for an unsupported location
|
||||
* @throws IllegalArgumentException if {@code moduleAndPkg} is ill-formed
|
||||
* @throws IllegalArgumentException if {@code relativeName} is not relative
|
||||
*/
|
||||
FileObject getResource(JavaFileManager.Location location,
|
||||
CharSequence pkg,
|
||||
CharSequence moduleAndPkg,
|
||||
CharSequence relativeName) throws IOException;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2016, 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
|
||||
@ -115,7 +115,17 @@ import javax.lang.model.SourceVersion;
|
||||
* the root elements of a round. For this purpose, a type parameter is
|
||||
* considered to be enclosed by its {@linkplain
|
||||
* TypeParameterElement#getGenericElement generic
|
||||
* element}. Annotations on {@linkplain
|
||||
* element}.
|
||||
|
||||
* For this purpose, a package element is <em>not</em> considered to
|
||||
* enclose the top-level types within that package. (A root element
|
||||
* representing a package is created when a {@code package-info} file
|
||||
* is processed.) Likewise, for this purpose, a module element is
|
||||
* <em>not</em> considered to enclose the packages within that
|
||||
* module. (A root element representing a module is created when a
|
||||
* {@code module-info} file is processed.)
|
||||
*
|
||||
* Annotations on {@linkplain
|
||||
* java.lang.annotation.ElementType#TYPE_USE type uses}, as opposed to
|
||||
* annotations on elements, are ignored when computing whether or not
|
||||
* an annotation type is present.
|
||||
@ -235,12 +245,20 @@ public interface Processor {
|
||||
* (fully qualified) name of a supported annotation type.
|
||||
* Alternately it may be of the form "<tt><i>name</i>.*</tt>"
|
||||
* representing the set of all annotation types with canonical
|
||||
* names beginning with "<tt><i>name.</i></tt>". Finally, {@code
|
||||
* "*"} by itself represents the set of all annotation types,
|
||||
* including the empty set. Note that a processor should not
|
||||
* claim {@code "*"} unless it is actually processing all files;
|
||||
* claiming unnecessary annotations may cause a performance
|
||||
* slowdown in some environments.
|
||||
* names beginning with "<tt><i>name.</i></tt>".
|
||||
*
|
||||
* In either of those cases, the name of the annotation type can
|
||||
* be optionally preceded by a module name followed by a {@code
|
||||
* "/"} character. For example, if a processor supports {@code
|
||||
* "a.B"}, this can include multiple annotation types named {@code
|
||||
* a.B} which reside in different modules. To only support {@code
|
||||
* a.B} in the {@code Foo} module, instead use {@code "Foo/a.B"}.
|
||||
*
|
||||
* Finally, {@code "*"} by itself represents the set of all
|
||||
* annotation types, including the empty set. Note that a
|
||||
* processor should not claim {@code "*"} unless it is actually
|
||||
* processing all files; claiming unnecessary annotations may
|
||||
* cause a performance slowdown in some environments.
|
||||
*
|
||||
* <p>Each string returned in the set must be accepted by the
|
||||
* following grammar:
|
||||
@ -248,9 +266,12 @@ public interface Processor {
|
||||
* <blockquote>
|
||||
* <dl>
|
||||
* <dt><i>SupportedAnnotationTypeString:</i>
|
||||
* <dd><i>TypeName</i> <i>DotStar</i><sub><i>opt</i></sub>
|
||||
* <dd><i>ModulePrefix</i><sub><i>opt</i></sub> <i>TypeName</i> <i>DotStar</i><sub><i>opt</i></sub>
|
||||
* <dd><tt>*</tt>
|
||||
*
|
||||
* <dt><i>ModulePrefix:</i>
|
||||
* <dd><i>TypeName</i> <tt>/</tt>
|
||||
*
|
||||
* <dt><i>DotStar:</i>
|
||||
* <dd><tt>.</tt> <tt>*</tt>
|
||||
* </dl>
|
||||
|
||||
@ -76,14 +76,17 @@ public interface RoundEnvironment {
|
||||
/**
|
||||
* Returns the elements annotated with the given annotation type.
|
||||
* The annotation may appear directly or be inherited. Only
|
||||
* package elements and type elements <i>included</i> in this
|
||||
* package elements, module elements, and type elements <i>included</i> in this
|
||||
* round of annotation processing, or declarations of members,
|
||||
* constructors, parameters, or type parameters declared within
|
||||
* those, are returned. Included type elements are {@linkplain
|
||||
* #getRootElements root types} and any member types nested within
|
||||
* them. Elements in a package are not considered included simply
|
||||
* them. Elements of a package are not considered included simply
|
||||
* because a {@code package-info} file for that package was
|
||||
* created.
|
||||
* Likewise, elements of a module are not considered included
|
||||
* simply because a {@code module-info} file for that module was
|
||||
* created
|
||||
*
|
||||
* @param a annotation type being requested
|
||||
* @return the elements annotated with the given annotation type,
|
||||
@ -128,7 +131,7 @@ public interface RoundEnvironment {
|
||||
/**
|
||||
* Returns the elements annotated with the given annotation type.
|
||||
* The annotation may appear directly or be inherited. Only
|
||||
* package elements and type elements <i>included</i> in this
|
||||
* package elements, module elements, and type elements <i>included</i> in this
|
||||
* round of annotation processing, or declarations of members,
|
||||
* constructors, parameters, or type parameters declared within
|
||||
* those, are returned. Included type elements are {@linkplain
|
||||
@ -136,6 +139,9 @@ public interface RoundEnvironment {
|
||||
* them. Elements in a package are not considered included simply
|
||||
* because a {@code package-info} file for that package was
|
||||
* created.
|
||||
* Likewise, elements of a module are not considered included
|
||||
* simply because a {@code module-info} file for that module was
|
||||
* created
|
||||
*
|
||||
* @param a annotation type being requested
|
||||
* @return the elements annotated with the given annotation type,
|
||||
|
||||
@ -479,8 +479,10 @@ public interface JavaFileManager extends Closeable, Flushable, OptionChecker {
|
||||
|
||||
/**
|
||||
* Gets a location for the module containing a specific file representing a Java
|
||||
* source or class, to be found in a module-oriented location.
|
||||
* The result will be a package-oriented location.
|
||||
* source or class, to be found within a location, which may be either
|
||||
* a module-oriented location or an output location.
|
||||
* The result will be an output location if the given location is
|
||||
* an output location, or it will be a package-oriented location.
|
||||
*
|
||||
* @apiNote the package name is used to identify the position of the file object
|
||||
* within the <em>module/package/class</em> hierarchy identified by by the location.
|
||||
@ -494,7 +496,8 @@ public interface JavaFileManager extends Closeable, Flushable, OptionChecker {
|
||||
*
|
||||
* @throws IOException if an I/O error occurred
|
||||
* @throws UnsupportedOperationException if this operation if not supported by this file manager
|
||||
* @throws IllegalArgumentException if the location is not a module-oriented location
|
||||
* @throws IllegalArgumentException if the location is neither an output location nor a
|
||||
* module-oriented location
|
||||
* @since 9
|
||||
*/
|
||||
default Location getLocationForModule(Location location, JavaFileObject fo, String pkgName) throws IOException {
|
||||
@ -543,8 +546,9 @@ public interface JavaFileManager extends Closeable, Flushable, OptionChecker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists the locations for all the modules in a module-oriented location.
|
||||
* The locations that are returned will be package-oriented locations.
|
||||
* Lists the locations for all the modules in a module-oriented location or an output location.
|
||||
* The locations that are returned will be output locations if the given location is an output,
|
||||
* or it will be a package-oriented locations.
|
||||
*
|
||||
* @implSpec This implementation throws {@code UnsupportedOperationException}.
|
||||
*
|
||||
|
||||
@ -476,8 +476,18 @@ public class Modules extends JCTree.Visitor {
|
||||
private Location getModuleLocation(JavaFileObject fo, Name pkgName) throws IOException {
|
||||
// For now, just check module source path.
|
||||
// We may want to check source path as well.
|
||||
return fileManager.getLocationForModule(StandardLocation.MODULE_SOURCE_PATH,
|
||||
fo, (pkgName == null) ? null : pkgName.toString());
|
||||
Location loc =
|
||||
fileManager.getLocationForModule(StandardLocation.MODULE_SOURCE_PATH,
|
||||
fo, (pkgName == null) ? null : pkgName.toString());
|
||||
if (loc == null) {
|
||||
Location sourceOutput = fileManager.hasLocation(StandardLocation.SOURCE_OUTPUT) ?
|
||||
StandardLocation.SOURCE_OUTPUT : StandardLocation.CLASS_OUTPUT;
|
||||
loc =
|
||||
fileManager.getLocationForModule(sourceOutput,
|
||||
fo, (pkgName == null) ? null : pkgName.toString());
|
||||
}
|
||||
|
||||
return loc;
|
||||
}
|
||||
|
||||
private void checkSpecifiedModule(List<JCCompilationUnit> trees, JCDiagnostic.Error error) {
|
||||
@ -614,6 +624,11 @@ public class Modules extends JCTree.Visitor {
|
||||
};
|
||||
}
|
||||
|
||||
public boolean isRootModule(ModuleSymbol module) {
|
||||
Assert.checkNonNull(rootModules);
|
||||
return rootModules.contains(module);
|
||||
}
|
||||
|
||||
class ModuleVisitor extends JCTree.Visitor {
|
||||
private ModuleSymbol sym;
|
||||
private final Set<ModuleSymbol> allRequires = new HashSet<>();
|
||||
|
||||
@ -950,12 +950,10 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER)
|
||||
public Location getLocationForModule(Location location, String moduleName) throws IOException {
|
||||
Objects.requireNonNull(location);
|
||||
if (!location.isOutputLocation() && !location.isModuleOrientedLocation())
|
||||
throw new IllegalArgumentException(
|
||||
"location is not an output location or a module-oriented location: "
|
||||
+ location.getName());
|
||||
checkModuleOrientedOrOutputLocation(location);
|
||||
nullCheck(moduleName);
|
||||
if (location == SOURCE_OUTPUT && getSourceOutDir() == null)
|
||||
location = CLASS_OUTPUT;
|
||||
return locations.getLocationForModule(location, moduleName);
|
||||
}
|
||||
|
||||
@ -978,7 +976,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER)
|
||||
public Location getLocationForModule(Location location, JavaFileObject fo, String pkgName) throws IOException {
|
||||
checkModuleOrientedLocation(location);
|
||||
checkModuleOrientedOrOutputLocation(location);
|
||||
if (!(fo instanceof PathFileObject))
|
||||
throw new IllegalArgumentException(fo.getName());
|
||||
int depth = 1; // allow 1 for filename
|
||||
@ -1012,7 +1010,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER)
|
||||
public Iterable<Set<Location>> listLocationsForModules(Location location) throws IOException {
|
||||
checkModuleOrientedLocation(location);
|
||||
checkModuleOrientedOrOutputLocation(location);
|
||||
return locations.listLocationsForModules(location);
|
||||
}
|
||||
|
||||
@ -1098,10 +1096,12 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
|
||||
throw new IllegalArgumentException("location is not an output location: " + location.getName());
|
||||
}
|
||||
|
||||
private void checkModuleOrientedLocation(Location location) {
|
||||
private void checkModuleOrientedOrOutputLocation(Location location) {
|
||||
Objects.requireNonNull(location);
|
||||
if (!location.isModuleOrientedLocation())
|
||||
throw new IllegalArgumentException("location is not module-oriented: " + location.getName());
|
||||
if (!location.isModuleOrientedLocation() && !location.isOutputLocation())
|
||||
throw new IllegalArgumentException(
|
||||
"location is not an output location or a module-oriented location: "
|
||||
+ location.getName());
|
||||
}
|
||||
|
||||
private void checkNotModuleOrientedLocation(Location location) {
|
||||
|
||||
@ -476,6 +476,7 @@ public class Locations {
|
||||
|
||||
private Path outputDir;
|
||||
private Map<String, Location> moduleLocations;
|
||||
private Map<Path, Location> pathLocations;
|
||||
|
||||
OutputLocationHandler(Location location, Option... options) {
|
||||
super(location, options);
|
||||
@ -521,22 +522,51 @@ public class Locations {
|
||||
outputDir = dir;
|
||||
}
|
||||
moduleLocations = null;
|
||||
pathLocations = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
Location getLocationForModule(String name) {
|
||||
if (moduleLocations == null)
|
||||
if (moduleLocations == null) {
|
||||
moduleLocations = new HashMap<>();
|
||||
pathLocations = new HashMap<>();
|
||||
}
|
||||
Location l = moduleLocations.get(name);
|
||||
if (l == null) {
|
||||
Path out = outputDir.resolve(name);
|
||||
l = new ModuleLocationHandler(location.getName() + "[" + name + "]",
|
||||
name,
|
||||
Collections.singleton(outputDir.resolve(name)),
|
||||
Collections.singleton(out),
|
||||
true, false);
|
||||
moduleLocations.put(name, l);
|
||||
}
|
||||
pathLocations.put(out.toAbsolutePath(), l);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
@Override
|
||||
Location getLocationForModule(Path dir) {
|
||||
return pathLocations.get(dir);
|
||||
}
|
||||
|
||||
private boolean listed;
|
||||
|
||||
@Override
|
||||
Iterable<Set<Location>> listLocationsForModules() throws IOException {
|
||||
if (!listed && outputDir != null) {
|
||||
try (DirectoryStream<Path> stream = Files.newDirectoryStream(outputDir)) {
|
||||
for (Path p : stream) {
|
||||
getLocationForModule(p.getFileName().toString());
|
||||
}
|
||||
}
|
||||
listed = true;
|
||||
}
|
||||
if (moduleLocations == null)
|
||||
return Collections.emptySet();
|
||||
Set<Location> locns = new LinkedHashSet<>();
|
||||
moduleLocations.forEach((k, v) -> locns.add(v));
|
||||
return Collections.singleton(locns);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -51,6 +51,9 @@ import static javax.tools.StandardLocation.SOURCE_OUTPUT;
|
||||
import static javax.tools.StandardLocation.CLASS_OUTPUT;
|
||||
|
||||
import com.sun.tools.javac.code.Lint;
|
||||
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
import com.sun.tools.javac.comp.Modules;
|
||||
import com.sun.tools.javac.util.*;
|
||||
import com.sun.tools.javac.util.DefinedBy.Api;
|
||||
|
||||
@ -114,10 +117,12 @@ public class JavacFiler implements Filer, Closeable {
|
||||
*/
|
||||
private class FilerOutputFileObject extends ForwardingFileObject<FileObject> {
|
||||
private boolean opened = false;
|
||||
private ModuleSymbol mod;
|
||||
private String name;
|
||||
|
||||
FilerOutputFileObject(String name, FileObject fileObject) {
|
||||
FilerOutputFileObject(ModuleSymbol mod, String name, FileObject fileObject) {
|
||||
super(fileObject);
|
||||
this.mod = mod;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@ -126,7 +131,7 @@ public class JavacFiler implements Filer, Closeable {
|
||||
if (opened)
|
||||
throw new IOException(ALREADY_OPENED);
|
||||
opened = true;
|
||||
return new FilerOutputStream(name, fileObject);
|
||||
return new FilerOutputStream(mod, name, fileObject);
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER)
|
||||
@ -134,7 +139,7 @@ public class JavacFiler implements Filer, Closeable {
|
||||
if (opened)
|
||||
throw new IOException(ALREADY_OPENED);
|
||||
opened = true;
|
||||
return new FilerWriter(name, fileObject);
|
||||
return new FilerWriter(mod, name, fileObject);
|
||||
}
|
||||
|
||||
// Three anti-literacy methods
|
||||
@ -161,8 +166,8 @@ public class JavacFiler implements Filer, Closeable {
|
||||
|
||||
private class FilerOutputJavaFileObject extends FilerOutputFileObject implements JavaFileObject {
|
||||
private final JavaFileObject javaFileObject;
|
||||
FilerOutputJavaFileObject(String name, JavaFileObject javaFileObject) {
|
||||
super(name, javaFileObject);
|
||||
FilerOutputJavaFileObject(ModuleSymbol mod, String name, JavaFileObject javaFileObject) {
|
||||
super(mod, name, javaFileObject);
|
||||
this.javaFileObject = javaFileObject;
|
||||
}
|
||||
|
||||
@ -248,6 +253,7 @@ public class JavacFiler implements Filer, Closeable {
|
||||
* when they are closed.
|
||||
*/
|
||||
private class FilerOutputStream extends FilterOutputStream {
|
||||
ModuleSymbol mod;
|
||||
String typeName;
|
||||
FileObject fileObject;
|
||||
boolean closed = false;
|
||||
@ -256,8 +262,9 @@ public class JavacFiler implements Filer, Closeable {
|
||||
* @param typeName name of class or {@code null} if just a
|
||||
* binary file
|
||||
*/
|
||||
FilerOutputStream(String typeName, FileObject fileObject) throws IOException {
|
||||
FilerOutputStream(ModuleSymbol mod, String typeName, FileObject fileObject) throws IOException {
|
||||
super(fileObject.openOutputStream());
|
||||
this.mod = mod;
|
||||
this.typeName = typeName;
|
||||
this.fileObject = fileObject;
|
||||
}
|
||||
@ -270,7 +277,7 @@ public class JavacFiler implements Filer, Closeable {
|
||||
* stream, still try to process the file.
|
||||
*/
|
||||
|
||||
closeFileObject(typeName, fileObject);
|
||||
closeFileObject(mod, typeName, fileObject);
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
@ -282,6 +289,7 @@ public class JavacFiler implements Filer, Closeable {
|
||||
* closed.
|
||||
*/
|
||||
private class FilerWriter extends FilterWriter {
|
||||
ModuleSymbol mod;
|
||||
String typeName;
|
||||
FileObject fileObject;
|
||||
boolean closed = false;
|
||||
@ -291,8 +299,9 @@ public class JavacFiler implements Filer, Closeable {
|
||||
* @param typeName name of source file or {@code null} if just a
|
||||
* text file
|
||||
*/
|
||||
FilerWriter(String typeName, FileObject fileObject) throws IOException {
|
||||
FilerWriter(ModuleSymbol mod, String typeName, FileObject fileObject) throws IOException {
|
||||
super(fileObject.openWriter());
|
||||
this.mod = mod;
|
||||
this.typeName = typeName;
|
||||
this.fileObject = fileObject;
|
||||
}
|
||||
@ -305,7 +314,7 @@ public class JavacFiler implements Filer, Closeable {
|
||||
* Writer, still try to process the file.
|
||||
*/
|
||||
|
||||
closeFileObject(typeName, fileObject);
|
||||
closeFileObject(mod, typeName, fileObject);
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
@ -313,6 +322,9 @@ public class JavacFiler implements Filer, Closeable {
|
||||
|
||||
JavaFileManager fileManager;
|
||||
Log log;
|
||||
Modules modules;
|
||||
Names names;
|
||||
Symtab syms;
|
||||
Context context;
|
||||
boolean lastRound;
|
||||
|
||||
@ -340,7 +352,7 @@ public class JavacFiler implements Filer, Closeable {
|
||||
* This set must be synchronized. Its iterators should preserve
|
||||
* insertion order.
|
||||
*/
|
||||
private final Map<String, JavaFileObject> generatedClasses;
|
||||
private final Map<ModuleSymbol, Map<String, JavaFileObject>> generatedClasses;
|
||||
|
||||
/**
|
||||
* JavaFileObjects for source files closed in this round. This
|
||||
@ -353,13 +365,13 @@ public class JavacFiler implements Filer, Closeable {
|
||||
* Names of all created source files. Its iterators should
|
||||
* preserve insertion order.
|
||||
*/
|
||||
private final Set<String> aggregateGeneratedSourceNames;
|
||||
private final Set<Pair<ModuleSymbol, String>> aggregateGeneratedSourceNames;
|
||||
|
||||
/**
|
||||
* Names of all created class files. Its iterators should
|
||||
* preserve insertion order.
|
||||
*/
|
||||
private final Set<String> aggregateGeneratedClassNames;
|
||||
private final Set<Pair<ModuleSymbol, String>> aggregateGeneratedClassNames;
|
||||
|
||||
|
||||
JavacFiler(Context context) {
|
||||
@ -367,12 +379,15 @@ public class JavacFiler implements Filer, Closeable {
|
||||
fileManager = context.get(JavaFileManager.class);
|
||||
|
||||
log = Log.instance(context);
|
||||
modules = Modules.instance(context);
|
||||
names = Names.instance(context);
|
||||
syms = Symtab.instance(context);
|
||||
|
||||
fileObjectHistory = synchronizedSet(new LinkedHashSet<FileObject>());
|
||||
generatedSourceNames = synchronizedSet(new LinkedHashSet<String>());
|
||||
generatedSourceFileObjects = synchronizedSet(new LinkedHashSet<JavaFileObject>());
|
||||
|
||||
generatedClasses = synchronizedMap(new LinkedHashMap<String, JavaFileObject>());
|
||||
generatedClasses = synchronizedMap(new LinkedHashMap<>());
|
||||
|
||||
openTypeNames = synchronizedSet(new LinkedHashSet<String>());
|
||||
|
||||
@ -382,19 +397,51 @@ public class JavacFiler implements Filer, Closeable {
|
||||
lint = (Lint.instance(context)).isEnabled(PROCESSING);
|
||||
}
|
||||
|
||||
@DefinedBy(Api.ANNOTATION_PROCESSING)
|
||||
public JavaFileObject createSourceFile(CharSequence name,
|
||||
@Override @DefinedBy(Api.ANNOTATION_PROCESSING)
|
||||
public JavaFileObject createSourceFile(CharSequence nameAndModule,
|
||||
Element... originatingElements) throws IOException {
|
||||
return createSourceOrClassFile(true, name.toString());
|
||||
Pair<ModuleSymbol, String> moduleAndClass = checkOrInferModule(nameAndModule);
|
||||
return createSourceOrClassFile(moduleAndClass.fst, true, moduleAndClass.snd);
|
||||
}
|
||||
|
||||
@DefinedBy(Api.ANNOTATION_PROCESSING)
|
||||
public JavaFileObject createClassFile(CharSequence name,
|
||||
Element... originatingElements) throws IOException {
|
||||
return createSourceOrClassFile(false, name.toString());
|
||||
@Override @DefinedBy(Api.ANNOTATION_PROCESSING)
|
||||
public JavaFileObject createClassFile(CharSequence nameAndModule,
|
||||
Element... originatingElements) throws IOException {
|
||||
Pair<ModuleSymbol, String> moduleAndClass = checkOrInferModule(nameAndModule);
|
||||
return createSourceOrClassFile(moduleAndClass.fst, false, moduleAndClass.snd);
|
||||
}
|
||||
|
||||
private JavaFileObject createSourceOrClassFile(boolean isSourceFile, String name) throws IOException {
|
||||
private Pair<ModuleSymbol, String> checkOrInferModule(CharSequence moduleAndPkg) throws FilerException {
|
||||
String moduleAndPkgString = moduleAndPkg.toString();
|
||||
int slash = moduleAndPkgString.indexOf('/');
|
||||
|
||||
if (slash != (-1)) {
|
||||
//module name specified:
|
||||
String module = moduleAndPkgString.substring(0, slash);
|
||||
|
||||
ModuleSymbol explicitModule = syms.getModule(names.fromString(module));
|
||||
|
||||
if (explicitModule == null) {
|
||||
throw new FilerException("Module: " + module + " does not exist.");
|
||||
}
|
||||
|
||||
if (!modules.isRootModule(explicitModule)) {
|
||||
throw new FilerException("Cannot write to the given module!");
|
||||
}
|
||||
|
||||
return Pair.of(explicitModule, moduleAndPkgString.substring(slash + 1));
|
||||
} else {
|
||||
if (modules.multiModuleMode) {
|
||||
throw new FilerException("No module to write to specified!");
|
||||
}
|
||||
|
||||
return Pair.of(modules.getDefaultModule(), moduleAndPkgString);
|
||||
}
|
||||
}
|
||||
|
||||
private JavaFileObject createSourceOrClassFile(ModuleSymbol mod, boolean isSourceFile, String name) throws IOException {
|
||||
Assert.checkNonNull(mod);
|
||||
|
||||
if (lint) {
|
||||
int periodIndex = name.lastIndexOf(".");
|
||||
if (periodIndex != -1) {
|
||||
@ -404,8 +451,12 @@ public class JavacFiler implements Filer, Closeable {
|
||||
log.warning("proc.suspicious.class.name", name, extn);
|
||||
}
|
||||
}
|
||||
checkNameAndExistence(name, isSourceFile);
|
||||
checkNameAndExistence(mod, name, isSourceFile);
|
||||
Location loc = (isSourceFile ? SOURCE_OUTPUT : CLASS_OUTPUT);
|
||||
|
||||
if (modules.multiModuleMode) {
|
||||
loc = this.fileManager.getLocationForModule(loc, mod.name.toString());
|
||||
}
|
||||
JavaFileObject.Kind kind = (isSourceFile ?
|
||||
JavaFileObject.Kind.SOURCE :
|
||||
JavaFileObject.Kind.CLASS);
|
||||
@ -418,21 +469,30 @@ public class JavacFiler implements Filer, Closeable {
|
||||
log.warning("proc.file.create.last.round", name);
|
||||
|
||||
if (isSourceFile)
|
||||
aggregateGeneratedSourceNames.add(name);
|
||||
aggregateGeneratedSourceNames.add(Pair.of(mod, name));
|
||||
else
|
||||
aggregateGeneratedClassNames.add(name);
|
||||
aggregateGeneratedClassNames.add(Pair.of(mod, name));
|
||||
openTypeNames.add(name);
|
||||
|
||||
return new FilerOutputJavaFileObject(name, fileObject);
|
||||
return new FilerOutputJavaFileObject(mod, name, fileObject);
|
||||
}
|
||||
|
||||
@DefinedBy(Api.ANNOTATION_PROCESSING)
|
||||
@Override @DefinedBy(Api.ANNOTATION_PROCESSING)
|
||||
public FileObject createResource(JavaFileManager.Location location,
|
||||
CharSequence pkg,
|
||||
CharSequence moduleAndPkg,
|
||||
CharSequence relativeName,
|
||||
Element... originatingElements) throws IOException {
|
||||
Pair<ModuleSymbol, String> moduleAndPackage = checkOrInferModule(moduleAndPkg);
|
||||
ModuleSymbol msym = moduleAndPackage.fst;
|
||||
String pkg = moduleAndPackage.snd;
|
||||
|
||||
locationCheck(location);
|
||||
|
||||
if (modules.multiModuleMode) {
|
||||
Assert.checkNonNull(msym);
|
||||
location = this.fileManager.getLocationForModule(location, msym.name.toString());
|
||||
}
|
||||
|
||||
String strPkg = pkg.toString();
|
||||
if (strPkg.length() > 0)
|
||||
checkName(strPkg);
|
||||
@ -443,9 +503,9 @@ public class JavacFiler implements Filer, Closeable {
|
||||
checkFileReopening(fileObject, true);
|
||||
|
||||
if (fileObject instanceof JavaFileObject)
|
||||
return new FilerOutputJavaFileObject(null, (JavaFileObject)fileObject);
|
||||
return new FilerOutputJavaFileObject(msym, null, (JavaFileObject)fileObject);
|
||||
else
|
||||
return new FilerOutputFileObject(null, fileObject);
|
||||
return new FilerOutputFileObject(msym, null, fileObject);
|
||||
}
|
||||
|
||||
private void locationCheck(JavaFileManager.Location location) {
|
||||
@ -457,13 +517,21 @@ public class JavacFiler implements Filer, Closeable {
|
||||
}
|
||||
}
|
||||
|
||||
@DefinedBy(Api.ANNOTATION_PROCESSING)
|
||||
@Override @DefinedBy(Api.ANNOTATION_PROCESSING)
|
||||
public FileObject getResource(JavaFileManager.Location location,
|
||||
CharSequence pkg,
|
||||
CharSequence moduleAndPkg,
|
||||
CharSequence relativeName) throws IOException {
|
||||
String strPkg = pkg.toString();
|
||||
if (strPkg.length() > 0)
|
||||
checkName(strPkg);
|
||||
Pair<ModuleSymbol, String> moduleAndPackage = checkOrInferModule(moduleAndPkg);
|
||||
ModuleSymbol msym = moduleAndPackage.fst;
|
||||
String pkg = moduleAndPackage.snd;
|
||||
|
||||
if (modules.multiModuleMode) {
|
||||
Assert.checkNonNull(msym);
|
||||
location = this.fileManager.getLocationForModule(location, msym.name.toString());
|
||||
}
|
||||
|
||||
if (pkg.length() > 0)
|
||||
checkName(pkg);
|
||||
|
||||
// TODO: Only support reading resources in selected output
|
||||
// locations? Only allow reading of non-source, non-class
|
||||
@ -478,12 +546,12 @@ public class JavacFiler implements Filer, Closeable {
|
||||
FileObject fileObject;
|
||||
if (location.isOutputLocation()) {
|
||||
fileObject = fileManager.getFileForOutput(location,
|
||||
pkg.toString(),
|
||||
pkg,
|
||||
relativeName.toString(),
|
||||
null);
|
||||
} else {
|
||||
fileObject = fileManager.getFileForInput(location,
|
||||
pkg.toString(),
|
||||
pkg,
|
||||
relativeName.toString());
|
||||
}
|
||||
if (fileObject == null) {
|
||||
@ -524,16 +592,19 @@ public class JavacFiler implements Filer, Closeable {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkNameAndExistence(String typename, boolean allowUnnamedPackageInfo) throws FilerException {
|
||||
private void checkNameAndExistence(ModuleSymbol mod, String typename, boolean allowUnnamedPackageInfo) throws FilerException {
|
||||
// TODO: Check if type already exists on source or class path?
|
||||
// If so, use warning message key proc.type.already.exists
|
||||
checkName(typename, allowUnnamedPackageInfo);
|
||||
if (aggregateGeneratedSourceNames.contains(typename) ||
|
||||
aggregateGeneratedClassNames.contains(typename)) {
|
||||
if (aggregateGeneratedSourceNames.contains(Pair.of(mod, typename)) ||
|
||||
aggregateGeneratedClassNames.contains(Pair.of(mod, typename))) {
|
||||
if (lint)
|
||||
log.warning("proc.type.recreate", typename);
|
||||
throw new FilerException("Attempt to recreate a file for type " + typename);
|
||||
}
|
||||
if (!mod.isUnnamed() && !typename.contains(".")) {
|
||||
throw new FilerException("Attempt to create a type in unnamed package of a named module: " + typename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -565,7 +636,7 @@ public class JavacFiler implements Filer, Closeable {
|
||||
return generatedSourceFileObjects;
|
||||
}
|
||||
|
||||
public Map<String, JavaFileObject> getGeneratedClasses() {
|
||||
public Map<ModuleSymbol, Map<String, JavaFileObject>> getGeneratedClasses() {
|
||||
return generatedClasses;
|
||||
}
|
||||
|
||||
@ -621,7 +692,7 @@ public class JavacFiler implements Filer, Closeable {
|
||||
* Upon close, register files opened by create{Source, Class}File
|
||||
* for annotation processing.
|
||||
*/
|
||||
private void closeFileObject(String typeName, FileObject fileObject) {
|
||||
private void closeFileObject(ModuleSymbol mod, String typeName, FileObject fileObject) {
|
||||
/*
|
||||
* If typeName is non-null, the file object was opened as a
|
||||
* source or class file by the user. If a file was opened as
|
||||
@ -640,7 +711,7 @@ public class JavacFiler implements Filer, Closeable {
|
||||
break;
|
||||
|
||||
case CLASS:
|
||||
generatedClasses.put(typeName, javaFileObject);
|
||||
generatedClasses.computeIfAbsent(mod, m -> Collections.synchronizedMap(new LinkedHashMap<>())).put(typeName, javaFileObject);
|
||||
openTypeNames.remove(typeName);
|
||||
break;
|
||||
|
||||
|
||||
@ -34,6 +34,7 @@ import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -827,12 +828,14 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
|
||||
private void discoverAndRunProcs(Set<TypeElement> annotationsPresent,
|
||||
List<ClassSymbol> topLevelClasses,
|
||||
List<PackageSymbol> packageInfoFiles) {
|
||||
List<PackageSymbol> packageInfoFiles,
|
||||
List<ModuleSymbol> moduleInfoFiles) {
|
||||
Map<String, TypeElement> unmatchedAnnotations = new HashMap<>(annotationsPresent.size());
|
||||
|
||||
for(TypeElement a : annotationsPresent) {
|
||||
unmatchedAnnotations.put(a.getQualifiedName().toString(),
|
||||
a);
|
||||
ModuleElement mod = elementUtils.getModuleOf(a);
|
||||
unmatchedAnnotations.put((mod != null ? mod.getSimpleName() + "/" : "") + a.getQualifiedName().toString(),
|
||||
a);
|
||||
}
|
||||
|
||||
// Give "*" processors a chance to match
|
||||
@ -849,6 +852,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
Set<Element> rootElements = new LinkedHashSet<>();
|
||||
rootElements.addAll(topLevelClasses);
|
||||
rootElements.addAll(packageInfoFiles);
|
||||
rootElements.addAll(moduleInfoFiles);
|
||||
rootElements = Collections.unmodifiableSet(rootElements);
|
||||
|
||||
RoundEnvironment renv = new JavacRoundEnvironment(false,
|
||||
@ -986,7 +990,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
/** The trees that need to be cleaned - includes roots and implicitly parsed trees. */
|
||||
Set<JCCompilationUnit> treesToClean;
|
||||
/** The classes to be compiler that have were generated. */
|
||||
Map<String, JavaFileObject> genClassFiles;
|
||||
Map<ModuleSymbol, Map<String, JavaFileObject>> genClassFiles;
|
||||
|
||||
/** The set of annotations to be processed this round. */
|
||||
Set<TypeElement> annotationsPresent;
|
||||
@ -994,6 +998,8 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
List<ClassSymbol> topLevelClasses;
|
||||
/** The set of package-info files to be processed this round. */
|
||||
List<PackageSymbol> packageInfoFiles;
|
||||
/** The set of module-info files to be processed this round. */
|
||||
List<ModuleSymbol> moduleInfoFiles;
|
||||
|
||||
/** Create a round (common code). */
|
||||
private Round(int number, Set<JCCompilationUnit> treesToClean,
|
||||
@ -1011,6 +1017,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
// the following will be populated as needed
|
||||
topLevelClasses = List.nil();
|
||||
packageInfoFiles = List.nil();
|
||||
moduleInfoFiles = List.nil();
|
||||
this.treesToClean = treesToClean;
|
||||
}
|
||||
|
||||
@ -1031,12 +1038,14 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
|
||||
packageInfoFiles = getPackageInfoFiles(roots);
|
||||
|
||||
moduleInfoFiles = getModuleInfoFiles(roots);
|
||||
|
||||
findAnnotationsPresent();
|
||||
}
|
||||
|
||||
/** Create a new round. */
|
||||
private Round(Round prev,
|
||||
Set<JavaFileObject> newSourceFiles, Map<String,JavaFileObject> newClassFiles) {
|
||||
Set<JavaFileObject> newSourceFiles, Map<ModuleSymbol, Map<String,JavaFileObject>> newClassFiles) {
|
||||
this(prev.number+1, prev.treesToClean, null);
|
||||
prev.newRound();
|
||||
this.genClassFiles = prev.genClassFiles;
|
||||
@ -1048,9 +1057,13 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
if (unrecoverableError())
|
||||
return;
|
||||
|
||||
roots = compiler.initModules(roots);
|
||||
|
||||
enterClassFiles(genClassFiles);
|
||||
List<ClassSymbol> newClasses = enterClassFiles(newClassFiles);
|
||||
genClassFiles.putAll(newClassFiles);
|
||||
for (Entry<ModuleSymbol, Map<String, JavaFileObject>> moduleAndClassFiles : newClassFiles.entrySet()) {
|
||||
genClassFiles.computeIfAbsent(moduleAndClassFiles.getKey(), m -> new LinkedHashMap<>()).putAll(moduleAndClassFiles.getValue());
|
||||
}
|
||||
enterTrees(roots);
|
||||
|
||||
if (unrecoverableError())
|
||||
@ -1064,11 +1077,13 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
getPackageInfoFiles(parsedFiles),
|
||||
getPackageInfoFilesFromClasses(newClasses));
|
||||
|
||||
moduleInfoFiles = List.nil(); //module-info cannot be generated
|
||||
|
||||
findAnnotationsPresent();
|
||||
}
|
||||
|
||||
/** Create the next round to be used. */
|
||||
Round next(Set<JavaFileObject> newSourceFiles, Map<String, JavaFileObject> newClassFiles) {
|
||||
Round next(Set<JavaFileObject> newSourceFiles, Map<ModuleSymbol, Map<String, JavaFileObject>> newClassFiles) {
|
||||
return new Round(this, newSourceFiles, newClassFiles);
|
||||
}
|
||||
|
||||
@ -1121,45 +1136,47 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
annotationComputer.scan(classSym, annotationsPresent);
|
||||
for (PackageSymbol pkgSym : packageInfoFiles)
|
||||
annotationComputer.scan(pkgSym, annotationsPresent);
|
||||
for (ModuleSymbol mdlSym : moduleInfoFiles)
|
||||
annotationComputer.scan(mdlSym, annotationsPresent);
|
||||
}
|
||||
|
||||
/** Enter a set of generated class files. */
|
||||
private List<ClassSymbol> enterClassFiles(Map<String, JavaFileObject> classFiles) {
|
||||
private List<ClassSymbol> enterClassFiles(Map<ModuleSymbol, Map<String, JavaFileObject>> modulesAndClassFiles) {
|
||||
List<ClassSymbol> list = List.nil();
|
||||
|
||||
for (Map.Entry<String,JavaFileObject> entry : classFiles.entrySet()) {
|
||||
Name name = names.fromString(entry.getKey());
|
||||
JavaFileObject file = entry.getValue();
|
||||
if (file.getKind() != JavaFileObject.Kind.CLASS)
|
||||
throw new AssertionError(file);
|
||||
ClassSymbol cs;
|
||||
// TODO: for now, we assume that generated code is in a default module;
|
||||
// in time, we need a way to be able to specify the module for generated code
|
||||
if (isPkgInfo(file, JavaFileObject.Kind.CLASS)) {
|
||||
Name packageName = Convert.packagePart(name);
|
||||
PackageSymbol p = symtab.enterPackage(defaultModule, packageName);
|
||||
if (p.package_info == null)
|
||||
p.package_info = symtab.enterClass(defaultModule, Convert.shortName(name), p);
|
||||
cs = p.package_info;
|
||||
cs.reset();
|
||||
if (cs.classfile == null)
|
||||
for (Entry<ModuleSymbol, Map<String, JavaFileObject>> moduleAndClassFiles : modulesAndClassFiles.entrySet()) {
|
||||
for (Map.Entry<String,JavaFileObject> entry : moduleAndClassFiles.getValue().entrySet()) {
|
||||
Name name = names.fromString(entry.getKey());
|
||||
JavaFileObject file = entry.getValue();
|
||||
if (file.getKind() != JavaFileObject.Kind.CLASS)
|
||||
throw new AssertionError(file);
|
||||
ClassSymbol cs;
|
||||
if (isPkgInfo(file, JavaFileObject.Kind.CLASS)) {
|
||||
Name packageName = Convert.packagePart(name);
|
||||
PackageSymbol p = symtab.enterPackage(moduleAndClassFiles.getKey(), packageName);
|
||||
if (p.package_info == null)
|
||||
p.package_info = symtab.enterClass(moduleAndClassFiles.getKey(), Convert.shortName(name), p);
|
||||
cs = p.package_info;
|
||||
cs.reset();
|
||||
if (cs.classfile == null)
|
||||
cs.classfile = file;
|
||||
cs.completer = initialCompleter;
|
||||
} else {
|
||||
cs = symtab.enterClass(moduleAndClassFiles.getKey(), name);
|
||||
cs.reset();
|
||||
cs.classfile = file;
|
||||
cs.completer = initialCompleter;
|
||||
} else {
|
||||
cs = symtab.enterClass(defaultModule, name);
|
||||
cs.reset();
|
||||
cs.classfile = file;
|
||||
cs.completer = initialCompleter;
|
||||
cs.owner.members().enter(cs); //XXX - OverwriteBetweenCompilations; syms.getClass is not sufficient anymore
|
||||
cs.completer = initialCompleter;
|
||||
cs.owner.members().enter(cs); //XXX - OverwriteBetweenCompilations; syms.getClass is not sufficient anymore
|
||||
}
|
||||
list = list.prepend(cs);
|
||||
}
|
||||
list = list.prepend(cs);
|
||||
}
|
||||
return list.reverse();
|
||||
}
|
||||
|
||||
/** Enter a set of syntax trees. */
|
||||
private void enterTrees(List<JCCompilationUnit> roots) {
|
||||
compiler.enterTrees(compiler.initModules(roots));
|
||||
compiler.enterTrees(roots);
|
||||
}
|
||||
|
||||
/** Run a processing round. */
|
||||
@ -1179,7 +1196,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
JavacProcessingEnvironment.this);
|
||||
discoveredProcs.iterator().runContributingProcs(renv);
|
||||
} else {
|
||||
discoverAndRunProcs(annotationsPresent, topLevelClasses, packageInfoFiles);
|
||||
discoverAndRunProcs(annotationsPresent, topLevelClasses, packageInfoFiles, moduleInfoFiles);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// we're specifically expecting Abort here, but if any Throwable
|
||||
@ -1418,6 +1435,18 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
return packages.reverse();
|
||||
}
|
||||
|
||||
private List<ModuleSymbol> getModuleInfoFiles(List<? extends JCCompilationUnit> units) {
|
||||
List<ModuleSymbol> modules = List.nil();
|
||||
for (JCCompilationUnit unit : units) {
|
||||
if (isModuleInfo(unit.sourcefile, JavaFileObject.Kind.SOURCE) &&
|
||||
unit.defs.nonEmpty() &&
|
||||
unit.defs.head.hasTag(Tag.MODULEDEF)) {
|
||||
modules = modules.prepend(unit.modle);
|
||||
}
|
||||
}
|
||||
return modules.reverse();
|
||||
}
|
||||
|
||||
// avoid unchecked warning from use of varargs
|
||||
private static <T> List<T> join(List<T> list1, List<T> list2) {
|
||||
return list1.appendList(list2);
|
||||
@ -1431,6 +1460,10 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
return isPkgInfo(sym.classfile, JavaFileObject.Kind.CLASS) && (sym.packge().package_info == sym);
|
||||
}
|
||||
|
||||
private boolean isModuleInfo(JavaFileObject fo, JavaFileObject.Kind kind) {
|
||||
return fo.isNameCompatible("module-info", kind);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called retroactively to determine if a class loader was required,
|
||||
* after we have failed to create one.
|
||||
@ -1625,8 +1658,21 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
* import-style string, return a regex that won't match anything.
|
||||
*/
|
||||
private static Pattern importStringToPattern(String s, Processor p, Log log) {
|
||||
if (MatchingUtils.isValidImportString(s)) {
|
||||
return MatchingUtils.validImportStringToPattern(s);
|
||||
String module;
|
||||
String pkg;
|
||||
int slash = s.indexOf('/');
|
||||
if (slash == (-1)) {
|
||||
if (s.equals("*")) {
|
||||
return MatchingUtils.validImportStringToPattern(s);
|
||||
}
|
||||
module = ".*/";
|
||||
pkg = s;
|
||||
} else {
|
||||
module = Pattern.quote(s.substring(0, slash + 1));
|
||||
pkg = s.substring(slash + 1);
|
||||
}
|
||||
if (MatchingUtils.isValidImportString(pkg)) {
|
||||
return Pattern.compile(module + MatchingUtils.validImportStringToPatternString(pkg));
|
||||
} else {
|
||||
log.warning("proc.malformed.supported.string", s, p.getClass().getName());
|
||||
return noMatches; // won't match any valid identifier
|
||||
|
||||
@ -36,7 +36,9 @@ import javax.lang.model.SourceVersion;
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
public class MatchingUtils {
|
||||
private static final Pattern allMatches = Pattern.compile(".*");
|
||||
|
||||
private static final String allMatchesString = ".*";
|
||||
private static final Pattern allMatches = Pattern.compile(allMatchesString);
|
||||
|
||||
/**
|
||||
* Return true if the argument string is a valid import-style
|
||||
@ -72,9 +74,9 @@ public class MatchingUtils {
|
||||
return valid;
|
||||
}
|
||||
|
||||
public static Pattern validImportStringToPattern(String s) {
|
||||
public static String validImportStringToPatternString(String s) {
|
||||
if (s.equals("*")) {
|
||||
return allMatches;
|
||||
return allMatchesString;
|
||||
} else {
|
||||
String s_prime = s.replace(".", "\\.");
|
||||
|
||||
@ -82,7 +84,17 @@ public class MatchingUtils {
|
||||
s_prime = s_prime.substring(0, s_prime.length() - 1) + ".+";
|
||||
}
|
||||
|
||||
return Pattern.compile(s_prime);
|
||||
return s_prime;
|
||||
}
|
||||
}
|
||||
|
||||
public static Pattern validImportStringToPattern(String s) {
|
||||
String pattern = validImportStringToPatternString(s);
|
||||
|
||||
if (pattern == allMatchesString) {
|
||||
return allMatches;
|
||||
} else {
|
||||
return Pattern.compile(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -360,7 +360,7 @@ public class AbstractIndexWriter extends HtmlDocletWriter {
|
||||
*/
|
||||
protected void addComment(Element element, Content contentTree) {
|
||||
List<? extends DocTree> tags;
|
||||
Content span = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, contents.deprecatedPhrase);
|
||||
Content span = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(element));
|
||||
HtmlTree div = new HtmlTree(HtmlTag.DIV);
|
||||
div.addStyle(HtmlStyle.block);
|
||||
if (utils.isDeprecated(element)) {
|
||||
|
||||
@ -404,46 +404,6 @@ public abstract class AbstractMemberWriter {
|
||||
ped.getEnclosingElement().equals(ped.getEnclosingElement())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add deprecated information to the documentation tree
|
||||
*
|
||||
* @param deprmembers list of deprecated members
|
||||
* @param headingKey the caption for the deprecated members table
|
||||
* @param tableSummary the summary for the deprecated members table
|
||||
* @param tableHeader table headers for the deprecated members table
|
||||
* @param contentTree the content tree to which the deprecated members table will be added
|
||||
*/
|
||||
protected void addDeprecatedAPI(Collection<Element> deprmembers, String headingKey,
|
||||
String tableSummary, List<String> tableHeader, Content contentTree) {
|
||||
if (deprmembers.size() > 0) {
|
||||
Content caption = writer.getTableCaption(configuration.getContent(headingKey));
|
||||
Content table = (configuration.isOutputHtml5())
|
||||
? HtmlTree.TABLE(HtmlStyle.deprecatedSummary, caption)
|
||||
: HtmlTree.TABLE(HtmlStyle.deprecatedSummary, tableSummary, caption);
|
||||
table.addContent(writer.getSummaryTableHeader(tableHeader, "col"));
|
||||
Content tbody = new HtmlTree(HtmlTag.TBODY);
|
||||
boolean altColor = true;
|
||||
for (Element member : deprmembers) {
|
||||
HtmlTree thRow = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, getDeprecatedLink(member));
|
||||
HtmlTree tr = HtmlTree.TR(thRow);
|
||||
HtmlTree td = new HtmlTree(HtmlTag.TD);
|
||||
td.addStyle(HtmlStyle.colLast);
|
||||
List<? extends DocTree> deprTrees = utils.getBlockTags(member, DocTree.Kind.DEPRECATED);
|
||||
if (!deprTrees.isEmpty()) {
|
||||
writer.addInlineDeprecatedComment(member, deprTrees.get(0), td);
|
||||
}
|
||||
tr.addContent(td);
|
||||
tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
|
||||
altColor = !altColor;
|
||||
tbody.addContent(tr);
|
||||
}
|
||||
table.addContent(tbody);
|
||||
Content li = HtmlTree.LI(HtmlStyle.blockList, table);
|
||||
Content ul = HtmlTree.UL(HtmlStyle.blockList, li);
|
||||
contentTree.addContent(ul);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add use information to the documentation tree.
|
||||
*
|
||||
|
||||
@ -317,7 +317,7 @@ public class AnnotationTypeWriterImpl extends SubWriterHolderWriter
|
||||
List<? extends DocTree> deprs = utils.getBlockTags(annotationType, DocTree.Kind.DEPRECATED);
|
||||
if (utils.isDeprecated(annotationType)) {
|
||||
CommentHelper ch = utils.getCommentHelper(annotationType);
|
||||
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, contents.deprecatedPhrase);
|
||||
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(annotationType));
|
||||
Content div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
|
||||
if (!deprs.isEmpty()) {
|
||||
|
||||
|
||||
@ -610,7 +610,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
|
||||
classInfoTree.addContent(hr);
|
||||
List<? extends DocTree> deprs = utils.getBlockTags(typeElement, DocTree.Kind.DEPRECATED);
|
||||
if (utils.isDeprecated(typeElement)) {
|
||||
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, contents.deprecatedPhrase);
|
||||
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(typeElement));
|
||||
Content div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
|
||||
if (!deprs.isEmpty()) {
|
||||
CommentHelper ch = utils.getCommentHelper(typeElement);
|
||||
|
||||
@ -73,6 +73,7 @@ public class Contents {
|
||||
public final Content deprecatedAPI;
|
||||
public final Content deprecatedLabel;
|
||||
public final Content deprecatedPhrase;
|
||||
public final Content deprecatedForRemovalPhrase;
|
||||
public final Content descfrmClassLabel;
|
||||
public final Content descfrmInterfaceLabel;
|
||||
public final Content descriptionLabel;
|
||||
@ -186,6 +187,7 @@ public class Contents {
|
||||
deprecatedAPI = getContent("doclet.Deprecated_API");
|
||||
deprecatedLabel = getContent("doclet.navDeprecated");
|
||||
deprecatedPhrase = getContent("doclet.Deprecated");
|
||||
deprecatedForRemovalPhrase = getContent("doclet.DeprecatedForRemoval");
|
||||
descfrmClassLabel = getContent("doclet.Description_From_Class");
|
||||
descfrmInterfaceLabel = getContent("doclet.Description_From_Interface");
|
||||
descriptionLabel = getContent("doclet.Description");
|
||||
|
||||
@ -64,6 +64,8 @@ public class DeprecatedListWriter extends SubWriterHolderWriter {
|
||||
|
||||
private String getAnchorName(DeprElementKind kind) {
|
||||
switch (kind) {
|
||||
case REMOVAL:
|
||||
return "forRemoval";
|
||||
case MODULE:
|
||||
return "module";
|
||||
case PACKAGE:
|
||||
@ -97,6 +99,8 @@ public class DeprecatedListWriter extends SubWriterHolderWriter {
|
||||
|
||||
private String getHeadingKey(DeprElementKind kind) {
|
||||
switch (kind) {
|
||||
case REMOVAL:
|
||||
return "doclet.Deprecated_For_Removal";
|
||||
case MODULE:
|
||||
return "doclet.Deprecated_Modules";
|
||||
case PACKAGE:
|
||||
@ -130,6 +134,8 @@ public class DeprecatedListWriter extends SubWriterHolderWriter {
|
||||
|
||||
private String getSummaryKey(DeprElementKind kind) {
|
||||
switch (kind) {
|
||||
case REMOVAL:
|
||||
return "doclet.deprecated_for_removal";
|
||||
case MODULE:
|
||||
return "doclet.deprecated_modules";
|
||||
case PACKAGE:
|
||||
@ -163,6 +169,8 @@ public class DeprecatedListWriter extends SubWriterHolderWriter {
|
||||
|
||||
private String getHeaderKey(DeprElementKind kind) {
|
||||
switch (kind) {
|
||||
case REMOVAL:
|
||||
return "doclet.Element";
|
||||
case MODULE:
|
||||
return "doclet.Module";
|
||||
case PACKAGE:
|
||||
@ -212,6 +220,7 @@ public class DeprecatedListWriter extends SubWriterHolderWriter {
|
||||
writerMap = new EnumMap<>(DeprElementKind.class);
|
||||
for (DeprElementKind kind : DeprElementKind.values()) {
|
||||
switch (kind) {
|
||||
case REMOVAL:
|
||||
case MODULE:
|
||||
case PACKAGE:
|
||||
case INTERFACE:
|
||||
@ -284,16 +293,8 @@ public class DeprecatedListWriter extends SubWriterHolderWriter {
|
||||
List<String> memberTableHeader = new ArrayList<>();
|
||||
memberTableHeader.add(resources.getText(getHeaderKey(kind)));
|
||||
memberTableHeader.add(resources.getText("doclet.Description"));
|
||||
if (kind == DeprElementKind.MODULE) {
|
||||
addModuleDeprecatedAPI(deprapi.getSet(kind),
|
||||
addDeprecatedAPI(deprapi.getSet(kind),
|
||||
getHeadingKey(kind), memberTableSummary, memberTableHeader, div);
|
||||
} else if (kind == DeprElementKind.PACKAGE) {
|
||||
addPackageDeprecatedAPI(deprapi.getSet(kind),
|
||||
getHeadingKey(kind), memberTableSummary, memberTableHeader, div);
|
||||
} else {
|
||||
writerMap.get(kind).addDeprecatedAPI(deprapi.getSet(kind),
|
||||
getHeadingKey(kind), memberTableSummary, memberTableHeader, div);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (configuration.allowTag(HtmlTag.MAIN)) {
|
||||
@ -395,17 +396,17 @@ public class DeprecatedListWriter extends SubWriterHolderWriter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add module deprecation information to the documentation tree
|
||||
* Add deprecated information to the documentation tree
|
||||
*
|
||||
* @param deprMdles list of deprecated modules
|
||||
* @param headingKey the caption for the deprecated module table
|
||||
* @param tableSummary the summary for the deprecated module table
|
||||
* @param tableHeader table headers for the deprecated module table
|
||||
* @param contentTree the content tree to which the deprecated module table will be added
|
||||
* @param deprList list of deprecated API elements
|
||||
* @param headingKey the caption for the deprecated table
|
||||
* @param tableSummary the summary for the deprecated table
|
||||
* @param tableHeader table headers for the deprecated table
|
||||
* @param contentTree the content tree to which the deprecated table will be added
|
||||
*/
|
||||
protected void addModuleDeprecatedAPI(SortedSet<Element> deprMdles, String headingKey,
|
||||
protected void addDeprecatedAPI(SortedSet<Element> deprList, String headingKey,
|
||||
String tableSummary, List<String> tableHeader, Content contentTree) {
|
||||
if (deprMdles.size() > 0) {
|
||||
if (deprList.size() > 0) {
|
||||
Content caption = getTableCaption(configuration.getContent(headingKey));
|
||||
Content table = (configuration.isOutputHtml5())
|
||||
? HtmlTree.TABLE(HtmlStyle.deprecatedSummary, caption)
|
||||
@ -413,16 +414,28 @@ public class DeprecatedListWriter extends SubWriterHolderWriter {
|
||||
table.addContent(getSummaryTableHeader(tableHeader, "col"));
|
||||
Content tbody = new HtmlTree(HtmlTag.TBODY);
|
||||
boolean altColor = true;
|
||||
for (Element e : deprMdles) {
|
||||
ModuleElement mdle = (ModuleElement) e;
|
||||
HtmlTree thRow = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst,
|
||||
getModuleLink(mdle, new StringContent(mdle.getQualifiedName())));
|
||||
for (Element e : deprList) {
|
||||
HtmlTree thRow;
|
||||
switch (e.getKind()) {
|
||||
case MODULE:
|
||||
ModuleElement m = (ModuleElement)e;
|
||||
thRow = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst,
|
||||
getModuleLink(m, new StringContent(m.getQualifiedName())));
|
||||
break;
|
||||
case PACKAGE:
|
||||
PackageElement pkg = (PackageElement)e;
|
||||
thRow = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst,
|
||||
getPackageLink(pkg, getPackageName(pkg)));
|
||||
break;
|
||||
default:
|
||||
thRow = getDeprecatedLink(e);
|
||||
}
|
||||
HtmlTree tr = HtmlTree.TR(thRow);
|
||||
HtmlTree tdDesc = new HtmlTree(HtmlTag.TD);
|
||||
tdDesc.addStyle(HtmlStyle.colLast);
|
||||
List<? extends DocTree> tags = utils.getDeprecatedTrees(mdle);
|
||||
List<? extends DocTree> tags = utils.getDeprecatedTrees(e);
|
||||
if (!tags.isEmpty()) {
|
||||
addInlineDeprecatedComment(mdle, tags.get(0), tdDesc);
|
||||
addInlineDeprecatedComment(e, tags.get(0), tdDesc);
|
||||
}
|
||||
tr.addContent(tdDesc);
|
||||
tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
|
||||
@ -436,45 +449,30 @@ public class DeprecatedListWriter extends SubWriterHolderWriter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add package deprecation information to the documentation tree
|
||||
*
|
||||
* @param deprPkgs list of deprecated packages
|
||||
* @param headingKey the caption for the deprecated package table
|
||||
* @param tableSummary the summary for the deprecated package table
|
||||
* @param tableHeader table headers for the deprecated package table
|
||||
* @param contentTree the content tree to which the deprecated package table will be added
|
||||
*/
|
||||
protected void addPackageDeprecatedAPI(SortedSet<Element> deprPkgs, String headingKey,
|
||||
String tableSummary, List<String> tableHeader, Content contentTree) {
|
||||
if (deprPkgs.size() > 0) {
|
||||
Content caption = getTableCaption(configuration.getContent(headingKey));
|
||||
Content table = (configuration.isOutputHtml5())
|
||||
? HtmlTree.TABLE(HtmlStyle.deprecatedSummary, caption)
|
||||
: HtmlTree.TABLE(HtmlStyle.deprecatedSummary, tableSummary, caption);
|
||||
table.addContent(getSummaryTableHeader(tableHeader, "col"));
|
||||
Content tbody = new HtmlTree(HtmlTag.TBODY);
|
||||
boolean altColor = true;
|
||||
for (Element e : deprPkgs) {
|
||||
PackageElement pkg = (PackageElement) e;
|
||||
HtmlTree thRow = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst,
|
||||
getPackageLink(pkg, getPackageName(pkg)));
|
||||
HtmlTree tr = HtmlTree.TR(thRow);
|
||||
HtmlTree tdDesc = new HtmlTree(HtmlTag.TD);
|
||||
tdDesc.addStyle(HtmlStyle.colLast);
|
||||
List<? extends DocTree> tags = utils.getDeprecatedTrees(pkg);
|
||||
if (!tags.isEmpty()) {
|
||||
addInlineDeprecatedComment(pkg, tags.get(0), tdDesc);
|
||||
}
|
||||
tr.addContent(tdDesc);
|
||||
tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
|
||||
altColor = !altColor;
|
||||
tbody.addContent(tr);
|
||||
}
|
||||
table.addContent(tbody);
|
||||
Content li = HtmlTree.LI(HtmlStyle.blockList, table);
|
||||
Content ul = HtmlTree.UL(HtmlStyle.blockList, li);
|
||||
contentTree.addContent(ul);
|
||||
protected HtmlTree getDeprecatedLink(Element e) {
|
||||
AbstractMemberWriter writer;
|
||||
switch (e.getKind()) {
|
||||
case INTERFACE:
|
||||
case CLASS:
|
||||
case ENUM:
|
||||
case ANNOTATION_TYPE:
|
||||
writer = new NestedClassWriterImpl(this);
|
||||
break;
|
||||
case FIELD:
|
||||
writer = new FieldWriterImpl(this);
|
||||
break;
|
||||
case METHOD:
|
||||
writer = new MethodWriterImpl(this);
|
||||
break;
|
||||
case CONSTRUCTOR:
|
||||
writer = new ConstructorWriterImpl(this);
|
||||
break;
|
||||
case ENUM_CONSTANT:
|
||||
writer = new EnumConstantWriterImpl(this);
|
||||
break;
|
||||
default:
|
||||
writer = new AnnotationTypeOptionalMemberWriterImpl(this, null);
|
||||
}
|
||||
return HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, writer.getDeprecatedLink(e));
|
||||
}
|
||||
}
|
||||
|
||||
@ -412,7 +412,7 @@ public class HtmlDocletWriter extends HtmlDocWriter {
|
||||
HtmlTree tdClassDescription = new HtmlTree(HtmlTag.TD);
|
||||
tdClassDescription.addStyle(HtmlStyle.colLast);
|
||||
if (utils.isDeprecated(te)) {
|
||||
tdClassDescription.addContent(contents.deprecatedLabel);
|
||||
tdClassDescription.addContent(getDeprecatedPhrase(te));
|
||||
List<? extends DocTree> tags = utils.getDeprecatedTrees(te);
|
||||
if (!tags.isEmpty()) {
|
||||
addSummaryDeprecatedComment(te, tags.get(0), tdClassDescription);
|
||||
@ -1616,6 +1616,18 @@ public class HtmlDocletWriter extends HtmlDocWriter {
|
||||
addCommentTags(element, tag, description, false, false, htmltree);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the deprecated phrase as content.
|
||||
*
|
||||
* @param e the Element for which the inline deprecated comment will be added
|
||||
* @return a content tree for the deprecated phrase.
|
||||
*/
|
||||
public Content getDeprecatedPhrase(Element e) {
|
||||
return (utils.isDeprecatedForRemoval(e))
|
||||
? contents.deprecatedForRemovalPhrase
|
||||
: contents.deprecatedPhrase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the inline deprecated comment.
|
||||
*
|
||||
|
||||
@ -506,7 +506,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
|
||||
CommentHelper ch = utils.getCommentHelper(mdle);
|
||||
HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
|
||||
deprDiv.addStyle(HtmlStyle.deprecatedContent);
|
||||
Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, contents.deprecatedPhrase);
|
||||
Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(mdle));
|
||||
deprDiv.addContent(deprPhrase);
|
||||
if (!deprs.isEmpty()) {
|
||||
List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
|
||||
@ -648,7 +648,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
|
||||
deprs = utils.getDeprecatedTrees(pkg);
|
||||
HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
|
||||
deprDiv.addStyle(HtmlStyle.deprecatedContent);
|
||||
Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, contents.deprecatedPhrase);
|
||||
Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(pkg));
|
||||
deprDiv.addContent(deprPhrase);
|
||||
if (!deprs.isEmpty()) {
|
||||
CommentHelper ch = utils.getCommentHelper(pkg);
|
||||
|
||||
@ -172,7 +172,7 @@ public class PackageWriterImpl extends HtmlDocletWriter
|
||||
CommentHelper ch = utils.getCommentHelper(packageElement);
|
||||
HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
|
||||
deprDiv.addStyle(HtmlStyle.deprecatedContent);
|
||||
Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, contents.deprecatedPhrase);
|
||||
Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(packageElement));
|
||||
deprDiv.addContent(deprPhrase);
|
||||
if (!deprs.isEmpty()) {
|
||||
List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
|
||||
@ -223,7 +223,7 @@ public class PackageWriterImpl extends HtmlDocletWriter
|
||||
HtmlTree tdClassDescription = new HtmlTree(HtmlTag.TD);
|
||||
tdClassDescription.addStyle(HtmlStyle.colLast);
|
||||
if (utils.isDeprecated(klass)) {
|
||||
tdClassDescription.addContent(contents.deprecatedLabel);
|
||||
tdClassDescription.addContent(getDeprecatedPhrase(klass));
|
||||
List<? extends DocTree> tags = utils.getDeprecatedTrees(klass);
|
||||
if (!tags.isEmpty()) {
|
||||
addSummaryDeprecatedComment(klass, tags.get(0), tdClassDescription);
|
||||
|
||||
@ -187,7 +187,7 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter {
|
||||
List<? extends DocTree> deprs = utils.getBlockTags(member, DocTree.Kind.DEPRECATED);
|
||||
Content div;
|
||||
if (utils.isDeprecated(member)) {
|
||||
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, contents.deprecatedPhrase);
|
||||
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(member));
|
||||
div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
|
||||
div.addContent(Contents.SPACE);
|
||||
if (!deprs.isEmpty()) {
|
||||
@ -198,7 +198,7 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter {
|
||||
} else {
|
||||
Element te = member.getEnclosingElement();
|
||||
if (te != null && utils.isTypeElement(te) && utils.isDeprecated(te)) {
|
||||
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, contents.deprecatedPhrase);
|
||||
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(te));
|
||||
div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
|
||||
div.addContent(Contents.SPACE);
|
||||
tdSummary.addContent(div);
|
||||
|
||||
@ -178,7 +178,7 @@ public class TagletWriterImpl extends TagletWriter {
|
||||
if (utils.isTypeElement(element)) {
|
||||
if (utils.isDeprecated(element)) {
|
||||
result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
|
||||
new StringContent(configuration.getText("doclet.Deprecated"))));
|
||||
htmlWriter.getDeprecatedPhrase(element)));
|
||||
result.addContent(RawHtml.nbsp);
|
||||
if (!deprs.isEmpty()) {
|
||||
List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
|
||||
@ -190,7 +190,7 @@ public class TagletWriterImpl extends TagletWriter {
|
||||
} else {
|
||||
if (utils.isDeprecated(element)) {
|
||||
result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
|
||||
new StringContent(configuration.getText("doclet.Deprecated"))));
|
||||
htmlWriter.getDeprecatedPhrase(element)));
|
||||
result.addContent(RawHtml.nbsp);
|
||||
if (!deprs.isEmpty()) {
|
||||
List<? extends DocTree> bodyTags = ch.getBody(configuration, deprs.get(0));
|
||||
@ -199,9 +199,10 @@ public class TagletWriterImpl extends TagletWriter {
|
||||
result.addContent(HtmlTree.SPAN(HtmlStyle.deprecationComment, body));
|
||||
}
|
||||
} else {
|
||||
if (utils.isDeprecated(utils.getEnclosingTypeElement(element))) {
|
||||
Element ee = utils.getEnclosingTypeElement(element);
|
||||
if (utils.isDeprecated(ee)) {
|
||||
result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
|
||||
new StringContent(configuration.getText("doclet.Deprecated"))));
|
||||
htmlWriter.getDeprecatedPhrase(ee)));
|
||||
result.addContent(RawHtml.nbsp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ doclet.Contents=Contents
|
||||
doclet.Overview=Overview
|
||||
doclet.Window_Overview=Overview List
|
||||
doclet.Window_Overview_Summary=Overview
|
||||
doclet.Element=Element
|
||||
doclet.Package=Package
|
||||
doclet.Module=Module
|
||||
doclet.All_Packages=All Packages
|
||||
@ -71,6 +72,7 @@ doclet.see.class_or_package_not_found=Tag {0}: reference not found: {1}
|
||||
doclet.see.class_or_package_not_accessible=Tag {0}: reference not accessible: {1}
|
||||
doclet.tag.invalid_usage=invalid usage of tag {0}
|
||||
doclet.Deprecated_API=Deprecated API
|
||||
doclet.Deprecated_For_Removal=Deprecated For Removal
|
||||
doclet.Deprecated_Modules=Deprecated Modules
|
||||
doclet.Deprecated_Packages=Deprecated Packages
|
||||
doclet.Deprecated_Classes=Deprecated Classes
|
||||
@ -84,6 +86,7 @@ doclet.Deprecated_Constructors=Deprecated Constructors
|
||||
doclet.Deprecated_Methods=Deprecated Methods
|
||||
doclet.Deprecated_Enum_Constants=Deprecated Enum Constants
|
||||
doclet.Deprecated_Annotation_Type_Members=Deprecated Annotation Type Elements
|
||||
doclet.deprecated_for_removal=deprecated for removal
|
||||
doclet.deprecated_modules=deprecated modules
|
||||
doclet.deprecated_packages=deprecated packages
|
||||
doclet.deprecated_classes=deprecated classes
|
||||
|
||||
@ -150,6 +150,7 @@ doclet.Property_Detail=Property Detail
|
||||
doclet.Method_Detail=Method Detail
|
||||
doclet.Constructor_Detail=Constructor Detail
|
||||
doclet.Deprecated=Deprecated.
|
||||
doclet.DeprecatedForRemoval=Deprecated, for removal: This API element is subject to removal in a future version.
|
||||
doclet.Hidden=Hidden
|
||||
doclet.Groupname_already_used=In -group option, groupname already used: {0}
|
||||
doclet.value_tag_invalid_reference={0} (referenced by @value tag) is an unknown reference.
|
||||
|
||||
@ -52,6 +52,7 @@ public class DeprecatedAPIListBuilder {
|
||||
private final Configuration configuration;
|
||||
private final Utils utils;
|
||||
public static enum DeprElementKind {
|
||||
REMOVAL,
|
||||
MODULE,
|
||||
PACKAGE,
|
||||
INTERFACE,
|
||||
@ -90,9 +91,13 @@ public class DeprecatedAPIListBuilder {
|
||||
* @param configuration the current configuration of the doclet.
|
||||
*/
|
||||
private void buildDeprecatedAPIInfo() {
|
||||
SortedSet<Element> rset = deprecatedMap.get(DeprElementKind.REMOVAL);
|
||||
SortedSet<ModuleElement> modules = configuration.modules;
|
||||
SortedSet<Element> mset = deprecatedMap.get(DeprElementKind.MODULE);
|
||||
for (Element me : modules) {
|
||||
if (utils.isDeprecatedForRemoval(me)) {
|
||||
rset.add(me);
|
||||
}
|
||||
if (utils.isDeprecated(me)) {
|
||||
mset.add(me);
|
||||
}
|
||||
@ -100,6 +105,9 @@ public class DeprecatedAPIListBuilder {
|
||||
SortedSet<PackageElement> packages = configuration.packages;
|
||||
SortedSet<Element> pset = deprecatedMap.get(DeprElementKind.PACKAGE);
|
||||
for (Element pe : packages) {
|
||||
if (utils.isDeprecatedForRemoval(pe)) {
|
||||
rset.add(pe);
|
||||
}
|
||||
if (utils.isDeprecated(pe)) {
|
||||
pset.add(pe);
|
||||
}
|
||||
@ -107,6 +115,9 @@ public class DeprecatedAPIListBuilder {
|
||||
for (Element e : configuration.getIncludedTypeElements()) {
|
||||
TypeElement te = (TypeElement)e;
|
||||
SortedSet<Element> eset;
|
||||
if (utils.isDeprecatedForRemoval(e)) {
|
||||
rset.add(e);
|
||||
}
|
||||
if (utils.isDeprecated(e)) {
|
||||
switch (e.getKind()) {
|
||||
case ANNOTATION_TYPE:
|
||||
@ -133,18 +144,18 @@ public class DeprecatedAPIListBuilder {
|
||||
break;
|
||||
}
|
||||
}
|
||||
composeDeprecatedList(deprecatedMap.get(DeprElementKind.FIELD),
|
||||
composeDeprecatedList(rset, deprecatedMap.get(DeprElementKind.FIELD),
|
||||
utils.getFields(te));
|
||||
composeDeprecatedList(deprecatedMap.get(DeprElementKind.METHOD),
|
||||
composeDeprecatedList(rset, deprecatedMap.get(DeprElementKind.METHOD),
|
||||
utils.getMethods(te));
|
||||
composeDeprecatedList(deprecatedMap.get(DeprElementKind.CONSTRUCTOR),
|
||||
composeDeprecatedList(rset, deprecatedMap.get(DeprElementKind.CONSTRUCTOR),
|
||||
utils.getConstructors(te));
|
||||
if (utils.isEnum(e)) {
|
||||
composeDeprecatedList(deprecatedMap.get(DeprElementKind.ENUM_CONSTANT),
|
||||
composeDeprecatedList(rset, deprecatedMap.get(DeprElementKind.ENUM_CONSTANT),
|
||||
utils.getEnumConstants(te));
|
||||
}
|
||||
if (utils.isAnnotationType(e)) {
|
||||
composeDeprecatedList(deprecatedMap.get(DeprElementKind.ANNOTATION_TYPE_MEMBER),
|
||||
composeDeprecatedList(rset, deprecatedMap.get(DeprElementKind.ANNOTATION_TYPE_MEMBER),
|
||||
utils.getAnnotationMembers(te));
|
||||
|
||||
}
|
||||
@ -154,11 +165,16 @@ public class DeprecatedAPIListBuilder {
|
||||
/**
|
||||
* Add the members into a single list of deprecated members.
|
||||
*
|
||||
* @param rset set of elements deprecated for removal.
|
||||
* @param sset set of deprecated elements.
|
||||
* @param list List of all the particular deprecated members, e.g. methods.
|
||||
* @param members members to be added in the list.
|
||||
*/
|
||||
private void composeDeprecatedList(SortedSet<Element> sset, List<? extends Element> members) {
|
||||
private void composeDeprecatedList(SortedSet<Element> rset, SortedSet<Element> sset, List<? extends Element> members) {
|
||||
for (Element member : members) {
|
||||
if (utils.isDeprecatedForRemoval(member)) {
|
||||
rset.add(member);
|
||||
}
|
||||
if (utils.isDeprecated(member)) {
|
||||
sset.add(member);
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.AnnotationValue;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
@ -74,10 +75,12 @@ import com.sun.source.tree.LineMap;
|
||||
import com.sun.source.util.DocSourcePositions;
|
||||
import com.sun.source.util.DocTrees;
|
||||
import com.sun.source.util.TreePath;
|
||||
import com.sun.tools.javac.model.JavacTypes;
|
||||
import jdk.javadoc.internal.doclets.toolkit.CommentUtils.DocCommentDuo;
|
||||
import jdk.javadoc.internal.doclets.toolkit.Configuration;
|
||||
import jdk.javadoc.internal.doclets.toolkit.Messages;
|
||||
import jdk.javadoc.internal.doclets.toolkit.WorkArounds;
|
||||
import jdk.javadoc.internal.tool.DocEnvImpl;
|
||||
|
||||
import static javax.lang.model.element.ElementKind.*;
|
||||
import static javax.lang.model.element.Modifier.*;
|
||||
@ -1476,6 +1479,30 @@ public class Utils {
|
||||
return elementUtils.isDeprecated(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given Element is deprecated for removal.
|
||||
*
|
||||
* @param e the Element to check.
|
||||
* @return true if the given Element is deprecated for removal.
|
||||
*/
|
||||
public boolean isDeprecatedForRemoval(Element e) {
|
||||
List<? extends AnnotationMirror> annotationList = e.getAnnotationMirrors();
|
||||
JavacTypes jctypes = ((DocEnvImpl) configuration.docEnv).toolEnv.typeutils;
|
||||
for (AnnotationMirror anno : annotationList) {
|
||||
if (jctypes.isSameType(anno.getAnnotationType().asElement().asType(), getDeprecatedType())) {
|
||||
Map<? extends ExecutableElement, ? extends AnnotationValue> pairs = anno.getElementValues();
|
||||
if (!pairs.isEmpty()) {
|
||||
for (ExecutableElement element : pairs.keySet()) {
|
||||
if (element.getSimpleName().contentEquals("forRemoval")) {
|
||||
return Boolean.parseBoolean((pairs.get(element)).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method to get property name from the name of the
|
||||
* getter or setter method.
|
||||
|
||||
26
langtools/src/jdk.javadoc/share/legal/jszip.md
Normal file
26
langtools/src/jdk.javadoc/share/legal/jszip.md
Normal file
@ -0,0 +1,26 @@
|
||||
## JSZip v2.5.0
|
||||
|
||||
### MIT License
|
||||
<pre>
|
||||
|
||||
Copyright (c) 2009-2014 Stuart Knightley, David Duponchel, Franz Buchinger, António Afonso
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
</pre>
|
||||
@ -39,22 +39,28 @@ import java.util.Set;
|
||||
* Build the profile information.
|
||||
*/
|
||||
enum Profile {
|
||||
COMPACT1("compact1", 1, "java.compact1"),
|
||||
COMPACT2("compact2", 2, "java.compact2"),
|
||||
COMPACT3("compact3", 3, "java.compact3", "java.smartcardio", "jdk.sctp",
|
||||
"jdk.httpserver", "jdk.security.auth",
|
||||
"jdk.naming.dns", "jdk.naming.rmi",
|
||||
"jdk.management"),
|
||||
// need a way to determine JRE modules
|
||||
SE_JRE("Java SE JRE", 4, "java.se", "jdk.charsets",
|
||||
"jdk.crypto.ec", "jdk.crypto.pkcs11",
|
||||
"jdk.crypto.mscapi", "jdk.crypto.ucrypto",
|
||||
"jdk.localedata", "jdk.scripting.nashorn", "jdk.zipfs"),
|
||||
FULL_JRE("Full JRE", 5, "java.se.ee", "jdk.charsets",
|
||||
"jdk.crypto.ec", "jdk.crypto.pkcs11",
|
||||
"jdk.crypto.mscapi", "jdk.crypto.ucrypto", "jdk.jvmstat",
|
||||
"jdk.localedata", "jdk.scripting.nashorn",
|
||||
"jdk.unsupported", "jdk.zipfs");
|
||||
COMPACT1("compact1", 1, "java.logging",
|
||||
"java.scripting"),
|
||||
COMPACT2("compact2", 2, "java.rmi",
|
||||
"java.sql",
|
||||
"java.xml",
|
||||
"jdk.xml.dom",
|
||||
"jdk.httpserver"),
|
||||
COMPACT3("compact3", 3, "java.smartcardio",
|
||||
"java.compiler",
|
||||
"java.instrument",
|
||||
"java.management",
|
||||
"java.naming",
|
||||
"java.prefs",
|
||||
"java.security.jgss",
|
||||
"java.security.sasl",
|
||||
"java.sql.rowset",
|
||||
"java.xml.crypto",
|
||||
"jdk.management",
|
||||
"jdk.naming.dns",
|
||||
"jdk.naming.rmi",
|
||||
"jdk.sctp",
|
||||
"jdk.security.auth");
|
||||
|
||||
final String name;
|
||||
final int profile;
|
||||
@ -80,12 +86,6 @@ enum Profile {
|
||||
return JDK.isEmpty() ? 0 : Profile.values().length;
|
||||
}
|
||||
|
||||
Optional<Module> findModule(String name) {
|
||||
return modules.containsKey(name)
|
||||
? Optional.of(modules.get(name))
|
||||
: Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Profile for the given package name; null if not found.
|
||||
*/
|
||||
@ -137,6 +137,9 @@ enum Profile {
|
||||
|
||||
// for debugging
|
||||
public static void main(String[] args) throws IOException {
|
||||
// initialize Profiles
|
||||
new JdepsConfiguration.Builder().allModules().build();
|
||||
|
||||
// find platform modules
|
||||
if (Profile.getProfileCount() == 0) {
|
||||
System.err.println("No profile is present in this JDK");
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 4927552 8026567 8071982
|
||||
* @bug 4927552 8026567 8071982 8162674
|
||||
* @summary <DESC>
|
||||
* @author jamieh
|
||||
* @library ../lib
|
||||
@ -79,14 +79,138 @@ public class TestDeprecatedDocs extends JavadocTester {
|
||||
"<pre>@Deprecated\n"
|
||||
+ "public class <span class=\"typeNameLabel\">DeprecatedClassByAnnotation</span>\n"
|
||||
+ "extends java.lang.Object</pre>",
|
||||
"<pre>@Deprecated\n"
|
||||
"<pre>@Deprecated(forRemoval=true)\n"
|
||||
+ "public int field</pre>\n"
|
||||
+ "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated.</span> </div>",
|
||||
"<pre>@Deprecated\n"
|
||||
+ "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version. </span> </div>",
|
||||
"<pre>@Deprecated(forRemoval=true)\n"
|
||||
+ "public DeprecatedClassByAnnotation()</pre>\n"
|
||||
+ "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated.</span> </div>",
|
||||
+ "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version. </span> </div>",
|
||||
"<pre>@Deprecated\n"
|
||||
+ "public void method()</pre>\n"
|
||||
+ "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated.</span> </div>");
|
||||
|
||||
checkOutput("pkg/TestAnnotationType.html", true,
|
||||
"<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version. </span> \n"
|
||||
+ "<div class=\"block\"><span class=\"deprecationComment\">annotation_test1 passes.</span></div>\n"
|
||||
+ "</div>\n"
|
||||
+ "<br>\n"
|
||||
+ "<pre>@Deprecated(forRemoval=true)\n"
|
||||
+ "@Documented\n"
|
||||
+ "public @interface <span class=\"memberNameLabel\">TestAnnotationType</span></pre>",
|
||||
"<pre>@Deprecated(forRemoval=true)\n"
|
||||
+ "static final int field</pre>\n"
|
||||
+ "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This "
|
||||
+ "API element is subject to removal in a future version. </span> <span class=\"deprecationComment\">annotation_test4 passes.</span></div>",
|
||||
"<pre>@Deprecated(forRemoval=true)\n"
|
||||
+ "int required</pre>\n"
|
||||
+ "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version. </span> "
|
||||
+ "<span class=\"deprecationComment\">annotation_test3 passes.</span></div>",
|
||||
"<pre>java.lang.String optional</pre>\n"
|
||||
+ "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated.</span> <span class=\"deprecationComment\">annotation_test2 passes.</span></div>");
|
||||
|
||||
checkOutput("pkg/TestClass.html", true,
|
||||
"<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version. </span> \n"
|
||||
+ "<div class=\"block\"><span class=\"deprecationComment\">class_test1 passes.</span></div>\n"
|
||||
+ "</div>\n"
|
||||
+ "<br>\n"
|
||||
+ "<pre>@Deprecated(forRemoval=true)\n"
|
||||
+ "public class <span class=\"typeNameLabel\">TestClass</span>\n"
|
||||
+ "extends java.lang.Object</pre>",
|
||||
"<pre>@Deprecated(forRemoval=true)\n"
|
||||
+ "public TestClass()</pre>\n"
|
||||
+ "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version. </span> "
|
||||
+ "<span class=\"deprecationComment\">class_test3 passes.</span></div>");
|
||||
|
||||
checkOutput("pkg/TestEnum.html", true,
|
||||
"<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version. </span> \n"
|
||||
+ "<div class=\"block\"><span class=\"deprecationComment\">enum_test1 passes.</span></div>\n"
|
||||
+ "</div>\n"
|
||||
+ "<br>\n"
|
||||
+ "<pre>@Deprecated(forRemoval=true)\n"
|
||||
+ "public enum <span class=\"typeNameLabel\">TestEnum</span>\n"
|
||||
+ "extends java.lang.Enum<<a href=\"../pkg/TestEnum.html\" title=\"enum in pkg\">TestEnum</a>></pre>",
|
||||
"<pre>@Deprecated(forRemoval=true)\n"
|
||||
+ "public static final <a href=\"../pkg/TestEnum.html\" title=\"enum in pkg\">TestEnum</a> FOR_REMOVAL</pre>\n"
|
||||
+ "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version. </span> "
|
||||
+ "<span class=\"deprecationComment\">enum_test3 passes.</span></div>");
|
||||
|
||||
checkOutput("pkg/TestError.html", true,
|
||||
"<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version. </span> \n"
|
||||
+ "<div class=\"block\"><span class=\"deprecationComment\">error_test1 passes.</span></div>\n"
|
||||
+ "</div>\n"
|
||||
+ "<br>\n"
|
||||
+ "<pre>@Deprecated(forRemoval=true)\n"
|
||||
+ "public class <span class=\"typeNameLabel\">TestError</span>\n"
|
||||
+ "extends java.lang.Error</pre>");
|
||||
|
||||
checkOutput("pkg/TestException.html", true,
|
||||
"<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version. </span> \n"
|
||||
+ "<div class=\"block\"><span class=\"deprecationComment\">exception_test1 passes.</span></div>\n"
|
||||
+ "</div>\n"
|
||||
+ "<br>\n"
|
||||
+ "<pre>@Deprecated(forRemoval=true)\n"
|
||||
+ "public class <span class=\"typeNameLabel\">TestException</span>\n"
|
||||
+ "extends java.lang.Exception</pre>");
|
||||
|
||||
checkOutput("pkg/TestInterface.html", true,
|
||||
"<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version. </span> \n"
|
||||
+ "<div class=\"block\"><span class=\"deprecationComment\">interface_test1 passes.</span></div>\n"
|
||||
+ "</div>\n"
|
||||
+ "<br>\n"
|
||||
+ "<pre>@Deprecated(forRemoval=true)\n"
|
||||
+ "public class <span class=\"typeNameLabel\">TestInterface</span>\n"
|
||||
+ "extends java.lang.Object</pre>");
|
||||
|
||||
checkOutput("deprecated-list.html", true,
|
||||
"<ul>\n"
|
||||
+ "<li><a href=\"#forRemoval\">Deprecated For Removal</a></li>\n"
|
||||
+ "<li><a href=\"#class\">Deprecated Classes</a></li>\n"
|
||||
+ "<li><a href=\"#enum\">Deprecated Enums</a></li>\n"
|
||||
+ "<li><a href=\"#exception\">Deprecated Exceptions</a></li>\n"
|
||||
+ "<li><a href=\"#error\">Deprecated Errors</a></li>\n"
|
||||
+ "<li><a href=\"#annotation.type\">Deprecated Annotation Types</a></li>\n"
|
||||
+ "<li><a href=\"#field\">Deprecated Fields</a></li>\n"
|
||||
+ "<li><a href=\"#method\">Deprecated Methods</a></li>\n"
|
||||
+ "<li><a href=\"#constructor\">Deprecated Constructors</a></li>\n"
|
||||
+ "<li><a href=\"#enum.constant\">Deprecated Enum Constants</a></li>\n"
|
||||
+ "<li><a href=\"#annotation.type.member\">Deprecated Annotation Type Elements</a></li>\n"
|
||||
+ "</ul>",
|
||||
"<a name=\"forRemoval\">",
|
||||
"<table class=\"deprecatedSummary\" summary=\"Deprecated For Removal table, listing deprecated for removal, and an explanation\">\n"
|
||||
+ "<caption><span>Deprecated For Removal</span><span class=\"tabEnd\"> </span></caption>\n"
|
||||
+ "<tr>\n"
|
||||
+ "<th class=\"colFirst\" scope=\"col\">Element</th>\n"
|
||||
+ "<th class=\"colLast\" scope=\"col\">Description</th>\n"
|
||||
+ "</tr>",
|
||||
"<table class=\"deprecatedSummary\" summary=\"Deprecated Enums table, listing deprecated enums, and an explanation\">\n"
|
||||
+ "<caption><span>Deprecated Enums</span><span class=\"tabEnd\"> </span></caption>\n"
|
||||
+ "<tr>\n"
|
||||
+ "<th class=\"colFirst\" scope=\"col\">Enum</th>\n"
|
||||
+ "<th class=\"colLast\" scope=\"col\">Description</th>\n"
|
||||
+ "</tr>\n"
|
||||
+ "<tbody>\n"
|
||||
+ "<tr class=\"altColor\">\n"
|
||||
+ "<th class=\"colFirst\" scope=\"row\"><a href=\"pkg/TestEnum.html\" title=\"enum in pkg\">pkg.TestEnum</a></th>\n"
|
||||
+ "<td class=\"colLast\">\n"
|
||||
+ "<div class=\"block\"><span class=\"deprecationComment\">enum_test1 passes.</span></div>\n"
|
||||
+ "</td>\n"
|
||||
+ "</tr>\n"
|
||||
+ "</tbody>\n"
|
||||
+ "</table>",
|
||||
"<table class=\"deprecatedSummary\" summary=\"Deprecated Exceptions table, listing deprecated exceptions, and an explanation\">\n"
|
||||
+ "<caption><span>Deprecated Exceptions</span><span class=\"tabEnd\"> </span></caption>\n"
|
||||
+ "<tr>\n"
|
||||
+ "<th class=\"colFirst\" scope=\"col\">Exceptions</th>\n"
|
||||
+ "<th class=\"colLast\" scope=\"col\">Description</th>\n"
|
||||
+ "</tr>\n"
|
||||
+ "<tbody>\n"
|
||||
+ "<tr class=\"altColor\">\n"
|
||||
+ "<th class=\"colFirst\" scope=\"row\"><a href=\"pkg/TestException.html\" title=\"class in pkg\">pkg.TestException</a></th>\n"
|
||||
+ "<td class=\"colLast\">\n"
|
||||
+ "<div class=\"block\"><span class=\"deprecationComment\">exception_test1 passes.</span></div>\n"
|
||||
+ "</td>\n"
|
||||
+ "</tr>\n"
|
||||
+ "</tbody>\n"
|
||||
+ "</table>");
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,10 +26,10 @@ package pkg;
|
||||
@Deprecated()
|
||||
public class DeprecatedClassByAnnotation {
|
||||
|
||||
@Deprecated()
|
||||
@Deprecated(forRemoval=true)
|
||||
public int field;
|
||||
|
||||
@Deprecated()
|
||||
@Deprecated(forRemoval=true)
|
||||
public DeprecatedClassByAnnotation() {}
|
||||
|
||||
@Deprecated()
|
||||
|
||||
@ -28,6 +28,7 @@ import java.lang.annotation.*;
|
||||
/**
|
||||
* @deprecated annotation_test1 passes.
|
||||
*/
|
||||
@Deprecated(forRemoval=true)
|
||||
@Documented public @interface TestAnnotationType {
|
||||
|
||||
/**
|
||||
@ -38,10 +39,12 @@ import java.lang.annotation.*;
|
||||
/**
|
||||
* @deprecated annotation_test3 passes.
|
||||
*/
|
||||
@Deprecated(forRemoval=true)
|
||||
int required();
|
||||
|
||||
/**
|
||||
* @deprecated annotation_test4 passes.
|
||||
*/
|
||||
@Deprecated(forRemoval=true)
|
||||
int field = 0;
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@ package pkg;
|
||||
/**
|
||||
* @deprecated class_test1 passes.
|
||||
*/
|
||||
@Deprecated(forRemoval=true)
|
||||
public class TestClass {
|
||||
|
||||
/**
|
||||
@ -36,6 +37,7 @@ public class TestClass {
|
||||
/**
|
||||
* @deprecated class_test3 passes.
|
||||
*/
|
||||
@Deprecated(forRemoval=true)
|
||||
public TestClass() {}
|
||||
|
||||
/**
|
||||
|
||||
@ -26,10 +26,17 @@ package pkg;
|
||||
/**
|
||||
* @deprecated enum_test1 passes.
|
||||
*/
|
||||
@Deprecated(forRemoval=true)
|
||||
public enum TestEnum {
|
||||
|
||||
/**
|
||||
* @deprecated enum_test2 passes.
|
||||
*/
|
||||
ONE, TWO, THREE;
|
||||
ONE, TWO, THREE,
|
||||
|
||||
/**
|
||||
* @deprecated enum_test3 passes.
|
||||
*/
|
||||
@Deprecated(forRemoval=true)
|
||||
FOR_REMOVAL;
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@ package pkg;
|
||||
/**
|
||||
* @deprecated error_test1 passes.
|
||||
*/
|
||||
@Deprecated(forRemoval=true)
|
||||
public class TestError extends Error {
|
||||
|
||||
/**
|
||||
|
||||
@ -26,6 +26,7 @@ package pkg;
|
||||
/**
|
||||
* @deprecated exception_test1 passes.
|
||||
*/
|
||||
@Deprecated(forRemoval=true)
|
||||
public class TestException extends Exception {
|
||||
|
||||
/**
|
||||
|
||||
@ -30,6 +30,7 @@ import java.util.Map;
|
||||
/**
|
||||
* @deprecated interface_test1 passes.
|
||||
*/
|
||||
@Deprecated(forRemoval=true)
|
||||
public class TestInterface {
|
||||
|
||||
/**
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8154119 8154262 8156077 8157987 8154261 8154817 8135291 8155995 8162363 8168766 8168688
|
||||
* @bug 8154119 8154262 8156077 8157987 8154261 8154817 8135291 8155995 8162363 8168766 8168688 8162674
|
||||
* @summary Test modules support in javadoc.
|
||||
* @author bpatel
|
||||
* @library ../lib
|
||||
@ -253,7 +253,8 @@ public class TestModules extends JavadocTester {
|
||||
void checkHtml5Description(boolean found) {
|
||||
checkOutput("module1-summary.html", found,
|
||||
"<section role=\"region\">\n"
|
||||
+ "<div class=\"deprecatedContent\"><span class=\"deprecatedLabel\">Deprecated.</span>\n"
|
||||
+ "<div class=\"deprecatedContent\"><span class=\"deprecatedLabel\">Deprecated, for removal:"
|
||||
+ " This API element is subject to removal in a future version. </span>\n"
|
||||
+ "<div class=\"block\"><span class=\"deprecationComment\">This module is deprecated.</span></div>\n"
|
||||
+ "</div>\n"
|
||||
+ "<!-- ============ MODULE DESCRIPTION =========== -->\n"
|
||||
@ -597,11 +598,13 @@ public class TestModules extends JavadocTester {
|
||||
|
||||
void checkModuleDeprecation(boolean found) {
|
||||
checkOutput("module1-summary.html", found,
|
||||
"<div class=\"deprecatedContent\"><span class=\"deprecatedLabel\">Deprecated.</span>\n"
|
||||
"<div class=\"deprecatedContent\"><span class=\"deprecatedLabel\">Deprecated, for removal:"
|
||||
+ " This API element is subject to removal in a future version. </span>\n"
|
||||
+ "<div class=\"block\"><span class=\"deprecationComment\">This module is deprecated.</span></div>\n"
|
||||
+ "</div>");
|
||||
checkOutput("deprecated-list.html", found,
|
||||
"<ul>\n"
|
||||
+ "<li><a href=\"#forRemoval\">Deprecated For Removal</a></li>\n"
|
||||
+ "<li><a href=\"#module\">Deprecated Modules</a></li>\n"
|
||||
+ "</ul>",
|
||||
"<tr class=\"altColor\">\n"
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
*
|
||||
* @deprecated This module is deprecated.
|
||||
*/
|
||||
@Deprecated
|
||||
@Deprecated(forRemoval=true)
|
||||
module module1 {
|
||||
requires module2;
|
||||
|
||||
|
||||
213
langtools/test/tools/javac/file/ModuleAndPackageLocations.java
Normal file
213
langtools/test/tools/javac/file/ModuleAndPackageLocations.java
Normal file
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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 8171005
|
||||
* @summary Verify behavior of JavaFileManager methods w.r.t. module/package oriented locations
|
||||
* @library /tools/lib
|
||||
* @modules java.compiler
|
||||
* @build toolbox.TestRunner ModuleAndPackageLocations
|
||||
* @run main ModuleAndPackageLocations
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaFileManager;
|
||||
import javax.tools.JavaFileManager.Location;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.JavaFileObject.Kind;
|
||||
import javax.tools.StandardJavaFileManager;
|
||||
import javax.tools.StandardLocation;
|
||||
import javax.tools.ToolProvider;
|
||||
|
||||
import toolbox.TestRunner;
|
||||
import toolbox.TestRunner.Test;
|
||||
|
||||
public class ModuleAndPackageLocations extends TestRunner {
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
new ModuleAndPackageLocations().runTests(m -> new Object[] { Paths.get(m.getName()) });
|
||||
}
|
||||
|
||||
public ModuleAndPackageLocations() {
|
||||
super(System.err);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListLocations(Path outerBase) throws Exception {
|
||||
doRunTest(outerBase, (base, fm) -> {
|
||||
assertLocations(fm.listLocationsForModules(StandardLocation.MODULE_SOURCE_PATH),
|
||||
toSet("MODULE_SOURCE_PATH[a]:false:false",
|
||||
"MODULE_SOURCE_PATH[b]:false:false",
|
||||
"MODULE_SOURCE_PATH[c]:false:false"));
|
||||
assertLocations(fm.listLocationsForModules(StandardLocation.MODULE_PATH),
|
||||
toSet("MODULE_PATH[0.X,a]:false:false",
|
||||
"MODULE_PATH[0.X,b]:false:false"),
|
||||
toSet("MODULE_PATH[1.X,c]:false:false",
|
||||
"MODULE_PATH[1.X,b]:false:false"));
|
||||
assertLocations(fm.listLocationsForModules(StandardLocation.SOURCE_OUTPUT),
|
||||
toSet("SOURCE_OUTPUT[a]:false:true",
|
||||
"SOURCE_OUTPUT[b]:false:true"));
|
||||
|
||||
fm.getLocationForModule(StandardLocation.SOURCE_OUTPUT, "c");
|
||||
|
||||
assertLocations(fm.listLocationsForModules(StandardLocation.SOURCE_OUTPUT),
|
||||
toSet("SOURCE_OUTPUT[a]:false:true",
|
||||
"SOURCE_OUTPUT[b]:false:true",
|
||||
"SOURCE_OUTPUT[c]:false:true"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetModuleForPath(Path outerBase) throws Exception {
|
||||
doRunTest(outerBase, (base, fm) -> {
|
||||
Location cOutput = fm.getLocationForModule(StandardLocation.SOURCE_OUTPUT, "c");
|
||||
JavaFileObject testFO = fm.getJavaFileForOutput(cOutput, "test.Test", Kind.CLASS, null);
|
||||
testFO.openOutputStream().close();
|
||||
Location cOutput2 = fm.getLocationForModule(StandardLocation.SOURCE_OUTPUT, testFO, "test");
|
||||
|
||||
if (cOutput != cOutput2) {
|
||||
throw new AssertionError("Unexpected location: " + cOutput2 + ", expected: " +cOutput);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRejects(Path outerBase) throws Exception {
|
||||
doRunTest(outerBase, (base, fm) -> {
|
||||
assertRefused(() -> fm.getClassLoader(StandardLocation.MODULE_SOURCE_PATH));
|
||||
assertRefused(() -> fm.getFileForInput(StandardLocation.MODULE_SOURCE_PATH, "", ""));
|
||||
assertRefused(() -> fm.getFileForOutput(StandardLocation.MODULE_SOURCE_PATH, "", "", null));
|
||||
assertRefused(() -> fm.getJavaFileForInput(StandardLocation.MODULE_SOURCE_PATH, "", Kind.SOURCE));
|
||||
assertRefused(() -> fm.getJavaFileForOutput(StandardLocation.MODULE_SOURCE_PATH, "", Kind.SOURCE, null));
|
||||
assertRefused(() -> fm.getLocationForModule(StandardLocation.SOURCE_PATH, "test"));
|
||||
JavaFileObject out = fm.getJavaFileForInput(StandardLocation.CLASS_OUTPUT, "test.Test", Kind.CLASS);
|
||||
assertRefused(() -> fm.getLocationForModule(StandardLocation.SOURCE_PATH, out, "test"));
|
||||
assertRefused(() -> fm.inferBinaryName(StandardLocation.MODULE_PATH, out));
|
||||
assertRefused(() -> fm.inferModuleName(StandardLocation.MODULE_SOURCE_PATH));
|
||||
assertRefused(() -> fm.list(StandardLocation.MODULE_SOURCE_PATH, "test", EnumSet.allOf(Kind.class), false));
|
||||
assertRefused(() -> fm.listLocationsForModules(StandardLocation.SOURCE_PATH));
|
||||
});
|
||||
}
|
||||
|
||||
void doRunTest(Path base, TestExec test) throws Exception {
|
||||
try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
|
||||
Path msp = base.resolve("msp");
|
||||
Path msp1 = msp.resolve("1");
|
||||
Path msp2 = msp.resolve("2");
|
||||
|
||||
Files.createDirectories(msp1.resolve("a"));
|
||||
Files.createDirectories(msp1.resolve("b"));
|
||||
Files.createDirectories(msp2.resolve("b"));
|
||||
Files.createDirectories(msp2.resolve("c"));
|
||||
|
||||
Path mp = base.resolve("mp");
|
||||
Path mp1 = mp.resolve("1");
|
||||
Path mp2 = mp.resolve("2");
|
||||
|
||||
touch(mp1.resolve("a/module-info.class"),
|
||||
mp1.resolve("b/module-info.class"),
|
||||
mp2.resolve("b/module-info.class"),
|
||||
mp2.resolve("c/module-info.class"));
|
||||
|
||||
Path so = base.resolve("so");
|
||||
|
||||
Files.createDirectories(so.resolve("a"));
|
||||
Files.createDirectories(so.resolve("b"));
|
||||
|
||||
List<String> mspOpt = Arrays.asList(msp1.toAbsolutePath().toString() +
|
||||
File.pathSeparatorChar +
|
||||
msp2.toAbsolutePath().toString());
|
||||
|
||||
List<String> mpOpt = Arrays.asList(mp1.toAbsolutePath().toString() +
|
||||
File.pathSeparatorChar +
|
||||
mp2.toAbsolutePath().toString());
|
||||
|
||||
fm.handleOption("--module-source-path", mspOpt.iterator());
|
||||
fm.handleOption("--module-path", mpOpt.iterator());
|
||||
fm.handleOption("-s", Arrays.asList(so.toString()).iterator());
|
||||
|
||||
test.run(base, fm);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> toSet(String... values) {
|
||||
return new HashSet<>(Arrays.asList(values));
|
||||
}
|
||||
|
||||
private void touch(Path... paths) throws IOException {
|
||||
for (Path p : paths) {
|
||||
Files.createDirectories(p.getParent());
|
||||
Files.newOutputStream(p).close();
|
||||
}
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private void assertLocations(Iterable<Set<Location>> locations, Set<String>... expected) {
|
||||
List<Set<String>> actual =
|
||||
StreamSupport.stream(locations.spliterator(), true)
|
||||
.map(locs -> locs.stream()
|
||||
.map(l -> toString(l))
|
||||
.collect(Collectors.toSet()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!Objects.equals(actual, Arrays.asList(expected))) {
|
||||
throw new AssertionError("Unexpected output: " + actual);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertRefused(Callable r) throws Exception {
|
||||
try {
|
||||
r.call();
|
||||
throw new AssertionError("Expected exception did not occur");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
//ok
|
||||
}
|
||||
}
|
||||
|
||||
private static String toString(Location l) {
|
||||
return l.getName().replaceAll("\\[([0-9])\\.[0-9]:", "[$1.X,") + ":" +
|
||||
l.isModuleOrientedLocation() + ":" + l.isOutputLocation();
|
||||
}
|
||||
|
||||
static interface TestExec {
|
||||
public void run(Path base, JavaFileManager fm) throws Exception;
|
||||
}
|
||||
|
||||
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
}
|
||||
@ -33,23 +33,35 @@
|
||||
* @run main AnnotationProcessing
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.Filer;
|
||||
import javax.annotation.processing.FilerException;
|
||||
import javax.annotation.processing.Messager;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
import javax.annotation.processing.SupportedOptions;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ModuleElement;
|
||||
import javax.lang.model.element.ModuleElement.ProvidesDirective;
|
||||
import javax.lang.model.element.ModuleElement.UsesDirective;
|
||||
@ -60,10 +72,20 @@ import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.util.ElementFilter;
|
||||
import javax.lang.model.util.ElementScanner9;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaCompiler.CompilationTask;
|
||||
import javax.tools.JavaFileManager;
|
||||
import javax.tools.JavaFileManager.Location;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.StandardJavaFileManager;
|
||||
import javax.tools.StandardLocation;
|
||||
import javax.tools.ToolProvider;
|
||||
|
||||
import toolbox.JavacTask;
|
||||
import toolbox.Task;
|
||||
import toolbox.Task.Mode;
|
||||
import toolbox.Task.OutputKind;
|
||||
|
||||
public class AnnotationProcessing extends ModuleTestBase {
|
||||
|
||||
@ -135,6 +157,7 @@ public class AnnotationProcessing extends ModuleTestBase {
|
||||
public static final class AP extends AbstractProcessor {
|
||||
|
||||
private Map<String, List<String>> module2ExpectedEnclosedElements;
|
||||
private Set<String> seenModules = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
@ -181,12 +204,16 @@ public class AnnotationProcessing extends ModuleTestBase {
|
||||
.map(p -> p.getQualifiedName().toString())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
assertEquals(module2ExpectedEnclosedElements.remove(module.getQualifiedName().toString()),
|
||||
String moduleName = module.getQualifiedName().toString();
|
||||
|
||||
assertEquals(module2ExpectedEnclosedElements.get(moduleName),
|
||||
actualElements);
|
||||
|
||||
seenModules.add(moduleName);
|
||||
}
|
||||
|
||||
if (roundEnv.processingOver()) {
|
||||
assertEquals(true, module2ExpectedEnclosedElements.isEmpty());
|
||||
assertEquals(module2ExpectedEnclosedElements.keySet(), seenModules);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -374,6 +401,617 @@ public class AnnotationProcessing extends ModuleTestBase {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testModuleInRootElements(Path base) throws Exception {
|
||||
Path moduleSrc = base.resolve("module-src");
|
||||
Path m1 = moduleSrc.resolve("m1");
|
||||
|
||||
Path classes = base.resolve("classes");
|
||||
|
||||
Files.createDirectories(classes);
|
||||
|
||||
tb.writeJavaFiles(m1,
|
||||
"module m1 { exports api; }",
|
||||
"package api; public class Api { }");
|
||||
|
||||
List<String> log = new JavacTask(tb)
|
||||
.options("-processor", ModuleInRootElementsAP.class.getName())
|
||||
.outdir(classes)
|
||||
.files(findJavaFiles(moduleSrc))
|
||||
.run()
|
||||
.writeAll()
|
||||
.getOutputLines(Task.OutputKind.STDERR);
|
||||
|
||||
assertEquals(Arrays.asList("module: m1"), log);
|
||||
}
|
||||
|
||||
@SupportedAnnotationTypes("*")
|
||||
public static final class ModuleInRootElementsAP extends AbstractProcessor {
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
roundEnv.getRootElements()
|
||||
.stream()
|
||||
.filter(el -> el.getKind() == ElementKind.MODULE)
|
||||
.forEach(mod -> System.err.println("module: " + mod.getSimpleName()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latest();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnnotationsInModuleInfo(Path base) throws Exception {
|
||||
Path moduleSrc = base.resolve("module-src");
|
||||
Path m1 = moduleSrc.resolve("m1");
|
||||
|
||||
tb.writeJavaFiles(m1,
|
||||
"@Deprecated module m1 { }");
|
||||
|
||||
Path m2 = moduleSrc.resolve("m2");
|
||||
|
||||
tb.writeJavaFiles(m2,
|
||||
"@SuppressWarnings(\"\") module m2 { }");
|
||||
|
||||
Path classes = base.resolve("classes");
|
||||
|
||||
Files.createDirectories(classes);
|
||||
|
||||
List<String> log = new JavacTask(tb)
|
||||
.options("-processor", AnnotationsInModuleInfoPrint.class.getName())
|
||||
.outdir(classes)
|
||||
.files(findJavaFiles(m1))
|
||||
.run()
|
||||
.writeAll()
|
||||
.getOutputLines(Task.OutputKind.DIRECT);
|
||||
|
||||
List<String> expectedLog = Arrays.asList("Note: AP Invoked",
|
||||
"Note: AP Invoked");
|
||||
|
||||
assertEquals(expectedLog, log);
|
||||
|
||||
new JavacTask(tb)
|
||||
.options("-processor", AnnotationsInModuleInfoFail.class.getName())
|
||||
.outdir(classes)
|
||||
.files(findJavaFiles(m2))
|
||||
.run()
|
||||
.writeAll();
|
||||
}
|
||||
|
||||
@SupportedAnnotationTypes("java.lang.Deprecated")
|
||||
public static final class AnnotationsInModuleInfoPrint extends AbstractProcessor {
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
processingEnv.getMessager().printMessage(Kind.NOTE, "AP Invoked");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latest();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SupportedAnnotationTypes("java.lang.Deprecated")
|
||||
public static final class AnnotationsInModuleInfoFail extends AbstractProcessor {
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latest();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateInMultiModeAPI(Path base) throws Exception {
|
||||
Path moduleSrc = base.resolve("module-src");
|
||||
Path classes = base.resolve("classes");
|
||||
|
||||
Files.createDirectories(classes);
|
||||
|
||||
Path m1 = moduleSrc.resolve("m1");
|
||||
|
||||
tb.writeJavaFiles(m1,
|
||||
"module m1 { exports api1; }",
|
||||
"package api1; public class Api { GenApi ga; impl.Impl i; }");
|
||||
|
||||
writeFile("1", m1, "api1", "api");
|
||||
writeFile("1", m1, "impl", "impl");
|
||||
|
||||
Path m2 = moduleSrc.resolve("m2");
|
||||
|
||||
tb.writeJavaFiles(m2,
|
||||
"module m2 { requires m1; exports api2; }",
|
||||
"package api2; public class Api { api1.GenApi ga1; GenApi qa2; impl.Impl i;}");
|
||||
|
||||
writeFile("2", m2, "api2", "api");
|
||||
writeFile("2", m2, "impl", "impl");
|
||||
|
||||
for (FileType fileType : FileType.values()) {
|
||||
if (Files.isDirectory(classes)) {
|
||||
tb.cleanDirectory(classes);
|
||||
} else {
|
||||
Files.createDirectories(classes);
|
||||
}
|
||||
|
||||
new JavacTask(tb)
|
||||
.options("-processor", MultiModeAPITestAP.class.getName(),
|
||||
"--module-source-path", moduleSrc.toString(),
|
||||
"-Afiletype=" + fileType.name())
|
||||
.outdir(classes)
|
||||
.files(findJavaFiles(moduleSrc))
|
||||
.run()
|
||||
.writeAll();
|
||||
|
||||
assertFileExists(classes, "m1", "api1", "GenApi.class");
|
||||
assertFileExists(classes, "m1", "impl", "Impl.class");
|
||||
assertFileExists(classes, "m1", "api1", "gen1");
|
||||
assertFileExists(classes, "m2", "api2", "GenApi.class");
|
||||
assertFileExists(classes, "m2", "impl", "Impl.class");
|
||||
assertFileExists(classes, "m2", "api2", "gen1");
|
||||
}
|
||||
}
|
||||
|
||||
enum FileType {
|
||||
SOURCE,
|
||||
CLASS;
|
||||
}
|
||||
|
||||
public static abstract class GeneratingAP extends AbstractProcessor {
|
||||
|
||||
void createSource(CreateFileObject file, String name, String content) {
|
||||
try (Writer out = file.create().openWriter()) {
|
||||
out.write(content);
|
||||
} catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
void createClass(CreateFileObject file, String name, String content) {
|
||||
String fileNameStub = name.replace(".", File.separator);
|
||||
|
||||
try (OutputStream out = file.create().openOutputStream()) {
|
||||
Path scratch = Files.createDirectories(Paths.get(""));
|
||||
Path scratchSrc = scratch.resolve(fileNameStub + ".java").toAbsolutePath();
|
||||
|
||||
Files.createDirectories(scratchSrc.getParent());
|
||||
|
||||
try (Writer w = Files.newBufferedWriter(scratchSrc)) {
|
||||
w.write(content);
|
||||
}
|
||||
|
||||
Path scratchClasses = scratch.resolve("classes");
|
||||
|
||||
Files.createDirectories(scratchClasses);
|
||||
|
||||
JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
|
||||
try (StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null)) {
|
||||
List<String> options = Arrays.asList("-d", scratchClasses.toString());
|
||||
Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(scratchSrc);
|
||||
CompilationTask task = comp.getTask(null, fm, null, options, null, files);
|
||||
|
||||
if (!task.call()) {
|
||||
throw new AssertionError("compilation failed");
|
||||
}
|
||||
}
|
||||
|
||||
Path classfile = scratchClasses.resolve(fileNameStub + ".class");
|
||||
|
||||
Files.copy(classfile, out);
|
||||
} catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
void doReadResource(CreateFileObject file, String expectedContent) {
|
||||
try {
|
||||
StringBuilder actualContent = new StringBuilder();
|
||||
|
||||
try (Reader r = file.create().openReader(true)) {
|
||||
int read;
|
||||
|
||||
while ((read = r.read()) != (-1)) {
|
||||
actualContent.append((char) read);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
assertEquals(expectedContent, actualContent.toString());
|
||||
} catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public interface CreateFileObject {
|
||||
public FileObject create() throws IOException;
|
||||
}
|
||||
|
||||
void expectFilerException(Callable<Object> c) {
|
||||
try {
|
||||
c.call();
|
||||
throw new AssertionError("Expected exception not thrown");
|
||||
} catch (FilerException ex) {
|
||||
//expected
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latest();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SupportedAnnotationTypes("*")
|
||||
@SupportedOptions({"filetype", "modulename"})
|
||||
public static final class MultiModeAPITestAP extends GeneratingAP {
|
||||
|
||||
int round;
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
if (round++ != 0)
|
||||
return false;
|
||||
|
||||
createClass("m1", "api1.GenApi", "package api1; public class GenApi {}");
|
||||
createClass("m1", "impl.Impl", "package impl; public class Impl {}");
|
||||
createClass("m2", "api2.GenApi", "package api2; public class GenApi {}");
|
||||
createClass("m2", "impl.Impl", "package impl; public class Impl {}");
|
||||
|
||||
createResource("m1", "api1", "gen1");
|
||||
createResource("m2", "api2", "gen1");
|
||||
|
||||
readResource("m1", "api1", "api", "1");
|
||||
readResource("m1", "impl", "impl", "1");
|
||||
readResource("m2", "api2", "api", "2");
|
||||
readResource("m2", "impl", "impl", "2");
|
||||
|
||||
Filer filer = processingEnv.getFiler();
|
||||
|
||||
expectFilerException(() -> filer.createSourceFile("fail.Fail"));
|
||||
expectFilerException(() -> filer.createClassFile("fail.Fail"));
|
||||
expectFilerException(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, "fail", "fail"));
|
||||
expectFilerException(() -> filer.getResource(StandardLocation.MODULE_SOURCE_PATH, "fail", "fail"));
|
||||
|
||||
//must not generate to unnamed package:
|
||||
expectFilerException(() -> filer.createSourceFile("m1/Fail"));
|
||||
expectFilerException(() -> filer.createClassFile("m1/Fail"));
|
||||
|
||||
//cannot generate resources to modules that are not root modules:
|
||||
expectFilerException(() -> filer.createSourceFile("java.base/fail.Fail"));
|
||||
expectFilerException(() -> filer.createClassFile("java.base/fail.Fail"));
|
||||
expectFilerException(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, "java.base/fail", "Fail"));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void createClass(String expectedModule, String name, String content) {
|
||||
Filer filer = processingEnv.getFiler();
|
||||
FileType filetype = FileType.valueOf(processingEnv.getOptions().getOrDefault("filetype", ""));
|
||||
|
||||
switch (filetype) {
|
||||
case SOURCE:
|
||||
createSource(() -> filer.createSourceFile(expectedModule + "/" + name), name, content);
|
||||
break;
|
||||
case CLASS:
|
||||
createClass(() -> filer.createClassFile(expectedModule + "/" + name), name, content);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Unexpected filetype: " + filetype);
|
||||
}
|
||||
}
|
||||
|
||||
void createResource(String expectedModule, String pkg, String relName) {
|
||||
try {
|
||||
Filer filer = processingEnv.getFiler();
|
||||
|
||||
filer.createResource(StandardLocation.CLASS_OUTPUT, expectedModule + "/" + pkg, relName)
|
||||
.openOutputStream()
|
||||
.close();
|
||||
} catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
void readResource(String expectedModule, String pkg, String relName, String expectedContent) {
|
||||
Filer filer = processingEnv.getFiler();
|
||||
|
||||
doReadResource(() -> filer.getResource(StandardLocation.MODULE_SOURCE_PATH, expectedModule + "/" + pkg, relName),
|
||||
expectedContent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateInSingleNameModeAPI(Path base) throws Exception {
|
||||
Path classes = base.resolve("classes");
|
||||
|
||||
Files.createDirectories(classes);
|
||||
|
||||
Path m1 = base.resolve("module-src");
|
||||
|
||||
tb.writeJavaFiles(m1,
|
||||
"module m1 { }");
|
||||
|
||||
writeFile("3", m1, "impl", "resource");
|
||||
|
||||
new JavacTask(tb)
|
||||
.options("-processor", SingleNameModeAPITestAP.class.getName(),
|
||||
"-sourcepath", m1.toString())
|
||||
.outdir(classes)
|
||||
.files(findJavaFiles(m1))
|
||||
.run()
|
||||
.writeAll();
|
||||
|
||||
assertFileExists(classes, "impl", "Impl1.class");
|
||||
assertFileExists(classes, "impl", "Impl2.class");
|
||||
assertFileExists(classes, "impl", "Impl3");
|
||||
assertFileExists(classes, "impl", "Impl4.class");
|
||||
assertFileExists(classes, "impl", "Impl5.class");
|
||||
assertFileExists(classes, "impl", "Impl6");
|
||||
assertFileExists(classes, "impl", "Impl7.class");
|
||||
assertFileExists(classes, "impl", "Impl8.class");
|
||||
assertFileExists(classes, "impl", "Impl9");
|
||||
}
|
||||
|
||||
|
||||
@SupportedAnnotationTypes("*")
|
||||
public static final class SingleNameModeAPITestAP extends GeneratingAP {
|
||||
|
||||
int round;
|
||||
|
||||
@Override
|
||||
public synchronized void init(ProcessingEnvironment processingEnv) {
|
||||
super.init(processingEnv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
if (round++ != 0)
|
||||
return false;
|
||||
|
||||
Filer filer = processingEnv.getFiler();
|
||||
|
||||
createSource(() -> filer.createSourceFile("impl.Impl1"), "impl.Impl1", "package impl; class Impl1 {}");
|
||||
createClass(() -> filer.createClassFile("impl.Impl2"), "impl.Impl2", "package impl; class Impl2 {}");
|
||||
createSource(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, "impl", "Impl3"), "impl.Impl3", "");
|
||||
doReadResource(() -> filer.getResource(StandardLocation.SOURCE_PATH, "impl", "resource"), "3");
|
||||
|
||||
createSource(() -> filer.createSourceFile("m1/impl.Impl4"), "impl.Impl4", "package impl; class Impl4 {}");
|
||||
createClass(() -> filer.createClassFile("m1/impl.Impl5"), "impl.Impl5", "package impl; class Impl5 {}");
|
||||
createSource(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, "m1/impl", "Impl6"), "impl.Impl6", "");
|
||||
doReadResource(() -> filer.getResource(StandardLocation.SOURCE_PATH, "m1/impl", "resource"), "3");
|
||||
|
||||
TypeElement jlObject = processingEnv.getElementUtils().getTypeElement("java.lang.Object");
|
||||
|
||||
//"broken" originating element:
|
||||
createSource(() -> filer.createSourceFile("impl.Impl7", jlObject), "impl.Impl7", "package impl; class Impl7 {}");
|
||||
createClass(() -> filer.createClassFile("impl.Impl8", jlObject), "impl.Impl8", "package impl; class Impl8 {}");
|
||||
createSource(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, "impl", "Impl9", jlObject), "impl.Impl9", "");
|
||||
|
||||
//must not generate to unnamed package:
|
||||
expectFilerException(() -> filer.createSourceFile("Fail"));
|
||||
expectFilerException(() -> filer.createClassFile("Fail"));
|
||||
expectFilerException(() -> filer.createSourceFile("m1/Fail"));
|
||||
expectFilerException(() -> filer.createClassFile("m1/Fail"));
|
||||
|
||||
//cannot generate resources to modules that are not root modules:
|
||||
expectFilerException(() -> filer.createSourceFile("java.base/fail.Fail"));
|
||||
expectFilerException(() -> filer.createClassFile("java.base/fail.Fail"));
|
||||
expectFilerException(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, "java.base/fail", "Fail"));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateInUnnamedModeAPI(Path base) throws Exception {
|
||||
Path classes = base.resolve("classes");
|
||||
|
||||
Files.createDirectories(classes);
|
||||
|
||||
Path src = base.resolve("src");
|
||||
|
||||
tb.writeJavaFiles(src,
|
||||
"class T {}");
|
||||
|
||||
new JavacTask(tb)
|
||||
.options("-processor", UnnamedModeAPITestAP.class.getName(),
|
||||
"-sourcepath", src.toString())
|
||||
.outdir(classes)
|
||||
.files(findJavaFiles(src))
|
||||
.run()
|
||||
.writeAll();
|
||||
|
||||
assertFileExists(classes, "Impl1.class");
|
||||
assertFileExists(classes, "Impl2.class");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateInNoModeAPI(Path base) throws Exception {
|
||||
Path classes = base.resolve("classes");
|
||||
|
||||
Files.createDirectories(classes);
|
||||
|
||||
Path src = base.resolve("src");
|
||||
|
||||
tb.writeJavaFiles(src,
|
||||
"class T {}");
|
||||
|
||||
new JavacTask(tb)
|
||||
.options("-processor", UnnamedModeAPITestAP.class.getName(),
|
||||
"-source", "8", "-target", "8",
|
||||
"-sourcepath", src.toString())
|
||||
.outdir(classes)
|
||||
.files(findJavaFiles(src))
|
||||
.run()
|
||||
.writeAll();
|
||||
|
||||
assertFileExists(classes, "Impl1.class");
|
||||
assertFileExists(classes, "Impl2.class");
|
||||
}
|
||||
|
||||
@SupportedAnnotationTypes("*")
|
||||
public static final class UnnamedModeAPITestAP extends GeneratingAP {
|
||||
|
||||
int round;
|
||||
|
||||
@Override
|
||||
public synchronized void init(ProcessingEnvironment processingEnv) {
|
||||
super.init(processingEnv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
if (round++ != 0)
|
||||
return false;
|
||||
|
||||
Filer filer = processingEnv.getFiler();
|
||||
|
||||
//must not generate to unnamed package:
|
||||
createSource(() -> filer.createSourceFile("Impl1"), "Impl1", "class Impl1 {}");
|
||||
createClass(() -> filer.createClassFile("Impl2"), "Impl2", "class Impl2 {}");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisambiguateAnnotations(Path base) throws Exception {
|
||||
Path classes = base.resolve("classes");
|
||||
|
||||
Files.createDirectories(classes);
|
||||
|
||||
Path src = base.resolve("src");
|
||||
Path m1 = src.resolve("m1");
|
||||
|
||||
tb.writeJavaFiles(m1,
|
||||
"module m1 { exports api; }",
|
||||
"package api; public @interface A {}",
|
||||
"package api; public @interface B {}");
|
||||
|
||||
Path m2 = src.resolve("m2");
|
||||
|
||||
tb.writeJavaFiles(m2,
|
||||
"module m2 { exports api; }",
|
||||
"package api; public @interface A {}",
|
||||
"package api; public @interface B {}");
|
||||
|
||||
Path m3 = src.resolve("m3");
|
||||
|
||||
tb.writeJavaFiles(m3,
|
||||
"module m3 { requires m1; }",
|
||||
"package impl; import api.*; @A @B public class T {}");
|
||||
|
||||
Path m4 = src.resolve("m4");
|
||||
|
||||
tb.writeJavaFiles(m4,
|
||||
"module m4 { requires m2; }",
|
||||
"package impl; import api.*; @A @B public class T {}");
|
||||
|
||||
List<String> log;
|
||||
List<String> expected;
|
||||
|
||||
log = new JavacTask(tb)
|
||||
.options("-processor", SelectAnnotationATestAP.class.getName() + "," + SelectAnnotationBTestAP.class.getName(),
|
||||
"--module-source-path", src.toString(),
|
||||
"-m", "m1,m2")
|
||||
.outdir(classes)
|
||||
.run()
|
||||
.writeAll()
|
||||
.getOutputLines(OutputKind.STDERR);
|
||||
|
||||
expected = Arrays.asList("");
|
||||
|
||||
if (!expected.equals(log)) {
|
||||
throw new AssertionError("Output does not match; output: " + log);
|
||||
}
|
||||
|
||||
log = new JavacTask(tb)
|
||||
.options("-processor", SelectAnnotationATestAP.class.getName() + "," + SelectAnnotationBTestAP.class.getName(),
|
||||
"--module-source-path", src.toString(),
|
||||
"-m", "m3")
|
||||
.outdir(classes)
|
||||
.run()
|
||||
.writeAll()
|
||||
.getOutputLines(OutputKind.STDERR);
|
||||
|
||||
expected = Arrays.asList("SelectAnnotationBTestAP",
|
||||
"SelectAnnotationBTestAP");
|
||||
|
||||
if (!expected.equals(log)) {
|
||||
throw new AssertionError("Output does not match; output: " + log);
|
||||
}
|
||||
|
||||
log = new JavacTask(tb)
|
||||
.options("-processor", SelectAnnotationATestAP.class.getName() + "," + SelectAnnotationBTestAP.class.getName(),
|
||||
"--module-source-path", src.toString(),
|
||||
"-m", "m4")
|
||||
.outdir(classes)
|
||||
.run()
|
||||
.writeAll()
|
||||
.getOutputLines(OutputKind.STDERR);
|
||||
|
||||
expected = Arrays.asList("SelectAnnotationATestAP",
|
||||
"SelectAnnotationBTestAP",
|
||||
"SelectAnnotationATestAP",
|
||||
"SelectAnnotationBTestAP");
|
||||
|
||||
if (!expected.equals(log)) {
|
||||
throw new AssertionError("Output does not match; output: " + log);
|
||||
}
|
||||
}
|
||||
|
||||
@SupportedAnnotationTypes("m2/api.A")
|
||||
public static final class SelectAnnotationATestAP extends AbstractProcessor {
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
System.err.println("SelectAnnotationATestAP");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SupportedAnnotationTypes("api.B")
|
||||
public static final class SelectAnnotationBTestAP extends AbstractProcessor {
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
System.err.println("SelectAnnotationBTestAP");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void writeFile(String content, Path base, String... pathElements) throws IOException {
|
||||
Path file = resolveFile(base, pathElements);
|
||||
|
||||
Files.createDirectories(file.getParent());
|
||||
|
||||
try (Writer out = Files.newBufferedWriter(file)) {
|
||||
out.append(content);
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertNonNull(String msg, Object val) {
|
||||
if (val == null) {
|
||||
throw new AssertionError(msg);
|
||||
@ -392,4 +1030,22 @@ public class AnnotationProcessing extends ModuleTestBase {
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertFileExists(Path base, String... pathElements) {
|
||||
Path file = resolveFile(base, pathElements);
|
||||
|
||||
if (!Files.exists(file)) {
|
||||
throw new AssertionError("Expected file: " + file + " exist, but it does not.");
|
||||
}
|
||||
}
|
||||
|
||||
static Path resolveFile(Path base, String... pathElements) {
|
||||
Path file = base;
|
||||
|
||||
for (String el : pathElements) {
|
||||
file = file.resolve(el);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
Processor Test matches [java.lang.Override] and returns true.
|
||||
Processor Test matches [java.base/java.lang.Override] and returns true.
|
||||
- compiler.note.proc.messager: round 1
|
||||
Processor Test matches [] and returns true.
|
||||
- compiler.note.proc.messager: round 2
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user