org.eclipse.xtext.xbase.testing.OnTheFlyJavaCompiler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.eclipse.xtext.xbase.testing Show documentation
Show all versions of org.eclipse.xtext.xbase.testing Show documentation
Infrastructure for testing Xbase languages.
The newest version!
/*******************************************************************************
* Copyright (c) 2011, 2024 itemis AG (http://www.itemis.eu) and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.xtext.xbase.testing;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static java.util.Collections.singletonMap;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.reflect.Type;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.URIUtil;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.jdt.internal.compiler.batch.Main;
import org.eclipse.xtext.util.Files;
import org.eclipse.xtext.util.JavaVersion;
import org.eclipse.xtext.util.Pair;
import org.eclipse.xtext.util.RuntimeIOException;
import org.eclipse.xtext.util.Tuples;
import org.eclipse.xtext.xbase.compiler.GeneratorConfig;
import org.eclipse.xtext.xbase.compiler.IGeneratorConfigProvider;
import org.eclipse.xtext.xbase.lib.Functions;
import org.eclipse.xtext.xbase.lib.Functions.Function0;
import com.google.inject.Inject;
/**
* @author Sven Efftinge - Initial contribution and API
* @noextend This class is not intended to be subclassed by clients.
* @noreference This class is not intended to be referenced by clients.
*
* @since 2.7
*
* @deprecated use {@link InMemoryJavaCompiler}
*/
@Deprecated
public class OnTheFlyJavaCompiler {
static class DelegateOutStream extends OutputStream {
private OutputStream delegate;
@Override
public void close() throws IOException {
delegate.close();
}
@Override
public boolean equals(Object obj) {
return delegate.equals(obj);
}
@Override
public void flush() throws IOException {
delegate.flush();
}
@Override
public int hashCode() {
return delegate.hashCode();
}
public void setDelegate(OutputStream delegate) {
this.delegate = delegate;
}
@Override
public String toString() {
return delegate.toString();
}
@Override
public void write(byte[] b) throws IOException {
delegate.write(b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
delegate.write(b, off, len);
}
@Override
public void write(int b) throws IOException {
delegate.write(b);
}
}
public static class EclipseRuntimeDependentJavaCompiler extends
OnTheFlyJavaCompiler {
@Override
protected URL resolveBundleResourceURL(URL url) throws IOException {
return FileLocator.resolve(url);
}
}
public static class ClassPathAssembler {
@Inject
private ClassLoader parentClassLoader;
public void assembleCompilerClassPath(OnTheFlyJavaCompiler compiler) {
if (parentClassLoader instanceof URLClassLoader) {
URL[] urLs = ((URLClassLoader) parentClassLoader).getURLs();
for (URL url : urLs) {
final String urlAsString = url.getFile();
compiler.addClassPath(urlAsString);
}
}
}
public ClassLoader getClassLoader() {
return parentClassLoader;
}
}
private List classpath = newArrayList();
private DelegateOutStream errorStream = new DelegateOutStream();
@Inject
private ClassPathAssembler classPathAssembler = new ClassPathAssembler();
@Inject(optional=true)
private TemporaryFolder temporaryFolder;
@Inject(optional=true)
private IGeneratorConfigProvider generatorConfigProvider;
public void addClassPath(String classpath) {
this.classpath.add(classpath);
}
public void setTemporaryFolder(TemporaryFolder temporaryFolder) {
this.temporaryFolder = temporaryFolder;
}
public void addClassPathOfClass(Class> clazz) {
final String classNameAsPath = "/"
+ clazz.getName().replace('.', '/');
String resourceName = classNameAsPath + ".class";
URL url = clazz.getResource(resourceName);
if (url == null)
throw new IllegalArgumentException(resourceName + " not found");
String pathToFolderOrJar = null;
if (url.getProtocol().startsWith("bundleresource")) {
try {
url = resolveBundleResourceURL(url);
} catch (IOException e) {
throw new WrappedException(e);
}
}
if (url.getProtocol().startsWith("jar")) {
try {
final String path = url.getPath().substring(0,
url.getPath().indexOf('!'));
String encodedPath = path.replace(" ","%20");
pathToFolderOrJar = new URL(encodedPath).toURI().getRawPath();
} catch (Exception e) {
throw new WrappedException(e);
}
} else {
String resolvedRawPath;
try {
if (url.toExternalForm().contains(" "))
resolvedRawPath = URIUtil.toURI(url).getRawPath();
else
resolvedRawPath = url.toURI().getRawPath();
} catch (URISyntaxException e) {
throw new WrappedException(e);
}
pathToFolderOrJar = resolvedRawPath.substring(0,
resolvedRawPath.indexOf(classNameAsPath));
}
this.classpath.add(pathToFolderOrJar);
}
public void clearClassPath() {
classpath.clear();
}
protected boolean compile(String arguments) {
// return BatchCompiler.compile(sb.toString(), new PrintWriter(new
// OutputStreamWriter(System.out)), new PrintWriter(
// new OutputStreamWriter(errorStream)), null);
return getMain().compile(Main.tokenize(arguments));
}
public Class> compileToClass(String classname, String code) {
return compileToClasses(singletonMap(classname, code)).get(classname);
}
public Map> compileToClasses(Map sources) {
return internalCompileToClasses(sources).getSecond();
}
public Pair>> internalCompileToClasses(Map sources) {
File tempDir = createTempDir();
try {
for (Entry entry : sources.entrySet()) {
String classname = entry.getKey();
String code = entry.getValue();
final String classNameAsPath = classname.replace('.', File.separatorChar);
final File srcFile = new File(tempDir, classNameAsPath + ".java");
createFolderStructure(srcFile.getParentFile());
srcFile.createNewFile();
Files.writeStringIntoFile(srcFile.getCanonicalPath(), code);
}
errorStream.setDelegate(new ByteArrayOutputStream());
StringBuilder sb = new StringBuilder(getComplianceLevelArg());
sb.append(" ");
sb.append(getClasspathArgs());
sb.append(" ");
sb.append('\"');
sb.append(tempDir.getCanonicalPath());
sb.append('\"');
boolean compile = compile(sb.toString());
if (!compile)
throw new IllegalArgumentException("Couldn't compile : "
+ errorStream.toString() + "\n" + sources);
final URL url = tempDir.toURI().toURL();
final URLClassLoader loader = new URLClassLoader(new URL[] { url },
classPathAssembler.getClassLoader());
Map> result = newHashMap();
for (String name : sources.keySet()) {
String qname = name.replace('/','.');
Class> clazz = loader.loadClass(qname);
result.put(name, clazz);
}
return Tuples.>>create(loader, result);
} catch (IllegalArgumentException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
cleanUpTmpFolder(tempDir);
}
}
protected File createTempDir() {
if (temporaryFolder != null && temporaryFolder.isInitialized()) {
try {
return temporaryFolder.newFolder();
} catch (IOException e) {
throw new RuntimeIOException(e);
}
}
return com.google.common.io.Files.createTempDir();
}
protected void cleanUpTmpFolder(File tempDir) {
if (temporaryFolder == null || !temporaryFolder.isInitialized()) {
try {
tempDir.deleteOnExit();
// Classloader needs .class files to lazy load an anonymous non static classes
Files.cleanFolder(tempDir, new FileFilter() {
@Override
public boolean accept(File pathname) {
boolean isClass = pathname.getName().endsWith(".class");
if(isClass) {
pathname.deleteOnExit();
}
return !isClass;
}
}, true, true);
} catch (FileNotFoundException e) {
// ignore
}
}
}
protected void createFolderStructure(File parent) {
if (parent.exists())
return;
parent.mkdirs();
}
protected Pair createFullCode(String statementCode,
Type returnType, @SuppressWarnings("unchecked") Pair... params) {
String className = "_$GeneratedClass";
StringBuilder sb = new StringBuilder("public class ").append(className)
.append(" implements ")
.append("org.eclipse.xtext.xbase.lib.Functions.Function")
.append(params.length).append("<");
for (Pair type : params) {
sb.append(toString(type.getFirst())).append(",");
}
sb.append(toString(returnType));
sb.append("> {\n");
sb.append("public ").append(toString(returnType));
sb.append(" apply(");
for (int i = 0; i < params.length; i++) {
Pair pair = params[i];
sb.append(toString(pair.getFirst())).append(" ")
.append(pair.getSecond());
if (i + 1 < params.length)
sb.append(",");
}
sb.append(") {\n");
sb.append(statementCode);
sb.append("\n}}");
return Tuples.pair(className, sb.toString());
}
@SuppressWarnings("unchecked")
public