Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 88 additions & 23 deletions src/main/java/run/myCode/compiler/CompileDiagnosticListener.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,88 @@
package run.myCode.compiler;

import java.util.Locale;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.JavaFileObject;

@SuppressWarnings("unused")
public class CompileDiagnosticListener implements DiagnosticListener<JavaFileObject>
{
@Override
public void report(Diagnostic<? extends JavaFileObject> diagnostic)
{
/*
System.out.println("Line Number->" + diagnostic.getLineNumber());
System.out.println("code->" + diagnostic.getCode());
System.out.println("Message->" + diagnostic.getMessage(Locale.ENGLISH));
System.out.println("Source->" + diagnostic.getSource());
System.out.println(" ");
*/
}
}
package run.myCode.compiler;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.JavaFileObject;

/**
* Collects diagnostics reported during compilation so that callers can display
* meaningful error messages.
*/
public class CompileDiagnosticListener implements DiagnosticListener<JavaFileObject> {

private final List<Diagnostic<? extends JavaFileObject>> diagnostics = new ArrayList<>();

@Override
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
diagnostics.add(diagnostic);
}

/**
* Retrieve all diagnostics that were reported during compilation.
*
* @return a list of diagnostics
*/
public List<Diagnostic<? extends JavaFileObject>> getDiagnostics() {
return diagnostics;
}

/**
* Format collected diagnostics into human readable messages that include the
* source line and a caret pointing to the error column when available.
*
* @return list of formatted diagnostic strings
*/
public List<String> getFormattedDiagnostics() {
List<String> messages = new ArrayList<>();
for (Diagnostic<? extends JavaFileObject> d : diagnostics) {
messages.add(formatDiagnostic(d));
}
return messages;
}

private String formatDiagnostic(Diagnostic<? extends JavaFileObject> d) {
StringBuilder sb = new StringBuilder();
String sourceName = d.getSource() == null ? "Unknown Source"
: new File(d.getSource().getName()).getName();

boolean appendedSource = false;
try {
if (d.getSource() != null) {
CharSequence content = d.getSource().getCharContent(true);
String[] lines = content.toString().split("\r?\n");
long lineNo = d.getLineNumber();
if (lineNo > 0 && lineNo <= lines.length) {
String line = lines[(int) lineNo - 1];
sb.append(line).append(System.lineSeparator());
long col = d.getColumnNumber();
if (col > 0) {
for (int i = 1; i < col; i++) {
sb.append(' ');
}
sb.append('^');
}
sb.append(System.lineSeparator());
appendedSource = true;
}
}
} catch (IOException e) {
// ignore - if we can't read the source, just return the basic message
}

if (!appendedSource && sb.length() > 0) {
sb.append(System.lineSeparator());
}

sb.append(sourceName).append(':').append(d.getLineNumber()).append(':')
.append(' ').append(d.getKind().toString().toLowerCase(Locale.ENGLISH))
.append(':').append(' ').append(d.getMessage(Locale.ENGLISH));

return sb.toString();
}
}
33 changes: 20 additions & 13 deletions src/main/java/run/myCode/compiler/JavaCodeCompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;

import javax.tools.ToolProvider;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class JavaCodeCompiler {

Expand Down Expand Up @@ -117,10 +116,18 @@ public static FromMemoryClassLoader compile(Iterable<? extends JavaFileObject> f
if (DEBUG) {
System.out.println("Starting compilation with mem URIs");
}
boolean result = task.call();

// Return the classloader containing the compiled classes
return classLoader;
}
boolean result = task.call();

if (!result) {
for (String msg : diag.getFormattedDiagnostics()) {
System.out.println(msg);
System.out.println();
}
throw new ClassNotFoundException("Compilation failed");
}

// Return the classloader containing the compiled classes
return classLoader;
}

}
107 changes: 88 additions & 19 deletions src/main/java/zss/compiler/CompileDiagnosticListener.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,88 @@
package zss.compiler;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.JavaFileObject;

public class CompileDiagnosticListener implements DiagnosticListener<JavaFileObject> {

@Override
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {

// System.err.println("Line Number->" + diagnostic.getLineNumber());
// System.err.println("code->" + diagnostic.getCode());
// System.err.println("Message->" + diagnostic.getMessage(Locale.ENGLISH));
// System.err.println("Source->" + diagnostic.getSource());
// System.err.println(" ");

}
}
package zss.compiler;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.JavaFileObject;

/**
* Collects diagnostics reported during compilation so that callers can display
* meaningful error messages.
*/
public class CompileDiagnosticListener implements DiagnosticListener<JavaFileObject> {

private final List<Diagnostic<? extends JavaFileObject>> diagnostics = new ArrayList<>();

@Override
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
diagnostics.add(diagnostic);
}

