37 import java.nio.file.Paths;
38 import java.util.List;
39 import java.util.Set;
40
41 import javax.annotation.processing.AbstractProcessor;
42 import javax.annotation.processing.RoundEnvironment;
43 import javax.annotation.processing.SupportedAnnotationTypes;
44 import javax.lang.model.SourceVersion;
45 import javax.lang.model.element.TypeElement;
46 import javax.tools.JavaCompiler;
47 import javax.tools.JavaFileObject;
48 import javax.tools.StandardJavaFileManager;
49 import javax.tools.ToolProvider;
50
51 import java.io.IOException;
52 import java.io.OutputStream;
53 import java.net.URI;
54 import java.util.ArrayList;
55 import java.util.Base64;
56 import java.util.Iterator;
57 import javax.annotation.processing.Filer;
58 import javax.annotation.processing.SupportedOptions;
59 import javax.lang.model.element.Element;
60 import javax.lang.model.element.ModuleElement;
61 import javax.lang.model.element.PackageElement;
62 import javax.lang.model.util.Elements;
63 import javax.tools.FileObject;
64 import javax.tools.ForwardingJavaFileManager;
65 import javax.tools.JavaFileManager;
66 import javax.tools.SimpleJavaFileObject;
67 import javax.tools.StandardLocation;
68 import toolbox.JavacTask;
69 import toolbox.TestRunner;
70 import toolbox.TestRunner.Test;
71 import toolbox.ToolBox;
72 import toolbox.ToolBox.MemoryFileManager;
73
74 public class TestOriginatingElements extends TestRunner {
75
76 public static void main(String... args) throws Exception {
77 new TestOriginatingElements().runTests(m -> new Object[] { Paths.get(m.getName()) });
78 }
79
80 private static final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
81 private final ToolBox tb = new ToolBox();
82
83 public TestOriginatingElements() {
84 super(System.err);
85 }
86
87 @Test
88 public void testOriginatingElements(Path outerBase) throws Exception {
89 Path libSrc = outerBase.resolve("lib-src");
90 tb.writeJavaFiles(libSrc,
117 module m {}
118 """,
119 """
120 package t;
121 public class T1 {
122 }
123 """,
124 """
125 package t;
126 public class T2 {
127 }
128 """,
129 """
130 package t;
131 public class T3 {
132 }
133 """);
134 tb.writeFile(src.resolve("p/package-info.java"), "package p;");
135 Path classes = outerBase.resolve("classes");
136 Files.createDirectories(classes);
137 try (StandardJavaFileManager sjfm = compiler.getStandardFileManager(null, null, null)) {
138 List<String> testOutput = new ArrayList<>();
139 JavaFileManager fm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
140 @Override
141 public JavaFileObject getJavaFileForOutputForOriginatingFiles(Location location,
142 String className,
143 JavaFileObject.Kind kind,
144 FileObject... originatingFiles) throws IOException {
145 List.of(originatingFiles)
146 .stream()
147 .map(fo -> getInfo(fo))
148 .forEach(testOutput::add);
149 return super.getJavaFileForOutputForOriginatingFiles(location, className, kind, originatingFiles);
150 }
151 @Override
152 public FileObject getFileForOutputForOriginatingFiles(Location location,
153 String packageName,
154 String relativeName,
155 FileObject... originatingFiles) throws IOException {
156 List.of(originatingFiles)
157 .stream()
158 .map(fo -> getInfo(fo))
159 .forEach(testOutput::add);
160 return super.getFileForOutputForOriginatingFiles(location, packageName, relativeName, originatingFiles);
161 }
162 private String getInfo(FileObject fo) {
163 try {
164 JavaFileObject jfo = (JavaFileObject) fo; //the test only expects JavaFileObjects here:
165 JavaFileManager.Location location = jfo.getKind() == JavaFileObject.Kind.SOURCE
166 ? StandardLocation.SOURCE_PATH
167 : sjfm.getLocationForModule(StandardLocation.SYSTEM_MODULES, "java.base");
168 String binaryName = inferBinaryName(location, jfo);
169 return binaryName + "(" + jfo.getKind() + ")";
170 } catch (IOException ex) {
171 throw new AssertionError(ex);
172 }
173 }
174 };
175 try {
176 String generatedData;
177 try (MemoryFileManager mfm = new MemoryFileManager(sjfm)) {
178 compiler.getTask(null, mfm, null, null, null,
179 List.of(new ToolBox.JavaSource("package test; public class Generated2 {}")))
180 .call();
181 generatedData =
182 Base64.getEncoder().encodeToString(mfm.getFileBytes(StandardLocation.CLASS_OUTPUT, "test.Generated2"));
183 }
184 List<String> options = List.of("-sourcepath", src.toString(),
185 "-processor", "TestOriginatingElements$P",
186 "-processorpath", System.getProperty("test.class.path"),
187 "--module-path", libClasses.toString(),
188 "--add-modules", "lib",
189 "-d", classes.toString(),
190 "-AgeneratedData=" + generatedData);
191 ToolProvider.getSystemJavaCompiler()
192 .getTask(null, fm, null, options, null, sjfm.getJavaFileObjects(tb.findJavaFiles(src)))
193 .call();
194 List<String> expectedOriginatingFiles = List.of("t.T1(SOURCE)",
195 "java.lang.String(CLASS)",
196 "p.package-info(SOURCE)",
197 "lib1.package-info(CLASS)",
198 "module-info(SOURCE)",
199 "module-info(CLASS)",
200 "t.T2(SOURCE)",
201 "java.lang.CharSequence(CLASS)",
202 "p.package-info(SOURCE)",
203 "lib1.package-info(CLASS)",
204 "module-info(SOURCE)",
205 "module-info(CLASS)",
206 "t.T3(SOURCE)",
207 "java.lang.Exception(CLASS)",
208 "p.package-info(SOURCE)",
209 "lib1.package-info(CLASS)",
210 "module-info(SOURCE)",
211 "module-info(CLASS)");
212 assertEquals(expectedOriginatingFiles, testOutput);
213 } catch (IOException ex) {
214 throw new IllegalStateException(ex);
215 }
216 }
217 }
218
219 @SupportedAnnotationTypes("*")
220 @SupportedOptions("generatedData")
221 public static class P extends AbstractProcessor {
222 int round;
223 @Override
224 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
225 if (round++ == 0) {
226 Elements elems = processingEnv.getElementUtils();
227 ModuleElement mdl = elems.getModuleElement("m");
228 ModuleElement java_base = elems.getModuleElement("java.base");
229 PackageElement pack = elems.getPackageElement("p");
230 PackageElement lib1Pack = elems.getPackageElement("lib1");
231 PackageElement lib2Pack = elems.getPackageElement("lib2");
232 Filer filer = processingEnv.getFiler();
233 try {
234 filer.createSourceFile("test.Generated1",
235 element("t.T1"),
236 element("java.lang.String"),
|
37 import java.nio.file.Paths;
38 import java.util.List;
39 import java.util.Set;
40
41 import javax.annotation.processing.AbstractProcessor;
42 import javax.annotation.processing.RoundEnvironment;
43 import javax.annotation.processing.SupportedAnnotationTypes;
44 import javax.lang.model.SourceVersion;
45 import javax.lang.model.element.TypeElement;
46 import javax.tools.JavaCompiler;
47 import javax.tools.JavaFileObject;
48 import javax.tools.StandardJavaFileManager;
49 import javax.tools.ToolProvider;
50
51 import java.io.IOException;
52 import java.io.OutputStream;
53 import java.net.URI;
54 import java.util.ArrayList;
55 import java.util.Base64;
56 import java.util.Iterator;
57 import java.util.stream.Stream;
58 import javax.annotation.processing.Filer;
59 import javax.annotation.processing.SupportedOptions;
60 import javax.lang.model.element.Element;
61 import javax.lang.model.element.ModuleElement;
62 import javax.lang.model.element.PackageElement;
63 import javax.lang.model.util.Elements;
64 import javax.tools.FileObject;
65 import javax.tools.ForwardingJavaFileManager;
66 import javax.tools.JavaFileManager;
67 import javax.tools.SimpleJavaFileObject;
68 import javax.tools.StandardLocation;
69 import toolbox.JavacTask;
70 import toolbox.TestRunner;
71 import toolbox.ToolBox;
72 import toolbox.ToolBox.MemoryFileManager;
73
74 public class TestOriginatingElements extends TestRunner {
75
76 public static void main(String... args) throws Exception {
77 new TestOriginatingElements().runTests(m -> new Object[] { Paths.get(m.getName()) });
78 }
79
80 private static final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
81 private final ToolBox tb = new ToolBox();
82
83 public TestOriginatingElements() {
84 super(System.err);
85 }
86
87 @Test
88 public void testOriginatingElements(Path outerBase) throws Exception {
89 Path libSrc = outerBase.resolve("lib-src");
90 tb.writeJavaFiles(libSrc,
117 module m {}
118 """,
119 """
120 package t;
121 public class T1 {
122 }
123 """,
124 """
125 package t;
126 public class T2 {
127 }
128 """,
129 """
130 package t;
131 public class T3 {
132 }
133 """);
134 tb.writeFile(src.resolve("p/package-info.java"), "package p;");
135 Path classes = outerBase.resolve("classes");
136 Files.createDirectories(classes);
137 List<String> testOutput = new ArrayList<>();
138 try (StandardJavaFileManager sjfm = compiler.getStandardFileManager(null, null, null);
139 JavaFileManager fm = capturingFileManager(sjfm, testOutput)) {
140 String generatedData;
141 try (MemoryFileManager mfm = new MemoryFileManager(sjfm, /* shouldClose */ false)) {
142 compiler.getTask(null, mfm, null, null, null,
143 List.of(new ToolBox.JavaSource("package test; public class Generated2 {}")))
144 .call();
145 generatedData =
146 Base64.getEncoder().encodeToString(mfm.getFileBytes(StandardLocation.CLASS_OUTPUT, "test.Generated2"));
147 }
148 List<String> options = List.of("-sourcepath", src.toString(),
149 "-processor", "TestOriginatingElements$P",
150 "-processorpath", System.getProperty("test.class.path"),
151 "--module-path", libClasses.toString(),
152 "--add-modules", "lib",
153 "-d", classes.toString(),
154 "-AgeneratedData=" + generatedData);
155 ToolProvider.getSystemJavaCompiler()
156 .getTask(null, fm, null, options, null, sjfm.getJavaFileObjects(tb.findJavaFiles(src)))
157 .call();
158 } catch (IOException ex) {
159 throw new IllegalStateException(ex);
160 }
161 List<String> expectedOriginatingFiles = List.of("t.T1(SOURCE)",
162 "java.lang.String(CLASS)",
163 "p.package-info(SOURCE)",
164 "lib1.package-info(CLASS)",
165 "module-info(SOURCE)",
166 "module-info(CLASS)",
167 "t.T2(SOURCE)",
168 "java.lang.CharSequence(CLASS)",
169 "p.package-info(SOURCE)",
170 "lib1.package-info(CLASS)",
171 "module-info(SOURCE)",
172 "module-info(CLASS)",
173 "t.T3(SOURCE)",
174 "java.lang.Exception(CLASS)",
175 "p.package-info(SOURCE)",
176 "lib1.package-info(CLASS)",
177 "module-info(SOURCE)",
178 "module-info(CLASS)");
179 assertEquals(expectedOriginatingFiles, testOutput);
180 }
181
182 static JavaFileManager capturingFileManager(JavaFileManager sjfm, List<String> testOutput) {
183 return new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
184 @Override
185 public JavaFileObject getJavaFileForOutputForOriginatingFiles(Location location,
186 String className,
187 JavaFileObject.Kind kind,
188 FileObject... originatingFiles) throws IOException {
189 Stream.of(originatingFiles)
190 .map(this::getInfo)
191 .forEach(testOutput::add);
192 return super.getJavaFileForOutputForOriginatingFiles(location, className, kind, originatingFiles);
193 }
194
195 @Override
196 public FileObject getFileForOutputForOriginatingFiles(Location location,
197 String packageName,
198 String relativeName,
199 FileObject... originatingFiles) throws IOException {
200 Stream.of(originatingFiles)
201 .map(this::getInfo)
202 .forEach(testOutput::add);
203 return super.getFileForOutputForOriginatingFiles(location, packageName, relativeName, originatingFiles);
204 }
205
206 private String getInfo(FileObject fo) {
207 try {
208 JavaFileObject jfo = (JavaFileObject) fo; //the test only expects JavaFileObjects here:
209 JavaFileManager.Location location = jfo.getKind() == JavaFileObject.Kind.SOURCE
210 ? StandardLocation.SOURCE_PATH
211 : sjfm.getLocationForModule(StandardLocation.SYSTEM_MODULES, "java.base");
212 String binaryName = inferBinaryName(location, jfo);
213 return binaryName + "(" + jfo.getKind() + ")";
214 } catch (IOException ex) {
215 throw new AssertionError(ex);
216 }
217 }
218
219 @Override
220 public void close() {
221 // Don't close the delegate.
222 }
223 };
224 }
225
226 @SupportedAnnotationTypes("*")
227 @SupportedOptions("generatedData")
228 public static class P extends AbstractProcessor {
229 int round;
230 @Override
231 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
232 if (round++ == 0) {
233 Elements elems = processingEnv.getElementUtils();
234 ModuleElement mdl = elems.getModuleElement("m");
235 ModuleElement java_base = elems.getModuleElement("java.base");
236 PackageElement pack = elems.getPackageElement("p");
237 PackageElement lib1Pack = elems.getPackageElement("lib1");
238 PackageElement lib2Pack = elems.getPackageElement("lib2");
239 Filer filer = processingEnv.getFiler();
240 try {
241 filer.createSourceFile("test.Generated1",
242 element("t.T1"),
243 element("java.lang.String"),
|