/** * Implementation of {@link ClassLoader#findClass(String)}. * * @throws ClassNotFoundException */ public Class<?> findClass(String className) throws ClassNotFoundException { byte[] ba; int size; try { // Maybe the bytecode is already there, because the class was // compiled as a side effect of a preceding // compilation. JavaFileObject classFileObject = this.getJavaFileManager() .getJavaFileForInput(StandardLocation.CLASS_OUTPUT, className, Kind.CLASS); if (classFileObject == null) { // Get the sourceFile. JavaFileObject sourceFileObject = this.getJavaFileManager() .getJavaFileForInput(StandardLocation.SOURCE_PATH, className, Kind.SOURCE); if (sourceFileObject == null) { throw new DiagnosticException("Source for '" + className + "' not found"); } // Compose the effective compiler options. Vector<String> optionList = new Vector<String>(); IPreferenceStore store = Bio7EditorPlugin.getDefault().getPreferenceStore(); String version = store.getString("compiler_version"); boolean debug = store.getBoolean("compiler_debug"); boolean verbose = store.getBoolean("compiler_verbose"); boolean warnings = store.getBoolean("compiler_warnings"); boolean createMarker = store.getBoolean("compiler_marker"); optionList.addElement("-source"); optionList.addElement(version); optionList.addElement("-target"); optionList.addElement(version); optionList.addElement("-classpath"); /* Add the Bio7 libs etc. for the compiler! */ optionList.addElement(new ScanClassPath().scan()); if (debug) { optionList.addElement("-g"); } else { optionList.addElement("-g:none"); } if (verbose) { optionList.addElement("-verbose"); } if (warnings == false) { optionList.addElement("-nowarn"); } DiagnosticCollector<JavaFileObject> diagnosticsCollector = new DiagnosticCollector<JavaFileObject>(); // Run the compiler. boolean success = this.compiler .getTask( null, // out this.getJavaFileManager(), // fileManager diagnosticsCollector, optionList, // options null, // classes Collections.singleton(sourceFileObject) // compilationUnits ) .call(); if (!success) { markError(diagnosticsCollector, createMarker); throw new ClassNotFoundException(className + ": Compilation failed"); } classFileObject = this.getJavaFileManager() .getJavaFileForInput(StandardLocation.CLASS_OUTPUT, className, Kind.CLASS); if (classFileObject == null) { throw new ClassNotFoundException(className + ": Class file not created by compilation"); } } if (classFileObject instanceof ByteArrayJavaFileObject) { ByteArrayJavaFileObject bajfo = (ByteArrayJavaFileObject) classFileObject; ba = bajfo.toByteArray(); size = ba.length; } else { ba = new byte[4096]; size = 0; InputStream is = classFileObject.openInputStream(); try { for (; ; ) { int res = is.read(ba, size, ba.length - size); if (res == -1) break; size += res; if (size == ba.length) { byte[] tmp = new byte[2 * size]; System.arraycopy(ba, 0, tmp, 0, size); ba = tmp; } } } finally { is.close(); } } } catch (IOException ioe) { throw new DiagnosticException(ioe); } return this.defineClass( className, ba, 0, size, (this.optionalProtectionDomainFactory == null ? null : this.optionalProtectionDomainFactory.getProtectionDomain( getSourceResourceName(className)))); }
/** * Save a compiled class and associated classes to a jar file. * * <p>With a packageName = "" and recursive = false, it will save clazz and any classes compiled * from the same source (I think); this is probably what you want. * * @param packageName package name prefix to search for classes, or "" for all * @param clazz a class that has been previously compiled by this bridge * @param mainClazz a class that will be installed as the "Main-Class" of a runnable jar * @param outStream output stream * @param recursive whether to retrieve classes from rest of the the JavaFileManager hierarchy * @throws FileNotFoundException * @throws IOException */ public void saveToJar( String packageName, Class<?> clazz, Class<?> mainClazz, OutputStream outStream, boolean recursive) throws IOException { JavaFileManager manager = fileManagerCache.get(clazz); List<JavaFileObject> list = new ArrayList<JavaFileObject>(); for (JavaFileObject obj : manager.list( StandardLocation.CLASS_PATH, packageName, Collections.singleton(JavaFileObject.Kind.CLASS), false)) list.add(obj); if (list.iterator().hasNext()) { Manifest manifest = new Manifest(); manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); if (mainClazz != null) { manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, mainClazz.getName()); } manifest .getMainAttributes() .put(new Attributes.Name("X-Rascal-Saved-Class"), clazz.getName()); JarOutputStream target = new JarOutputStream(outStream, manifest); JarEntry entry = new JarEntry("META-INF/"); target.putNextEntry(entry); Collection<String> dirs = new ArrayList<String>(); for (JavaFileObject o : list) { String path = o.toUri().getPath().replace(".", "/"); makeJarDirs(target, dirs, path); entry = new JarEntry(path + ".class"); entry.setTime(o.getLastModified()); target.putNextEntry(entry); try (InputStream stream = o.openInputStream()) { byte[] buffer = new byte[8192]; int c = stream.read(buffer); while (c > -1) { target.write(buffer, 0, c); c = stream.read(buffer); } } target.closeEntry(); } if (mainClazz != null) { String name = mainClazz.getName(); String path = name.replace(".", "/") + ".class"; String dir = path.substring(0, path.lastIndexOf('/')); StringBuilder dirTmp = new StringBuilder(dir.length()); for (String d : dir.split("/")) { dirTmp.append(d); dirTmp.append("/"); String tmp = dirTmp.toString(); if (!dirs.contains(tmp)) { dirs.add(tmp); entry = new JarEntry(tmp); target.putNextEntry(entry); } } entry = new JarEntry(path); target.putNextEntry(entry); try (InputStream stream = mainClazz.getClassLoader().getResourceAsStream(path)) { byte[] buffer = new byte[8192]; int c = stream.read(buffer); while (c > -1) { target.write(buffer, 0, c); c = stream.read(buffer); } } target.closeEntry(); } target.close(); } }