/**
* Retrieve all diagnostics that were reported during compilation.
*
* @return a list of diagnostics
*/
public List<Diagnostic<? extends JavaFileObject>> getDiagnostics() {
return diagnostics;
}

/**
* Format collected diagnostics into human readable messages that include the
* source line and a caret pointing to the error column when available.
*
* @return list of formatted diagnostic strings
*/
public List<String> getFormattedDiagnostics() {
List<String> messages = new ArrayList<>();
for (Diagnostic<? extends JavaFileObject> d : diagnostics) {
messages.add(formatDiagnostic(d));
}
return messages;
}

private String formatDiagnostic(Diagnostic<? extends JavaFileObject> d) {
StringBuilder sb = new StringBuilder();
String sourceName = d.getSource() == null ? "Unknown Source"
: new File(d.getSource().getName()).getName();

boolean appendedSource = false;
try {
if (d.getSource() != null) {
CharSequence content = d.getSource().getCharContent(true);
String[] lines = content.toString().split("\r?\n");
long lineNo = d.getLineNumber();
if (lineNo > 0 && lineNo <= lines.length) {
String line = lines[(int) lineNo - 1];
sb.append(line).append(System.lineSeparator());
long col = d.getColumnNumber();
if (col > 0) {
for (int i = 1; i < col; i++) {
sb.append(' ');
}
sb.append('^');
}
sb.append(System.lineSeparator());
appendedSource = true;
}
}
} catch (IOException e) {
// ignore - if we can't read the source, just return the basic message
}

if (!appendedSource && sb.length() > 0) {
sb.append(System.lineSeparator());
}

sb.append(sourceName).append(':').append(d.getLineNumber()).append(':')
.append(' ').append(d.getKind().toString().toLowerCase(Locale.ENGLISH))
.append(':').append(' ').append(d.getMessage(Locale.ENGLISH));

return sb.toString();
}
}
33 changes: 19 additions & 14 deletions src/main/java/zss/compiler/MemoryCompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.util.Locale;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;

import javax.tools.ToolProvider;

/**
* Compiles in-memory source files into byte code using the standard JDK
Expand Down Expand Up @@ -60,10 +60,15 @@ public static FromMemoryClassLoader compile(Iterable<? extends JavaFileObject> f
Writer out = new PrintWriter(System.out);
JavaCompiler.CompilationTask task = compiler.getTask(out, fileManager, diag, options, null, files);

Boolean result = task.call();
if (result == true) {
return classLoader;
}
return null;
}
}
Boolean result = task.call();
if (Boolean.TRUE.equals(result)) {
return classLoader;
}

for (String msg : diag.getFormattedDiagnostics()) {
System.out.println(msg);
System.out.println();
}
return null;
}
}
69 changes: 69 additions & 0 deletions src/test/java/example/HelloFailureTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package example;

import java.io.IOException;
import java.io.InputStream;
import java.io.ByteArrayOutputStream;

import org.junit.Test;
import static org.junit.Assert.*;

import com.amazonaws.services.lambda.runtime.Context;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

import run.myCode.CompileResponse;
import run.myCode.Hello;

/**
* Tests compilation failures for the Hello lambda.
*/
public class HelloFailureTest {
private Context createContext() {
TestContext ctx = new TestContext();

ctx.setFunctionName("HelloFunction");

return ctx;
}

@Test
public void testCompilationFailureShowsDiagnostics() {
CompileResponse resp = doTest("jsonDataFiles/brokenLocal.json");

assertFalse("Compiler returned no response", resp == null);
assertFalse("Compilation unexpectedly succeeded", resp.getSucceeded());
String diag = resp.getResult();
assertTrue("Missing source line", diag.contains("System.out.println(\"hi\")"));
assertTrue("Missing caret in diagnostics", diag.contains("^"));
assertTrue("Missing file/line in diagnostics", diag.contains("Broken.java:3"));

int lineIdx = diag.indexOf("System.out.println(\"hi\")");
int caretIdx = diag.indexOf("^");
int fileIdx = diag.indexOf("Broken.java:3");
assertTrue("Caret should follow source line", lineIdx >= 0 && caretIdx > lineIdx);
assertTrue("File info should follow caret", fileIdx > caretIdx);

System.out.println("Result: " + diag);
}

private CompileResponse doTest(String resourceName) {
Hello handler = new Hello();

System.out.println("Working Directory: " + System.getProperty("java.io.tmpdir"));
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

ByteArrayOutputStream outContent = new ByteArrayOutputStream();
CompileResponse resp = null;

try (InputStream input = this.getClass().getClassLoader().getResourceAsStream(resourceName)) {
handler.handleRequest(input, outContent, createContext());
resp = mapper.readValue(outContent.toString(), CompileResponse.class);
}
catch (IOException e) {
throw new AssertionError(e);
}

return resp;
}
}
Loading
Loading