src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java

Print this page
rev 378 : 6548708: Annotation processing should free service loader if there are no processors
Reviewed-by: jjg


 270     private void handleException(String key, Exception e) {
 271         if (e != null) {
 272             log.error(key, e.getLocalizedMessage());
 273             throw new Abort(e);
 274         } else {
 275             log.error(key);
 276             throw new Abort();
 277         }
 278     }
 279 
 280     /**
 281      * Use a service loader appropriate for the platform to provide an
 282      * iterator over annotations processors.  If
 283      * java.util.ServiceLoader is present use it, otherwise, use
 284      * sun.misc.Service, otherwise fail if a loader is needed.
 285      */
 286     private class ServiceIterator implements Iterator<Processor> {
 287         // The to-be-wrapped iterator.
 288         private Iterator<?> iterator;
 289         private Log log;



 290 
 291         ServiceIterator(ClassLoader classLoader, Log log) {
 292             Class<?> loaderClass;
 293             String loadMethodName;
 294             boolean jusl;
 295 
 296             this.log = log;
 297             try {
 298                 try {
 299                     loaderClass = Class.forName("java.util.ServiceLoader");
 300                     loadMethodName = "load";
 301                     jusl = true;
 302                 } catch (ClassNotFoundException cnfe) {
 303                     try {
 304                         loaderClass = Class.forName("sun.misc.Service");
 305                         loadMethodName = "providers";
 306                         jusl = false;
 307                     } catch (ClassNotFoundException cnfe2) {
 308                         // Fail softly if a loader is not actually needed.
 309                         this.iterator = handleServiceLoaderUnavailability("proc.no.service",
 310                                                                           null);
 311                         return;
 312                     }
 313                 }
 314 
 315                 // java.util.ServiceLoader.load or sun.misc.Service.providers
 316                 Method loadMethod = loaderClass.getMethod(loadMethodName,
 317                                                           Class.class,
 318                                                           ClassLoader.class);
 319 
 320                 Object result = loadMethod.invoke(null,
 321                                                   Processor.class,
 322                                                   classLoader);
 323 
 324                 // For java.util.ServiceLoader, we have to call another
 325                 // method to get the iterator.
 326                 if (jusl) {

 327                     Method m = loaderClass.getMethod("iterator");
 328                     result = m.invoke(result); // serviceLoader.iterator();
 329                 }
 330 
 331                 // The result should now be an iterator.
 332                 this.iterator = (Iterator<?>) result;
 333             } catch (Throwable t) {
 334                 log.error("proc.service.problem");
 335                 throw new Abort(t);
 336             }
 337         }
 338 
 339         public boolean hasNext() {
 340             try {
 341                 return iterator.hasNext();
 342             } catch (Throwable t) {
 343                 if ("ServiceConfigurationError".
 344                     equals(t.getClass().getSimpleName())) {
 345                     log.error("proc.bad.config.file", t.getLocalizedMessage());
 346                 }


 348             }
 349         }
 350 
 351         public Processor next() {
 352             try {
 353                 return (Processor)(iterator.next());
 354             } catch (Throwable t) {
 355                 if ("ServiceConfigurationError".
 356                     equals(t.getClass().getSimpleName())) {
 357                     log.error("proc.bad.config.file", t.getLocalizedMessage());
 358                 } else {
 359                     log.error("proc.processor.constructor.error", t.getLocalizedMessage());
 360                 }
 361                 throw new Abort(t);
 362             }
 363         }
 364 
 365         public void remove() {
 366             throw new UnsupportedOperationException();
 367         }












 368     }
 369 
 370 
 371     private static class NameProcessIterator implements Iterator<Processor> {
 372         Processor nextProc = null;
 373         Iterator<String> names;
 374         ClassLoader processorCL;
 375         Log log;
 376 
 377         NameProcessIterator(String names, ClassLoader processorCL, Log log) {
 378             this.names = Arrays.asList(names.split(",")).iterator();
 379             this.processorCL = processorCL;
 380             this.log = log;
 381         }
 382 
 383         public boolean hasNext() {
 384             if (nextProc != null)
 385                 return true;
 386             else {
 387                 if (!names.hasNext())


 535                 if (p.matcher(annotationName).matches())
 536                     return true;
 537             }
 538             return false;
 539         }
 540 
 541         /**
 542          * Remove options that are matched by this processor.
 543          */
 544         public void removeSupportedOptions(Set<String> unmatchedProcessorOptions) {
 545             unmatchedProcessorOptions.removeAll(supportedOptionNames);
 546         }
 547     }
 548 
 549     // TODO: These two classes can probably be rewritten better...
 550     /**
 551      * This class holds information about the processors that have
 552      * been discoverd so far as well as the means to discover more, if
 553      * necessary.  A single iterator should be used per round of
 554      * annotation processing.  The iterator first visits already
 555      * discovered processors then fails over to the service provided
 556      * mechanism if additional queries are made.
 557      */
 558     class DiscoveredProcessors implements Iterable<ProcessorState> {
 559 
 560         class ProcessorStateIterator implements Iterator<ProcessorState> {
 561             DiscoveredProcessors psi;
 562             Iterator<ProcessorState> innerIter;
 563             boolean onProcInterator;
 564 
 565             ProcessorStateIterator(DiscoveredProcessors psi) {
 566                 this.psi = psi;
 567                 this.innerIter = psi.procStateList.iterator();
 568                 this.onProcInterator = false;
 569             }
 570 
 571             public ProcessorState next() {
 572                 if (!onProcInterator) {
 573                     if (innerIter.hasNext())
 574                         return innerIter.next();
 575                     else


 607                     while(innerIter.hasNext()) {
 608                         ProcessorState ps = innerIter.next();
 609                         if (ps.contributed)
 610                             callProcessor(ps.processor, emptyTypeElements, re);
 611                     }
 612                 }
 613             }
 614         }
 615 
 616         Iterator<? extends Processor> processorIterator;
 617         ArrayList<ProcessorState>  procStateList;
 618 
 619         public ProcessorStateIterator iterator() {
 620             return new ProcessorStateIterator(this);
 621         }
 622 
 623         DiscoveredProcessors(Iterator<? extends Processor> processorIterator) {
 624             this.processorIterator = processorIterator;
 625             this.procStateList = new ArrayList<ProcessorState>();
 626         }










 627     }
 628 
 629     private void discoverAndRunProcs(Context context,
 630                                      Set<TypeElement> annotationsPresent,
 631                                      List<ClassSymbol> topLevelClasses,
 632                                      List<PackageSymbol> packageInfoFiles) {
 633         // Writer for -XprintRounds and -XprintProcessorInfo data
 634         PrintWriter xout = context.get(Log.outKey);
 635 
 636         Map<String, TypeElement> unmatchedAnnotations =
 637             new HashMap<String, TypeElement>(annotationsPresent.size());
 638 
 639         for(TypeElement a  : annotationsPresent) {
 640                 unmatchedAnnotations.put(a.getQualifiedName().toString(),
 641                                          a);
 642         }
 643 
 644         // Give "*" processors a chance to match
 645         if (unmatchedAnnotations.size() == 0)
 646             unmatchedAnnotations.put("", null);


1006         ClassReader reader = ClassReader.instance(currentContext);
1007         Names names = Names.instance(currentContext);
1008         ListBuffer<ClassSymbol> list = new ListBuffer<ClassSymbol>();
1009 
1010         for (Map.Entry<String,JavaFileObject> entry : filer.getGeneratedClasses().entrySet()) {
1011             Name name = names.fromString(entry.getKey());
1012             JavaFileObject file = entry.getValue();
1013             if (file.getKind() != JavaFileObject.Kind.CLASS)
1014                 throw new AssertionError(file);
1015             ClassSymbol cs = reader.enterClass(name, file);
1016             list.append(cs);
1017         }
1018         return list;
1019     }
1020 
1021     /**
1022      * Free resources related to annotation processing.
1023      */
1024     public void close() throws IOException {
1025         filer.close();


1026         discoveredProcs = null;
1027         if (processorClassLoader != null && processorClassLoader instanceof Closeable)
1028             ((Closeable) processorClassLoader).close();
1029     }
1030 
1031     private List<ClassSymbol> getTopLevelClasses(List<? extends JCCompilationUnit> units) {
1032         List<ClassSymbol> classes = List.nil();
1033         for (JCCompilationUnit unit : units) {
1034             for (JCTree node : unit.defs) {
1035                 if (node.getTag() == JCTree.CLASSDEF) {
1036                     classes = classes.prepend(((JCClassDecl) node).sym);
1037                 }
1038             }
1039         }
1040         return classes.reverse();
1041     }
1042 
1043     private List<PackageSymbol> getPackageInfoFiles(List<? extends JCCompilationUnit> units) {
1044         List<PackageSymbol> packages = List.nil();
1045         for (JCCompilationUnit unit : units) {




 270     private void handleException(String key, Exception e) {
 271         if (e != null) {
 272             log.error(key, e.getLocalizedMessage());
 273             throw new Abort(e);
 274         } else {
 275             log.error(key);
 276             throw new Abort();
 277         }
 278     }
 279 
 280     /**
 281      * Use a service loader appropriate for the platform to provide an
 282      * iterator over annotations processors.  If
 283      * java.util.ServiceLoader is present use it, otherwise, use
 284      * sun.misc.Service, otherwise fail if a loader is needed.
 285      */
 286     private class ServiceIterator implements Iterator<Processor> {
 287         // The to-be-wrapped iterator.
 288         private Iterator<?> iterator;
 289         private Log log;
 290         private Class<?> loaderClass;
 291         private boolean jusl;
 292         private Object loader;
 293 
 294         ServiceIterator(ClassLoader classLoader, Log log) {

 295             String loadMethodName;

 296 
 297             this.log = log;
 298             try {
 299                 try {
 300                     loaderClass = Class.forName("java.util.ServiceLoader");
 301                     loadMethodName = "load";
 302                     jusl = true;
 303                 } catch (ClassNotFoundException cnfe) {
 304                     try {
 305                         loaderClass = Class.forName("sun.misc.Service");
 306                         loadMethodName = "providers";
 307                         jusl = false;
 308                     } catch (ClassNotFoundException cnfe2) {
 309                         // Fail softly if a loader is not actually needed.
 310                         this.iterator = handleServiceLoaderUnavailability("proc.no.service",
 311                                                                           null);
 312                         return;
 313                     }
 314                 }
 315 
 316                 // java.util.ServiceLoader.load or sun.misc.Service.providers
 317                 Method loadMethod = loaderClass.getMethod(loadMethodName,
 318                                                           Class.class,
 319                                                           ClassLoader.class);
 320 
 321                 Object result = loadMethod.invoke(null,
 322                                                   Processor.class,
 323                                                   classLoader);
 324 
 325                 // For java.util.ServiceLoader, we have to call another
 326                 // method to get the iterator.
 327                 if (jusl) {
 328                     loader = result; // Store ServiceLoader to call reload later
 329                     Method m = loaderClass.getMethod("iterator");
 330                     result = m.invoke(result); // serviceLoader.iterator();
 331                 }
 332 
 333                 // The result should now be an iterator.
 334                 this.iterator = (Iterator<?>) result;
 335             } catch (Throwable t) {
 336                 log.error("proc.service.problem");
 337                 throw new Abort(t);
 338             }
 339         }
 340 
 341         public boolean hasNext() {
 342             try {
 343                 return iterator.hasNext();
 344             } catch (Throwable t) {
 345                 if ("ServiceConfigurationError".
 346                     equals(t.getClass().getSimpleName())) {
 347                     log.error("proc.bad.config.file", t.getLocalizedMessage());
 348                 }


 350             }
 351         }
 352 
 353         public Processor next() {
 354             try {
 355                 return (Processor)(iterator.next());
 356             } catch (Throwable t) {
 357                 if ("ServiceConfigurationError".
 358                     equals(t.getClass().getSimpleName())) {
 359                     log.error("proc.bad.config.file", t.getLocalizedMessage());
 360                 } else {
 361                     log.error("proc.processor.constructor.error", t.getLocalizedMessage());
 362                 }
 363                 throw new Abort(t);
 364             }
 365         }
 366 
 367         public void remove() {
 368             throw new UnsupportedOperationException();
 369         }
 370 
 371         public void close() {
 372             if (jusl) {
 373                 try {
 374                     // Call java.util.ServiceLoader.reload
 375                     Method reloadMethod = loaderClass.getMethod("reload");
 376                     reloadMethod.invoke(loader);
 377                 } catch(Exception e) {
 378                     ; // Ignore problems during a call to reload.
 379                 }
 380             }
 381         }
 382     }
 383 
 384 
 385     private static class NameProcessIterator implements Iterator<Processor> {
 386         Processor nextProc = null;
 387         Iterator<String> names;
 388         ClassLoader processorCL;
 389         Log log;
 390 
 391         NameProcessIterator(String names, ClassLoader processorCL, Log log) {
 392             this.names = Arrays.asList(names.split(",")).iterator();
 393             this.processorCL = processorCL;
 394             this.log = log;
 395         }
 396 
 397         public boolean hasNext() {
 398             if (nextProc != null)
 399                 return true;
 400             else {
 401                 if (!names.hasNext())


 549                 if (p.matcher(annotationName).matches())
 550                     return true;
 551             }
 552             return false;
 553         }
 554 
 555         /**
 556          * Remove options that are matched by this processor.
 557          */
 558         public void removeSupportedOptions(Set<String> unmatchedProcessorOptions) {
 559             unmatchedProcessorOptions.removeAll(supportedOptionNames);
 560         }
 561     }
 562 
 563     // TODO: These two classes can probably be rewritten better...
 564     /**
 565      * This class holds information about the processors that have
 566      * been discoverd so far as well as the means to discover more, if
 567      * necessary.  A single iterator should be used per round of
 568      * annotation processing.  The iterator first visits already
 569      * discovered processors then fails over to the service provider
 570      * mechanism if additional queries are made.
 571      */
 572     class DiscoveredProcessors implements Iterable<ProcessorState> {
 573 
 574         class ProcessorStateIterator implements Iterator<ProcessorState> {
 575             DiscoveredProcessors psi;
 576             Iterator<ProcessorState> innerIter;
 577             boolean onProcInterator;
 578 
 579             ProcessorStateIterator(DiscoveredProcessors psi) {
 580                 this.psi = psi;
 581                 this.innerIter = psi.procStateList.iterator();
 582                 this.onProcInterator = false;
 583             }
 584 
 585             public ProcessorState next() {
 586                 if (!onProcInterator) {
 587                     if (innerIter.hasNext())
 588                         return innerIter.next();
 589                     else


 621                     while(innerIter.hasNext()) {
 622                         ProcessorState ps = innerIter.next();
 623                         if (ps.contributed)
 624                             callProcessor(ps.processor, emptyTypeElements, re);
 625                     }
 626                 }
 627             }
 628         }
 629 
 630         Iterator<? extends Processor> processorIterator;
 631         ArrayList<ProcessorState>  procStateList;
 632 
 633         public ProcessorStateIterator iterator() {
 634             return new ProcessorStateIterator(this);
 635         }
 636 
 637         DiscoveredProcessors(Iterator<? extends Processor> processorIterator) {
 638             this.processorIterator = processorIterator;
 639             this.procStateList = new ArrayList<ProcessorState>();
 640         }
 641 
 642         /**
 643          * Free jar files, etc. if using a service loader.
 644          */
 645         public void close() {
 646             if (processorIterator != null &&
 647                 processorIterator instanceof ServiceIterator) {
 648                 ((ServiceIterator) processorIterator).close();
 649             }
 650         }
 651     }
 652 
 653     private void discoverAndRunProcs(Context context,
 654                                      Set<TypeElement> annotationsPresent,
 655                                      List<ClassSymbol> topLevelClasses,
 656                                      List<PackageSymbol> packageInfoFiles) {
 657         // Writer for -XprintRounds and -XprintProcessorInfo data
 658         PrintWriter xout = context.get(Log.outKey);
 659 
 660         Map<String, TypeElement> unmatchedAnnotations =
 661             new HashMap<String, TypeElement>(annotationsPresent.size());
 662 
 663         for(TypeElement a  : annotationsPresent) {
 664                 unmatchedAnnotations.put(a.getQualifiedName().toString(),
 665                                          a);
 666         }
 667 
 668         // Give "*" processors a chance to match
 669         if (unmatchedAnnotations.size() == 0)
 670             unmatchedAnnotations.put("", null);


1030         ClassReader reader = ClassReader.instance(currentContext);
1031         Names names = Names.instance(currentContext);
1032         ListBuffer<ClassSymbol> list = new ListBuffer<ClassSymbol>();
1033 
1034         for (Map.Entry<String,JavaFileObject> entry : filer.getGeneratedClasses().entrySet()) {
1035             Name name = names.fromString(entry.getKey());
1036             JavaFileObject file = entry.getValue();
1037             if (file.getKind() != JavaFileObject.Kind.CLASS)
1038                 throw new AssertionError(file);
1039             ClassSymbol cs = reader.enterClass(name, file);
1040             list.append(cs);
1041         }
1042         return list;
1043     }
1044 
1045     /**
1046      * Free resources related to annotation processing.
1047      */
1048     public void close() throws IOException {
1049         filer.close();
1050         if (discoveredProcs != null) // Make calling close idempotent
1051             discoveredProcs.close();
1052         discoveredProcs = null;
1053         if (processorClassLoader != null && processorClassLoader instanceof Closeable)
1054             ((Closeable) processorClassLoader).close();
1055     }
1056 
1057     private List<ClassSymbol> getTopLevelClasses(List<? extends JCCompilationUnit> units) {
1058         List<ClassSymbol> classes = List.nil();
1059         for (JCCompilationUnit unit : units) {
1060             for (JCTree node : unit.defs) {
1061                 if (node.getTag() == JCTree.CLASSDEF) {
1062                     classes = classes.prepend(((JCClassDecl) node).sym);
1063                 }
1064             }
1065         }
1066         return classes.reverse();
1067     }
1068 
1069     private List<PackageSymbol> getPackageInfoFiles(List<? extends JCCompilationUnit> units) {
1070         List<PackageSymbol> packages = List.nil();
1071         for (JCCompilationUnit unit : units) {