feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.tools.javac.processing;
|
||||
|
||||
|
||||
/**
|
||||
* Error thrown for problems encountered during annotation processing.
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
public class AnnotationProcessingError extends Error {
|
||||
static final long serialVersionUID = 305337707019230790L;
|
||||
AnnotationProcessingError(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
642
jdkSrc/jdk8/com/sun/tools/javac/processing/JavacFiler.java
Normal file
642
jdkSrc/jdk8/com/sun/tools/javac/processing/JavacFiler.java
Normal file
@@ -0,0 +1,642 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.tools.javac.processing;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.io.FilterWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.Collections.*;
|
||||
|
||||
import javax.annotation.processing.*;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.NestingKind;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.tools.*;
|
||||
import javax.tools.JavaFileManager.Location;
|
||||
|
||||
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.util.*;
|
||||
|
||||
import static com.sun.tools.javac.code.Lint.LintCategory.PROCESSING;
|
||||
|
||||
/**
|
||||
* The FilerImplementation class must maintain a number of
|
||||
* constraints. First, multiple attempts to open the same path within
|
||||
* the same invocation of the tool results in an IOException being
|
||||
* thrown. For example, trying to open the same source file twice:
|
||||
*
|
||||
* <pre>
|
||||
* createSourceFile("foo.Bar")
|
||||
* ...
|
||||
* createSourceFile("foo.Bar")
|
||||
* </pre>
|
||||
*
|
||||
* is disallowed as is opening a text file that happens to have
|
||||
* the same name as a source file:
|
||||
*
|
||||
* <pre>
|
||||
* createSourceFile("foo.Bar")
|
||||
* ...
|
||||
* createTextFile(SOURCE_TREE, "foo", new File("Bar"), null)
|
||||
* </pre>
|
||||
*
|
||||
* <p>Additionally, creating a source file that corresponds to an
|
||||
* already created class file (or vice versa) also results in an
|
||||
* IOException since each type can only be created once. However, if
|
||||
* the Filer is used to create a text file named *.java that happens
|
||||
* to correspond to an existing class file, a warning is *not*
|
||||
* generated. Similarly, a warning is not generated for a binary file
|
||||
* named *.class and an existing source file.
|
||||
*
|
||||
* <p>The reason for this difference is that source files and class
|
||||
* files are registered with the tool and can get passed on as
|
||||
* declarations to the next round of processing. Files that are just
|
||||
* named *.java and *.class are not processed in that manner; although
|
||||
* having extra source files and class files on the source path and
|
||||
* class path can alter the behavior of the tool and any final
|
||||
* compile.
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
public class JavacFiler implements Filer, Closeable {
|
||||
// TODO: Implement different transaction model for updating the
|
||||
// Filer's record keeping on file close.
|
||||
|
||||
private static final String ALREADY_OPENED =
|
||||
"Output stream or writer has already been opened.";
|
||||
private static final String NOT_FOR_READING =
|
||||
"FileObject was not opened for reading.";
|
||||
private static final String NOT_FOR_WRITING =
|
||||
"FileObject was not opened for writing.";
|
||||
|
||||
/**
|
||||
* Wrap a JavaFileObject to manage writing by the Filer.
|
||||
*/
|
||||
private class FilerOutputFileObject extends ForwardingFileObject<FileObject> {
|
||||
private boolean opened = false;
|
||||
private String name;
|
||||
|
||||
FilerOutputFileObject(String name, FileObject fileObject) {
|
||||
super(fileObject);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized OutputStream openOutputStream() throws IOException {
|
||||
if (opened)
|
||||
throw new IOException(ALREADY_OPENED);
|
||||
opened = true;
|
||||
return new FilerOutputStream(name, fileObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Writer openWriter() throws IOException {
|
||||
if (opened)
|
||||
throw new IOException(ALREADY_OPENED);
|
||||
opened = true;
|
||||
return new FilerWriter(name, fileObject);
|
||||
}
|
||||
|
||||
// Three anti-literacy methods
|
||||
@Override
|
||||
public InputStream openInputStream() throws IOException {
|
||||
throw new IllegalStateException(NOT_FOR_READING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
|
||||
throw new IllegalStateException(NOT_FOR_READING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
|
||||
throw new IllegalStateException(NOT_FOR_READING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class FilerOutputJavaFileObject extends FilerOutputFileObject implements JavaFileObject {
|
||||
private final JavaFileObject javaFileObject;
|
||||
FilerOutputJavaFileObject(String name, JavaFileObject javaFileObject) {
|
||||
super(name, javaFileObject);
|
||||
this.javaFileObject = javaFileObject;
|
||||
}
|
||||
|
||||
public JavaFileObject.Kind getKind() {
|
||||
return javaFileObject.getKind();
|
||||
}
|
||||
|
||||
public boolean isNameCompatible(String simpleName,
|
||||
JavaFileObject.Kind kind) {
|
||||
return javaFileObject.isNameCompatible(simpleName, kind);
|
||||
}
|
||||
|
||||
public NestingKind getNestingKind() {
|
||||
return javaFileObject.getNestingKind();
|
||||
}
|
||||
|
||||
public Modifier getAccessLevel() {
|
||||
return javaFileObject.getAccessLevel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a JavaFileObject to manage reading by the Filer.
|
||||
*/
|
||||
private class FilerInputFileObject extends ForwardingFileObject<FileObject> {
|
||||
FilerInputFileObject(FileObject fileObject) {
|
||||
super(fileObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream openOutputStream() throws IOException {
|
||||
throw new IllegalStateException(NOT_FOR_WRITING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Writer openWriter() throws IOException {
|
||||
throw new IllegalStateException(NOT_FOR_WRITING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class FilerInputJavaFileObject extends FilerInputFileObject implements JavaFileObject {
|
||||
private final JavaFileObject javaFileObject;
|
||||
FilerInputJavaFileObject(JavaFileObject javaFileObject) {
|
||||
super(javaFileObject);
|
||||
this.javaFileObject = javaFileObject;
|
||||
}
|
||||
|
||||
public JavaFileObject.Kind getKind() {
|
||||
return javaFileObject.getKind();
|
||||
}
|
||||
|
||||
public boolean isNameCompatible(String simpleName,
|
||||
JavaFileObject.Kind kind) {
|
||||
return javaFileObject.isNameCompatible(simpleName, kind);
|
||||
}
|
||||
|
||||
public NestingKind getNestingKind() {
|
||||
return javaFileObject.getNestingKind();
|
||||
}
|
||||
|
||||
public Modifier getAccessLevel() {
|
||||
return javaFileObject.getAccessLevel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wrap a {@code OutputStream} returned from the {@code
|
||||
* JavaFileManager} to properly register source or class files
|
||||
* when they are closed.
|
||||
*/
|
||||
private class FilerOutputStream extends FilterOutputStream {
|
||||
String typeName;
|
||||
FileObject fileObject;
|
||||
boolean closed = false;
|
||||
|
||||
/**
|
||||
* @param typeName name of class or {@code null} if just a
|
||||
* binary file
|
||||
*/
|
||||
FilerOutputStream(String typeName, FileObject fileObject) throws IOException {
|
||||
super(fileObject.openOutputStream());
|
||||
this.typeName = typeName;
|
||||
this.fileObject = fileObject;
|
||||
}
|
||||
|
||||
public synchronized void close() throws IOException {
|
||||
if (!closed) {
|
||||
closed = true;
|
||||
/*
|
||||
* If an IOException occurs when closing the underlying
|
||||
* stream, still try to process the file.
|
||||
*/
|
||||
|
||||
closeFileObject(typeName, fileObject);
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a {@code Writer} returned from the {@code JavaFileManager}
|
||||
* to properly register source or class files when they are
|
||||
* closed.
|
||||
*/
|
||||
private class FilerWriter extends FilterWriter {
|
||||
String typeName;
|
||||
FileObject fileObject;
|
||||
boolean closed = false;
|
||||
|
||||
/**
|
||||
* @param fileObject the fileObject to be written to
|
||||
* @param typeName name of source file or {@code null} if just a
|
||||
* text file
|
||||
*/
|
||||
FilerWriter(String typeName, FileObject fileObject) throws IOException {
|
||||
super(fileObject.openWriter());
|
||||
this.typeName = typeName;
|
||||
this.fileObject = fileObject;
|
||||
}
|
||||
|
||||
public synchronized void close() throws IOException {
|
||||
if (!closed) {
|
||||
closed = true;
|
||||
/*
|
||||
* If an IOException occurs when closing the underlying
|
||||
* Writer, still try to process the file.
|
||||
*/
|
||||
|
||||
closeFileObject(typeName, fileObject);
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JavaFileManager fileManager;
|
||||
Log log;
|
||||
Context context;
|
||||
boolean lastRound;
|
||||
|
||||
private final boolean lint;
|
||||
|
||||
/**
|
||||
* Logical names of all created files. This set must be
|
||||
* synchronized.
|
||||
*/
|
||||
private final Set<FileObject> fileObjectHistory;
|
||||
|
||||
/**
|
||||
* Names of types that have had files created but not closed.
|
||||
*/
|
||||
private final Set<String> openTypeNames;
|
||||
|
||||
/**
|
||||
* Names of source files closed in this round. This set must be
|
||||
* synchronized. Its iterators should preserve insertion order.
|
||||
*/
|
||||
private Set<String> generatedSourceNames;
|
||||
|
||||
/**
|
||||
* Names and class files of the class files closed in this round.
|
||||
* This set must be synchronized. Its iterators should preserve
|
||||
* insertion order.
|
||||
*/
|
||||
private final Map<String, JavaFileObject> generatedClasses;
|
||||
|
||||
/**
|
||||
* JavaFileObjects for source files closed in this round. This
|
||||
* set must be synchronized. Its iterators should preserve
|
||||
* insertion order.
|
||||
*/
|
||||
private Set<JavaFileObject> generatedSourceFileObjects;
|
||||
|
||||
/**
|
||||
* Names of all created source files. Its iterators should
|
||||
* preserve insertion order.
|
||||
*/
|
||||
private final Set<String> aggregateGeneratedSourceNames;
|
||||
|
||||
/**
|
||||
* Names of all created class files. Its iterators should
|
||||
* preserve insertion order.
|
||||
*/
|
||||
private final Set<String> aggregateGeneratedClassNames;
|
||||
|
||||
|
||||
JavacFiler(Context context) {
|
||||
this.context = context;
|
||||
fileManager = context.get(JavaFileManager.class);
|
||||
|
||||
log = Log.instance(context);
|
||||
|
||||
fileObjectHistory = synchronizedSet(new LinkedHashSet<FileObject>());
|
||||
generatedSourceNames = synchronizedSet(new LinkedHashSet<String>());
|
||||
generatedSourceFileObjects = synchronizedSet(new LinkedHashSet<JavaFileObject>());
|
||||
|
||||
generatedClasses = synchronizedMap(new LinkedHashMap<String, JavaFileObject>());
|
||||
|
||||
openTypeNames = synchronizedSet(new LinkedHashSet<String>());
|
||||
|
||||
aggregateGeneratedSourceNames = new LinkedHashSet<String>();
|
||||
aggregateGeneratedClassNames = new LinkedHashSet<String>();
|
||||
|
||||
lint = (Lint.instance(context)).isEnabled(PROCESSING);
|
||||
}
|
||||
|
||||
public JavaFileObject createSourceFile(CharSequence name,
|
||||
Element... originatingElements) throws IOException {
|
||||
return createSourceOrClassFile(true, name.toString());
|
||||
}
|
||||
|
||||
public JavaFileObject createClassFile(CharSequence name,
|
||||
Element... originatingElements) throws IOException {
|
||||
return createSourceOrClassFile(false, name.toString());
|
||||
}
|
||||
|
||||
private JavaFileObject createSourceOrClassFile(boolean isSourceFile, String name) throws IOException {
|
||||
if (lint) {
|
||||
int periodIndex = name.lastIndexOf(".");
|
||||
if (periodIndex != -1) {
|
||||
String base = name.substring(periodIndex);
|
||||
String extn = (isSourceFile ? ".java" : ".class");
|
||||
if (base.equals(extn))
|
||||
log.warning("proc.suspicious.class.name", name, extn);
|
||||
}
|
||||
}
|
||||
checkNameAndExistence(name, isSourceFile);
|
||||
Location loc = (isSourceFile ? SOURCE_OUTPUT : CLASS_OUTPUT);
|
||||
JavaFileObject.Kind kind = (isSourceFile ?
|
||||
JavaFileObject.Kind.SOURCE :
|
||||
JavaFileObject.Kind.CLASS);
|
||||
|
||||
JavaFileObject fileObject =
|
||||
fileManager.getJavaFileForOutput(loc, name, kind, null);
|
||||
checkFileReopening(fileObject, true);
|
||||
|
||||
if (lastRound)
|
||||
log.warning("proc.file.create.last.round", name);
|
||||
|
||||
if (isSourceFile)
|
||||
aggregateGeneratedSourceNames.add(name);
|
||||
else
|
||||
aggregateGeneratedClassNames.add(name);
|
||||
openTypeNames.add(name);
|
||||
|
||||
return new FilerOutputJavaFileObject(name, fileObject);
|
||||
}
|
||||
|
||||
public FileObject createResource(JavaFileManager.Location location,
|
||||
CharSequence pkg,
|
||||
CharSequence relativeName,
|
||||
Element... originatingElements) throws IOException {
|
||||
locationCheck(location);
|
||||
|
||||
String strPkg = pkg.toString();
|
||||
if (strPkg.length() > 0)
|
||||
checkName(strPkg);
|
||||
|
||||
FileObject fileObject =
|
||||
fileManager.getFileForOutput(location, strPkg,
|
||||
relativeName.toString(), null);
|
||||
checkFileReopening(fileObject, true);
|
||||
|
||||
if (fileObject instanceof JavaFileObject)
|
||||
return new FilerOutputJavaFileObject(null, (JavaFileObject)fileObject);
|
||||
else
|
||||
return new FilerOutputFileObject(null, fileObject);
|
||||
}
|
||||
|
||||
private void locationCheck(JavaFileManager.Location location) {
|
||||
if (location instanceof StandardLocation) {
|
||||
StandardLocation stdLoc = (StandardLocation) location;
|
||||
if (!stdLoc.isOutputLocation())
|
||||
throw new IllegalArgumentException("Resource creation not supported in location " +
|
||||
stdLoc);
|
||||
}
|
||||
}
|
||||
|
||||
public FileObject getResource(JavaFileManager.Location location,
|
||||
CharSequence pkg,
|
||||
CharSequence relativeName) throws IOException {
|
||||
String strPkg = pkg.toString();
|
||||
if (strPkg.length() > 0)
|
||||
checkName(strPkg);
|
||||
|
||||
// TODO: Only support reading resources in selected output
|
||||
// locations? Only allow reading of non-source, non-class
|
||||
// files from the supported input locations?
|
||||
|
||||
// In the following, getFileForInput is the "obvious" method
|
||||
// to use, but it does not have the "obvious" semantics for
|
||||
// SOURCE_OUTPUT and CLASS_OUTPUT. Conversely, getFileForOutput
|
||||
// does not have the correct semantics for any "path" location
|
||||
// with more than one component. So, for now, we use a hybrid
|
||||
// invocation.
|
||||
FileObject fileObject;
|
||||
if (location.isOutputLocation()) {
|
||||
fileObject = fileManager.getFileForOutput(location,
|
||||
pkg.toString(),
|
||||
relativeName.toString(),
|
||||
null);
|
||||
} else {
|
||||
fileObject = fileManager.getFileForInput(location,
|
||||
pkg.toString(),
|
||||
relativeName.toString());
|
||||
}
|
||||
if (fileObject == null) {
|
||||
String name = (pkg.length() == 0)
|
||||
? relativeName.toString() : (pkg + "/" + relativeName);
|
||||
throw new FileNotFoundException(name);
|
||||
}
|
||||
|
||||
// If the path was already opened for writing, throw an exception.
|
||||
checkFileReopening(fileObject, false);
|
||||
return new FilerInputFileObject(fileObject);
|
||||
}
|
||||
|
||||
private void checkName(String name) throws FilerException {
|
||||
checkName(name, false);
|
||||
}
|
||||
|
||||
private void checkName(String name, boolean allowUnnamedPackageInfo) throws FilerException {
|
||||
if (!SourceVersion.isName(name) && !isPackageInfo(name, allowUnnamedPackageInfo)) {
|
||||
if (lint)
|
||||
log.warning("proc.illegal.file.name", name);
|
||||
throw new FilerException("Illegal name " + name);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPackageInfo(String name, boolean allowUnnamedPackageInfo) {
|
||||
// Is the name of the form "package-info" or
|
||||
// "foo.bar.package-info"?
|
||||
final String PKG_INFO = "package-info";
|
||||
int periodIndex = name.lastIndexOf(".");
|
||||
if (periodIndex == -1) {
|
||||
return allowUnnamedPackageInfo ? name.equals(PKG_INFO) : false;
|
||||
} else {
|
||||
// "foo.bar.package-info." illegal
|
||||
String prefix = name.substring(0, periodIndex);
|
||||
String simple = name.substring(periodIndex+1);
|
||||
return SourceVersion.isName(prefix) && simple.equals(PKG_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkNameAndExistence(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 (lint)
|
||||
log.warning("proc.type.recreate", typename);
|
||||
throw new FilerException("Attempt to recreate a file for type " + typename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the file has already been opened; if so, throw
|
||||
* an exception, otherwise add it to the set of files.
|
||||
*/
|
||||
private void checkFileReopening(FileObject fileObject, boolean addToHistory) throws FilerException {
|
||||
for(FileObject veteran : fileObjectHistory) {
|
||||
if (fileManager.isSameFile(veteran, fileObject)) {
|
||||
if (lint)
|
||||
log.warning("proc.file.reopening", fileObject.getName());
|
||||
throw new FilerException("Attempt to reopen a file for path " + fileObject.getName());
|
||||
}
|
||||
}
|
||||
if (addToHistory)
|
||||
fileObjectHistory.add(fileObject);
|
||||
}
|
||||
|
||||
public boolean newFiles() {
|
||||
return (!generatedSourceNames.isEmpty())
|
||||
|| (!generatedClasses.isEmpty());
|
||||
}
|
||||
|
||||
public Set<String> getGeneratedSourceNames() {
|
||||
return generatedSourceNames;
|
||||
}
|
||||
|
||||
public Set<JavaFileObject> getGeneratedSourceFileObjects() {
|
||||
return generatedSourceFileObjects;
|
||||
}
|
||||
|
||||
public Map<String, JavaFileObject> getGeneratedClasses() {
|
||||
return generatedClasses;
|
||||
}
|
||||
|
||||
public void warnIfUnclosedFiles() {
|
||||
if (!openTypeNames.isEmpty())
|
||||
log.warning("proc.unclosed.type.files", openTypeNames.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Update internal state for a new round.
|
||||
*/
|
||||
public void newRound(Context context) {
|
||||
this.context = context;
|
||||
this.log = Log.instance(context);
|
||||
clearRoundState();
|
||||
}
|
||||
|
||||
void setLastRound(boolean lastRound) {
|
||||
this.lastRound = lastRound;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
clearRoundState();
|
||||
// Cross-round state
|
||||
fileObjectHistory.clear();
|
||||
openTypeNames.clear();
|
||||
aggregateGeneratedSourceNames.clear();
|
||||
aggregateGeneratedClassNames.clear();
|
||||
}
|
||||
|
||||
private void clearRoundState() {
|
||||
generatedSourceNames.clear();
|
||||
generatedSourceFileObjects.clear();
|
||||
generatedClasses.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugging function to display internal state.
|
||||
*/
|
||||
public void displayState() {
|
||||
PrintWriter xout = context.get(Log.outKey);
|
||||
xout.println("File Object History : " + fileObjectHistory);
|
||||
xout.println("Open Type Names : " + openTypeNames);
|
||||
xout.println("Gen. Src Names : " + generatedSourceNames);
|
||||
xout.println("Gen. Cls Names : " + generatedClasses.keySet());
|
||||
xout.println("Agg. Gen. Src Names : " + aggregateGeneratedSourceNames);
|
||||
xout.println("Agg. Gen. Cls Names : " + aggregateGeneratedClassNames);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "javac Filer";
|
||||
}
|
||||
|
||||
/**
|
||||
* Upon close, register files opened by create{Source, Class}File
|
||||
* for annotation processing.
|
||||
*/
|
||||
private void closeFileObject(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
|
||||
* a resource, typeName will be null and the file is *not*
|
||||
* subject to annotation processing.
|
||||
*/
|
||||
if ((typeName != null)) {
|
||||
if (!(fileObject instanceof JavaFileObject))
|
||||
throw new AssertionError("JavaFileOject not found for " + fileObject);
|
||||
JavaFileObject javaFileObject = (JavaFileObject)fileObject;
|
||||
switch(javaFileObject.getKind()) {
|
||||
case SOURCE:
|
||||
generatedSourceNames.add(typeName);
|
||||
generatedSourceFileObjects.add(javaFileObject);
|
||||
openTypeNames.remove(typeName);
|
||||
break;
|
||||
|
||||
case CLASS:
|
||||
generatedClasses.put(typeName, javaFileObject);
|
||||
openTypeNames.remove(typeName);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
187
jdkSrc/jdk8/com/sun/tools/javac/processing/JavacMessager.java
Normal file
187
jdkSrc/jdk8/com/sun/tools/javac/processing/JavacMessager.java
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.tools.javac.processing;
|
||||
|
||||
import com.sun.tools.javac.model.JavacElements;
|
||||
import com.sun.tools.javac.util.*;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.*;
|
||||
import javax.lang.model.element.*;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.annotation.processing.*;
|
||||
|
||||
/**
|
||||
* An implementation of the Messager built on top of log.
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
public class JavacMessager implements Messager {
|
||||
Log log;
|
||||
JavacProcessingEnvironment processingEnv;
|
||||
int errorCount = 0;
|
||||
int warningCount = 0;
|
||||
|
||||
JavacMessager(Context context, JavacProcessingEnvironment processingEnv) {
|
||||
log = Log.instance(context);
|
||||
this.processingEnv = processingEnv;
|
||||
}
|
||||
|
||||
// processingEnv.getElementUtils()
|
||||
|
||||
public void printMessage(Diagnostic.Kind kind, CharSequence msg) {
|
||||
printMessage(kind, msg, null, null, null);
|
||||
}
|
||||
|
||||
public void printMessage(Diagnostic.Kind kind, CharSequence msg,
|
||||
Element e) {
|
||||
printMessage(kind, msg, e, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message of the specified kind at the location of the
|
||||
* annotation mirror of the annotated element.
|
||||
*
|
||||
* @param kind the kind of message
|
||||
* @param msg the message, or an empty string if none
|
||||
* @param e the annotated element
|
||||
* @param a the annotation to use as a position hint
|
||||
*/
|
||||
public void printMessage(Diagnostic.Kind kind, CharSequence msg,
|
||||
Element e, AnnotationMirror a) {
|
||||
printMessage(kind, msg, e, a, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message of the specified kind at the location of the
|
||||
* annotation value inside the annotation mirror of the annotated
|
||||
* element.
|
||||
*
|
||||
* @param kind the kind of message
|
||||
* @param msg the message, or an empty string if none
|
||||
* @param e the annotated element
|
||||
* @param a the annotation containing the annotaiton value
|
||||
* @param v the annotation value to use as a position hint
|
||||
*/
|
||||
public void printMessage(Diagnostic.Kind kind, CharSequence msg,
|
||||
Element e, AnnotationMirror a, AnnotationValue v) {
|
||||
JavaFileObject oldSource = null;
|
||||
JavaFileObject newSource = null;
|
||||
JCDiagnostic.DiagnosticPosition pos = null;
|
||||
JavacElements elemUtils = processingEnv.getElementUtils();
|
||||
Pair<JCTree, JCCompilationUnit> treeTop = elemUtils.getTreeAndTopLevel(e, a, v);
|
||||
if (treeTop != null) {
|
||||
newSource = treeTop.snd.sourcefile;
|
||||
if (newSource != null) {
|
||||
// save the old version and reinstate it later
|
||||
oldSource = log.useSource(newSource);
|
||||
pos = treeTop.fst.pos();
|
||||
}
|
||||
}
|
||||
try {
|
||||
switch (kind) {
|
||||
case ERROR:
|
||||
errorCount++;
|
||||
boolean prev = log.multipleErrors;
|
||||
log.multipleErrors = true;
|
||||
try {
|
||||
log.error(pos, "proc.messager", msg.toString());
|
||||
} finally {
|
||||
log.multipleErrors = prev;
|
||||
}
|
||||
break;
|
||||
|
||||
case WARNING:
|
||||
warningCount++;
|
||||
log.warning(pos, "proc.messager", msg.toString());
|
||||
break;
|
||||
|
||||
case MANDATORY_WARNING:
|
||||
warningCount++;
|
||||
log.mandatoryWarning(pos, "proc.messager", msg.toString());
|
||||
break;
|
||||
|
||||
default:
|
||||
log.note(pos, "proc.messager", msg.toString());
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
// reinstate the saved version, only if it was saved earlier
|
||||
if (newSource != null)
|
||||
log.useSource(oldSource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints an error message.
|
||||
* Equivalent to {@code printError(null, msg)}.
|
||||
* @param msg the message, or an empty string if none
|
||||
*/
|
||||
public void printError(String msg) {
|
||||
printMessage(Diagnostic.Kind.ERROR, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a warning message.
|
||||
* Equivalent to {@code printWarning(null, msg)}.
|
||||
* @param msg the message, or an empty string if none
|
||||
*/
|
||||
public void printWarning(String msg) {
|
||||
printMessage(Diagnostic.Kind.WARNING, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a notice.
|
||||
* @param msg the message, or an empty string if none
|
||||
*/
|
||||
public void printNotice(String msg) {
|
||||
printMessage(Diagnostic.Kind.NOTE, msg);
|
||||
}
|
||||
|
||||
public boolean errorRaised() {
|
||||
return errorCount > 0;
|
||||
}
|
||||
|
||||
public int errorCount() {
|
||||
return errorCount;
|
||||
}
|
||||
|
||||
public int warningCount() {
|
||||
return warningCount;
|
||||
}
|
||||
|
||||
public void newRound(Context context) {
|
||||
log = Log.instance(context);
|
||||
errorCount = 0;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "javac Messager";
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.tools.javac.processing;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import javax.annotation.processing.*;
|
||||
import javax.lang.model.element.*;
|
||||
import javax.lang.model.util.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Object providing state about a prior round of annotation processing.
|
||||
*
|
||||
* <p>The methods in this class do not take type annotations into account,
|
||||
* as target types, not java elements.
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
public class JavacRoundEnvironment implements RoundEnvironment {
|
||||
// Default equals and hashCode methods are okay.
|
||||
|
||||
private final boolean processingOver;
|
||||
private final boolean errorRaised;
|
||||
private final ProcessingEnvironment processingEnv;
|
||||
|
||||
// Caller must pass in an immutable set
|
||||
private final Set<? extends Element> rootElements;
|
||||
|
||||
JavacRoundEnvironment(boolean processingOver,
|
||||
boolean errorRaised,
|
||||
Set<? extends Element> rootElements,
|
||||
ProcessingEnvironment processingEnv) {
|
||||
this.processingOver = processingOver;
|
||||
this.errorRaised = errorRaised;
|
||||
this.rootElements = rootElements;
|
||||
this.processingEnv = processingEnv;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("[errorRaised=%b, rootElements=%s, processingOver=%b]",
|
||||
errorRaised,
|
||||
rootElements,
|
||||
processingOver);
|
||||
}
|
||||
|
||||
public boolean processingOver() {
|
||||
return processingOver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if an error was raised in the prior round
|
||||
* of processing; returns {@code false} otherwise.
|
||||
*
|
||||
* @return {@code true} if an error was raised in the prior round
|
||||
* of processing; returns {@code false} otherwise.
|
||||
*/
|
||||
public boolean errorRaised() {
|
||||
return errorRaised;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type elements specified by the prior round.
|
||||
*
|
||||
* @return the types elements specified by the prior round, or an
|
||||
* empty set if there were none
|
||||
*/
|
||||
public Set<? extends Element> getRootElements() {
|
||||
return rootElements;
|
||||
}
|
||||
|
||||
private static final String NOT_AN_ANNOTATION_TYPE =
|
||||
"The argument does not represent an annotation type: ";
|
||||
|
||||
/**
|
||||
* Returns the elements annotated with the given annotation type.
|
||||
* Only type elements <i>included</i> in this round of annotation
|
||||
* processing, or declarations of members, parameters, or type
|
||||
* parameters declared within those, are returned. Included type
|
||||
* elements are {@linkplain #getRootElements specified
|
||||
* types} and any types nested within them.
|
||||
*
|
||||
* @param a annotation type being requested
|
||||
* @return the elements annotated with the given annotation type,
|
||||
* or an empty set if there are none
|
||||
*/
|
||||
public Set<? extends Element> getElementsAnnotatedWith(TypeElement a) {
|
||||
Set<Element> result = Collections.emptySet();
|
||||
if (a.getKind() != ElementKind.ANNOTATION_TYPE)
|
||||
throw new IllegalArgumentException(NOT_AN_ANNOTATION_TYPE + a);
|
||||
|
||||
ElementScanner8<Set<Element>, TypeElement> scanner =
|
||||
new AnnotationSetScanner(result);
|
||||
|
||||
for (Element element : rootElements)
|
||||
result = scanner.scan(element, a);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Could be written as a local class inside getElementsAnnotatedWith
|
||||
private class AnnotationSetScanner extends
|
||||
ElementScanner8<Set<Element>, TypeElement> {
|
||||
// Insertion-order preserving set
|
||||
Set<Element> annotatedElements = new LinkedHashSet<Element>();
|
||||
|
||||
AnnotationSetScanner(Set<Element> defaultSet) {
|
||||
super(defaultSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Element> visitType(TypeElement e, TypeElement p) {
|
||||
// Type parameters are not considered to be enclosed by a type
|
||||
scan(e.getTypeParameters(), p);
|
||||
return super.visitType(e, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Element> visitExecutable(ExecutableElement e, TypeElement p) {
|
||||
// Type parameters are not considered to be enclosed by an executable
|
||||
scan(e.getTypeParameters(), p);
|
||||
return super.visitExecutable(e, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Element> scan(Element e, TypeElement p) {
|
||||
java.util.List<? extends AnnotationMirror> annotationMirrors =
|
||||
processingEnv.getElementUtils().getAllAnnotationMirrors(e);
|
||||
for (AnnotationMirror annotationMirror : annotationMirrors) {
|
||||
if (p.equals(annotationMirror.getAnnotationType().asElement()))
|
||||
annotatedElements.add(e);
|
||||
}
|
||||
e.accept(this, p);
|
||||
return annotatedElements;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a) {
|
||||
if (!a.isAnnotation())
|
||||
throw new IllegalArgumentException(NOT_AN_ANNOTATION_TYPE + a);
|
||||
String name = a.getCanonicalName();
|
||||
if (name == null)
|
||||
return Collections.emptySet();
|
||||
else {
|
||||
TypeElement annotationType = processingEnv.getElementUtils().getTypeElement(name);
|
||||
if (annotationType == null)
|
||||
return Collections.emptySet();
|
||||
else
|
||||
return getElementsAnnotatedWith(annotationType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,545 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.tools.javac.processing;
|
||||
|
||||
import javax.annotation.processing.*;
|
||||
import javax.lang.model.*;
|
||||
import javax.lang.model.element.*;
|
||||
import static javax.lang.model.element.ElementKind.*;
|
||||
import static javax.lang.model.element.NestingKind.*;
|
||||
import javax.lang.model.type.*;
|
||||
import javax.lang.model.util.*;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.*;
|
||||
import com.sun.tools.javac.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A processor which prints out elements. Used to implement the
|
||||
* -Xprint option; the included visitor class is used to implement
|
||||
* Elements.printElements.
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
@SupportedAnnotationTypes("*")
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
||||
public class PrintingProcessor extends AbstractProcessor {
|
||||
PrintWriter writer;
|
||||
|
||||
public PrintingProcessor() {
|
||||
super();
|
||||
writer = new PrintWriter(System.out);
|
||||
}
|
||||
|
||||
public void setWriter(Writer w) {
|
||||
writer = new PrintWriter(w);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> tes,
|
||||
RoundEnvironment renv) {
|
||||
|
||||
for(Element element : renv.getRootElements()) {
|
||||
print(element);
|
||||
}
|
||||
|
||||
// Just print the elements, nothing more to do.
|
||||
return true;
|
||||
}
|
||||
|
||||
void print(Element element) {
|
||||
new PrintingElementVisitor(writer, processingEnv.getElementUtils()).
|
||||
visit(element).flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for the -Xprint option and called by Elements.printElements
|
||||
*/
|
||||
public static class PrintingElementVisitor
|
||||
extends SimpleElementVisitor8<PrintingElementVisitor, Boolean> {
|
||||
int indentation; // Indentation level;
|
||||
final PrintWriter writer;
|
||||
final Elements elementUtils;
|
||||
|
||||
public PrintingElementVisitor(Writer w, Elements elementUtils) {
|
||||
super();
|
||||
this.writer = new PrintWriter(w);
|
||||
this.elementUtils = elementUtils;
|
||||
indentation = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PrintingElementVisitor defaultAction(Element e, Boolean newLine) {
|
||||
if (newLine != null && newLine)
|
||||
writer.println();
|
||||
printDocComment(e);
|
||||
printModifiers(e);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintingElementVisitor visitExecutable(ExecutableElement e, Boolean p) {
|
||||
ElementKind kind = e.getKind();
|
||||
|
||||
if (kind != STATIC_INIT &&
|
||||
kind != INSTANCE_INIT) {
|
||||
Element enclosing = e.getEnclosingElement();
|
||||
|
||||
// Don't print out the constructor of an anonymous class
|
||||
if (kind == CONSTRUCTOR &&
|
||||
enclosing != null &&
|
||||
NestingKind.ANONYMOUS ==
|
||||
// Use an anonymous class to determine anonymity!
|
||||
(new SimpleElementVisitor7<NestingKind, Void>() {
|
||||
@Override
|
||||
public NestingKind visitType(TypeElement e, Void p) {
|
||||
return e.getNestingKind();
|
||||
}
|
||||
}).visit(enclosing))
|
||||
return this;
|
||||
|
||||
defaultAction(e, true);
|
||||
printFormalTypeParameters(e, true);
|
||||
|
||||
switch(kind) {
|
||||
case CONSTRUCTOR:
|
||||
// Print out simple name of the class
|
||||
writer.print(e.getEnclosingElement().getSimpleName());
|
||||
break;
|
||||
|
||||
case METHOD:
|
||||
writer.print(e.getReturnType().toString());
|
||||
writer.print(" ");
|
||||
writer.print(e.getSimpleName().toString());
|
||||
break;
|
||||
}
|
||||
|
||||
writer.print("(");
|
||||
printParameters(e);
|
||||
writer.print(")");
|
||||
AnnotationValue defaultValue = e.getDefaultValue();
|
||||
if (defaultValue != null)
|
||||
writer.print(" default " + defaultValue);
|
||||
|
||||
printThrows(e);
|
||||
writer.println(";");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public PrintingElementVisitor visitType(TypeElement e, Boolean p) {
|
||||
ElementKind kind = e.getKind();
|
||||
NestingKind nestingKind = e.getNestingKind();
|
||||
|
||||
if (NestingKind.ANONYMOUS == nestingKind) {
|
||||
// Print out an anonymous class in the style of a
|
||||
// class instance creation expression rather than a
|
||||
// class declaration.
|
||||
writer.print("new ");
|
||||
|
||||
// If the anonymous class implements an interface
|
||||
// print that name, otherwise print the superclass.
|
||||
List<? extends TypeMirror> interfaces = e.getInterfaces();
|
||||
if (!interfaces.isEmpty())
|
||||
writer.print(interfaces.get(0));
|
||||
else
|
||||
writer.print(e.getSuperclass());
|
||||
|
||||
writer.print("(");
|
||||
// Anonymous classes that implement an interface can't
|
||||
// have any constructor arguments.
|
||||
if (interfaces.isEmpty()) {
|
||||
// Print out the parameter list from the sole
|
||||
// constructor. For now, don't try to elide any
|
||||
// synthetic parameters by determining if the
|
||||
// anonymous class is in a static context, etc.
|
||||
List<? extends ExecutableElement> constructors =
|
||||
ElementFilter.constructorsIn(e.getEnclosedElements());
|
||||
|
||||
if (!constructors.isEmpty())
|
||||
printParameters(constructors.get(0));
|
||||
}
|
||||
writer.print(")");
|
||||
} else {
|
||||
if (nestingKind == TOP_LEVEL) {
|
||||
PackageElement pkg = elementUtils.getPackageOf(e);
|
||||
if (!pkg.isUnnamed())
|
||||
writer.print("package " + pkg.getQualifiedName() + ";\n");
|
||||
}
|
||||
|
||||
defaultAction(e, true);
|
||||
|
||||
switch(kind) {
|
||||
case ANNOTATION_TYPE:
|
||||
writer.print("@interface");
|
||||
break;
|
||||
default:
|
||||
writer.print(StringUtils.toLowerCase(kind.toString()));
|
||||
}
|
||||
writer.print(" ");
|
||||
writer.print(e.getSimpleName());
|
||||
|
||||
printFormalTypeParameters(e, false);
|
||||
|
||||
// Print superclass information if informative
|
||||
if (kind == CLASS) {
|
||||
TypeMirror supertype = e.getSuperclass();
|
||||
if (supertype.getKind() != TypeKind.NONE) {
|
||||
TypeElement e2 = (TypeElement)
|
||||
((DeclaredType) supertype).asElement();
|
||||
if (e2.getSuperclass().getKind() != TypeKind.NONE)
|
||||
writer.print(" extends " + supertype);
|
||||
}
|
||||
}
|
||||
|
||||
printInterfaces(e);
|
||||
}
|
||||
writer.println(" {");
|
||||
indentation++;
|
||||
|
||||
if (kind == ENUM) {
|
||||
List<Element> enclosedElements =
|
||||
new ArrayList<Element>(e.getEnclosedElements());
|
||||
// Handle any enum constants specially before other entities.
|
||||
List<Element> enumConstants = new ArrayList<Element>();
|
||||
for(Element element : enclosedElements) {
|
||||
if (element.getKind() == ENUM_CONSTANT)
|
||||
enumConstants.add(element);
|
||||
}
|
||||
if (!enumConstants.isEmpty()) {
|
||||
int i;
|
||||
for(i = 0; i < enumConstants.size()-1; i++) {
|
||||
this.visit(enumConstants.get(i), true);
|
||||
writer.print(",");
|
||||
}
|
||||
this.visit(enumConstants.get(i), true);
|
||||
writer.println(";\n");
|
||||
|
||||
enclosedElements.removeAll(enumConstants);
|
||||
}
|
||||
|
||||
for(Element element : enclosedElements)
|
||||
this.visit(element);
|
||||
} else {
|
||||
for(Element element : e.getEnclosedElements())
|
||||
this.visit(element);
|
||||
}
|
||||
|
||||
indentation--;
|
||||
indent();
|
||||
writer.println("}");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintingElementVisitor visitVariable(VariableElement e, Boolean newLine) {
|
||||
ElementKind kind = e.getKind();
|
||||
defaultAction(e, newLine);
|
||||
|
||||
if (kind == ENUM_CONSTANT)
|
||||
writer.print(e.getSimpleName());
|
||||
else {
|
||||
writer.print(e.asType().toString() + " " + e.getSimpleName() );
|
||||
Object constantValue = e.getConstantValue();
|
||||
if (constantValue != null) {
|
||||
writer.print(" = ");
|
||||
writer.print(elementUtils.getConstantExpression(constantValue));
|
||||
}
|
||||
writer.println(";");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintingElementVisitor visitTypeParameter(TypeParameterElement e, Boolean p) {
|
||||
writer.print(e.getSimpleName());
|
||||
return this;
|
||||
}
|
||||
|
||||
// Should we do more here?
|
||||
@Override
|
||||
public PrintingElementVisitor visitPackage(PackageElement e, Boolean p) {
|
||||
defaultAction(e, false);
|
||||
if (!e.isUnnamed())
|
||||
writer.println("package " + e.getQualifiedName() + ";");
|
||||
else
|
||||
writer.println("// Unnamed package");
|
||||
return this;
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
private void printDocComment(Element e) {
|
||||
String docComment = elementUtils.getDocComment(e);
|
||||
|
||||
if (docComment != null) {
|
||||
// Break comment into lines
|
||||
java.util.StringTokenizer st = new StringTokenizer(docComment,
|
||||
"\n\r");
|
||||
indent();
|
||||
writer.println("/**");
|
||||
|
||||
while(st.hasMoreTokens()) {
|
||||
indent();
|
||||
writer.print(" *");
|
||||
writer.println(st.nextToken());
|
||||
}
|
||||
|
||||
indent();
|
||||
writer.println(" */");
|
||||
}
|
||||
}
|
||||
|
||||
private void printModifiers(Element e) {
|
||||
ElementKind kind = e.getKind();
|
||||
if (kind == PARAMETER) {
|
||||
printAnnotationsInline(e);
|
||||
} else {
|
||||
printAnnotations(e);
|
||||
indent();
|
||||
}
|
||||
|
||||
if (kind == ENUM_CONSTANT)
|
||||
return;
|
||||
|
||||
Set<Modifier> modifiers = new LinkedHashSet<Modifier>();
|
||||
modifiers.addAll(e.getModifiers());
|
||||
|
||||
switch (kind) {
|
||||
case ANNOTATION_TYPE:
|
||||
case INTERFACE:
|
||||
modifiers.remove(Modifier.ABSTRACT);
|
||||
break;
|
||||
|
||||
case ENUM:
|
||||
modifiers.remove(Modifier.FINAL);
|
||||
modifiers.remove(Modifier.ABSTRACT);
|
||||
break;
|
||||
|
||||
case METHOD:
|
||||
case FIELD:
|
||||
Element enclosingElement = e.getEnclosingElement();
|
||||
if (enclosingElement != null &&
|
||||
enclosingElement.getKind().isInterface()) {
|
||||
modifiers.remove(Modifier.PUBLIC);
|
||||
modifiers.remove(Modifier.ABSTRACT); // only for methods
|
||||
modifiers.remove(Modifier.STATIC); // only for fields
|
||||
modifiers.remove(Modifier.FINAL); // only for fields
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
for(Modifier m: modifiers) {
|
||||
writer.print(m.toString() + " ");
|
||||
}
|
||||
}
|
||||
|
||||
private void printFormalTypeParameters(Parameterizable e,
|
||||
boolean pad) {
|
||||
List<? extends TypeParameterElement> typeParams = e.getTypeParameters();
|
||||
if (typeParams.size() > 0) {
|
||||
writer.print("<");
|
||||
|
||||
boolean first = true;
|
||||
for(TypeParameterElement tpe: typeParams) {
|
||||
if (!first)
|
||||
writer.print(", ");
|
||||
printAnnotationsInline(tpe);
|
||||
writer.print(tpe.toString());
|
||||
first = false;
|
||||
}
|
||||
|
||||
writer.print(">");
|
||||
if (pad)
|
||||
writer.print(" ");
|
||||
}
|
||||
}
|
||||
|
||||
private void printAnnotationsInline(Element e) {
|
||||
List<? extends AnnotationMirror> annots = e.getAnnotationMirrors();
|
||||
for(AnnotationMirror annotationMirror : annots) {
|
||||
writer.print(annotationMirror);
|
||||
writer.print(" ");
|
||||
}
|
||||
}
|
||||
|
||||
private void printAnnotations(Element e) {
|
||||
List<? extends AnnotationMirror> annots = e.getAnnotationMirrors();
|
||||
for(AnnotationMirror annotationMirror : annots) {
|
||||
indent();
|
||||
writer.println(annotationMirror);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Refactor
|
||||
private void printParameters(ExecutableElement e) {
|
||||
List<? extends VariableElement> parameters = e.getParameters();
|
||||
int size = parameters.size();
|
||||
|
||||
switch (size) {
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case 1:
|
||||
for(VariableElement parameter: parameters) {
|
||||
printModifiers(parameter);
|
||||
|
||||
if (e.isVarArgs() ) {
|
||||
TypeMirror tm = parameter.asType();
|
||||
if (tm.getKind() != TypeKind.ARRAY)
|
||||
throw new AssertionError("Var-args parameter is not an array type: " + tm);
|
||||
writer.print((ArrayType.class.cast(tm)).getComponentType() );
|
||||
writer.print("...");
|
||||
} else
|
||||
writer.print(parameter.asType());
|
||||
writer.print(" " + parameter.getSimpleName());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
int i = 1;
|
||||
for(VariableElement parameter: parameters) {
|
||||
if (i == 2)
|
||||
indentation++;
|
||||
|
||||
if (i > 1)
|
||||
indent();
|
||||
|
||||
printModifiers(parameter);
|
||||
|
||||
if (i == size && e.isVarArgs() ) {
|
||||
TypeMirror tm = parameter.asType();
|
||||
if (tm.getKind() != TypeKind.ARRAY)
|
||||
throw new AssertionError("Var-args parameter is not an array type: " + tm);
|
||||
writer.print((ArrayType.class.cast(tm)).getComponentType() );
|
||||
|
||||
writer.print("...");
|
||||
} else
|
||||
writer.print(parameter.asType());
|
||||
writer.print(" " + parameter.getSimpleName());
|
||||
|
||||
if (i < size)
|
||||
writer.println(",");
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (parameters.size() >= 2)
|
||||
indentation--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void printInterfaces(TypeElement e) {
|
||||
ElementKind kind = e.getKind();
|
||||
|
||||
if(kind != ANNOTATION_TYPE) {
|
||||
List<? extends TypeMirror> interfaces = e.getInterfaces();
|
||||
if (interfaces.size() > 0) {
|
||||
writer.print((kind.isClass() ? " implements" : " extends"));
|
||||
|
||||
boolean first = true;
|
||||
for(TypeMirror interf: interfaces) {
|
||||
if (!first)
|
||||
writer.print(",");
|
||||
writer.print(" ");
|
||||
writer.print(interf.toString());
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void printThrows(ExecutableElement e) {
|
||||
List<? extends TypeMirror> thrownTypes = e.getThrownTypes();
|
||||
final int size = thrownTypes.size();
|
||||
if (size != 0) {
|
||||
writer.print(" throws");
|
||||
|
||||
int i = 1;
|
||||
for(TypeMirror thrownType: thrownTypes) {
|
||||
if (i == 1)
|
||||
writer.print(" ");
|
||||
|
||||
if (i == 2)
|
||||
indentation++;
|
||||
|
||||
if (i >= 2)
|
||||
indent();
|
||||
|
||||
writer.print(thrownType);
|
||||
|
||||
if (i != size)
|
||||
writer.println(", ");
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (size >= 2)
|
||||
indentation--;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String [] spaces = {
|
||||
"",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" "
|
||||
};
|
||||
|
||||
private void indent() {
|
||||
int indentation = this.indentation;
|
||||
if (indentation < 0)
|
||||
return;
|
||||
final int maxIndex = spaces.length - 1;
|
||||
|
||||
while (indentation > maxIndex) {
|
||||
writer.print(spaces[maxIndex]);
|
||||
indentation -= maxIndex;
|
||||
}
|
||||
writer.print(spaces[indentation]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
149
jdkSrc/jdk8/com/sun/tools/javac/processing/ServiceProxy.java
Normal file
149
jdkSrc/jdk8/com/sun/tools/javac/processing/ServiceProxy.java
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.tools.javac.processing;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Utility class to determine if a service can be found on the
|
||||
* path that might be used to create a class loader.
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*
|
||||
*/
|
||||
// based on sun.misc.Service
|
||||
class ServiceProxy {
|
||||
static class ServiceConfigurationError extends Error {
|
||||
static final long serialVersionUID = 7732091036771098303L;
|
||||
|
||||
ServiceConfigurationError(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private static final String prefix = "META-INF/services/";
|
||||
|
||||
private static void fail(Class<?> service, String msg)
|
||||
throws ServiceConfigurationError {
|
||||
throw new ServiceConfigurationError(service.getName() + ": " + msg);
|
||||
}
|
||||
|
||||
private static void fail(Class<?> service, URL u, int line, String msg)
|
||||
throws ServiceConfigurationError {
|
||||
fail(service, u + ":" + line + ": " + msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the content of the given URL as a provider-configuration file.
|
||||
*
|
||||
* @param service
|
||||
* The service class for which providers are being sought;
|
||||
* used to construct error detail strings
|
||||
*
|
||||
* @param u
|
||||
* The URL naming the configuration file to be parsed
|
||||
*
|
||||
* @return true if the name of a service is found
|
||||
*
|
||||
* @throws ServiceConfigurationError
|
||||
* If an I/O error occurs while reading from the given URL, or
|
||||
* if a configuration-file format error is detected
|
||||
*/
|
||||
private static boolean parse(Class<?> service, URL u) throws ServiceConfigurationError {
|
||||
InputStream in = null;
|
||||
BufferedReader r = null;
|
||||
try {
|
||||
in = u.openStream();
|
||||
r = new BufferedReader(new InputStreamReader(in, "utf-8"));
|
||||
int lc = 1;
|
||||
String ln;
|
||||
while ((ln = r.readLine()) != null) {
|
||||
int ci = ln.indexOf('#');
|
||||
if (ci >= 0) ln = ln.substring(0, ci);
|
||||
ln = ln.trim();
|
||||
int n = ln.length();
|
||||
if (n != 0) {
|
||||
if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
|
||||
fail(service, u, lc, "Illegal configuration-file syntax");
|
||||
int cp = ln.codePointAt(0);
|
||||
if (!Character.isJavaIdentifierStart(cp))
|
||||
fail(service, u, lc, "Illegal provider-class name: " + ln);
|
||||
for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
|
||||
cp = ln.codePointAt(i);
|
||||
if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
|
||||
fail(service, u, lc, "Illegal provider-class name: " + ln);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException x) {
|
||||
return false;
|
||||
} catch (IOException x) {
|
||||
fail(service, ": " + x);
|
||||
} finally {
|
||||
try {
|
||||
if (r != null) r.close();
|
||||
} catch (IOException y) {
|
||||
fail(service, ": " + y);
|
||||
}
|
||||
try {
|
||||
if (in != null) in.close();
|
||||
} catch (IOException y) {
|
||||
fail(service, ": " + y);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if a description for at least one service is found in the
|
||||
* service configuration files in the given URLs.
|
||||
*/
|
||||
public static boolean hasService(Class<?> service, URL[] urls)
|
||||
throws ServiceConfigurationError {
|
||||
for (URL url: urls) {
|
||||
try {
|
||||
String fullName = prefix + service.getName();
|
||||
URL u = new URL(url, fullName);
|
||||
boolean found = parse(service, u);
|
||||
if (found)
|
||||
return true;
|
||||
} catch (MalformedURLException e) {
|
||||
// should not happen; ignore it if it does
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user