langtools/test/tools/javac/sym/ElementStructureTest.java
changeset 31506 4e07f827a794
child 32546 e695f47efdfc
equal deleted inserted replaced
31505:98c52b994430 31506:4e07f827a794
       
     1 /*
       
     2  * Copyright (c) 2015, 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 8072480
       
    27  * @summary Check the platform classpath contains the correct elements.
       
    28  * @library /tools/lib
       
    29  * @build ToolBox ElementStructureTest
       
    30  * @run main ElementStructureTest
       
    31  */
       
    32 
       
    33 import java.io.BufferedReader;
       
    34 import java.io.ByteArrayInputStream;
       
    35 import java.io.ByteArrayOutputStream;
       
    36 import java.io.File;
       
    37 import java.io.IOException;
       
    38 import java.io.InputStream;
       
    39 import java.io.OutputStream;
       
    40 import java.io.OutputStreamWriter;
       
    41 import java.io.Reader;
       
    42 import java.io.Writer;
       
    43 import java.net.URI;
       
    44 import java.net.URL;
       
    45 import java.net.URLClassLoader;
       
    46 import java.nio.file.Files;
       
    47 import java.nio.file.Path;
       
    48 import java.nio.file.Paths;
       
    49 import java.security.MessageDigest;
       
    50 import java.util.ArrayList;
       
    51 import java.util.Arrays;
       
    52 import java.util.Collections;
       
    53 import java.util.EnumSet;
       
    54 import java.util.HashMap;
       
    55 import java.util.Iterator;
       
    56 import java.util.List;
       
    57 import java.util.Map;
       
    58 import java.util.Map.Entry;
       
    59 import java.util.Set;
       
    60 import java.util.TreeMap;
       
    61 import java.util.TreeSet;
       
    62 import java.util.function.Predicate;
       
    63 import java.util.regex.Pattern;
       
    64 import java.util.stream.Stream;
       
    65 
       
    66 import javax.lang.model.element.AnnotationMirror;
       
    67 import javax.lang.model.element.AnnotationValue;
       
    68 import javax.lang.model.element.Element;
       
    69 import javax.lang.model.element.ElementVisitor;
       
    70 import javax.lang.model.element.ExecutableElement;
       
    71 import javax.lang.model.element.Modifier;
       
    72 import javax.lang.model.element.NestingKind;
       
    73 import javax.lang.model.element.PackageElement;
       
    74 import javax.lang.model.element.TypeElement;
       
    75 import javax.lang.model.element.TypeParameterElement;
       
    76 import javax.lang.model.element.VariableElement;
       
    77 import javax.lang.model.type.TypeMirror;
       
    78 import javax.tools.FileObject;
       
    79 import javax.tools.JavaFileManager;
       
    80 import javax.tools.JavaFileObject;
       
    81 import javax.tools.JavaFileObject.Kind;
       
    82 import javax.tools.StandardLocation;
       
    83 import javax.tools.ToolProvider;
       
    84 
       
    85 import com.sun.source.util.JavacTask;
       
    86 import com.sun.tools.classfile.ClassFile;
       
    87 import com.sun.tools.classfile.ConstantPoolException;
       
    88 import com.sun.tools.javac.api.JavacTaskImpl;
       
    89 import com.sun.tools.javac.code.Symbol.CompletionFailure;
       
    90 import com.sun.tools.javac.platform.PlatformProvider;
       
    91 import com.sun.tools.javac.util.ServiceLoader;
       
    92 
       
    93 /**To generate the hash values for version N, invoke this class like:
       
    94  *
       
    95  *     java ElementStructureTest generate-hashes $LANGTOOLS_DIR/make/data/symbols/include.list (<classes-for-N> N)+
       
    96  *
       
    97  * Where <classes-for-N> is the file produced by make/src/classes/build/tools/symbolgenerator/Probe.java.
       
    98  * So, to produce hashes for 6, 7 and 8, this command can be used:
       
    99  *
       
   100  *     java ElementStructureTest generate-hashes classes-6 6 classes-7 7 classes-8 8
       
   101  *
       
   102  * To inspect differences between the actual and expected output for version N, invoke this class like:
       
   103  *
       
   104  *     java ElementStructureTest generate-output $LANGTOOLS_DIR/make/data/symbols/include.list (<classes-for-N> N <actual-output-file> <expected-output-file>)+
       
   105  *
       
   106  * For example, to get the actual and expected output for 6 in /tmp/actual and /tmp/expected, respectively:
       
   107  *
       
   108  *     java ElementStructureTest generate-output $LANGTOOLS_DIR/make/data/symbols/include.list classes-6 6 /tmp/actual /tmp/expected
       
   109  */
       
   110 public class ElementStructureTest {
       
   111 
       
   112     static final byte[] hash6 = new byte[] {
       
   113         (byte) 0x99, (byte) 0x34, (byte) 0x82, (byte) 0xCF,
       
   114         (byte) 0xE0, (byte) 0x53, (byte) 0xF3, (byte) 0x13,
       
   115         (byte) 0x4E, (byte) 0xCF, (byte) 0x49, (byte) 0x32,
       
   116         (byte) 0xB7, (byte) 0x52, (byte) 0x0F, (byte) 0x68
       
   117     };
       
   118     static final byte[] hash7 = new byte[] {
       
   119         (byte) 0x6B, (byte) 0xA2, (byte) 0xE9, (byte) 0x8E,
       
   120         (byte) 0xE1, (byte) 0x8E, (byte) 0x60, (byte) 0xBE,
       
   121         (byte) 0x54, (byte) 0xC4, (byte) 0x33, (byte) 0x3E,
       
   122         (byte) 0x0C, (byte) 0x2D, (byte) 0x3A, (byte) 0x7C
       
   123     };
       
   124     static final byte[] hash8 = new byte[] {
       
   125         (byte) 0x37, (byte) 0x0C, (byte) 0xBA, (byte) 0xCE,
       
   126         (byte) 0xCF, (byte) 0x81, (byte) 0xAE, (byte) 0xA8,
       
   127         (byte) 0x1E, (byte) 0x10, (byte) 0xAB, (byte) 0x72,
       
   128         (byte) 0xF7, (byte) 0xE5, (byte) 0x34, (byte) 0x72
       
   129     };
       
   130 
       
   131     final static Map<String, byte[]> version2Hash = new HashMap<>();
       
   132 
       
   133     static {
       
   134         version2Hash.put("6", hash6);
       
   135         version2Hash.put("7", hash7);
       
   136         version2Hash.put("8", hash8);
       
   137     }
       
   138 
       
   139     public static void main(String... args) throws Exception {
       
   140         if (args.length == 0) {
       
   141             new ElementStructureTest().doTest();
       
   142             return ;
       
   143         }
       
   144         switch (args[0]) {
       
   145             case "generate-hashes":
       
   146                 new ElementStructureTest().generateHashes(args);
       
   147                 break;
       
   148             case "generate-output":
       
   149                 new ElementStructureTest().generateOutput(args);
       
   150                 break;
       
   151             default:
       
   152                 throw new IllegalStateException("Unrecognized request: " + args[0]);
       
   153         }
       
   154     }
       
   155 
       
   156     void doTest() throws Exception {
       
   157         for (PlatformProvider provider : ServiceLoader.load(PlatformProvider.class)) {
       
   158             for (String ver : provider.getSupportedPlatformNames()) {
       
   159                 if (!version2Hash.containsKey(ver))
       
   160                     continue;
       
   161                 try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); Writer output = new OutputStreamWriter(baos, "UTF-8")) {
       
   162                     run(output, ver);
       
   163                     output.close();
       
   164                     byte[] actual = MessageDigest.getInstance("MD5").digest(baos.toByteArray());
       
   165                     if (!Arrays.equals(version2Hash.get(ver), actual))
       
   166                         throw new AssertionError("Wrong hash: " + toHex(actual) + " for version: " + ver);
       
   167                 }
       
   168             }
       
   169         }
       
   170     }
       
   171 
       
   172     void generateHashes(String... args) throws Exception {
       
   173         Predicate<String> ignoreList = constructAcceptIgnoreList(args[1]);
       
   174         for (int i = 2; i < args.length; i += 2) {
       
   175             try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); Writer output = new OutputStreamWriter(baos, "UTF-8")) {
       
   176                 realClasses(args[i], ignoreList, output, args[i + 1]);
       
   177                 output.close();
       
   178                 System.err.println("version:" + args[i + 1] + "; " + toHex(MessageDigest.getInstance("MD5").digest(baos.toByteArray())));
       
   179             }
       
   180         }
       
   181     }
       
   182 
       
   183     void generateOutput(String... args) throws Exception {
       
   184         Predicate<String> ignoreList = constructAcceptIgnoreList(args[1]);
       
   185         for (int i = 2; i < args.length; i += 4) {
       
   186             try (Writer actual = Files.newBufferedWriter(Paths.get(args[i + 2]));
       
   187                  Writer expected = Files.newBufferedWriter(Paths.get(args[i + 3]))) {
       
   188                 run(actual, args[i + 1]);
       
   189                 realClasses(args[i], ignoreList, expected, args[i + 1]);
       
   190             }
       
   191         }
       
   192     }
       
   193 
       
   194     Predicate<String> constructAcceptIgnoreList(String fromFiles) throws IOException {
       
   195         StringBuilder acceptPattern = new StringBuilder();
       
   196         StringBuilder rejectPattern = new StringBuilder();
       
   197         for (String file : fromFiles.split(File.pathSeparator)) {
       
   198             try (Stream<String> lines = Files.lines(Paths.get(file))) {
       
   199                 lines.forEach(line -> {
       
   200                     if (line.isEmpty())
       
   201                         return;
       
   202                     StringBuilder targetPattern;
       
   203                     switch (line.charAt(0)) {
       
   204                         case '+':
       
   205                             targetPattern = acceptPattern;
       
   206                             break;
       
   207                         case '-':
       
   208                             targetPattern = rejectPattern;
       
   209                             break;
       
   210                         default:
       
   211                             return ;
       
   212                     }
       
   213                     line = line.substring(1);
       
   214                     if (line.endsWith("/")) {
       
   215                         line += "[^/]*";
       
   216                     } else {
       
   217                         line += "|" + line + "$[^/]*";
       
   218                     }
       
   219                     line = line.replace("/", ".");
       
   220                     if (targetPattern.length() != 0)
       
   221                         targetPattern.append("|");
       
   222                     targetPattern.append(line);
       
   223                 });
       
   224             }
       
   225         }
       
   226         Pattern accept = Pattern.compile(acceptPattern.toString());
       
   227         Pattern reject = Pattern.compile(rejectPattern.toString());
       
   228 
       
   229         return clazzName -> accept.matcher(clazzName).matches() && !reject.matcher(clazzName).matches();
       
   230     }
       
   231 
       
   232     private static String toHex(byte[] bytes) {
       
   233         StringBuilder hex = new StringBuilder();
       
   234         String delim = "";
       
   235 
       
   236         for (byte b : bytes) {
       
   237             hex.append(delim);
       
   238             hex.append(String.format("(byte) 0x%02X", b));
       
   239             delim = ", ";
       
   240         }
       
   241 
       
   242         return hex.toString();
       
   243     }
       
   244 
       
   245     void run(Writer output, String version) throws Exception {
       
   246         JavacTaskImpl task = (JavacTaskImpl) ToolProvider.getSystemJavaCompiler().getTask(null, null, null, Arrays.asList("-release", version), null, Arrays.asList(new ToolBox.JavaSource("Test", "")));
       
   247         task.parse();
       
   248 
       
   249         JavaFileManager fm = task.getContext().get(JavaFileManager.class);
       
   250 
       
   251         for (String pack : packages(fm)) {
       
   252             PackageElement packEl = task.getElements().getPackageElement(pack);
       
   253             if (packEl == null) {
       
   254                 throw new AssertionError("Cannot find package: " + pack);
       
   255             }
       
   256             new ExhaustiveElementScanner(task, output, p -> true).visit(packEl);
       
   257         }
       
   258     }
       
   259 
       
   260     void realClasses(String location, Predicate<String> acceptor, Writer output, String version) throws Exception {
       
   261         Path classes = Paths.get(location);
       
   262         Map<String, JavaFileObject> className2File = new HashMap<>();
       
   263         Map<JavaFileObject, String> file2ClassName = new HashMap<>();
       
   264 
       
   265         try (BufferedReader descIn = Files.newBufferedReader(classes)) {
       
   266             String classFileData;
       
   267 
       
   268             while ((classFileData = descIn.readLine()) != null) {
       
   269                 ByteArrayOutputStream data = new ByteArrayOutputStream();
       
   270                 for (int i = 0; i < classFileData.length(); i += 2) {
       
   271                     data.write(Integer.parseInt(classFileData.substring(i, i + 2), 16));
       
   272                 }
       
   273                 JavaFileObject file = new ByteArrayJavaFileObject(data.toByteArray());
       
   274                 try (InputStream in = new ByteArrayInputStream(data.toByteArray())) {
       
   275                     String name = ClassFile.read(in).getName().replace("/", ".");
       
   276                     className2File.put(name, file);
       
   277                     file2ClassName.put(file, name);
       
   278                 } catch (IOException | ConstantPoolException ex) {
       
   279                     throw new IllegalStateException(ex);
       
   280                 }
       
   281             }
       
   282         }
       
   283 
       
   284         try (JavaFileManager fm = new TestFileManager(className2File, file2ClassName)) {
       
   285             JavacTaskImpl task = (JavacTaskImpl) ToolProvider.getSystemJavaCompiler().getTask(null, fm, null, Arrays.asList("-source", version), null, Arrays.asList(new ToolBox.JavaSource("Test", "")));
       
   286             task.parse();
       
   287 
       
   288             PACK: for (String pack : packages(fm)) {
       
   289                 PackageElement packEl = task.getElements().getPackageElement(pack);
       
   290                 assert packEl != null;
       
   291                 new ExhaustiveElementScanner(task, output, acceptor).visit(packEl);
       
   292             }
       
   293         }
       
   294     }
       
   295 
       
   296     Set<String> packages(JavaFileManager fm) throws IOException {
       
   297         Set<String> packages = new TreeSet<>();
       
   298         EnumSet<Kind> kinds = EnumSet.of(JavaFileObject.Kind.CLASS, JavaFileObject.Kind.OTHER);
       
   299 
       
   300         for (JavaFileObject file : fm.list(StandardLocation.PLATFORM_CLASS_PATH, "", kinds, true)) {
       
   301             String binary = fm.inferBinaryName(StandardLocation.PLATFORM_CLASS_PATH, file);
       
   302             packages.add(binary.substring(0, binary.lastIndexOf('.')));
       
   303         }
       
   304 
       
   305         return packages;
       
   306     }
       
   307 
       
   308     final class ExhaustiveElementScanner implements ElementVisitor<Void, Void> {
       
   309 
       
   310         final JavacTask task;
       
   311         final Writer out;
       
   312         final Predicate<String> acceptType;
       
   313 
       
   314         public ExhaustiveElementScanner(JavacTask task, Writer out, Predicate<String> acceptType) {
       
   315             this.task = task;
       
   316             this.out = out;
       
   317             this.acceptType = acceptType;
       
   318         }
       
   319 
       
   320         @Override
       
   321         public Void visit(Element e, Void p) {
       
   322             return e.accept(this, p);
       
   323         }
       
   324 
       
   325         @Override
       
   326         public Void visit(Element e) {
       
   327             return e.accept(this, null);
       
   328         }
       
   329 
       
   330         private void write(TypeMirror type) throws IOException {
       
   331             try {
       
   332                 out.write(type.toString()
       
   333                               .replace("java.lang.invoke.MethodHandle$PolymorphicSignature", "java.lang.invoke.MethodHandle.PolymorphicSignature")
       
   334                               .replace("javax.swing.JRootPane$DefaultAction", "javax.swing.JRootPane.DefaultAction")
       
   335                               .replace("javax.swing.plaf.metal.MetalFileChooserUI$DirectoryComboBoxRenderer", "javax.swing.plaf.metal.MetalFileChooserUI.DirectoryComboBoxRenderer")
       
   336                          );
       
   337             } catch (CompletionFailure cf) {
       
   338                 out.write("cf");
       
   339             }
       
   340         }
       
   341 
       
   342         private void writeTypes(Iterable<? extends TypeMirror> types) throws IOException {
       
   343             String sep = "";
       
   344 
       
   345             for (TypeMirror type : types) {
       
   346                 out.write(sep);
       
   347                 write(type);
       
   348                 sep = ", ";
       
   349             }
       
   350         }
       
   351 
       
   352         private void writeAnnotations(Iterable<? extends AnnotationMirror> annotations) throws IOException {
       
   353             for (AnnotationMirror ann : annotations) {
       
   354                 out.write("@");
       
   355                 write(ann.getAnnotationType());
       
   356                 if (!ann.getElementValues().isEmpty()) {
       
   357                     out.write("(");
       
   358                     Map<ExecutableElement, AnnotationValue> valuesMap = new TreeMap<>((a1, a2) -> a1.getSimpleName().toString().compareTo(a2.getSimpleName().toString()));
       
   359                     valuesMap.putAll(ann.getElementValues());
       
   360                     for (Entry<? extends ExecutableElement, ? extends AnnotationValue> ev : valuesMap.entrySet()) {
       
   361                         out.write(ev.getKey().getSimpleName().toString());
       
   362                         out.write(" = ");
       
   363                         out.write(ev.getValue().toString());
       
   364                     }
       
   365                     out.write(")");
       
   366                 }
       
   367             }
       
   368         }
       
   369 
       
   370         void analyzeElement(Element e) {
       
   371             try {
       
   372                 write(e.asType());
       
   373                 writeAnnotations(e.getAnnotationMirrors());
       
   374                 out.write(e.getKind().toString());
       
   375                 out.write(e.getModifiers().toString());
       
   376                 out.write(e.getSimpleName().toString());
       
   377             } catch (IOException ex) {
       
   378                 ex.printStackTrace();
       
   379             }
       
   380         }
       
   381 
       
   382         boolean acceptAccess(Element e) {
       
   383             return e.getModifiers().contains(Modifier.PUBLIC) || e.getModifiers().contains(Modifier.PROTECTED);
       
   384         }
       
   385 
       
   386         @Override
       
   387         public Void visitExecutable(ExecutableElement e, Void p) {
       
   388             if (!acceptAccess(e))
       
   389                 return null;
       
   390             try {
       
   391                 analyzeElement(e);
       
   392                 out.write(String.valueOf(e.getDefaultValue()));
       
   393                 for (VariableElement param : e.getParameters()) {
       
   394                     visit(param, p);
       
   395                 }
       
   396                 out.write(String.valueOf(e.getReceiverType()));
       
   397                 write(e.getReturnType());
       
   398                 out.write(e.getSimpleName().toString());
       
   399                 writeTypes(e.getThrownTypes());
       
   400                 for (TypeParameterElement param : e.getTypeParameters()) {
       
   401                     visit(param, p);
       
   402                 }
       
   403                 out.write(String.valueOf(e.isDefault()));
       
   404                 out.write(String.valueOf(e.isVarArgs()));
       
   405                 out.write("\n");
       
   406             } catch (IOException ex) {
       
   407                 ex.printStackTrace();
       
   408             }
       
   409             return null;
       
   410         }
       
   411 
       
   412         @Override
       
   413         public Void visitPackage(PackageElement e, Void p) {
       
   414             List<Element> types = new ArrayList<>(e.getEnclosedElements());
       
   415             Collections.sort(types, (e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString()));
       
   416             for (Element encl : types) {
       
   417                 visit(encl, p);
       
   418             }
       
   419             return null;
       
   420         }
       
   421 
       
   422         @Override
       
   423         public Void visitType(TypeElement e, Void p) {
       
   424             if (!acceptAccess(e))
       
   425                 return null;
       
   426             writeType(e);
       
   427             return null;
       
   428         }
       
   429 
       
   430         void writeType(TypeElement e) {
       
   431             if (!acceptType.test(task.getElements().getBinaryName(e).toString()))
       
   432                 return ;
       
   433             try {
       
   434                 analyzeElement(e);
       
   435                 writeTypes(e.getInterfaces());
       
   436                 out.write(e.getNestingKind().toString());
       
   437                 out.write(e.getQualifiedName().toString());
       
   438                 write(e.getSuperclass());
       
   439                 for (TypeParameterElement param : e.getTypeParameters()) {
       
   440                     visit(param, null);
       
   441                 }
       
   442                 List<Element> defs = new ArrayList<>(e.getEnclosedElements()); //XXX: forcing ordering for members - not completely correct!
       
   443                 Collections.sort(defs, (e1, e2) -> e1.toString().compareTo(e2.toString()));
       
   444                 for (Element def : defs) {
       
   445                     visit(def, null);
       
   446                 }
       
   447                 out.write("\n");
       
   448             } catch (IOException ex) {
       
   449                 ex.printStackTrace();
       
   450             }
       
   451         }
       
   452 
       
   453         @Override
       
   454         public Void visitVariable(VariableElement e, Void p) {
       
   455             if (!acceptAccess(e))
       
   456                 return null;
       
   457             try {
       
   458                 analyzeElement(e);
       
   459                 out.write(String.valueOf(e.getConstantValue()));
       
   460                 out.write("\n");
       
   461             } catch (IOException ex) {
       
   462                 ex.printStackTrace();
       
   463             }
       
   464             return null;
       
   465         }
       
   466 
       
   467         @Override
       
   468         public Void visitTypeParameter(TypeParameterElement e, Void p) {
       
   469             try {
       
   470                 analyzeElement(e);
       
   471                 out.write(e.getBounds().toString());
       
   472                 out.write("\n");
       
   473             } catch (IOException ex) {
       
   474                 ex.printStackTrace();
       
   475             }
       
   476             return null;
       
   477         }
       
   478 
       
   479         @Override
       
   480         public Void visitUnknown(Element e, Void p) {
       
   481             throw new IllegalStateException("Should not get here.");
       
   482         }
       
   483 
       
   484     }
       
   485 
       
   486     final class TestFileManager implements JavaFileManager {
       
   487 
       
   488         final Map<String, JavaFileObject> className2File;
       
   489         final Map<JavaFileObject, String> file2ClassName;
       
   490 
       
   491         public TestFileManager(Map<String, JavaFileObject> className2File, Map<JavaFileObject, String> file2ClassName) {
       
   492             this.className2File = className2File;
       
   493             this.file2ClassName = file2ClassName;
       
   494         }
       
   495 
       
   496         @Override
       
   497         public ClassLoader getClassLoader(Location location) {
       
   498             return new URLClassLoader(new URL[0]);
       
   499         }
       
   500 
       
   501         @Override
       
   502         public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse) throws IOException {
       
   503             if (location != StandardLocation.PLATFORM_CLASS_PATH || !kinds.contains(Kind.CLASS))
       
   504                 return Collections.emptyList();
       
   505 
       
   506             if (!packageName.isEmpty())
       
   507                 packageName += ".";
       
   508 
       
   509             List<JavaFileObject> result = new ArrayList<>();
       
   510 
       
   511             for (Entry<String, JavaFileObject> e : className2File.entrySet()) {
       
   512                 String currentPackage = e.getKey().substring(0, e.getKey().lastIndexOf(".") + 1);
       
   513                 if (recurse ? currentPackage.startsWith(packageName) : packageName.equals(currentPackage))
       
   514                     result.add(e.getValue());
       
   515             }
       
   516 
       
   517             return result;
       
   518         }
       
   519 
       
   520         @Override
       
   521         public String inferBinaryName(Location location, JavaFileObject file) {
       
   522             return file2ClassName.get(file);
       
   523         }
       
   524 
       
   525         @Override
       
   526         public boolean isSameFile(FileObject a, FileObject b) {
       
   527             return a == b;
       
   528         }
       
   529 
       
   530         @Override
       
   531         public boolean handleOption(String current, Iterator<String> remaining) {
       
   532             return false;
       
   533         }
       
   534 
       
   535         @Override
       
   536         public boolean hasLocation(Location location) {
       
   537             return location == StandardLocation.PLATFORM_CLASS_PATH;
       
   538         }
       
   539 
       
   540         @Override
       
   541         public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException {
       
   542             if (location != StandardLocation.PLATFORM_CLASS_PATH || kind != Kind.CLASS)
       
   543                 return null;
       
   544 
       
   545             return className2File.get(className);
       
   546         }
       
   547 
       
   548         @Override
       
   549         public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
       
   550             throw new UnsupportedOperationException("");
       
   551         }
       
   552 
       
   553         @Override
       
   554         public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
       
   555             return null;
       
   556         }
       
   557 
       
   558         @Override
       
   559         public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException {
       
   560             throw new UnsupportedOperationException("");
       
   561         }
       
   562 
       
   563         @Override
       
   564         public void flush() throws IOException {
       
   565         }
       
   566 
       
   567         @Override
       
   568         public void close() throws IOException {
       
   569         }
       
   570 
       
   571         @Override
       
   572         public int isSupportedOption(String option) {
       
   573             return -1;
       
   574         }
       
   575 
       
   576     }
       
   577 
       
   578     static class ByteArrayJavaFileObject implements JavaFileObject {
       
   579 
       
   580         private final byte[] data;
       
   581 
       
   582         public ByteArrayJavaFileObject(byte[] data) {
       
   583             this.data = data;
       
   584         }
       
   585 
       
   586         @Override
       
   587         public Kind getKind() {
       
   588             return Kind.CLASS;
       
   589         }
       
   590 
       
   591         @Override
       
   592         public boolean isNameCompatible(String simpleName, Kind kind) {
       
   593             return true;
       
   594         }
       
   595 
       
   596         @Override
       
   597         public NestingKind getNestingKind() {
       
   598             return null;
       
   599         }
       
   600 
       
   601         @Override
       
   602         public Modifier getAccessLevel() {
       
   603             return null;
       
   604         }
       
   605 
       
   606         @Override
       
   607         public URI toUri() {
       
   608             return null;
       
   609         }
       
   610 
       
   611         @Override
       
   612         public String getName() {
       
   613             return null;
       
   614         }
       
   615 
       
   616         @Override
       
   617         public InputStream openInputStream() throws IOException {
       
   618             return new ByteArrayInputStream(data);
       
   619         }
       
   620 
       
   621         @Override
       
   622         public OutputStream openOutputStream() throws IOException {
       
   623             throw new UnsupportedOperationException();
       
   624         }
       
   625 
       
   626         @Override
       
   627         public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
       
   628             throw new UnsupportedOperationException();
       
   629         }
       
   630 
       
   631         @Override
       
   632         public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
       
   633             throw new UnsupportedOperationException();
       
   634         }
       
   635 
       
   636         @Override
       
   637         public Writer openWriter() throws IOException {
       
   638             throw new UnsupportedOperationException();
       
   639         }
       
   640 
       
   641         @Override
       
   642         public long getLastModified() {
       
   643             return 0;
       
   644         }
       
   645 
       
   646         @Override
       
   647         public boolean delete() {
       
   648             throw new UnsupportedOperationException();
       
   649         }
       
   650     }
       
   651 
       
   652 }