|
1 /* |
|
2 * Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. |
|
8 * |
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 * version 2 for more details (a copy is included in the LICENSE file that |
|
13 * accompanied this code). |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License version |
|
16 * 2 along with this work; if not, write to the Free Software Foundation, |
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 * |
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
20 * or visit www.oracle.com if you need additional information or have any |
|
21 * questions. |
|
22 */ |
|
23 |
|
24 /* |
|
25 * @test |
|
26 * @bug 6437138 6482554 |
|
27 * @summary JSR 199: Compiler doesn't diagnose crash in user code |
|
28 * @library ../lib |
|
29 * @build JavacTestingAbstractProcessor TestClientCodeWrapper |
|
30 * @run main TestClientCodeWrapper |
|
31 */ |
|
32 |
|
33 import java.io.*; |
|
34 import java.lang.reflect.Method; |
|
35 import java.net.URI; |
|
36 import java.util.*; |
|
37 import javax.annotation.processing.*; |
|
38 import javax.lang.model.*; |
|
39 import javax.lang.model.element.*; |
|
40 import javax.tools.*; |
|
41 import com.sun.source.util.*; |
|
42 import com.sun.tools.javac.api.*; |
|
43 import javax.tools.JavaFileObject.Kind; |
|
44 |
|
45 public class TestClientCodeWrapper extends JavacTestingAbstractProcessor { |
|
46 public static void main(String... args) throws Exception { |
|
47 new TestClientCodeWrapper().run(); |
|
48 } |
|
49 |
|
50 /** |
|
51 * Run a series of compilations, each with a different user-provided object |
|
52 * configured to throw an exception when a specific method is invoked. |
|
53 * Then, verify the exception is thrown as expected. |
|
54 * |
|
55 * Some methods are not invoked from the compiler, and are excluded from the test. |
|
56 */ |
|
57 void run() throws Exception { |
|
58 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); |
|
59 defaultFileManager = compiler.getStandardFileManager(null, null, null); |
|
60 |
|
61 for (Method m: getMethodsExcept(JavaFileManager.class, "close", "getJavaFileForInput")) { |
|
62 test(m); |
|
63 } |
|
64 |
|
65 for (Method m: getMethodsExcept(FileObject.class, "delete")) { |
|
66 test(m); |
|
67 } |
|
68 |
|
69 for (Method m: getMethods(JavaFileObject.class)) { |
|
70 test(m); |
|
71 } |
|
72 |
|
73 for (Method m: getMethodsExcept(Processor.class, "getCompletions")) { |
|
74 test(m); |
|
75 } |
|
76 |
|
77 for (Method m: DiagnosticListener.class.getDeclaredMethods()) { |
|
78 test(m); |
|
79 } |
|
80 |
|
81 for (Method m: TaskListener.class.getDeclaredMethods()) { |
|
82 test(m); |
|
83 } |
|
84 |
|
85 if (errors > 0) |
|
86 throw new Exception(errors + " errors occurred"); |
|
87 } |
|
88 |
|
89 /** Get a sorted set of the methods declared on a class. */ |
|
90 Set<Method> getMethods(Class<?> clazz) { |
|
91 return getMethodsExcept(clazz, new String[0]); |
|
92 } |
|
93 |
|
94 /** Get a sorted set of the methods declared on a class, excluding |
|
95 * specified methods by name. */ |
|
96 Set<Method> getMethodsExcept(Class<?> clazz, String... exclude) { |
|
97 Set<Method> methods = new TreeSet<Method>(new Comparator<Method>() { |
|
98 public int compare(Method m1, Method m2) { |
|
99 return m1.toString().compareTo(m2.toString()); |
|
100 } |
|
101 }); |
|
102 Set<String> e = new HashSet<String>(Arrays.asList(exclude)); |
|
103 for (Method m: clazz.getDeclaredMethods()) { |
|
104 if (!e.contains(m.getName())) |
|
105 methods.add(m); |
|
106 } |
|
107 return methods; |
|
108 } |
|
109 |
|
110 /** |
|
111 * Test a method in a user supplied component, to verify javac's handling |
|
112 * of any exceptions thrown by that method. |
|
113 */ |
|
114 void test(Method m) throws Exception { |
|
115 testNum++; |
|
116 |
|
117 File extDirs = new File("empty-extdirs"); |
|
118 extDirs.mkdirs(); |
|
119 |
|
120 File testClasses = new File("test" + testNum); |
|
121 testClasses.mkdirs(); |
|
122 defaultFileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(testClasses)); |
|
123 |
|
124 System.err.println("test " + testNum + ": " |
|
125 + m.getDeclaringClass().getSimpleName() + "." + m.getName()); |
|
126 |
|
127 StringWriter sw = new StringWriter(); |
|
128 PrintWriter pw = new PrintWriter(sw); |
|
129 |
|
130 List<String> javacOptions = Arrays.asList( |
|
131 "-extdirs", extDirs.getPath(), // for use by filemanager handleOption |
|
132 "-processor", TestClientCodeWrapper.class.getName() |
|
133 ); |
|
134 |
|
135 List<String> classes = Collections.emptyList(); |
|
136 |
|
137 JavacTool tool = JavacTool.create(); |
|
138 try { |
|
139 JavacTask task = tool.getTask(pw, |
|
140 getFileManager(m, defaultFileManager), |
|
141 getDiagnosticListener(m, pw), |
|
142 javacOptions, |
|
143 classes, |
|
144 getCompilationUnits(m)); |
|
145 |
|
146 if (isDeclaredIn(m, Processor.class)) |
|
147 task.setProcessors(getProcessors(m)); |
|
148 |
|
149 if (isDeclaredIn(m, TaskListener.class)) |
|
150 task.setTaskListener(getTaskListener(m, pw)); |
|
151 |
|
152 boolean ok = task.call(); |
|
153 error("compilation " + (ok ? "succeeded" : "failed") + " unexpectedly"); |
|
154 } catch (RuntimeException e) { |
|
155 System.err.println("caught " + e); |
|
156 if (e.getClass() == RuntimeException.class) { |
|
157 Throwable cause = e.getCause(); |
|
158 if (cause instanceof UserError) { |
|
159 String expect = m.getName(); |
|
160 String found = cause.getMessage(); |
|
161 checkEqual("exception messaqe", expect, found); |
|
162 } else { |
|
163 cause.printStackTrace(System.err); |
|
164 error("Unexpected exception: " + cause); |
|
165 } |
|
166 } else { |
|
167 e.printStackTrace(System.err); |
|
168 error("Unexpected exception: " + e); |
|
169 } |
|
170 } |
|
171 |
|
172 pw.close(); |
|
173 String out = sw.toString(); |
|
174 System.err.println(out); |
|
175 } |
|
176 |
|
177 /** Get a file manager to use for the test compilation. */ |
|
178 JavaFileManager getFileManager(Method m, JavaFileManager defaultFileManager) { |
|
179 return isDeclaredIn(m, JavaFileManager.class, FileObject.class, JavaFileObject.class) |
|
180 ? new UserFileManager(m, defaultFileManager) |
|
181 : defaultFileManager; |
|
182 } |
|
183 |
|
184 /** Get a diagnostic listener to use for the test compilation. */ |
|
185 DiagnosticListener<JavaFileObject> getDiagnosticListener(Method m, PrintWriter out) { |
|
186 return isDeclaredIn(m, DiagnosticListener.class) |
|
187 ? new UserDiagnosticListener(m, out) |
|
188 : null; |
|
189 } |
|
190 |
|
191 /** Get a set of file objects to use for the test compilation. */ |
|
192 Iterable<? extends JavaFileObject> getCompilationUnits(Method m) { |
|
193 File testSrc = new File(System.getProperty("test.src")); |
|
194 File thisSrc = new File(testSrc, TestClientCodeWrapper.class.getName() + ".java"); |
|
195 Iterable<? extends JavaFileObject> files = defaultFileManager.getJavaFileObjects(thisSrc); |
|
196 if (isDeclaredIn(m, FileObject.class, JavaFileObject.class)) |
|
197 return Arrays.asList(new UserFileObject(m, files.iterator().next())); |
|
198 else |
|
199 return files; |
|
200 } |
|
201 |
|
202 /** Get a set of annotation processors to use for the test compilation. */ |
|
203 Iterable<? extends Processor> getProcessors(Method m) { |
|
204 return Arrays.asList(new UserProcessor(m)); |
|
205 } |
|
206 |
|
207 /** Get a task listener to use for the test compilation. */ |
|
208 TaskListener getTaskListener(Method m, PrintWriter out) { |
|
209 return new UserTaskListener(m, out); |
|
210 } |
|
211 |
|
212 /** Check if two values are .equal, and report an error if not. */ |
|
213 <T> void checkEqual(String label, T expect, T found) { |
|
214 if (!expect.equals(found)) |
|
215 error("Unexpected value for " + label + ": " + found + "; expected: " + expect); |
|
216 } |
|
217 |
|
218 /** Report an error. */ |
|
219 void error(String msg) { |
|
220 System.err.println("Error: " + msg); |
|
221 errors++; |
|
222 } |
|
223 |
|
224 /** Check if a method is declared in any of a set of classes */ |
|
225 static boolean isDeclaredIn(Method m, Class<?>... classes) { |
|
226 Class<?> dc = m.getDeclaringClass(); |
|
227 for (Class<?> c: classes) { |
|
228 if (c == dc) return true; |
|
229 } |
|
230 return false; |
|
231 } |
|
232 |
|
233 /** Throw an intentional error if the method has a given name. */ |
|
234 static void throwUserExceptionIfNeeded(Method m, String name) { |
|
235 if (m != null && m.getName().equals(name)) |
|
236 throw new UserError(name); |
|
237 } |
|
238 |
|
239 StandardJavaFileManager defaultFileManager; |
|
240 int testNum; |
|
241 int errors; |
|
242 |
|
243 //-------------------------------------------------------------------------- |
|
244 |
|
245 /** |
|
246 * Processor used to trigger use of methods not normally used by javac. |
|
247 */ |
|
248 @Override |
|
249 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { |
|
250 boolean firstRound = false; |
|
251 for (Element e: roundEnv.getRootElements()) { |
|
252 if (e.getSimpleName().contentEquals(TestClientCodeWrapper.class.getSimpleName())) |
|
253 firstRound = true; |
|
254 } |
|
255 if (firstRound) { |
|
256 try { |
|
257 FileObject f1 = filer.getResource(StandardLocation.CLASS_PATH, "", |
|
258 TestClientCodeWrapper.class.getName() + ".java"); |
|
259 f1.openInputStream().close(); |
|
260 f1.openReader(false).close(); |
|
261 |
|
262 FileObject f2 = filer.createResource( |
|
263 StandardLocation.CLASS_OUTPUT, "", "f2.txt", (Element[]) null); |
|
264 f2.openOutputStream().close(); |
|
265 |
|
266 FileObject f3 = filer.createResource( |
|
267 StandardLocation.CLASS_OUTPUT, "", "f3.txt", (Element[]) null); |
|
268 f3.openWriter().close(); |
|
269 |
|
270 JavaFileObject f4 = filer.createSourceFile("f4", (Element[]) null); |
|
271 f4.openWriter().close(); |
|
272 f4.getNestingKind(); |
|
273 f4.getAccessLevel(); |
|
274 |
|
275 messager.printMessage(Diagnostic.Kind.NOTE, "informational note", |
|
276 roundEnv.getRootElements().iterator().next()); |
|
277 |
|
278 } catch (IOException e) { |
|
279 throw new UserError(e); |
|
280 } |
|
281 } |
|
282 return true; |
|
283 } |
|
284 |
|
285 //-------------------------------------------------------------------------- |
|
286 |
|
287 // <editor-fold defaultstate="collapsed" desc="User classes"> |
|
288 |
|
289 static class UserError extends Error { |
|
290 private static final long serialVersionUID = 1L; |
|
291 UserError(String msg) { |
|
292 super(msg); |
|
293 } |
|
294 UserError(Throwable t) { |
|
295 super(t); |
|
296 } |
|
297 } |
|
298 |
|
299 static class UserFileManager extends ForwardingJavaFileManager<JavaFileManager> { |
|
300 Method fileManagerMethod; |
|
301 Method fileObjectMethod; |
|
302 |
|
303 UserFileManager(Method m, JavaFileManager delegate) { |
|
304 super(delegate); |
|
305 if (isDeclaredIn(m, JavaFileManager.class)) { |
|
306 fileManagerMethod = m; |
|
307 } else if (isDeclaredIn(m, FileObject.class, JavaFileObject.class)) { |
|
308 fileObjectMethod = m; |
|
309 } else |
|
310 assert false; |
|
311 } |
|
312 |
|
313 @Override |
|
314 public ClassLoader getClassLoader(Location location) { |
|
315 throwUserExceptionIfNeeded(fileManagerMethod, "getClassLoader"); |
|
316 return super.getClassLoader(location); |
|
317 } |
|
318 |
|
319 @Override |
|
320 public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse) throws IOException { |
|
321 throwUserExceptionIfNeeded(fileManagerMethod, "list"); |
|
322 return wrap(super.list(location, packageName, kinds, recurse)); |
|
323 } |
|
324 |
|
325 @Override |
|
326 public String inferBinaryName(Location location, JavaFileObject file) { |
|
327 throwUserExceptionIfNeeded(fileManagerMethod, "inferBinaryName"); |
|
328 return super.inferBinaryName(location, unwrap(file)); |
|
329 } |
|
330 |
|
331 @Override |
|
332 public boolean isSameFile(FileObject a, FileObject b) { |
|
333 throwUserExceptionIfNeeded(fileManagerMethod, "isSameFile"); |
|
334 return super.isSameFile(unwrap(a), unwrap(b)); |
|
335 } |
|
336 |
|
337 @Override |
|
338 public boolean handleOption(String current, Iterator<String> remaining) { |
|
339 throwUserExceptionIfNeeded(fileManagerMethod, "handleOption"); |
|
340 return super.handleOption(current, remaining); |
|
341 } |
|
342 |
|
343 @Override |
|
344 public boolean hasLocation(Location location) { |
|
345 throwUserExceptionIfNeeded(fileManagerMethod, "hasLocation"); |
|
346 return super.hasLocation(location); |
|
347 } |
|
348 |
|
349 @Override |
|
350 public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException { |
|
351 throwUserExceptionIfNeeded(fileManagerMethod, "getJavaFileForInput"); |
|
352 return wrap(super.getJavaFileForInput(location, className, kind)); |
|
353 } |
|
354 |
|
355 @Override |
|
356 public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException { |
|
357 throwUserExceptionIfNeeded(fileManagerMethod, "getJavaFileForOutput"); |
|
358 return wrap(super.getJavaFileForOutput(location, className, kind, sibling)); |
|
359 } |
|
360 |
|
361 @Override |
|
362 public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException { |
|
363 throwUserExceptionIfNeeded(fileManagerMethod, "getFileForInput"); |
|
364 return wrap(super.getFileForInput(location, packageName, relativeName)); |
|
365 } |
|
366 |
|
367 @Override |
|
368 public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException { |
|
369 throwUserExceptionIfNeeded(fileManagerMethod, "getFileForOutput"); |
|
370 return wrap(super.getFileForOutput(location, packageName, relativeName, sibling)); |
|
371 } |
|
372 |
|
373 @Override |
|
374 public void flush() throws IOException { |
|
375 throwUserExceptionIfNeeded(fileManagerMethod, "flush"); |
|
376 super.flush(); |
|
377 } |
|
378 |
|
379 @Override |
|
380 public void close() throws IOException { |
|
381 throwUserExceptionIfNeeded(fileManagerMethod, "close"); |
|
382 super.close(); |
|
383 } |
|
384 |
|
385 @Override |
|
386 public int isSupportedOption(String option) { |
|
387 throwUserExceptionIfNeeded(fileManagerMethod, "isSupportedOption"); |
|
388 return super.isSupportedOption(option); |
|
389 } |
|
390 |
|
391 public FileObject wrap(FileObject fo) { |
|
392 if (fileObjectMethod == null) |
|
393 return fo; |
|
394 return new UserFileObject(fileObjectMethod, (JavaFileObject)fo); |
|
395 } |
|
396 |
|
397 FileObject unwrap(FileObject fo) { |
|
398 if (fo instanceof UserFileObject) |
|
399 return ((UserFileObject) fo).unwrap(); |
|
400 else |
|
401 return fo; |
|
402 } |
|
403 |
|
404 public JavaFileObject wrap(JavaFileObject fo) { |
|
405 if (fileObjectMethod == null) |
|
406 return fo; |
|
407 return new UserFileObject(fileObjectMethod, fo); |
|
408 } |
|
409 |
|
410 public Iterable<JavaFileObject> wrap(Iterable<? extends JavaFileObject> list) { |
|
411 List<JavaFileObject> wrapped = new ArrayList<JavaFileObject>(); |
|
412 for (JavaFileObject fo : list) |
|
413 wrapped.add(wrap(fo)); |
|
414 return Collections.unmodifiableList(wrapped); |
|
415 } |
|
416 |
|
417 JavaFileObject unwrap(JavaFileObject fo) { |
|
418 if (fo instanceof UserFileObject) |
|
419 return ((UserFileObject) fo).unwrap(); |
|
420 else |
|
421 return fo; |
|
422 } |
|
423 } |
|
424 |
|
425 static class UserFileObject extends ForwardingJavaFileObject<JavaFileObject> { |
|
426 Method method; |
|
427 |
|
428 UserFileObject(Method m, JavaFileObject delegate) { |
|
429 super(delegate); |
|
430 assert isDeclaredIn(m, FileObject.class, JavaFileObject.class); |
|
431 this.method = m; |
|
432 } |
|
433 |
|
434 JavaFileObject unwrap() { |
|
435 return fileObject; |
|
436 } |
|
437 |
|
438 @Override |
|
439 public Kind getKind() { |
|
440 throwUserExceptionIfNeeded(method, "getKind"); |
|
441 return super.getKind(); |
|
442 } |
|
443 |
|
444 @Override |
|
445 public boolean isNameCompatible(String simpleName, Kind kind) { |
|
446 throwUserExceptionIfNeeded(method, "isNameCompatible"); |
|
447 return super.isNameCompatible(simpleName, kind); |
|
448 } |
|
449 |
|
450 @Override |
|
451 public NestingKind getNestingKind() { |
|
452 throwUserExceptionIfNeeded(method, "getNestingKind"); |
|
453 return super.getNestingKind(); |
|
454 } |
|
455 |
|
456 @Override |
|
457 public Modifier getAccessLevel() { |
|
458 throwUserExceptionIfNeeded(method, "getAccessLevel"); |
|
459 return super.getAccessLevel(); |
|
460 } |
|
461 |
|
462 @Override |
|
463 public URI toUri() { |
|
464 throwUserExceptionIfNeeded(method, "toUri"); |
|
465 return super.toUri(); |
|
466 } |
|
467 |
|
468 @Override |
|
469 public String getName() { |
|
470 throwUserExceptionIfNeeded(method, "getName"); |
|
471 return super.getName(); |
|
472 } |
|
473 |
|
474 @Override |
|
475 public InputStream openInputStream() throws IOException { |
|
476 throwUserExceptionIfNeeded(method, "openInputStream"); |
|
477 return super.openInputStream(); |
|
478 } |
|
479 |
|
480 @Override |
|
481 public OutputStream openOutputStream() throws IOException { |
|
482 throwUserExceptionIfNeeded(method, "openOutputStream"); |
|
483 return super.openOutputStream(); |
|
484 } |
|
485 |
|
486 @Override |
|
487 public Reader openReader(boolean ignoreEncodingErrors) throws IOException { |
|
488 throwUserExceptionIfNeeded(method, "openReader"); |
|
489 return super.openReader(ignoreEncodingErrors); |
|
490 } |
|
491 |
|
492 @Override |
|
493 public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { |
|
494 throwUserExceptionIfNeeded(method, "getCharContent"); |
|
495 return super.getCharContent(ignoreEncodingErrors); |
|
496 } |
|
497 |
|
498 @Override |
|
499 public Writer openWriter() throws IOException { |
|
500 throwUserExceptionIfNeeded(method, "openWriter"); |
|
501 return super.openWriter(); |
|
502 } |
|
503 |
|
504 @Override |
|
505 public long getLastModified() { |
|
506 throwUserExceptionIfNeeded(method, "getLastModified"); |
|
507 return super.getLastModified(); |
|
508 } |
|
509 |
|
510 @Override |
|
511 public boolean delete() { |
|
512 throwUserExceptionIfNeeded(method, "delete"); |
|
513 return super.delete(); |
|
514 } |
|
515 |
|
516 } |
|
517 |
|
518 static class UserProcessor extends JavacTestingAbstractProcessor { |
|
519 Method method; |
|
520 |
|
521 UserProcessor(Method m) { |
|
522 assert isDeclaredIn(m, Processor.class); |
|
523 method = m; |
|
524 } |
|
525 |
|
526 @Override |
|
527 public Set<String> getSupportedOptions() { |
|
528 throwUserExceptionIfNeeded(method, "getSupportedOptions"); |
|
529 return super.getSupportedOptions(); |
|
530 } |
|
531 |
|
532 @Override |
|
533 public Set<String> getSupportedAnnotationTypes() { |
|
534 throwUserExceptionIfNeeded(method, "getSupportedAnnotationTypes"); |
|
535 return super.getSupportedAnnotationTypes(); |
|
536 } |
|
537 |
|
538 @Override |
|
539 public SourceVersion getSupportedSourceVersion() { |
|
540 throwUserExceptionIfNeeded(method, "getSupportedSourceVersion"); |
|
541 return super.getSupportedSourceVersion(); |
|
542 } |
|
543 |
|
544 @Override |
|
545 public void init(ProcessingEnvironment processingEnv) { |
|
546 throwUserExceptionIfNeeded(method, "init"); |
|
547 super.init(processingEnv); |
|
548 } |
|
549 |
|
550 @Override |
|
551 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { |
|
552 throwUserExceptionIfNeeded(method, "process"); |
|
553 return true; |
|
554 } |
|
555 |
|
556 @Override |
|
557 public Iterable<? extends Completion> getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) { |
|
558 throwUserExceptionIfNeeded(method, "getCompletions"); |
|
559 return super.getCompletions(element, annotation, member, userText); |
|
560 } |
|
561 } |
|
562 |
|
563 static class UserDiagnosticListener implements DiagnosticListener<JavaFileObject> { |
|
564 Method method; |
|
565 PrintWriter out; |
|
566 |
|
567 UserDiagnosticListener(Method m, PrintWriter out) { |
|
568 assert isDeclaredIn(m, DiagnosticListener.class); |
|
569 this.method = m; |
|
570 this.out = out; |
|
571 } |
|
572 |
|
573 @Override |
|
574 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { |
|
575 throwUserExceptionIfNeeded(method, "report"); |
|
576 out.println("report: " + diagnostic); |
|
577 } |
|
578 } |
|
579 |
|
580 static class UserTaskListener implements TaskListener { |
|
581 Method method; |
|
582 PrintWriter out; |
|
583 |
|
584 UserTaskListener(Method m, PrintWriter out) { |
|
585 assert isDeclaredIn(m, TaskListener.class); |
|
586 this.method = m; |
|
587 this.out = out; |
|
588 } |
|
589 |
|
590 @Override |
|
591 public void started(TaskEvent e) { |
|
592 throwUserExceptionIfNeeded(method, "started"); |
|
593 out.println("started: " + e); |
|
594 } |
|
595 |
|
596 @Override |
|
597 public void finished(TaskEvent e) { |
|
598 throwUserExceptionIfNeeded(method, "finished"); |
|
599 out.println("finished: " + e); |
|
600 } |
|
601 } |
|
602 |
|
603 // </editor-fold> |
|
604 } |