views:

81

answers:

2

I have recently come into the need of modifying some Java code (adding methods, changing the signatures of some fields and removing methods) and I think that all of this can be accomplished though the use of the Eclipse SDK's AST.

I know from some research how to parse in a source file but I don't know how to do the things mentioned above. Does anyone know a good tutorial or could someone give me a brief explanation on how to resolve these issues?

Thanks a lot,

ExtremeCoder


Edit:

I have now started to look more into the JCodeModel and I think this could be much easier to use but I do not know if an exististing document can be loaded into it?

If this could work let me know ;)

Thanks again.

+1  A: 

I will not post the whole source code to this problem here because it is quite long but I will get people started.

All the docs that you will need are here: http://publib.boulder.ibm.com/infocenter/iadthelp/v6r0/index.jsp?topic=/org.eclipse.jdt.doc.isv/reference/api/org/eclipse/jdt/core/dom/package-summary.html

Document document = new Document("import java.util.List;\n\nclass X\n{\n\n\tpublic void deleteme()\n\t{\n\t}\n\n}\n");
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setSource(document.get().toCharArray());
CompilationUnit cu = (CompilationUnit)parser.createAST(null);
cu.recordModifications();

That will create a compilation unit for you from the source code that you pass in.

Now this is a simple function that prints out all of the methods inside the class definitions in what you have passed:

List<AbstractTypeDeclaration> types = cu.types();
for(AbstractTypeDeclaration type : types) {
    if(type.getNodeType() == ASTNode.TYPE_DECLARATION) {
        // Class def found
        List<BodyDeclaration> bodies = type.bodyDeclarations();
        for(BodyDeclaration body : bodies) {
            if(body.getNodeType() == ASTNode.METHOD_DECLARATION) {
                MethodDeclaration method = (MethodDeclaration)body;
                System.out.println("method declaration: ");
                System.out.println("name: " + method.getName().getFullyQualifiedName());
                System.out.println("modifiers: " + method.getModifiers());
                System.out.println("return type: " + method.getReturnType2().toString());
            }
        }
    }
}

This should get you all started.

It does take some time to get used to this (a lot in my case). But it does work and is the best method I could get my hands on.

Good luck ;)

ExtremeCoder


Edit:

Before I forget, these are the imports that I used to get this working (I took quite a bit of time to get these organized):

org.eclipse.jdt.core_xxxx.jar
org.eclipse.core.resources_xxxx.jar
org.eclipse.core.jobs_xxxx.jar
org.eclipse.core.runtime_xxxx.jar
org.eclipse.core.contenttype_xxxx.jar
org.eclipse.equinox.common_xxxx.jar
org.eclipse.equinox.preferences_xxxx.jar
org.eclipse.osgi_xxxx.jar
org.eclipse.text_xxxx.jar

Where xxxx represents a version number.

ExtremeCoder
A: 

You can do this with Eclipse by calling APIs that let you manipulate the ASTs.

Or you can apply program transformations to achieve your effect in way that doesn't depend on the microscopic details of the AST.

As an example you might write the following program transformation:

add_int_parameter(p:parameter_list, i: identifier): parameters -> parameters
  " \p " -> " \p , int \i";

to add an integer parameter with an arbitrary name to a parameter list. This achieves the same effect as a whole set of API calls but it is a lot more readable because it is in the surface syntax of your language (in this case, Java).

Our DMS Software Reengineering Toolkit can accept such program transformations and apply them to many languages, including Java.

Ira Baxter