use of org.codehaus.commons.compiler.CompileException in project drill by apache.
the class ClassTransformer method getImplementationClass.
public Class<?> getImplementationClass(final QueryClassLoader classLoader, final TemplateClassDefinition<?> templateDefinition, final String entireClass, final String materializedClassName) throws ClassTransformationException {
// unfortunately, this hasn't been set up at construction time, so we have to do it here
final ScalarReplacementOption scalarReplacementOption = ScalarReplacementOption.fromString(optionManager.getOption(SCALAR_REPLACEMENT_VALIDATOR));
try {
final long t1 = System.nanoTime();
final ClassSet set = new ClassSet(null, templateDefinition.getTemplateClassName(), materializedClassName);
final byte[][] implementationClasses = classLoader.getClassByteCode(set.generated, entireClass);
long totalBytecodeSize = 0;
Map<String, Pair<byte[], ClassNode>> classesToMerge = Maps.newHashMap();
for (byte[] clazz : implementationClasses) {
totalBytecodeSize += clazz.length;
final ClassNode node = AsmUtil.classFromBytes(clazz, ClassReader.EXPAND_FRAMES);
if (!AsmUtil.isClassOk(logger, "implementationClasses", node)) {
throw new IllegalStateException("Problem found with implementationClasses");
}
classesToMerge.put(node.name, Pair.of(clazz, node));
}
final LinkedList<ClassSet> names = Lists.newLinkedList();
final Set<ClassSet> namesCompleted = Sets.newHashSet();
names.add(set);
while (!names.isEmpty()) {
final ClassSet nextSet = names.removeFirst();
if (namesCompleted.contains(nextSet)) {
continue;
}
final ClassNames nextPrecompiled = nextSet.precompiled;
final byte[] precompiledBytes = byteCodeLoader.getClassByteCodeFromPath(nextPrecompiled.clazz);
final ClassNames nextGenerated = nextSet.generated;
// keeps only classes that have not be merged
Pair<byte[], ClassNode> classNodePair = classesToMerge.remove(nextGenerated.slash);
final ClassNode generatedNode;
if (classNodePair != null) {
generatedNode = classNodePair.getValue();
} else {
generatedNode = null;
}
/*
* TODO
* We're having a problem with some cases of scalar replacement, but we want to get
* the code in so it doesn't rot anymore.
*
* Here, we use the specified replacement option. The loop will allow us to retry if
* we're using TRY.
*/
MergedClassResult result = null;
boolean scalarReplace = scalarReplacementOption != ScalarReplacementOption.OFF && entireClass.length() < MAX_SCALAR_REPLACE_CODE_SIZE;
while (true) {
try {
result = MergeAdapter.getMergedClass(nextSet, precompiledBytes, generatedNode, scalarReplace);
break;
} catch (RuntimeException e) {
// if we had a problem without using scalar replacement, then rethrow
if (!scalarReplace) {
throw e;
}
// if we did try to use scalar replacement, decide if we need to retry or not
if (scalarReplacementOption == ScalarReplacementOption.ON) {
// option is forced on, so this is a hard error
throw e;
}
/*
* We tried to use scalar replacement, with the option to fall back to not using it.
* Log this failure before trying again without scalar replacement.
*/
logger.info("scalar replacement failure (retrying)\n", e);
scalarReplace = false;
}
}
for (String s : result.innerClasses) {
s = s.replace(FileUtils.separatorChar, '.');
names.add(nextSet.getChild(s));
}
classLoader.injectByteCode(nextGenerated.dot, result.bytes);
namesCompleted.add(nextSet);
}
// adds byte code of the classes that have not been merged to make them accessible for outer class
for (Map.Entry<String, Pair<byte[], ClassNode>> clazz : classesToMerge.entrySet()) {
classLoader.injectByteCode(clazz.getKey().replace(FileUtils.separatorChar, '.'), clazz.getValue().getKey());
}
Class<?> c = classLoader.findClass(set.generated.dot);
if (templateDefinition.getExternalInterface().isAssignableFrom(c)) {
logger.debug("Compiled and merged {}: bytecode size = {}, time = {} ms.", c.getSimpleName(), DrillStringUtils.readable(totalBytecodeSize), (System.nanoTime() - t1 + 500_000) / 1_000_000);
return c;
}
throw new ClassTransformationException("The requested class did not implement the expected interface.");
} catch (CompileException | IOException | ClassNotFoundException e) {
throw new ClassTransformationException(String.format("Failure generating transformation classes for value: \n %s", entireClass), e);
}
}
use of org.codehaus.commons.compiler.CompileException in project drill by apache.
the class DrillDiagnosticListener method report.
@Override
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
if (diagnostic.getKind() == javax.tools.Diagnostic.Kind.ERROR) {
String message = diagnostic.toString() + " (" + diagnostic.getCode() + ")";
logger.error(message);
Location loc = new //
Location(//
diagnostic.getSource().toString(), //
(short) diagnostic.getLineNumber(), //
(short) diagnostic.getColumnNumber());
// does not declare checked exceptions.
throw new RuntimeException(new CompileException(message, loc));
} else if (logger.isTraceEnabled()) {
logger.trace(diagnostic.toString() + " (" + diagnostic.getCode() + ")");
}
}
use of org.codehaus.commons.compiler.CompileException in project drill by apache.
the class FunctionInitializer method convertToCompilationUnit.
/**
* Using class name generates path to class source code (*.java),
* reads its content as string and parses it into {@link org.codehaus.janino.Java.CompilationUnit}.
*
* @param clazz function class
* @return compilation unit
* @throws IOException if did not find class or could not load it
*/
private CompilationUnit convertToCompilationUnit(Class<?> clazz) throws IOException {
String path = clazz.getName();
path = path.replaceFirst("\\$.*", "");
path = path.replace(".", FileUtils.separator);
path = "/" + path + ".java";
logger.trace("Loading function code from the {}", path);
try (InputStream is = clazz.getResourceAsStream(path)) {
if (is == null) {
throw new IOException(String.format("Failure trying to locate source code for class %s, tried to read on classpath location %s", clazz.getName(), path));
}
String body = IO.toString(is);
// TODO: Hack to remove annotations so Janino doesn't choke. Need to reconsider this problem...
body = body.replaceAll("@\\w+(?:\\([^\\\\]*?\\))?", "");
try {
return new Parser(new Scanner(null, new StringReader(body))).parseCompilationUnit();
} catch (CompileException e) {
throw new IOException(String.format("Failure while loading class %s.", clazz.getName()), e);
}
}
}
use of org.codehaus.commons.compiler.CompileException in project drill by apache.
the class JDKClassCompiler method doCompile.
private DrillJavaFileObject doCompile(final ClassNames className, final String sourceCode) throws CompileException, IOException, ClassNotFoundException {
try {
// Create one Java source file in memory, which will be compiled later.
DrillJavaFileObject compilationUnit = new DrillJavaFileObject(className.dot, sourceCode);
CompilationTask task = compiler.getTask(null, fileManager, listener, compilerOptions, null, Collections.singleton(compilationUnit));
// Run the compiler.
if (!task.call()) {
throw new CompileException("Compilation failed", null);
} else if (!compilationUnit.isCompiled()) {
throw new ClassNotFoundException(className + ": Class file not created by compilation.");
}
// all good
return compilationUnit;
} catch (RuntimeException rte) {
// Unwrap the compilation exception and throw it.
Throwable cause = rte.getCause();
if (cause != null) {
cause = cause.getCause();
if (cause instanceof CompileException) {
throw (CompileException) cause;
}
if (cause instanceof IOException) {
throw (IOException) cause;
}
}
throw rte;
}
}
Aggregations