package gxtbeans.actions;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
public class NewClassGenerator extends ASTVisitor{
private AST ast = AST.newAST(AST.JLS3);
private ICompilationUnit newCompilationUnit;
private ICompilationUnit oldCompilationUnit;
private List<MethodDeclaration> getMethods;
private List<MethodDeclaration> setMethods;
public NewClassGenerator(ICompilationUnit oldCompilationUnit, ICompilationUnit newCompilationUnit){
super();
this.newCompilationUnit = newCompilationUnit;
this.oldCompilationUnit = oldCompilationUnit;
}
@Override
public boolean visit(TypeDeclaration node) {
Type superType = node.getSuperclassType();
// System.out.println("Class: " + node.getName() + " extends " + ((superType == null) ? "Object" : superType));
String superTypeName = "";
if (superType == null){
superTypeName = "BaseModel";
} else {
superTypeName = superType.toString();
}
/*
* build the new class using AST
*/
TypeDeclaration newType = ast.newTypeDeclaration();
newType.setInterface(node.isInterface());
newType.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD));
newType.setName(ast.newSimpleName(node.getName().getIdentifier()));
newType.setSuperclassType(ast.newSimpleType(ast.newSimpleName(superTypeName)));
/*
* create the get and set methods only
*/
MethodDeclaration[] methods = node.getMethods();
setMethods = new ArrayList<MethodDeclaration>();
getMethods = new ArrayList<MethodDeclaration>();
for (MethodDeclaration method : methods){
if (method.isConstructor()) // it is a constructor
continue;
if (method.thrownExceptions().size() > 0) // it throws exceptions
continue;
if ((method.getModifiers() & Modifier.PUBLIC) == 0) // is not public
continue;
if (method.getName().getIdentifier().startsWith("get")) {
MethodDeclaration newMethod = copyMethodDeclaration(newType.getAST(), method);
getMethods.add(method);
/*
* the statement
*/
org.eclipse.jdt.core.dom.Block block = ast.newBlock();
MethodInvocation methodInvocation = ast.newMethodInvocation();
methodInvocation.setName(ast.newSimpleName("get"));
/*
* the parameter
*/
String thePropertyKey = method.getName().toString().substring(3);
StringLiteral literal = ast.newStringLiteral();
literal.setLiteralValue(thePropertyKey);
methodInvocation.arguments().add(literal);
/*
* the return statement
*/
ReturnStatement returnStatement = ast.newReturnStatement();
returnStatement.setExpression(methodInvocation);
block.statements().add(returnStatement); //add the return statement to the block
newMethod.setBody(block); // add the block to the method
newType.bodyDeclarations().add(newMethod); //add the method to the type
}
if (method.getName().getIdentifier().startsWith("set")) {
List<SingleVariableDeclaration> parameters = method.parameters();
if (parameters.size() != 1)
continue;
setMethods.add(method);
MethodDeclaration newMethod = copyMethodDeclaration(newType.getAST(), method);
SingleVariableDeclaration oldParameter = parameters.get(0);
SimpleName paramName = oldParameter.getName();
/*
* the statement
*/
org.eclipse.jdt.core.dom.Block block = ast.newBlock();
MethodInvocation methodInvocation = ast.newMethodInvocation();
methodInvocation.setName(ast.newSimpleName("set"));
/*
* the parameters
*/
String thePropertyKey = method.getName().toString().substring(3);
StringLiteral literal = ast.newStringLiteral();
literal.setLiteralValue(thePropertyKey);
methodInvocation.arguments().add(literal);
methodInvocation.arguments().add(paramName.copySubtree(newMethod.getAST(), paramName));
ExpressionStatement expressionStatement = ast.newExpressionStatement(methodInvocation);
block.statements().add(expressionStatement);
newMethod.setBody(block); // add the block to the method
newType.bodyDeclarations().add(newMethod); //add the method to the type
}
}
/*
* create the new class
*/
try {
IType newClass = this.newCompilationUnit.createType(newType.toString(), null, true, null);
/*
* add a new method to the original class. this method makes the new object from the old
*/
// creation of a Document
String source = oldCompilationUnit.getSource();
Document document= new Document(source);
CompilationUnit astRoot = (CompilationUnit) node.getRoot();
// start record of the modifications
astRoot.recordModifications();
// modify the AST
node.bodyDeclarations().add(createToGXT(node.getAST(), getMethods, newClass.getFullyQualifiedName()));
// computation of the text edits
TextEdit edits = astRoot.rewrite(document, oldCompilationUnit.getJavaProject().getOptions(true));
// computation of the new source code
edits.apply(document);
String newSource = document.get();
// update of the compilation unit
oldCompilationUnit.getBuffer().setContents(newSource);
} catch (JavaModelException e) {
e.printStackTrace();
}
return super.visit(node);
}
private MethodDeclaration createToGXT(AST ast, List<MethodDeclaration> getMethods, String newType){
/*
* method header
*/
MethodDeclaration toGXTmethod = ast.newMethodDeclaration();
toGXTmethod.setConstructor(false);
List modifiers = toGXTmethod.modifiers();
modifiers.add(ast.newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD));
toGXTmethod.setName(ast.newSimpleName("toGXTModelBean"));
Type returnType = ast.newSimpleType(ast.newName(newType));
toGXTmethod.setReturnType2(returnType);
/*
* method body starting with the block
*/
org.eclipse.jdt.core.dom.Block block = ast.newBlock();
/*
* define the return value
*/
SimpleName returnValueName = ast.newSimpleName("newGXTBean");
VariableDeclarationFragment fragment = ast.newVariableDeclarationFragment();
fragment.setName(returnValueName);
ClassInstanceCreation newClassInstance = ast.newClassInstanceCreation();
newClassInstance.setType((Type)returnType.copySubtree(ast, returnType));
fragment.setInitializer(newClassInstance);
VariableDeclarationStatement returnValue = ast.newVariableDeclarationStatement(fragment);
returnValue.setType((Type)returnType.copySubtree(ast, returnType));
block.statements().add(returnValue);
/*
* call each get method in the original and pass the result to the new set method
*
*/
for (MethodDeclaration method : getMethods){
/*
* the set expression
*/
String propertyName = method.getName().toString().substring(3);
MethodInvocation methodInvocation = ast.newMethodInvocation();
methodInvocation.setExpression((Name)returnValueName.copySubtree(ast, returnValueName));
methodInvocation.setName(ast.newSimpleName("set"));
/*
* the get expression
*/
MethodInvocation paramInvocation = ast.newMethodInvocation();
String getterName = "get" + propertyName;
paramInvocation.setName(ast.newSimpleName(getterName));
methodInvocation.arguments().add(paramInvocation);
ExpressionStatement expressionStatement = ast.newExpressionStatement(methodInvocation);
block.statements().add(expressionStatement);
}
/*
* return the newly created object
*/
ReturnStatement returnStatement = ast.newReturnStatement();
returnStatement.setExpression((SimpleName)returnValueName.copySubtree(ast, returnValueName));
block.statements().add(returnStatement);
toGXTmethod.setBody(block); // add the block to the method
return toGXTmethod;
}
private MethodDeclaration copyMethodDeclaration(AST targetAST, MethodDeclaration source){
@SuppressWarnings("static-access")
MethodDeclaration target = (MethodDeclaration) source.copySubtree(targetAST, source);
return target;
}
}