Fri, 25 Mar 2011 07:58:53 -0700
6437138: JSR 199: Compiler doesn't diagnose crash in user code
6482554: uncaught exception from annotation processor not reported through JavaCompiler.CompilationTask.call
Reviewed-by: mcimadamore
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/tools/javac/api/ClientCodeWrapper.java Fri Mar 25 07:58:53 2011 -0700 1.3 @@ -0,0 +1,593 @@ 1.4 +/* 1.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 + 1.30 +package com.sun.tools.javac.api; 1.31 + 1.32 +import java.io.IOException; 1.33 +import java.io.InputStream; 1.34 +import java.io.OutputStream; 1.35 +import java.io.Reader; 1.36 +import java.io.Writer; 1.37 +import java.net.URI; 1.38 +import java.util.ArrayList; 1.39 +import java.util.Collections; 1.40 +import java.util.HashMap; 1.41 +import java.util.Iterator; 1.42 +import java.util.List; 1.43 +import java.util.Map; 1.44 +import java.util.Set; 1.45 + 1.46 +import javax.lang.model.element.NestingKind; 1.47 +import javax.tools.Diagnostic; 1.48 +import javax.tools.FileObject; 1.49 +import javax.tools.JavaFileManager; 1.50 +import javax.tools.JavaFileManager.Location; 1.51 +import javax.tools.JavaFileObject; 1.52 + 1.53 +import com.sun.source.util.TaskEvent; 1.54 +import com.sun.source.util.TaskListener; 1.55 +import com.sun.tools.javac.util.ClientCodeException; 1.56 +import com.sun.tools.javac.util.Context; 1.57 +import java.lang.annotation.ElementType; 1.58 +import java.lang.annotation.Retention; 1.59 +import java.lang.annotation.RetentionPolicy; 1.60 +import java.lang.annotation.Target; 1.61 +import javax.lang.model.element.Modifier; 1.62 +import javax.tools.DiagnosticListener; 1.63 +import javax.tools.JavaFileObject.Kind; 1.64 + 1.65 +/** 1.66 + * Wrap objects to enable unchecked exceptions to be caught and handled. 1.67 + * 1.68 + * For each method, exceptions are handled as follows: 1.69 + * <ul> 1.70 + * <li>Checked exceptions are left alone and propogate upwards in the 1.71 + * obvious way, since they are an expected aspect of the method's 1.72 + * specification. 1.73 + * <li>Unchecked exceptions which have already been caught and wrapped in 1.74 + * ClientCodeException are left alone to continue propogating upwards. 1.75 + * <li>All other unchecked exceptions (i.e. subtypes of RuntimeException 1.76 + * and Error) and caught, and rethrown as a ClientCodeException with 1.77 + * its cause set to the original exception. 1.78 + * </ul> 1.79 + * 1.80 + * The intent is that ClientCodeException can be caught at an appropriate point 1.81 + * in the program and can be distinguished from any unanticipated unchecked 1.82 + * exceptions arising in the main body of the code (i.e. bugs.) When the 1.83 + * ClientCodeException has been caught, either a suitable message can be 1.84 + * generated, or if appropriate, the original cause can be rethrown. 1.85 + * 1.86 + * <p><b>This is NOT part of any supported API. 1.87 + * If you write code that depends on this, you do so at your own risk. 1.88 + * This code and its internal interfaces are subject to change or 1.89 + * deletion without notice.</b> 1.90 + */ 1.91 +public class ClientCodeWrapper { 1.92 + @Retention(RetentionPolicy.RUNTIME) 1.93 + @Target(ElementType.TYPE) 1.94 + public @interface Trusted { } 1.95 + 1.96 + public static ClientCodeWrapper instance(Context context) { 1.97 + ClientCodeWrapper instance = context.get(ClientCodeWrapper.class); 1.98 + if (instance == null) 1.99 + instance = new ClientCodeWrapper(context); 1.100 + return instance; 1.101 + } 1.102 + 1.103 + /** 1.104 + * A map to cache the results of whether or not a specific classes can 1.105 + * be "trusted", and thus does not need to be wrapped. 1.106 + */ 1.107 + Map<Class<?>, Boolean> trustedClasses; 1.108 + 1.109 + protected ClientCodeWrapper(Context context) { 1.110 + trustedClasses = new HashMap<Class<?>, Boolean>(); 1.111 + } 1.112 + 1.113 + public JavaFileManager wrap(JavaFileManager fm) { 1.114 + if (isTrusted(fm)) 1.115 + return fm; 1.116 + return new WrappedJavaFileManager(fm); 1.117 + } 1.118 + 1.119 + public FileObject wrap(FileObject fo) { 1.120 + if (isTrusted(fo)) 1.121 + return fo; 1.122 + return new WrappedFileObject(fo); 1.123 + } 1.124 + 1.125 + FileObject unwrap(FileObject fo) { 1.126 + if (fo instanceof WrappedFileObject) 1.127 + return ((WrappedFileObject) fo).clientFileObject; 1.128 + else 1.129 + return fo; 1.130 + } 1.131 + 1.132 + public JavaFileObject wrap(JavaFileObject fo) { 1.133 + if (isTrusted(fo)) 1.134 + return fo; 1.135 + return new WrappedJavaFileObject(fo); 1.136 + } 1.137 + 1.138 + public Iterable<JavaFileObject> wrapJavaFileObjects(Iterable<? extends JavaFileObject> list) { 1.139 + List<JavaFileObject> wrapped = new ArrayList<JavaFileObject>(); 1.140 + for (JavaFileObject fo : list) 1.141 + wrapped.add(wrap(fo)); 1.142 + return Collections.unmodifiableList(wrapped); 1.143 + } 1.144 + 1.145 + JavaFileObject unwrap(JavaFileObject fo) { 1.146 + if (fo instanceof WrappedJavaFileObject) 1.147 + return ((JavaFileObject) ((WrappedJavaFileObject) fo).clientFileObject); 1.148 + else 1.149 + return fo; 1.150 + } 1.151 + 1.152 + <T> DiagnosticListener<T> wrap(DiagnosticListener<T> dl) { 1.153 + if (isTrusted(dl)) 1.154 + return dl; 1.155 + return new WrappedDiagnosticListener<T>(dl); 1.156 + } 1.157 + 1.158 + TaskListener wrap(TaskListener tl) { 1.159 + if (isTrusted(tl)) 1.160 + return tl; 1.161 + return new WrappedTaskListener(tl); 1.162 + } 1.163 + 1.164 + protected boolean isTrusted(Object o) { 1.165 + Class<?> c = o.getClass(); 1.166 + Boolean trusted = trustedClasses.get(c); 1.167 + if (trusted == null) { 1.168 + trusted = c.getName().startsWith("com.sun.tools.javac.") 1.169 + || c.isAnnotationPresent(Trusted.class); 1.170 + trustedClasses.put(c, trusted); 1.171 + } 1.172 + return trusted; 1.173 + } 1.174 + 1.175 + // <editor-fold defaultstate="collapsed" desc="Wrapper classes"> 1.176 + 1.177 + // FIXME: all these classes should be converted to use multi-catch when 1.178 + // that is available in the bootstrap compiler. 1.179 + 1.180 + protected class WrappedJavaFileManager implements JavaFileManager { 1.181 + protected JavaFileManager clientJavaFileManager; 1.182 + WrappedJavaFileManager(JavaFileManager clientJavaFileManager) { 1.183 + clientJavaFileManager.getClass(); // null check 1.184 + this.clientJavaFileManager = clientJavaFileManager; 1.185 + } 1.186 + 1.187 + @Override 1.188 + public ClassLoader getClassLoader(Location location) { 1.189 + try { 1.190 + return clientJavaFileManager.getClassLoader(location); 1.191 + } catch (ClientCodeException e) { 1.192 + throw e; 1.193 + } catch (RuntimeException e) { 1.194 + throw new ClientCodeException(e); 1.195 + } catch (Error e) { 1.196 + throw new ClientCodeException(e); 1.197 + } 1.198 + } 1.199 + 1.200 + @Override 1.201 + public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse) throws IOException { 1.202 + try { 1.203 + return wrapJavaFileObjects(clientJavaFileManager.list(location, packageName, kinds, recurse)); 1.204 + } catch (ClientCodeException e) { 1.205 + throw e; 1.206 + } catch (RuntimeException e) { 1.207 + throw new ClientCodeException(e); 1.208 + } catch (Error e) { 1.209 + throw new ClientCodeException(e); 1.210 + } 1.211 + } 1.212 + 1.213 + @Override 1.214 + public String inferBinaryName(Location location, JavaFileObject file) { 1.215 + try { 1.216 + return clientJavaFileManager.inferBinaryName(location, unwrap(file)); 1.217 + } catch (ClientCodeException e) { 1.218 + throw e; 1.219 + } catch (RuntimeException e) { 1.220 + throw new ClientCodeException(e); 1.221 + } catch (Error e) { 1.222 + throw new ClientCodeException(e); 1.223 + } 1.224 + } 1.225 + 1.226 + @Override 1.227 + public boolean isSameFile(FileObject a, FileObject b) { 1.228 + try { 1.229 + return clientJavaFileManager.isSameFile(unwrap(a), unwrap(b)); 1.230 + } catch (ClientCodeException e) { 1.231 + throw e; 1.232 + } catch (RuntimeException e) { 1.233 + throw new ClientCodeException(e); 1.234 + } catch (Error e) { 1.235 + throw new ClientCodeException(e); 1.236 + } 1.237 + } 1.238 + 1.239 + @Override 1.240 + public boolean handleOption(String current, Iterator<String> remaining) { 1.241 + try { 1.242 + return clientJavaFileManager.handleOption(current, remaining); 1.243 + } catch (ClientCodeException e) { 1.244 + throw e; 1.245 + } catch (RuntimeException e) { 1.246 + throw new ClientCodeException(e); 1.247 + } catch (Error e) { 1.248 + throw new ClientCodeException(e); 1.249 + } 1.250 + } 1.251 + 1.252 + @Override 1.253 + public boolean hasLocation(Location location) { 1.254 + try { 1.255 + return clientJavaFileManager.hasLocation(location); 1.256 + } catch (ClientCodeException e) { 1.257 + throw e; 1.258 + } catch (RuntimeException e) { 1.259 + throw new ClientCodeException(e); 1.260 + } catch (Error e) { 1.261 + throw new ClientCodeException(e); 1.262 + } 1.263 + } 1.264 + 1.265 + @Override 1.266 + public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException { 1.267 + try { 1.268 + return wrap(clientJavaFileManager.getJavaFileForInput(location, className, kind)); 1.269 + } catch (ClientCodeException e) { 1.270 + throw e; 1.271 + } catch (RuntimeException e) { 1.272 + throw new ClientCodeException(e); 1.273 + } catch (Error e) { 1.274 + throw new ClientCodeException(e); 1.275 + } 1.276 + } 1.277 + 1.278 + @Override 1.279 + public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException { 1.280 + try { 1.281 + return wrap(clientJavaFileManager.getJavaFileForOutput(location, className, kind, unwrap(sibling))); 1.282 + } catch (ClientCodeException e) { 1.283 + throw e; 1.284 + } catch (RuntimeException e) { 1.285 + throw new ClientCodeException(e); 1.286 + } catch (Error e) { 1.287 + throw new ClientCodeException(e); 1.288 + } 1.289 + } 1.290 + 1.291 + @Override 1.292 + public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException { 1.293 + try { 1.294 + return wrap(clientJavaFileManager.getFileForInput(location, packageName, relativeName)); 1.295 + } catch (ClientCodeException e) { 1.296 + throw e; 1.297 + } catch (RuntimeException e) { 1.298 + throw new ClientCodeException(e); 1.299 + } catch (Error e) { 1.300 + throw new ClientCodeException(e); 1.301 + } 1.302 + } 1.303 + 1.304 + @Override 1.305 + public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException { 1.306 + try { 1.307 + return wrap(clientJavaFileManager.getFileForOutput(location, packageName, relativeName, unwrap(sibling))); 1.308 + } catch (ClientCodeException e) { 1.309 + throw e; 1.310 + } catch (RuntimeException e) { 1.311 + throw new ClientCodeException(e); 1.312 + } catch (Error e) { 1.313 + throw new ClientCodeException(e); 1.314 + } 1.315 + } 1.316 + 1.317 + @Override 1.318 + public void flush() throws IOException { 1.319 + try { 1.320 + clientJavaFileManager.flush(); 1.321 + } catch (ClientCodeException e) { 1.322 + throw e; 1.323 + } catch (RuntimeException e) { 1.324 + throw new ClientCodeException(e); 1.325 + } catch (Error e) { 1.326 + throw new ClientCodeException(e); 1.327 + } 1.328 + } 1.329 + 1.330 + @Override 1.331 + public void close() throws IOException { 1.332 + try { 1.333 + clientJavaFileManager.close(); 1.334 + } catch (ClientCodeException e) { 1.335 + throw e; 1.336 + } catch (RuntimeException e) { 1.337 + throw new ClientCodeException(e); 1.338 + } catch (Error e) { 1.339 + throw new ClientCodeException(e); 1.340 + } 1.341 + } 1.342 + 1.343 + @Override 1.344 + public int isSupportedOption(String option) { 1.345 + try { 1.346 + return clientJavaFileManager.isSupportedOption(option); 1.347 + } catch (ClientCodeException e) { 1.348 + throw e; 1.349 + } catch (RuntimeException e) { 1.350 + throw new ClientCodeException(e); 1.351 + } catch (Error e) { 1.352 + throw new ClientCodeException(e); 1.353 + } 1.354 + } 1.355 + } 1.356 + 1.357 + protected class WrappedFileObject implements FileObject { 1.358 + protected FileObject clientFileObject; 1.359 + WrappedFileObject(FileObject clientFileObject) { 1.360 + clientFileObject.getClass(); // null check 1.361 + this.clientFileObject = clientFileObject; 1.362 + } 1.363 + 1.364 + @Override 1.365 + public URI toUri() { 1.366 + try { 1.367 + return clientFileObject.toUri(); 1.368 + } catch (ClientCodeException e) { 1.369 + throw e; 1.370 + } catch (RuntimeException e) { 1.371 + throw new ClientCodeException(e); 1.372 + } catch (Error e) { 1.373 + throw new ClientCodeException(e); 1.374 + } 1.375 + } 1.376 + 1.377 + @Override 1.378 + public String getName() { 1.379 + try { 1.380 + return clientFileObject.getName(); 1.381 + } catch (ClientCodeException e) { 1.382 + throw e; 1.383 + } catch (RuntimeException e) { 1.384 + throw new ClientCodeException(e); 1.385 + } catch (Error e) { 1.386 + throw new ClientCodeException(e); 1.387 + } 1.388 + } 1.389 + 1.390 + @Override 1.391 + public InputStream openInputStream() throws IOException { 1.392 + try { 1.393 + return clientFileObject.openInputStream(); 1.394 + } catch (ClientCodeException e) { 1.395 + throw e; 1.396 + } catch (RuntimeException e) { 1.397 + throw new ClientCodeException(e); 1.398 + } catch (Error e) { 1.399 + throw new ClientCodeException(e); 1.400 + } 1.401 + } 1.402 + 1.403 + @Override 1.404 + public OutputStream openOutputStream() throws IOException { 1.405 + try { 1.406 + return clientFileObject.openOutputStream(); 1.407 + } catch (ClientCodeException e) { 1.408 + throw e; 1.409 + } catch (RuntimeException e) { 1.410 + throw new ClientCodeException(e); 1.411 + } catch (Error e) { 1.412 + throw new ClientCodeException(e); 1.413 + } 1.414 + } 1.415 + 1.416 + @Override 1.417 + public Reader openReader(boolean ignoreEncodingErrors) throws IOException { 1.418 + try { 1.419 + return clientFileObject.openReader(ignoreEncodingErrors); 1.420 + } catch (ClientCodeException e) { 1.421 + throw e; 1.422 + } catch (RuntimeException e) { 1.423 + throw new ClientCodeException(e); 1.424 + } catch (Error e) { 1.425 + throw new ClientCodeException(e); 1.426 + } 1.427 + } 1.428 + 1.429 + @Override 1.430 + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { 1.431 + try { 1.432 + return clientFileObject.getCharContent(ignoreEncodingErrors); 1.433 + } catch (ClientCodeException e) { 1.434 + throw e; 1.435 + } catch (RuntimeException e) { 1.436 + throw new ClientCodeException(e); 1.437 + } catch (Error e) { 1.438 + throw new ClientCodeException(e); 1.439 + } 1.440 + } 1.441 + 1.442 + @Override 1.443 + public Writer openWriter() throws IOException { 1.444 + try { 1.445 + return clientFileObject.openWriter(); 1.446 + } catch (ClientCodeException e) { 1.447 + throw e; 1.448 + } catch (RuntimeException e) { 1.449 + throw new ClientCodeException(e); 1.450 + } catch (Error e) { 1.451 + throw new ClientCodeException(e); 1.452 + } 1.453 + } 1.454 + 1.455 + @Override 1.456 + public long getLastModified() { 1.457 + try { 1.458 + return clientFileObject.getLastModified(); 1.459 + } catch (ClientCodeException e) { 1.460 + throw e; 1.461 + } catch (RuntimeException e) { 1.462 + throw new ClientCodeException(e); 1.463 + } catch (Error e) { 1.464 + throw new ClientCodeException(e); 1.465 + } 1.466 + } 1.467 + 1.468 + @Override 1.469 + public boolean delete() { 1.470 + try { 1.471 + return clientFileObject.delete(); 1.472 + } catch (ClientCodeException e) { 1.473 + throw e; 1.474 + } catch (RuntimeException e) { 1.475 + throw new ClientCodeException(e); 1.476 + } catch (Error e) { 1.477 + throw new ClientCodeException(e); 1.478 + } 1.479 + } 1.480 + } 1.481 + 1.482 + protected class WrappedJavaFileObject extends WrappedFileObject implements JavaFileObject { 1.483 + WrappedJavaFileObject(JavaFileObject clientJavaFileObject) { 1.484 + super(clientJavaFileObject); 1.485 + } 1.486 + 1.487 + @Override 1.488 + public Kind getKind() { 1.489 + try { 1.490 + return ((JavaFileObject)clientFileObject).getKind(); 1.491 + } catch (ClientCodeException e) { 1.492 + throw e; 1.493 + } catch (RuntimeException e) { 1.494 + throw new ClientCodeException(e); 1.495 + } catch (Error e) { 1.496 + throw new ClientCodeException(e); 1.497 + } 1.498 + } 1.499 + 1.500 + @Override 1.501 + public boolean isNameCompatible(String simpleName, Kind kind) { 1.502 + try { 1.503 + return ((JavaFileObject)clientFileObject).isNameCompatible(simpleName, kind); 1.504 + } catch (ClientCodeException e) { 1.505 + throw e; 1.506 + } catch (RuntimeException e) { 1.507 + throw new ClientCodeException(e); 1.508 + } catch (Error e) { 1.509 + throw new ClientCodeException(e); 1.510 + } 1.511 + } 1.512 + 1.513 + @Override 1.514 + public NestingKind getNestingKind() { 1.515 + try { 1.516 + return ((JavaFileObject)clientFileObject).getNestingKind(); 1.517 + } catch (ClientCodeException e) { 1.518 + throw e; 1.519 + } catch (RuntimeException e) { 1.520 + throw new ClientCodeException(e); 1.521 + } catch (Error e) { 1.522 + throw new ClientCodeException(e); 1.523 + } 1.524 + } 1.525 + 1.526 + @Override 1.527 + public Modifier getAccessLevel() { 1.528 + try { 1.529 + return ((JavaFileObject)clientFileObject).getAccessLevel(); 1.530 + } catch (ClientCodeException e) { 1.531 + throw e; 1.532 + } catch (RuntimeException e) { 1.533 + throw new ClientCodeException(e); 1.534 + } catch (Error e) { 1.535 + throw new ClientCodeException(e); 1.536 + } 1.537 + } 1.538 + } 1.539 + 1.540 + protected class WrappedDiagnosticListener<T> implements DiagnosticListener<T> { 1.541 + protected DiagnosticListener<T> clientDiagnosticListener; 1.542 + WrappedDiagnosticListener(DiagnosticListener<T> clientDiagnosticListener) { 1.543 + clientDiagnosticListener.getClass(); // null check 1.544 + this.clientDiagnosticListener = clientDiagnosticListener; 1.545 + } 1.546 + 1.547 + @Override 1.548 + public void report(Diagnostic<? extends T> diagnostic) { 1.549 + try { 1.550 + clientDiagnosticListener.report(diagnostic); 1.551 + } catch (ClientCodeException e) { 1.552 + throw e; 1.553 + } catch (RuntimeException e) { 1.554 + throw new ClientCodeException(e); 1.555 + } catch (Error e) { 1.556 + throw new ClientCodeException(e); 1.557 + } 1.558 + } 1.559 + } 1.560 + 1.561 + protected class WrappedTaskListener implements TaskListener { 1.562 + protected TaskListener clientTaskListener; 1.563 + WrappedTaskListener(TaskListener clientTaskListener) { 1.564 + clientTaskListener.getClass(); // null check 1.565 + this.clientTaskListener = clientTaskListener; 1.566 + } 1.567 + 1.568 + @Override 1.569 + public void started(TaskEvent ev) { 1.570 + try { 1.571 + clientTaskListener.started(ev); 1.572 + } catch (ClientCodeException e) { 1.573 + throw e; 1.574 + } catch (RuntimeException e) { 1.575 + throw new ClientCodeException(e); 1.576 + } catch (Error e) { 1.577 + throw new ClientCodeException(e); 1.578 + } 1.579 + } 1.580 + 1.581 + @Override 1.582 + public void finished(TaskEvent ev) { 1.583 + try { 1.584 + clientTaskListener.finished(ev); 1.585 + } catch (ClientCodeException e) { 1.586 + throw e; 1.587 + } catch (RuntimeException e) { 1.588 + throw new ClientCodeException(e); 1.589 + } catch (Error e) { 1.590 + throw new ClientCodeException(e); 1.591 + } 1.592 + } 1.593 + } 1.594 + 1.595 + // </editor-fold> 1.596 +}
2.1 --- a/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Fri Mar 25 07:39:30 2011 -0700 2.2 +++ b/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Fri Mar 25 07:58:53 2011 -0700 2.3 @@ -65,7 +65,7 @@ 2.4 * @author Jonathan Gibbons 2.5 */ 2.6 public class JavacTaskImpl extends JavacTask { 2.7 - private JavacTool tool; 2.8 + private ClientCodeWrapper ccw; 2.9 private Main compilerMain; 2.10 private JavaCompiler compiler; 2.11 private Locale locale; 2.12 @@ -80,12 +80,11 @@ 2.13 2.14 private Integer result = null; 2.15 2.16 - JavacTaskImpl(JavacTool tool, 2.17 - Main compilerMain, 2.18 + JavacTaskImpl(Main compilerMain, 2.19 String[] args, 2.20 Context context, 2.21 List<JavaFileObject> fileObjects) { 2.22 - this.tool = tool; 2.23 + this.ccw = ClientCodeWrapper.instance(context); 2.24 this.compilerMain = compilerMain; 2.25 this.args = args; 2.26 this.context = context; 2.27 @@ -94,17 +93,15 @@ 2.28 // null checks 2.29 compilerMain.getClass(); 2.30 args.getClass(); 2.31 - context.getClass(); 2.32 fileObjects.getClass(); 2.33 } 2.34 2.35 - JavacTaskImpl(JavacTool tool, 2.36 - Main compilerMain, 2.37 + JavacTaskImpl(Main compilerMain, 2.38 Iterable<String> flags, 2.39 Context context, 2.40 Iterable<String> classes, 2.41 Iterable<? extends JavaFileObject> fileObjects) { 2.42 - this(tool, compilerMain, toArray(flags, classes), context, toList(fileObjects)); 2.43 + this(compilerMain, toArray(flags, classes), context, toList(fileObjects)); 2.44 } 2.45 2.46 static private String[] toArray(Iterable<String> flags, Iterable<String> classes) { 2.47 @@ -131,7 +128,7 @@ 2.48 if (!used.getAndSet(true)) { 2.49 initContext(); 2.50 notYetEntered = new HashMap<JavaFileObject, JCCompilationUnit>(); 2.51 - compilerMain.setFatalErrors(true); 2.52 + compilerMain.setAPIMode(true); 2.53 result = compilerMain.compile(args, context, fileObjects, processors); 2.54 cleanup(); 2.55 return result == 0; 2.56 @@ -185,32 +182,10 @@ 2.57 if (context.get(TaskListener.class) != null) 2.58 context.put(TaskListener.class, (TaskListener)null); 2.59 if (taskListener != null) 2.60 - context.put(TaskListener.class, wrap(taskListener)); 2.61 + context.put(TaskListener.class, ccw.wrap(taskListener)); 2.62 //initialize compiler's default locale 2.63 context.put(Locale.class, locale); 2.64 } 2.65 - // where 2.66 - private TaskListener wrap(final TaskListener tl) { 2.67 - tl.getClass(); // null check 2.68 - return new TaskListener() { 2.69 - public void started(TaskEvent e) { 2.70 - try { 2.71 - tl.started(e); 2.72 - } catch (Throwable t) { 2.73 - throw new ClientCodeException(t); 2.74 - } 2.75 - } 2.76 - 2.77 - public void finished(TaskEvent e) { 2.78 - try { 2.79 - tl.finished(e); 2.80 - } catch (Throwable t) { 2.81 - throw new ClientCodeException(t); 2.82 - } 2.83 - } 2.84 - 2.85 - }; 2.86 - } 2.87 2.88 void cleanup() { 2.89 if (compiler != null)
3.1 --- a/src/share/classes/com/sun/tools/javac/api/JavacTool.java Fri Mar 25 07:39:30 2011 -0700 3.2 +++ b/src/share/classes/com/sun/tools/javac/api/JavacTool.java Fri Mar 25 07:58:53 2011 -0700 3.3 @@ -49,6 +49,7 @@ 3.4 import com.sun.tools.javac.main.Main; 3.5 import com.sun.tools.javac.main.RecognizedOptions.GrumpyHelper; 3.6 import com.sun.tools.javac.main.RecognizedOptions; 3.7 +import com.sun.tools.javac.util.ClientCodeException; 3.8 import com.sun.tools.javac.util.Context; 3.9 import com.sun.tools.javac.util.Log; 3.10 import com.sun.tools.javac.util.Options; 3.11 @@ -162,38 +163,45 @@ 3.12 Iterable<String> classes, 3.13 Iterable<? extends JavaFileObject> compilationUnits) 3.14 { 3.15 - final String kindMsg = "All compilation units must be of SOURCE kind"; 3.16 - if (options != null) 3.17 - for (String option : options) 3.18 - option.getClass(); // null check 3.19 - if (classes != null) { 3.20 - for (String cls : classes) 3.21 - if (!SourceVersion.isName(cls)) // implicit null check 3.22 - throw new IllegalArgumentException("Not a valid class name: " + cls); 3.23 + try { 3.24 + Context context = new Context(); 3.25 + ClientCodeWrapper ccw = ClientCodeWrapper.instance(context); 3.26 + 3.27 + final String kindMsg = "All compilation units must be of SOURCE kind"; 3.28 + if (options != null) 3.29 + for (String option : options) 3.30 + option.getClass(); // null check 3.31 + if (classes != null) { 3.32 + for (String cls : classes) 3.33 + if (!SourceVersion.isName(cls)) // implicit null check 3.34 + throw new IllegalArgumentException("Not a valid class name: " + cls); 3.35 + } 3.36 + if (compilationUnits != null) { 3.37 + compilationUnits = ccw.wrapJavaFileObjects(compilationUnits); // implicit null check 3.38 + for (JavaFileObject cu : compilationUnits) { 3.39 + if (cu.getKind() != JavaFileObject.Kind.SOURCE) 3.40 + throw new IllegalArgumentException(kindMsg); 3.41 + } 3.42 + } 3.43 + 3.44 + if (diagnosticListener != null) 3.45 + context.put(DiagnosticListener.class, ccw.wrap(diagnosticListener)); 3.46 + 3.47 + if (out == null) 3.48 + context.put(Log.outKey, new PrintWriter(System.err, true)); 3.49 + else 3.50 + context.put(Log.outKey, new PrintWriter(out, true)); 3.51 + 3.52 + if (fileManager == null) 3.53 + fileManager = getStandardFileManager(diagnosticListener, null, null); 3.54 + fileManager = ccw.wrap(fileManager); 3.55 + context.put(JavaFileManager.class, fileManager); 3.56 + processOptions(context, fileManager, options); 3.57 + Main compiler = new Main("javacTask", context.get(Log.outKey)); 3.58 + return new JavacTaskImpl(compiler, options, context, classes, compilationUnits); 3.59 + } catch (ClientCodeException ex) { 3.60 + throw new RuntimeException(ex.getCause()); 3.61 } 3.62 - if (compilationUnits != null) { 3.63 - for (JavaFileObject cu : compilationUnits) { 3.64 - if (cu.getKind() != JavaFileObject.Kind.SOURCE) // implicit null check 3.65 - throw new IllegalArgumentException(kindMsg); 3.66 - } 3.67 - } 3.68 - 3.69 - Context context = new Context(); 3.70 - 3.71 - if (diagnosticListener != null) 3.72 - context.put(DiagnosticListener.class, diagnosticListener); 3.73 - 3.74 - if (out == null) 3.75 - context.put(Log.outKey, new PrintWriter(System.err, true)); 3.76 - else 3.77 - context.put(Log.outKey, new PrintWriter(out, true)); 3.78 - 3.79 - if (fileManager == null) 3.80 - fileManager = getStandardFileManager(diagnosticListener, null, null); 3.81 - context.put(JavaFileManager.class, fileManager); 3.82 - processOptions(context, fileManager, options); 3.83 - Main compiler = new Main("javacTask", context.get(Log.outKey)); 3.84 - return new JavacTaskImpl(this, compiler, options, context, classes, compilationUnits); 3.85 } 3.86 3.87 private static void processOptions(Context context,
4.1 --- a/src/share/classes/com/sun/tools/javac/main/Main.java Fri Mar 25 07:39:30 2011 -0700 4.2 +++ b/src/share/classes/com/sun/tools/javac/main/Main.java Fri Mar 25 07:58:53 2011 -0700 4.3 @@ -65,9 +65,11 @@ 4.4 PrintWriter out; 4.5 4.6 /** 4.7 - * If true, any command line arg errors will cause an exception. 4.8 + * If true, certain errors will cause an exception, such as command line 4.9 + * arg errors, or exceptions in user provided code. 4.10 */ 4.11 - boolean fatalErrors; 4.12 + boolean apiMode; 4.13 + 4.14 4.15 /** Result codes. 4.16 */ 4.17 @@ -163,7 +165,7 @@ 4.18 /** Report a usage error. 4.19 */ 4.20 void error(String key, Object... args) { 4.21 - if (fatalErrors) { 4.22 + if (apiMode) { 4.23 String msg = getLocalizedString(key, args); 4.24 throw new PropagatedException(new IllegalStateException(msg)); 4.25 } 4.26 @@ -192,8 +194,8 @@ 4.27 this.options = options; 4.28 } 4.29 4.30 - public void setFatalErrors(boolean fatalErrors) { 4.31 - this.fatalErrors = fatalErrors; 4.32 + public void setAPIMode(boolean apiMode) { 4.33 + this.apiMode = apiMode; 4.34 } 4.35 4.36 /** Process command line arguments: store all command line options 4.37 @@ -440,7 +442,9 @@ 4.38 } catch (FatalError ex) { 4.39 feMessage(ex); 4.40 return EXIT_SYSERR; 4.41 - } catch(AnnotationProcessingError ex) { 4.42 + } catch (AnnotationProcessingError ex) { 4.43 + if (apiMode) 4.44 + throw new RuntimeException(ex.getCause()); 4.45 apMessage(ex); 4.46 return EXIT_SYSERR; 4.47 } catch (ClientCodeException ex) { 4.48 @@ -458,7 +462,13 @@ 4.49 bugMessage(ex); 4.50 return EXIT_ABNORMAL; 4.51 } finally { 4.52 - if (comp != null) comp.close(); 4.53 + if (comp != null) { 4.54 + try { 4.55 + comp.close(); 4.56 + } catch (ClientCodeException ex) { 4.57 + throw new RuntimeException(ex.getCause()); 4.58 + } 4.59 + } 4.60 filenames = null; 4.61 options = null; 4.62 }
5.1 --- a/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Fri Mar 25 07:39:30 2011 -0700 5.2 +++ b/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Fri Mar 25 07:58:53 2011 -0700 5.3 @@ -67,6 +67,7 @@ 5.4 import com.sun.tools.javac.tree.JCTree.*; 5.5 import com.sun.tools.javac.util.Abort; 5.6 import com.sun.tools.javac.util.Assert; 5.7 +import com.sun.tools.javac.util.ClientCodeException; 5.8 import com.sun.tools.javac.util.Context; 5.9 import com.sun.tools.javac.util.Convert; 5.10 import com.sun.tools.javac.util.FatalError; 5.11 @@ -432,6 +433,8 @@ 5.12 log.error("proc.processor.cant.instantiate", processorName); 5.13 return false; 5.14 } 5.15 + } catch(ClientCodeException e) { 5.16 + throw e; 5.17 } catch(Throwable t) { 5.18 throw new AnnotationProcessingError(t); 5.19 } 5.20 @@ -527,6 +530,8 @@ 5.21 supportedOptionNames.add(optionName); 5.22 } 5.23 5.24 + } catch (ClientCodeException e) { 5.25 + throw e; 5.26 } catch (Throwable t) { 5.27 throw new AnnotationProcessingError(t); 5.28 } 5.29 @@ -790,6 +795,8 @@ 5.30 ex.printStackTrace(new PrintWriter(out)); 5.31 log.error("proc.cant.access", ex.sym, ex.getDetailValue(), out.toString()); 5.32 return false; 5.33 + } catch (ClientCodeException e) { 5.34 + throw e; 5.35 } catch (Throwable t) { 5.36 throw new AnnotationProcessingError(t); 5.37 }
6.1 --- a/src/share/classes/com/sun/tools/javac/util/Log.java Fri Mar 25 07:39:30 2011 -0700 6.2 +++ b/src/share/classes/com/sun/tools/javac/util/Log.java Fri Mar 25 07:58:53 2011 -0700 6.3 @@ -425,13 +425,8 @@ 6.4 */ 6.5 protected void writeDiagnostic(JCDiagnostic diag) { 6.6 if (diagListener != null) { 6.7 - try { 6.8 - diagListener.report(diag); 6.9 - return; 6.10 - } 6.11 - catch (Throwable t) { 6.12 - throw new ClientCodeException(t); 6.13 - } 6.14 + diagListener.report(diag); 6.15 + return; 6.16 } 6.17 6.18 PrintWriter writer = getWriterForDiagnosticType(diag.getType());
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/test/tools/javac/api/T6437138.java Fri Mar 25 07:58:53 2011 -0700 7.3 @@ -0,0 +1,61 @@ 7.4 +/* 7.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7.7 + * 7.8 + * This code is free software; you can redistribute it and/or modify it 7.9 + * under the terms of the GNU General Public License version 2 only, as 7.10 + * published by the Free Software Foundation. 7.11 + * 7.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 7.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 7.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 7.15 + * version 2 for more details (a copy is included in the LICENSE file that 7.16 + * accompanied this code). 7.17 + * 7.18 + * You should have received a copy of the GNU General Public License version 7.19 + * 2 along with this work; if not, write to the Free Software Foundation, 7.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 7.21 + * 7.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 7.23 + * or visit www.oracle.com if you need additional information or have any 7.24 + * questions. 7.25 + */ 7.26 + 7.27 +/* 7.28 + * @test 7.29 + * @bug 6437138 7.30 + * @summary JSR 199: Compiler doesn't diagnose crash in user code 7.31 + */ 7.32 + 7.33 +import java.net.URI; 7.34 +import java.util.Arrays; 7.35 +import javax.tools.*; 7.36 +import static javax.tools.JavaFileObject.Kind.*; 7.37 + 7.38 + 7.39 +public class T6437138 { 7.40 + static class JFO extends SimpleJavaFileObject { 7.41 + public JFO(URI uri, JavaFileObject.Kind kind) { 7.42 + super(uri, kind); 7.43 + } 7.44 + // getCharContent not impl, will throw UnsupportedOperationException 7.45 + } 7.46 + 7.47 + public static void main(String... arg) throws Exception { 7.48 + try { 7.49 + JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); 7.50 + JavaFileObject jfo = new JFO(new URI("JFOTest04.java"),SOURCE); 7.51 + JavaCompiler.CompilationTask ct = javac.getTask(null,null,null,null, 7.52 + null, Arrays.asList(jfo)); 7.53 + ct.call(); 7.54 + throw new Exception("no exception thrown by JavaCompiler.CompilationTask"); 7.55 + } catch (RuntimeException e) { 7.56 + if (e.getCause() instanceof UnsupportedOperationException) { 7.57 + System.err.println("RuntimeException(UnsupportedOperationException) caught as expected"); 7.58 + return; 7.59 + } 7.60 + throw new Exception("unexpected exception caught", e); 7.61 + } 7.62 + } 7.63 +} 7.64 +
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/test/tools/javac/api/TestClientCodeWrapper.java Fri Mar 25 07:58:53 2011 -0700 8.3 @@ -0,0 +1,604 @@ 8.4 +/* 8.5 + * Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved. 8.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 8.7 + * 8.8 + * This code is free software; you can redistribute it and/or modify it 8.9 + * under the terms of the GNU General Public License version 2 only, as 8.10 + * published by the Free Software Foundation. 8.11 + * 8.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 8.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 8.15 + * version 2 for more details (a copy is included in the LICENSE file that 8.16 + * accompanied this code). 8.17 + * 8.18 + * You should have received a copy of the GNU General Public License version 8.19 + * 2 along with this work; if not, write to the Free Software Foundation, 8.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 8.21 + * 8.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 8.23 + * or visit www.oracle.com if you need additional information or have any 8.24 + * questions. 8.25 + */ 8.26 + 8.27 +/* 8.28 + * @test 8.29 + * @bug 6437138 6482554 8.30 + * @summary JSR 199: Compiler doesn't diagnose crash in user code 8.31 + * @library ../lib 8.32 + * @build JavacTestingAbstractProcessor TestClientCodeWrapper 8.33 + * @run main TestClientCodeWrapper 8.34 + */ 8.35 + 8.36 +import java.io.*; 8.37 +import java.lang.reflect.Method; 8.38 +import java.net.URI; 8.39 +import java.util.*; 8.40 +import javax.annotation.processing.*; 8.41 +import javax.lang.model.*; 8.42 +import javax.lang.model.element.*; 8.43 +import javax.tools.*; 8.44 +import com.sun.source.util.*; 8.45 +import com.sun.tools.javac.api.*; 8.46 +import javax.tools.JavaFileObject.Kind; 8.47 + 8.48 +public class TestClientCodeWrapper extends JavacTestingAbstractProcessor { 8.49 + public static void main(String... args) throws Exception { 8.50 + new TestClientCodeWrapper().run(); 8.51 + } 8.52 + 8.53 + /** 8.54 + * Run a series of compilations, each with a different user-provided object 8.55 + * configured to throw an exception when a specific method is invoked. 8.56 + * Then, verify the exception is thrown as expected. 8.57 + * 8.58 + * Some methods are not invoked from the compiler, and are excluded from the test. 8.59 + */ 8.60 + void run() throws Exception { 8.61 + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 8.62 + defaultFileManager = compiler.getStandardFileManager(null, null, null); 8.63 + 8.64 + for (Method m: getMethodsExcept(JavaFileManager.class, "close", "getJavaFileForInput")) { 8.65 + test(m); 8.66 + } 8.67 + 8.68 + for (Method m: getMethodsExcept(FileObject.class, "delete")) { 8.69 + test(m); 8.70 + } 8.71 + 8.72 + for (Method m: getMethods(JavaFileObject.class)) { 8.73 + test(m); 8.74 + } 8.75 + 8.76 + for (Method m: getMethodsExcept(Processor.class, "getCompletions")) { 8.77 + test(m); 8.78 + } 8.79 + 8.80 + for (Method m: DiagnosticListener.class.getDeclaredMethods()) { 8.81 + test(m); 8.82 + } 8.83 + 8.84 + for (Method m: TaskListener.class.getDeclaredMethods()) { 8.85 + test(m); 8.86 + } 8.87 + 8.88 + if (errors > 0) 8.89 + throw new Exception(errors + " errors occurred"); 8.90 + } 8.91 + 8.92 + /** Get a sorted set of the methods declared on a class. */ 8.93 + Set<Method> getMethods(Class<?> clazz) { 8.94 + return getMethodsExcept(clazz, new String[0]); 8.95 + } 8.96 + 8.97 + /** Get a sorted set of the methods declared on a class, excluding 8.98 + * specified methods by name. */ 8.99 + Set<Method> getMethodsExcept(Class<?> clazz, String... exclude) { 8.100 + Set<Method> methods = new TreeSet<Method>(new Comparator<Method>() { 8.101 + public int compare(Method m1, Method m2) { 8.102 + return m1.toString().compareTo(m2.toString()); 8.103 + } 8.104 + }); 8.105 + Set<String> e = new HashSet<String>(Arrays.asList(exclude)); 8.106 + for (Method m: clazz.getDeclaredMethods()) { 8.107 + if (!e.contains(m.getName())) 8.108 + methods.add(m); 8.109 + } 8.110 + return methods; 8.111 + } 8.112 + 8.113 + /** 8.114 + * Test a method in a user supplied component, to verify javac's handling 8.115 + * of any exceptions thrown by that method. 8.116 + */ 8.117 + void test(Method m) throws Exception { 8.118 + testNum++; 8.119 + 8.120 + File extDirs = new File("empty-extdirs"); 8.121 + extDirs.mkdirs(); 8.122 + 8.123 + File testClasses = new File("test" + testNum); 8.124 + testClasses.mkdirs(); 8.125 + defaultFileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(testClasses)); 8.126 + 8.127 + System.err.println("test " + testNum + ": " 8.128 + + m.getDeclaringClass().getSimpleName() + "." + m.getName()); 8.129 + 8.130 + StringWriter sw = new StringWriter(); 8.131 + PrintWriter pw = new PrintWriter(sw); 8.132 + 8.133 + List<String> javacOptions = Arrays.asList( 8.134 + "-extdirs", extDirs.getPath(), // for use by filemanager handleOption 8.135 + "-processor", TestClientCodeWrapper.class.getName() 8.136 + ); 8.137 + 8.138 + List<String> classes = Collections.emptyList(); 8.139 + 8.140 + JavacTool tool = JavacTool.create(); 8.141 + try { 8.142 + JavacTask task = tool.getTask(pw, 8.143 + getFileManager(m, defaultFileManager), 8.144 + getDiagnosticListener(m, pw), 8.145 + javacOptions, 8.146 + classes, 8.147 + getCompilationUnits(m)); 8.148 + 8.149 + if (isDeclaredIn(m, Processor.class)) 8.150 + task.setProcessors(getProcessors(m)); 8.151 + 8.152 + if (isDeclaredIn(m, TaskListener.class)) 8.153 + task.setTaskListener(getTaskListener(m, pw)); 8.154 + 8.155 + boolean ok = task.call(); 8.156 + error("compilation " + (ok ? "succeeded" : "failed") + " unexpectedly"); 8.157 + } catch (RuntimeException e) { 8.158 + System.err.println("caught " + e); 8.159 + if (e.getClass() == RuntimeException.class) { 8.160 + Throwable cause = e.getCause(); 8.161 + if (cause instanceof UserError) { 8.162 + String expect = m.getName(); 8.163 + String found = cause.getMessage(); 8.164 + checkEqual("exception messaqe", expect, found); 8.165 + } else { 8.166 + cause.printStackTrace(System.err); 8.167 + error("Unexpected exception: " + cause); 8.168 + } 8.169 + } else { 8.170 + e.printStackTrace(System.err); 8.171 + error("Unexpected exception: " + e); 8.172 + } 8.173 + } 8.174 + 8.175 + pw.close(); 8.176 + String out = sw.toString(); 8.177 + System.err.println(out); 8.178 + } 8.179 + 8.180 + /** Get a file manager to use for the test compilation. */ 8.181 + JavaFileManager getFileManager(Method m, JavaFileManager defaultFileManager) { 8.182 + return isDeclaredIn(m, JavaFileManager.class, FileObject.class, JavaFileObject.class) 8.183 + ? new UserFileManager(m, defaultFileManager) 8.184 + : defaultFileManager; 8.185 + } 8.186 + 8.187 + /** Get a diagnostic listener to use for the test compilation. */ 8.188 + DiagnosticListener<JavaFileObject> getDiagnosticListener(Method m, PrintWriter out) { 8.189 + return isDeclaredIn(m, DiagnosticListener.class) 8.190 + ? new UserDiagnosticListener(m, out) 8.191 + : null; 8.192 + } 8.193 + 8.194 + /** Get a set of file objects to use for the test compilation. */ 8.195 + Iterable<? extends JavaFileObject> getCompilationUnits(Method m) { 8.196 + File testSrc = new File(System.getProperty("test.src")); 8.197 + File thisSrc = new File(testSrc, TestClientCodeWrapper.class.getName() + ".java"); 8.198 + Iterable<? extends JavaFileObject> files = defaultFileManager.getJavaFileObjects(thisSrc); 8.199 + if (isDeclaredIn(m, FileObject.class, JavaFileObject.class)) 8.200 + return Arrays.asList(new UserFileObject(m, files.iterator().next())); 8.201 + else 8.202 + return files; 8.203 + } 8.204 + 8.205 + /** Get a set of annotation processors to use for the test compilation. */ 8.206 + Iterable<? extends Processor> getProcessors(Method m) { 8.207 + return Arrays.asList(new UserProcessor(m)); 8.208 + } 8.209 + 8.210 + /** Get a task listener to use for the test compilation. */ 8.211 + TaskListener getTaskListener(Method m, PrintWriter out) { 8.212 + return new UserTaskListener(m, out); 8.213 + } 8.214 + 8.215 + /** Check if two values are .equal, and report an error if not. */ 8.216 + <T> void checkEqual(String label, T expect, T found) { 8.217 + if (!expect.equals(found)) 8.218 + error("Unexpected value for " + label + ": " + found + "; expected: " + expect); 8.219 + } 8.220 + 8.221 + /** Report an error. */ 8.222 + void error(String msg) { 8.223 + System.err.println("Error: " + msg); 8.224 + errors++; 8.225 + } 8.226 + 8.227 + /** Check if a method is declared in any of a set of classes */ 8.228 + static boolean isDeclaredIn(Method m, Class<?>... classes) { 8.229 + Class<?> dc = m.getDeclaringClass(); 8.230 + for (Class<?> c: classes) { 8.231 + if (c == dc) return true; 8.232 + } 8.233 + return false; 8.234 + } 8.235 + 8.236 + /** Throw an intentional error if the method has a given name. */ 8.237 + static void throwUserExceptionIfNeeded(Method m, String name) { 8.238 + if (m != null && m.getName().equals(name)) 8.239 + throw new UserError(name); 8.240 + } 8.241 + 8.242 + StandardJavaFileManager defaultFileManager; 8.243 + int testNum; 8.244 + int errors; 8.245 + 8.246 + //-------------------------------------------------------------------------- 8.247 + 8.248 + /** 8.249 + * Processor used to trigger use of methods not normally used by javac. 8.250 + */ 8.251 + @Override 8.252 + public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 8.253 + boolean firstRound = false; 8.254 + for (Element e: roundEnv.getRootElements()) { 8.255 + if (e.getSimpleName().contentEquals(TestClientCodeWrapper.class.getSimpleName())) 8.256 + firstRound = true; 8.257 + } 8.258 + if (firstRound) { 8.259 + try { 8.260 + FileObject f1 = filer.getResource(StandardLocation.CLASS_PATH, "", 8.261 + TestClientCodeWrapper.class.getName() + ".java"); 8.262 + f1.openInputStream().close(); 8.263 + f1.openReader(false).close(); 8.264 + 8.265 + FileObject f2 = filer.createResource( 8.266 + StandardLocation.CLASS_OUTPUT, "", "f2.txt", (Element[]) null); 8.267 + f2.openOutputStream().close(); 8.268 + 8.269 + FileObject f3 = filer.createResource( 8.270 + StandardLocation.CLASS_OUTPUT, "", "f3.txt", (Element[]) null); 8.271 + f3.openWriter().close(); 8.272 + 8.273 + JavaFileObject f4 = filer.createSourceFile("f4", (Element[]) null); 8.274 + f4.openWriter().close(); 8.275 + f4.getNestingKind(); 8.276 + f4.getAccessLevel(); 8.277 + 8.278 + messager.printMessage(Diagnostic.Kind.NOTE, "informational note", 8.279 + roundEnv.getRootElements().iterator().next()); 8.280 + 8.281 + } catch (IOException e) { 8.282 + throw new UserError(e); 8.283 + } 8.284 + } 8.285 + return true; 8.286 + } 8.287 + 8.288 + //-------------------------------------------------------------------------- 8.289 + 8.290 + // <editor-fold defaultstate="collapsed" desc="User classes"> 8.291 + 8.292 + static class UserError extends Error { 8.293 + private static final long serialVersionUID = 1L; 8.294 + UserError(String msg) { 8.295 + super(msg); 8.296 + } 8.297 + UserError(Throwable t) { 8.298 + super(t); 8.299 + } 8.300 + } 8.301 + 8.302 + static class UserFileManager extends ForwardingJavaFileManager<JavaFileManager> { 8.303 + Method fileManagerMethod; 8.304 + Method fileObjectMethod; 8.305 + 8.306 + UserFileManager(Method m, JavaFileManager delegate) { 8.307 + super(delegate); 8.308 + if (isDeclaredIn(m, JavaFileManager.class)) { 8.309 + fileManagerMethod = m; 8.310 + } else if (isDeclaredIn(m, FileObject.class, JavaFileObject.class)) { 8.311 + fileObjectMethod = m; 8.312 + } else 8.313 + assert false; 8.314 + } 8.315 + 8.316 + @Override 8.317 + public ClassLoader getClassLoader(Location location) { 8.318 + throwUserExceptionIfNeeded(fileManagerMethod, "getClassLoader"); 8.319 + return super.getClassLoader(location); 8.320 + } 8.321 + 8.322 + @Override 8.323 + public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse) throws IOException { 8.324 + throwUserExceptionIfNeeded(fileManagerMethod, "list"); 8.325 + return wrap(super.list(location, packageName, kinds, recurse)); 8.326 + } 8.327 + 8.328 + @Override 8.329 + public String inferBinaryName(Location location, JavaFileObject file) { 8.330 + throwUserExceptionIfNeeded(fileManagerMethod, "inferBinaryName"); 8.331 + return super.inferBinaryName(location, unwrap(file)); 8.332 + } 8.333 + 8.334 + @Override 8.335 + public boolean isSameFile(FileObject a, FileObject b) { 8.336 + throwUserExceptionIfNeeded(fileManagerMethod, "isSameFile"); 8.337 + return super.isSameFile(unwrap(a), unwrap(b)); 8.338 + } 8.339 + 8.340 + @Override 8.341 + public boolean handleOption(String current, Iterator<String> remaining) { 8.342 + throwUserExceptionIfNeeded(fileManagerMethod, "handleOption"); 8.343 + return super.handleOption(current, remaining); 8.344 + } 8.345 + 8.346 + @Override 8.347 + public boolean hasLocation(Location location) { 8.348 + throwUserExceptionIfNeeded(fileManagerMethod, "hasLocation"); 8.349 + return super.hasLocation(location); 8.350 + } 8.351 + 8.352 + @Override 8.353 + public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException { 8.354 + throwUserExceptionIfNeeded(fileManagerMethod, "getJavaFileForInput"); 8.355 + return wrap(super.getJavaFileForInput(location, className, kind)); 8.356 + } 8.357 + 8.358 + @Override 8.359 + public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException { 8.360 + throwUserExceptionIfNeeded(fileManagerMethod, "getJavaFileForOutput"); 8.361 + return wrap(super.getJavaFileForOutput(location, className, kind, sibling)); 8.362 + } 8.363 + 8.364 + @Override 8.365 + public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException { 8.366 + throwUserExceptionIfNeeded(fileManagerMethod, "getFileForInput"); 8.367 + return wrap(super.getFileForInput(location, packageName, relativeName)); 8.368 + } 8.369 + 8.370 + @Override 8.371 + public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException { 8.372 + throwUserExceptionIfNeeded(fileManagerMethod, "getFileForOutput"); 8.373 + return wrap(super.getFileForOutput(location, packageName, relativeName, sibling)); 8.374 + } 8.375 + 8.376 + @Override 8.377 + public void flush() throws IOException { 8.378 + throwUserExceptionIfNeeded(fileManagerMethod, "flush"); 8.379 + super.flush(); 8.380 + } 8.381 + 8.382 + @Override 8.383 + public void close() throws IOException { 8.384 + throwUserExceptionIfNeeded(fileManagerMethod, "close"); 8.385 + super.close(); 8.386 + } 8.387 + 8.388 + @Override 8.389 + public int isSupportedOption(String option) { 8.390 + throwUserExceptionIfNeeded(fileManagerMethod, "isSupportedOption"); 8.391 + return super.isSupportedOption(option); 8.392 + } 8.393 + 8.394 + public FileObject wrap(FileObject fo) { 8.395 + if (fileObjectMethod == null) 8.396 + return fo; 8.397 + return new UserFileObject(fileObjectMethod, (JavaFileObject)fo); 8.398 + } 8.399 + 8.400 + FileObject unwrap(FileObject fo) { 8.401 + if (fo instanceof UserFileObject) 8.402 + return ((UserFileObject) fo).unwrap(); 8.403 + else 8.404 + return fo; 8.405 + } 8.406 + 8.407 + public JavaFileObject wrap(JavaFileObject fo) { 8.408 + if (fileObjectMethod == null) 8.409 + return fo; 8.410 + return new UserFileObject(fileObjectMethod, fo); 8.411 + } 8.412 + 8.413 + public Iterable<JavaFileObject> wrap(Iterable<? extends JavaFileObject> list) { 8.414 + List<JavaFileObject> wrapped = new ArrayList<JavaFileObject>(); 8.415 + for (JavaFileObject fo : list) 8.416 + wrapped.add(wrap(fo)); 8.417 + return Collections.unmodifiableList(wrapped); 8.418 + } 8.419 + 8.420 + JavaFileObject unwrap(JavaFileObject fo) { 8.421 + if (fo instanceof UserFileObject) 8.422 + return ((UserFileObject) fo).unwrap(); 8.423 + else 8.424 + return fo; 8.425 + } 8.426 + } 8.427 + 8.428 + static class UserFileObject extends ForwardingJavaFileObject<JavaFileObject> { 8.429 + Method method; 8.430 + 8.431 + UserFileObject(Method m, JavaFileObject delegate) { 8.432 + super(delegate); 8.433 + assert isDeclaredIn(m, FileObject.class, JavaFileObject.class); 8.434 + this.method = m; 8.435 + } 8.436 + 8.437 + JavaFileObject unwrap() { 8.438 + return fileObject; 8.439 + } 8.440 + 8.441 + @Override 8.442 + public Kind getKind() { 8.443 + throwUserExceptionIfNeeded(method, "getKind"); 8.444 + return super.getKind(); 8.445 + } 8.446 + 8.447 + @Override 8.448 + public boolean isNameCompatible(String simpleName, Kind kind) { 8.449 + throwUserExceptionIfNeeded(method, "isNameCompatible"); 8.450 + return super.isNameCompatible(simpleName, kind); 8.451 + } 8.452 + 8.453 + @Override 8.454 + public NestingKind getNestingKind() { 8.455 + throwUserExceptionIfNeeded(method, "getNestingKind"); 8.456 + return super.getNestingKind(); 8.457 + } 8.458 + 8.459 + @Override 8.460 + public Modifier getAccessLevel() { 8.461 + throwUserExceptionIfNeeded(method, "getAccessLevel"); 8.462 + return super.getAccessLevel(); 8.463 + } 8.464 + 8.465 + @Override 8.466 + public URI toUri() { 8.467 + throwUserExceptionIfNeeded(method, "toUri"); 8.468 + return super.toUri(); 8.469 + } 8.470 + 8.471 + @Override 8.472 + public String getName() { 8.473 + throwUserExceptionIfNeeded(method, "getName"); 8.474 + return super.getName(); 8.475 + } 8.476 + 8.477 + @Override 8.478 + public InputStream openInputStream() throws IOException { 8.479 + throwUserExceptionIfNeeded(method, "openInputStream"); 8.480 + return super.openInputStream(); 8.481 + } 8.482 + 8.483 + @Override 8.484 + public OutputStream openOutputStream() throws IOException { 8.485 + throwUserExceptionIfNeeded(method, "openOutputStream"); 8.486 + return super.openOutputStream(); 8.487 + } 8.488 + 8.489 + @Override 8.490 + public Reader openReader(boolean ignoreEncodingErrors) throws IOException { 8.491 + throwUserExceptionIfNeeded(method, "openReader"); 8.492 + return super.openReader(ignoreEncodingErrors); 8.493 + } 8.494 + 8.495 + @Override 8.496 + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { 8.497 + throwUserExceptionIfNeeded(method, "getCharContent"); 8.498 + return super.getCharContent(ignoreEncodingErrors); 8.499 + } 8.500 + 8.501 + @Override 8.502 + public Writer openWriter() throws IOException { 8.503 + throwUserExceptionIfNeeded(method, "openWriter"); 8.504 + return super.openWriter(); 8.505 + } 8.506 + 8.507 + @Override 8.508 + public long getLastModified() { 8.509 + throwUserExceptionIfNeeded(method, "getLastModified"); 8.510 + return super.getLastModified(); 8.511 + } 8.512 + 8.513 + @Override 8.514 + public boolean delete() { 8.515 + throwUserExceptionIfNeeded(method, "delete"); 8.516 + return super.delete(); 8.517 + } 8.518 + 8.519 + } 8.520 + 8.521 + static class UserProcessor extends JavacTestingAbstractProcessor { 8.522 + Method method; 8.523 + 8.524 + UserProcessor(Method m) { 8.525 + assert isDeclaredIn(m, Processor.class); 8.526 + method = m; 8.527 + } 8.528 + 8.529 + @Override 8.530 + public Set<String> getSupportedOptions() { 8.531 + throwUserExceptionIfNeeded(method, "getSupportedOptions"); 8.532 + return super.getSupportedOptions(); 8.533 + } 8.534 + 8.535 + @Override 8.536 + public Set<String> getSupportedAnnotationTypes() { 8.537 + throwUserExceptionIfNeeded(method, "getSupportedAnnotationTypes"); 8.538 + return super.getSupportedAnnotationTypes(); 8.539 + } 8.540 + 8.541 + @Override 8.542 + public SourceVersion getSupportedSourceVersion() { 8.543 + throwUserExceptionIfNeeded(method, "getSupportedSourceVersion"); 8.544 + return super.getSupportedSourceVersion(); 8.545 + } 8.546 + 8.547 + @Override 8.548 + public void init(ProcessingEnvironment processingEnv) { 8.549 + throwUserExceptionIfNeeded(method, "init"); 8.550 + super.init(processingEnv); 8.551 + } 8.552 + 8.553 + @Override 8.554 + public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 8.555 + throwUserExceptionIfNeeded(method, "process"); 8.556 + return true; 8.557 + } 8.558 + 8.559 + @Override 8.560 + public Iterable<? extends Completion> getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) { 8.561 + throwUserExceptionIfNeeded(method, "getCompletions"); 8.562 + return super.getCompletions(element, annotation, member, userText); 8.563 + } 8.564 + } 8.565 + 8.566 + static class UserDiagnosticListener implements DiagnosticListener<JavaFileObject> { 8.567 + Method method; 8.568 + PrintWriter out; 8.569 + 8.570 + UserDiagnosticListener(Method m, PrintWriter out) { 8.571 + assert isDeclaredIn(m, DiagnosticListener.class); 8.572 + this.method = m; 8.573 + this.out = out; 8.574 + } 8.575 + 8.576 + @Override 8.577 + public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 8.578 + throwUserExceptionIfNeeded(method, "report"); 8.579 + out.println("report: " + diagnostic); 8.580 + } 8.581 + } 8.582 + 8.583 + static class UserTaskListener implements TaskListener { 8.584 + Method method; 8.585 + PrintWriter out; 8.586 + 8.587 + UserTaskListener(Method m, PrintWriter out) { 8.588 + assert isDeclaredIn(m, TaskListener.class); 8.589 + this.method = m; 8.590 + this.out = out; 8.591 + } 8.592 + 8.593 + @Override 8.594 + public void started(TaskEvent e) { 8.595 + throwUserExceptionIfNeeded(method, "started"); 8.596 + out.println("started: " + e); 8.597 + } 8.598 + 8.599 + @Override 8.600 + public void finished(TaskEvent e) { 8.601 + throwUserExceptionIfNeeded(method, "finished"); 8.602 + out.println("finished: " + e); 8.603 + } 8.604 + } 8.605 + 8.606 + // </editor-fold> 8.607 +}