mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8173636: Results from Processor.getSupportedAnnotationTypes should be intepreted strictly
Co-authored-by: Joe Darcy <joe.darcy@oracle.com> Reviewed-by: darcy, jjg
This commit is contained in:
parent
d6090047be
commit
eb5ba01b02
4 changed files with 114 additions and 28 deletions
|
@ -83,7 +83,7 @@ public abstract class AbstractProcessor implements Processor {
|
|||
if (so == null)
|
||||
return Collections.emptySet();
|
||||
else
|
||||
return arrayToSet(so.value());
|
||||
return arrayToSet(so.value(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -92,21 +92,31 @@ public abstract class AbstractProcessor implements Processor {
|
|||
* same set of strings as the annotation. If the class is not so
|
||||
* annotated, an empty set is returned.
|
||||
*
|
||||
* If the {@link ProcessingEvironment#getSourceVersion source
|
||||
* version} does not support modules, in other words if it is less
|
||||
* than or equal to {@link SourceVersion#RELEASE_8 RELEASE_8},
|
||||
* then any leading {@link Processor#getSupportedAnnotationTypes
|
||||
* module prefixes} are stripped from the names.
|
||||
*
|
||||
* @return the names of the annotation types supported by this
|
||||
* processor, or an empty set if none
|
||||
*/
|
||||
public Set<String> getSupportedAnnotationTypes() {
|
||||
SupportedAnnotationTypes sat = this.getClass().getAnnotation(SupportedAnnotationTypes.class);
|
||||
boolean initialized = isInitialized();
|
||||
if (sat == null) {
|
||||
if (isInitialized())
|
||||
if (initialized)
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,
|
||||
"No SupportedAnnotationTypes annotation " +
|
||||
"found on " + this.getClass().getName() +
|
||||
", returning an empty set.");
|
||||
return Collections.emptySet();
|
||||
} else {
|
||||
boolean stripModulePrefixes =
|
||||
initialized &&
|
||||
processingEnv.getSourceVersion().compareTo(SourceVersion.RELEASE_8) <= 0;
|
||||
return arrayToSet(sat.value(), stripModulePrefixes);
|
||||
}
|
||||
else
|
||||
return arrayToSet(sat.value());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -185,11 +195,18 @@ public abstract class AbstractProcessor implements Processor {
|
|||
return initialized;
|
||||
}
|
||||
|
||||
private static Set<String> arrayToSet(String[] array) {
|
||||
private static Set<String> arrayToSet(String[] array,
|
||||
boolean stripModulePrefixes) {
|
||||
assert array != null;
|
||||
Set<String> set = new HashSet<>(array.length);
|
||||
for (String s : array)
|
||||
for (String s : array) {
|
||||
if (stripModulePrefixes) {
|
||||
int index = s.indexOf('/');
|
||||
if (index != -1)
|
||||
s = s.substring(index + 1);
|
||||
}
|
||||
set.add(s);
|
||||
}
|
||||
return Collections.unmodifiableSet(set);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -254,6 +254,14 @@ public interface Processor {
|
|||
* a.B} which reside in different modules. To only support {@code
|
||||
* a.B} in the {@code Foo} module, instead use {@code "Foo/a.B"}.
|
||||
*
|
||||
* If a module name is included, only an annotation in that module
|
||||
* is matched. In particular, if a module name is given in an
|
||||
* environment where modules are not supported, such as an
|
||||
* annotation processing environment configured for a {@linkplain
|
||||
* javax.annotation.processing.ProcessingEnvironment#getSourceVersion
|
||||
* source version} without modules, then the annotation types with
|
||||
* a module name do <em>not</em> match.
|
||||
*
|
||||
* 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
|
||||
|
@ -280,6 +288,14 @@ public interface Processor {
|
|||
* where <i>TypeName</i> is as defined in
|
||||
* <cite>The Java™ Language Specification</cite>.
|
||||
*
|
||||
* @apiNote When running in an environment which supports modules,
|
||||
* processors are encouraged to include the module prefix when
|
||||
* describing their supported annotation types. The method {@link
|
||||
* AbstractProcessor.getSupportedAnnotationTypes
|
||||
* AbstractProcessor.getSupportedAnnotationTypes} provides support
|
||||
* for stripping off the module prefix when running in an
|
||||
* environment without modules.
|
||||
*
|
||||
* @return the names of the annotation types supported by this processor
|
||||
* @see javax.annotation.processing.SupportedAnnotationTypes
|
||||
* @jls 3.8 Identifiers
|
||||
|
|
|
@ -1671,14 +1671,14 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
|||
if (s.equals("*")) {
|
||||
return MatchingUtils.validImportStringToPattern(s);
|
||||
}
|
||||
module = ".*/";
|
||||
module = allowModules ? ".*/" : "";
|
||||
pkg = s;
|
||||
} else {
|
||||
module = Pattern.quote(s.substring(0, slash + 1));
|
||||
pkg = s.substring(slash + 1);
|
||||
}
|
||||
if (MatchingUtils.isValidImportString(pkg)) {
|
||||
return Pattern.compile((allowModules ? module : "") + MatchingUtils.validImportStringToPatternString(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
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8133884 8162711 8133896 8172158 8172262
|
||||
* @bug 8133884 8162711 8133896 8172158 8172262 8173636
|
||||
* @summary Verify that annotation processing works.
|
||||
* @library /tools/lib
|
||||
* @modules
|
||||
|
@ -173,7 +173,7 @@ public class AnnotationProcessing extends ModuleTestBase {
|
|||
String[] module2Packages = moduleDef.split("=>");
|
||||
|
||||
module2ExpectedEnclosedElements.put(module2Packages[0],
|
||||
Arrays.asList(module2Packages[1].split(":")));
|
||||
List.of(module2Packages[1].split(":")));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -359,7 +359,7 @@ public class AnnotationProcessing extends ModuleTestBase {
|
|||
.writeAll()
|
||||
.getOutput(Task.OutputKind.DIRECT);
|
||||
|
||||
List<String> expected = Arrays.asList("Note: field: m1x");
|
||||
List<String> expected = List.of("Note: field: m1x");
|
||||
|
||||
for (Mode mode : new Mode[] {Mode.API, Mode.CMDLINE}) {
|
||||
List<String> log = new JavacTask(tb, mode)
|
||||
|
@ -424,7 +424,7 @@ public class AnnotationProcessing extends ModuleTestBase {
|
|||
.writeAll()
|
||||
.getOutputLines(Task.OutputKind.STDERR);
|
||||
|
||||
assertEquals(Arrays.asList("module: m1x"), log);
|
||||
assertEquals(List.of("module: m1x"), log);
|
||||
}
|
||||
|
||||
@SupportedAnnotationTypes("*")
|
||||
|
@ -472,8 +472,8 @@ public class AnnotationProcessing extends ModuleTestBase {
|
|||
.writeAll()
|
||||
.getOutputLines(Task.OutputKind.DIRECT);
|
||||
|
||||
List<String> expectedLog = Arrays.asList("Note: AP Invoked",
|
||||
"Note: AP Invoked");
|
||||
List<String> expectedLog = List.of("Note: AP Invoked",
|
||||
"Note: AP Invoked");
|
||||
|
||||
assertEquals(expectedLog, log);
|
||||
|
||||
|
@ -600,7 +600,7 @@ public class AnnotationProcessing extends ModuleTestBase {
|
|||
|
||||
JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
|
||||
try (StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null)) {
|
||||
List<String> options = Arrays.asList("-d", scratchClasses.toString());
|
||||
List<String> options = List.of("-d", scratchClasses.toString());
|
||||
Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(scratchSrc);
|
||||
CompilationTask task = comp.getTask(null, fm, null, options, null, files);
|
||||
|
||||
|
@ -939,7 +939,7 @@ public class AnnotationProcessing extends ModuleTestBase {
|
|||
.writeAll()
|
||||
.getOutputLines(OutputKind.STDERR);
|
||||
|
||||
expected = Arrays.asList("");
|
||||
expected = List.of("");
|
||||
|
||||
if (!expected.equals(log)) {
|
||||
throw new AssertionError("Output does not match; output: " + log);
|
||||
|
@ -954,15 +954,17 @@ public class AnnotationProcessing extends ModuleTestBase {
|
|||
.writeAll()
|
||||
.getOutputLines(OutputKind.STDERR);
|
||||
|
||||
expected = Arrays.asList("SelectAnnotationBTestAP",
|
||||
"SelectAnnotationBTestAP");
|
||||
expected = List.of("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(),
|
||||
.options("-processor", SelectAnnotationATestAP.class.getName() + "," +
|
||||
SelectAnnotationBTestAP.class.getName() + "," +
|
||||
SelectAnnotationAStrictTestAP.class.getName(),
|
||||
"--module-source-path", src.toString(),
|
||||
"-m", "m4x")
|
||||
.outdir(classes)
|
||||
|
@ -970,10 +972,43 @@ public class AnnotationProcessing extends ModuleTestBase {
|
|||
.writeAll()
|
||||
.getOutputLines(OutputKind.STDERR);
|
||||
|
||||
expected = Arrays.asList("SelectAnnotationATestAP",
|
||||
"SelectAnnotationBTestAP",
|
||||
"SelectAnnotationATestAP",
|
||||
"SelectAnnotationBTestAP");
|
||||
expected = List.of("SelectAnnotationATestAP",
|
||||
"SelectAnnotationBTestAP",
|
||||
"SelectAnnotationAStrictTestAP",
|
||||
"SelectAnnotationATestAP",
|
||||
"SelectAnnotationBTestAP",
|
||||
"SelectAnnotationAStrictTestAP");
|
||||
|
||||
if (!expected.equals(log)) {
|
||||
throw new AssertionError("Output does not match; output: " + log);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisambiguateAnnotationsUnnamedModule(Path base) throws Exception {
|
||||
Path classes = base.resolve("classes");
|
||||
|
||||
Files.createDirectories(classes);
|
||||
|
||||
Path src = base.resolve("src");
|
||||
|
||||
tb.writeJavaFiles(src,
|
||||
"package api; public @interface A {}",
|
||||
"package api; public @interface B {}",
|
||||
"package impl; import api.*; @A @B public class T {}");
|
||||
|
||||
List<String> log = new JavacTask(tb)
|
||||
.options("-processor", SelectAnnotationATestAP.class.getName() + "," +
|
||||
SelectAnnotationBTestAP.class.getName() + "," +
|
||||
SelectAnnotationAStrictTestAP.class.getName())
|
||||
.outdir(classes)
|
||||
.files(findJavaFiles(src))
|
||||
.run()
|
||||
.writeAll()
|
||||
.getOutputLines(OutputKind.STDERR);
|
||||
|
||||
List<String> expected = List.of("SelectAnnotationBTestAP",
|
||||
"SelectAnnotationBTestAP");
|
||||
|
||||
if (!expected.equals(log)) {
|
||||
throw new AssertionError("Output does not match; output: " + log);
|
||||
|
@ -994,7 +1029,9 @@ public class AnnotationProcessing extends ModuleTestBase {
|
|||
"package impl; import api.*; @A @B public class T {}");
|
||||
|
||||
List<String> log = new JavacTask(tb)
|
||||
.options("-processor", SelectAnnotationATestAP.class.getName() + "," + SelectAnnotationBTestAP.class.getName(),
|
||||
.options("-processor", SelectAnnotationATestAP.class.getName() + "," +
|
||||
SelectAnnotationBTestAP.class.getName() + "," +
|
||||
SelectAnnotationAStrictTestAP.class.getName(),
|
||||
"-source", "8", "-target", "8")
|
||||
.outdir(classes)
|
||||
.files(findJavaFiles(src))
|
||||
|
@ -1002,10 +1039,10 @@ public class AnnotationProcessing extends ModuleTestBase {
|
|||
.writeAll()
|
||||
.getOutputLines(OutputKind.STDERR);
|
||||
|
||||
List<String> expected = Arrays.asList("SelectAnnotationATestAP",
|
||||
"SelectAnnotationBTestAP",
|
||||
"SelectAnnotationATestAP",
|
||||
"SelectAnnotationBTestAP");
|
||||
List<String> expected = List.of("SelectAnnotationATestAP",
|
||||
"SelectAnnotationBTestAP",
|
||||
"SelectAnnotationATestAP",
|
||||
"SelectAnnotationBTestAP");
|
||||
|
||||
if (!expected.equals(log)) {
|
||||
throw new AssertionError("Output does not match; output: " + log);
|
||||
|
@ -1036,6 +1073,22 @@ public class AnnotationProcessing extends ModuleTestBase {
|
|||
|
||||
}
|
||||
|
||||
public static final class SelectAnnotationAStrictTestAP extends AbstractProcessor {
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
System.err.println("SelectAnnotationAStrictTestAP");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedAnnotationTypes() {
|
||||
return Set.of("m2x/api.A");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void writeFile(String content, Path base, String... pathElements) throws IOException {
|
||||
Path file = resolveFile(base, pathElements);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue