Obtain AST from JavaCompiler

I would like to use the javax.tools API in jdk 6.0 to obtain the AST from a Java source file and then visit the AST. I'm pretty sure the class JavaCompiler and ClassTree can help me, but I have not been able to find any information (or examples) on how to do this, or work it out myself.

If someboby out there could give me some pointers that would be great (I'll continue on my own of course, and post the answer here once I find it).

I'm in the process of creating a Java to C compiler to run Java on our small embedded devices. I want to translate the Java source (not the class file) to C. Mostly for fun, but also because I think the result will be much more readable and compact than translating from bytescodes.

[740 byte] By [Stephan_Korsholma] at [2007-11-26 21:35:50]
# 1

This demonstrates how to get it from an annotation processor:

https://openjdk.dev.java.net/source/browse/openjdk/compiler/trunk/test/tools/javac/api/TestOperators.java?rev=HEAD&view=text

You can also pass an instance of JavaCompiler.CompilationTask to Trees.instance

if you are not using an annotation processor. See also:

https://openjdk.dev.java.net/nonav/compiler/guide/compilerAPI.html

http://java.sun.com/javase/6/docs/technotes/guides/javac/index.html

PeterAhea at 2007-7-10 3:16:39 > top of Java-index,Developer Tools,Java Compiler...
# 2

Thank you very much! That helped a lot. I have included below a small HelloWorld type of example. It is basically the same as yours. This example illustrates how the framework can be used to visit the AST obtained from a single (simple) Java source file.

I think it's a brilliant idea to make this framework publicly available :-)

package main;

import java.io.File;

import java.io.IOException;

import java.util.LinkedList;

import java.util.List;

import java.util.Set;

import javax.annotation.processing.AbstractProcessor;

import javax.annotation.processing.RoundEnvironment;

import javax.annotation.processing.SupportedAnnotationTypes;

import javax.annotation.processing.SupportedSourceVersion;

import javax.lang.model.SourceVersion;

import javax.lang.model.element.Element;

import javax.lang.model.element.ExecutableElement;

import javax.lang.model.element.PackageElement;

import javax.lang.model.element.TypeElement;

import javax.lang.model.element.TypeParameterElement;

import javax.lang.model.element.VariableElement;

import javax.lang.model.util.ElementScanner6;

import javax.tools.JavaCompiler;

import javax.tools.JavaFileObject;

import javax.tools.StandardJavaFileManager;

import javax.tools.ToolProvider;

import javax.tools.JavaCompiler.CompilationTask;

public class Main {

@SupportedSourceVersion(SourceVersion.RELEASE_6)

@SupportedAnnotationTypes("*")

private static class MyProcessor extends AbstractProcessor {

@Override

public boolean process(Set<? extends TypeElement> annotations,

RoundEnvironment roundEnvironment) {

class Scan extends ElementScanner6<Void, Void> {

@Override

public Void visitExecutable(ExecutableElement e, Void p) {

System.out.println("method : " + e.toString());

return super.visitExecutable(e, p);

}

@Override

public Void visitPackage(PackageElement e, Void p) {

System.out.println("package : " + e.toString());

return super.visitPackage(e, p);

}

@Override

public Void visitType(TypeElement e, Void p) {

System.out.println("Type: " + e.toString());

return super.visitType(e, p);

}

@Override

public Void visitTypeParameter(TypeParameterElement e, Void p) {

System.out.println("param: "+ e.toString());

return super.visitTypeParameter(e, p);

}

@Override

public Void visitVariable(VariableElement e, Void p) {

System.out.println("variable: " + e.toString());

return super.visitVariable(e, p);

}

}

Scan scan = new Scan();

for (Element e : roundEnvironment.getRootElements()) {

scan.scan(e);

}

return true;

}

}

public static void main(String[] args) {

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

try {

StandardJavaFileManager fileManager = compiler

.getStandardFileManager(null, null, null);

List<File> files = new LinkedList<File>();

files.add(new File(

"C:\\home\\workspace\\JavaC\\main\\HelloWorld.java"));

Iterable<? extends JavaFileObject> compilationUnits1 = fileManager

.getJavaFileObjectsFromFiles(files);

CompilationTask task = compiler.getTask(null, fileManager, null,

null, null, compilationUnits1);

LinkedList<MyProcessor> processors = new LinkedList<MyProcessor>();

processors.add(new MyProcessor());

task.setProcessors(processors);

task.call();

try {

fileManager.close();

} catch (IOException e) {

}

} catch (Throwable t) {

System.out.println(t.getLocalizedMessage());

}

}

}

Stephan_Korsholma at 2007-7-10 3:16:39 > top of Java-index,Developer Tools,Java Compiler...
# 3

Hi,

I am trying to hash the AST of source-code in order to uniquely identify the version of a class. I tried using Stephan's source-code to this end but the problem is that ElementScanner6 does not seem to visit method bodies. I am expecting to get a callback literally for every single line of code within a class. Is such a thing possible using the Java6 API or will I have to turn to other AST generators?

Thank you,

Gili

cowwoca at 2007-7-10 3:16:39 > top of Java-index,Developer Tools,Java Compiler...
# 4
On second thought I will redirect my conversation back to http://forum.java.sun.com/thread.jspa?forumID=7&threadID=5171243 because it seems I am doing something slightly different from what is originally discussed here. Sorry for the interruption :)Gili
cowwoca at 2007-7-10 3:16:39 > top of Java-index,Developer Tools,Java Compiler...