Syntax Checking in Java

Steven Morad picture Steven Morad · Jul 2, 2012 · Viewed 17.9k times · Source

I am currently working on a program that has an embedded text editor. The users are supposed to type java code in the editor. The code typed into the editor is then made into a string. I just want something that would check for missing parenthesis or a try without a catch, etc. It doesn't need to be compiled. I've looked around quite a bit, but I'm still new to programming and can't implement some of the harder stuff.

So to make it shorter: I'm looking for some java package that will analyze code for syntax errors.

Answer

orangepips picture orangepips · Jul 2, 2012

As of Java 6 you can use JavaCompiler to compile the text and get back Diagnostic objects that tell you what problems the file has (if any). So for your example you'd need to take the content of the editor and pass it to the JavaCompiler, run it, and report back any problems. Example that follows assumes editor text written out to a file.

Example code:

File to Check

public class HelloBuggyWorld {
    String test // missing a semicolon

    public static void main (String [] args) {
        System.out.println('Hello World!');  // should be double quoted
    }
}

Checker

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Formatter;
import java.util.List;
import java.util.Locale;

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

public class JavaSyntaxChecker {
    public static void main(String[] args) {
        System.out.println(JavaSyntaxChecker.check("/path/to/HelloBuggyWorld.java"));
    }

    public static List<String> check(String file) {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
        Iterable<? extends JavaFileObject> compilationUnits =
                fileManager.getJavaFileObjectsFromStrings(Arrays.asList(file));

        DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
        compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits).call();

        List<String> messages = new ArrayList<String>();
        Formatter formatter = new Formatter();
        for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
            messages.add(diagnostic.getKind() + ":\t Line [" + diagnostic.getLineNumber() + "] \t Position [" + diagnostic.getPosition() + "]\t" + diagnostic.getMessage(Locale.ROOT) + "\n");
        }

        return messages;
    }
}

Output

From running the main method.

[ERROR:  Line [5]    Position [124] HelloBuggyWorld.java:5: unclosed character literal
, ERROR:     Line [5]    Position [126] HelloBuggyWorld.java:5: ';' expected
, ERROR:     Line [5]    Position [131] HelloBuggyWorld.java:5: not a statement
, ERROR:     Line [5]    Position [136] HelloBuggyWorld.java:5: ';' expected
, ERROR:     Line [5]    Position [137] HelloBuggyWorld.java:5: unclosed character literal
]