All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gr.uom.java.xmi.UMLModelASTReader Maven / Gradle / Ivy

package gr.uom.java.xmi;

import static gr.uom.java.xmi.decomposition.Visitor.stringify;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;

import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.ToolFactory;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.compiler.IScanner;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.AbstractTagElement;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration;
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.Comment;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
import org.eclipse.jdt.core.dom.EnumDeclaration;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.IDocElement;
import org.eclipse.jdt.core.dom.IExtendedModifier;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.Initializer;
import org.eclipse.jdt.core.dom.JavaDocRegion;
import org.eclipse.jdt.core.dom.Javadoc;
import org.eclipse.jdt.core.dom.MemberRef;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.MethodRef;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.PackageDeclaration;
import org.eclipse.jdt.core.dom.RecordDeclaration;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
import org.eclipse.jdt.core.dom.TagElement;
import org.eclipse.jdt.core.dom.TagProperty;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclarationStatement;
import org.eclipse.jdt.core.dom.TypeParameter;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;

import com.github.gumtreediff.gen.jdt.JdtVisitor;
import com.github.gumtreediff.tree.TreeContext;

import gr.uom.java.xmi.LocationInfo.CodeElementType;
import gr.uom.java.xmi.decomposition.AbstractExpression;
import gr.uom.java.xmi.decomposition.OperationBody;
import gr.uom.java.xmi.decomposition.VariableDeclaration;

public class UMLModelASTReader {
	private static final String FREE_MARKER_GENERATED = "generated using freemarker";
	private static final String FREE_MARKER_GENERATED_2 = "generated using FreeMarker";
	private static final String ANTLR_GENERATED = "// $ANTLR";
	private static final String XTEXT_GENERATED = "generated by Xtext";
	private static final String LWJGL_GENERATED = "MACHINE GENERATED FILE, DO NOT EDIT";
	private static final String TEST_GENERATOR_GENERATED = "generated by TestGenerator";
	private static final String THRIFT_GENERATED = "Autogenerated by Thrift Compiler";
	private static final String AUTOREST_GENERATED = "AutoRest Code Generator";
	private static final String FHIR_GENERATED = "for FHIR";
	private static final String CAMEL_GENERATED = "Generated by camel-package-maven-plugin";
	private static final String DEFAULT_JAVA_CORE_VERSION = JavaCore.VERSION_14;
	private static final Pattern LEAD_WHITE_SPACE_JAVADOC = Pattern.compile("^\s+\\*", Pattern.MULTILINE);
	private UMLModel umlModel;

	public UMLModelASTReader(Map javaFileContents, Set repositoryDirectories, boolean astDiff) {
		this.umlModel = new UMLModel(repositoryDirectories);
		processJavaFileContents(javaFileContents, astDiff);
	}

	public static ASTNode processBlock(String methodBody) {
		ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
		Map options = JavaCore.getOptions();
		options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_8);
		options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8);
		options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_8);
		parser.setCompilerOptions(options);
		parser.setResolveBindings(false);
		parser.setKind(ASTParser.K_STATEMENTS);
		parser.setStatementsRecovery(true);
		char[] charArray = methodBody.toCharArray();
		parser.setSource(charArray);
		ASTNode node = parser.createAST(null);
		ASTNode methodBodyBlock = null;
		if(node instanceof Block) {
			Block extraBlockAddedByParser = (Block)node;
			if(extraBlockAddedByParser.statements().size() > 0) {
				methodBodyBlock = (ASTNode)extraBlockAddedByParser.statements().get(0);
			}
		}
		return methodBodyBlock;
	}

	private void processJavaFileContents(Map javaFileContents, boolean astDiff) {
		ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
		for(String filePath : javaFileContents.keySet()) {
			String javaFileContent = javaFileContents.get(filePath);
			if((javaFileContent.contains(FREE_MARKER_GENERATED) || javaFileContent.contains(FREE_MARKER_GENERATED_2) || javaFileContent.contains(ANTLR_GENERATED) ||
					javaFileContent.contains(XTEXT_GENERATED) || javaFileContent.contains(LWJGL_GENERATED) || javaFileContent.contains(TEST_GENERATOR_GENERATED) ||
					javaFileContent.contains(THRIFT_GENERATED) || javaFileContent.contains(AUTOREST_GENERATED) || javaFileContent.contains(FHIR_GENERATED) ||
					javaFileContent.contains(CAMEL_GENERATED)) &&
					!javaFileContent.contains("\"" + CAMEL_GENERATED + "\"") &&
					!javaFileContent.contains("private static final String FREE_MARKER_GENERATED = \"generated using freemarker\";")) {
				continue;
			}
			char[] charArray = javaFileContent.toCharArray();
			try {
				CompilationUnit compilationUnit = getCompilationUnit(DEFAULT_JAVA_CORE_VERSION, parser, charArray);
				String maxRecommendedVersionFromProblems = getMaxRecommendedVersionFromProblems(compilationUnit);
				if (maxRecommendedVersionFromProblems != null)
					compilationUnit = getCompilationUnit(maxRecommendedVersionFromProblems, parser, charArray);
				processCompilationUnit(filePath, compilationUnit, javaFileContent);
				if(astDiff) {
					IScanner scanner = ToolFactory.createScanner(true, false, false, false);
					scanner.setSource(charArray);
					JdtVisitor visitor = new JdtVisitor(scanner);
					compilationUnit.accept(visitor);
					TreeContext treeContext = visitor.getTreeContext();
					this.umlModel.getTreeContextMap().put(filePath, treeContext);
				}
			}
			catch(Exception e) {
				//e.printStackTrace();
			}
		}
	}

	private static CompilationUnit getCompilationUnit(String javaCoreVersion, ASTParser parser, char[] charArray) {
		Map options = JavaCore.getOptions();
		options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, javaCoreVersion);
		options.put(JavaCore.COMPILER_SOURCE, javaCoreVersion);
		options.put(JavaCore.COMPILER_COMPLIANCE, javaCoreVersion);
		parser.setCompilerOptions(options);
		parser.setResolveBindings(false);
		parser.setKind(ASTParser.K_COMPILATION_UNIT);
		parser.setStatementsRecovery(true);
		parser.setSource(charArray);
		return (CompilationUnit) parser.createAST(null);
	}

	private static String getMaxRecommendedVersionFromProblems(CompilationUnit compilationUnit) {
		IProblem[] problems = compilationUnit.getProblems();
		String result = null;
		for (IProblem problem : problems) {
			String[] arguments = problem.getArguments();
			if (arguments != null && arguments.length > 1) {
				try {
					double value = Double.parseDouble(arguments[1]);
					if (result == null || value > Double.parseDouble(result)) {
						result = arguments[1];
					}
				} catch (NumberFormatException e) {
//					System.out.println("Invalid number format in arguments: " + arguments[1]);
				}
			}
		}
		return result;
	}

	public UMLModel getUmlModel() {
		return this.umlModel;
	}

	protected void processCompilationUnit(String sourceFilePath, CompilationUnit compilationUnit, String javaFileContent) {
		List comments = extractInternalComments(compilationUnit, sourceFilePath, javaFileContent);
		this.umlModel.getCommentMap().put(sourceFilePath, comments);
		PackageDeclaration packageDeclaration = compilationUnit.getPackage();
		String packageName = null;
		UMLJavadoc packageDoc = null;
		UMLPackage umlPackage = null;
		if(packageDeclaration != null) {
			packageName = packageDeclaration.getName().getFullyQualifiedName();
			packageDoc = generateJavadoc(compilationUnit, sourceFilePath, packageDeclaration.getJavadoc(), javaFileContent);
			LocationInfo packageLocationInfo = generateLocationInfo(compilationUnit, sourceFilePath, packageDeclaration, CodeElementType.PACKAGE_DECLARATION);
			umlPackage = new UMLPackage(packageName, packageLocationInfo);
		}
		else {
			packageName = "";
		}
		
		List imports = compilationUnit.imports();
		List importedTypes = new ArrayList();
		for(ImportDeclaration importDeclaration : imports) {
			String elementName = importDeclaration.getName().getFullyQualifiedName();
			LocationInfo locationInfo = generateLocationInfo(compilationUnit, sourceFilePath, importDeclaration, CodeElementType.IMPORT_DECLARATION);
			UMLImport imported = new UMLImport(elementName, importDeclaration.isOnDemand(), importDeclaration.isStatic(), locationInfo);
			importedTypes.add(imported);
		}
		List topLevelTypeDeclarations = compilationUnit.types();
        for(AbstractTypeDeclaration abstractTypeDeclaration : topLevelTypeDeclarations) {
        	if(abstractTypeDeclaration instanceof TypeDeclaration) {
        		TypeDeclaration topLevelTypeDeclaration = (TypeDeclaration)abstractTypeDeclaration;
        		processTypeDeclaration(compilationUnit, topLevelTypeDeclaration, umlPackage, packageName, sourceFilePath, importedTypes, packageDoc, comments, javaFileContent);
        	}
        	else if(abstractTypeDeclaration instanceof EnumDeclaration) {
        		EnumDeclaration enumDeclaration = (EnumDeclaration)abstractTypeDeclaration;
        		processEnumDeclaration(compilationUnit, enumDeclaration, umlPackage, packageName, sourceFilePath, importedTypes, packageDoc, comments, javaFileContent);
        	}
        	else if(abstractTypeDeclaration instanceof AnnotationTypeDeclaration) {
        		AnnotationTypeDeclaration annotationDeclaration = (AnnotationTypeDeclaration)abstractTypeDeclaration;
        		processAnnotationTypeDeclaration(compilationUnit, annotationDeclaration, umlPackage, packageName, sourceFilePath, importedTypes, packageDoc, comments, javaFileContent);
        	}
        	else if(abstractTypeDeclaration instanceof RecordDeclaration) {
        		RecordDeclaration recordDeclaration = (RecordDeclaration)abstractTypeDeclaration;
        		processRecordDeclaration(compilationUnit, recordDeclaration, umlPackage, packageName, sourceFilePath, importedTypes, packageDoc, comments, javaFileContent);
        	}
        }
	}

	private List extractInternalComments(CompilationUnit cu, String sourceFile, String javaFileContent) {
		List astComments = cu.getCommentList();
		List comments = new ArrayList();
		for(Comment comment : astComments) {
			LocationInfo locationInfo = null;
			if(comment.isLineComment()) {
				locationInfo = generateLocationInfo(cu, sourceFile, comment, CodeElementType.LINE_COMMENT);
			}
			else if(comment.isBlockComment()) {
				locationInfo = generateLocationInfo(cu, sourceFile, comment, CodeElementType.BLOCK_COMMENT);
			}
			else if(comment.isDocComment() && comment.getParent() == null) {
				locationInfo = generateLocationInfo(cu, sourceFile, comment, CodeElementType.BLOCK_COMMENT);
			}
			if(locationInfo != null) {
				int start = comment.getStartPosition();
				int end = start + comment.getLength();
				String text = javaFileContent.substring(start, end);
				UMLComment umlComment = new UMLComment(text, locationInfo);
				comments.add(umlComment);
			}
		}
		return comments;
	}

	private void distributeComments(List compilationUnitComments, LocationInfo codeElementLocationInfo, List codeElementComments) {
		ListIterator listIterator = compilationUnitComments.listIterator(compilationUnitComments.size());
		while(listIterator.hasPrevious()) {
			UMLComment comment = listIterator.previous();
			LocationInfo commentLocationInfo = comment.getLocationInfo();
			if(codeElementLocationInfo.subsumes(commentLocationInfo) ||
					codeElementLocationInfo.sameLine(commentLocationInfo) ||
					(codeElementLocationInfo.nextLine(commentLocationInfo) && !codeElementLocationInfo.getCodeElementType().equals(CodeElementType.ANONYMOUS_CLASS_DECLARATION)) ||
					(codeElementComments.size() > 0 && codeElementComments.get(0).getLocationInfo().nextLine(commentLocationInfo))) {
				codeElementComments.add(0, comment);
			}
		}
		compilationUnitComments.removeAll(codeElementComments);
	}

	private UMLJavadoc generateJavadoc(CompilationUnit cu, BodyDeclaration bodyDeclaration, String sourceFile, String javaFileContent) {
		Javadoc javaDoc = bodyDeclaration.getJavadoc();
		return generateJavadoc(cu, sourceFile, javaDoc, javaFileContent);
	}

	private UMLJavadoc generateJavadoc(CompilationUnit cu, String sourceFile, Javadoc javaDoc, String javaFileContent) {
		UMLJavadoc doc = null;
		if(javaDoc != null) {
			LocationInfo locationInfo = generateLocationInfo(cu, sourceFile, javaDoc, CodeElementType.JAVADOC);
			int start = javaDoc.getStartPosition();
			int end = start + javaDoc.getLength();
			String text = javaFileContent.substring(start, end);
			Matcher matcher = LEAD_WHITE_SPACE_JAVADOC.matcher(text); 
			StringBuilder sb = new StringBuilder(); 
			while (matcher.find()) { 
				matcher.appendReplacement(sb, " \\*"); 
			} 
			matcher.appendTail(sb); 
			String trimLeadWhiteSpace = sb.toString();
			doc = new UMLJavadoc(trimLeadWhiteSpace, locationInfo);
			List tags = javaDoc.tags();
			for(TagElement parentTag : tags) {
				LocationInfo tagLocationInfo = generateLocationInfo(cu, sourceFile, parentTag, CodeElementType.TAG_ELEMENT);
				UMLTagElement parentTagElement = new UMLTagElement(parentTag.getTagName(), tagLocationInfo);
				processTagFragments(cu, sourceFile, parentTag, parentTagElement);
				doc.addTag(parentTagElement);
			}
		}
		return doc;
	}

	private void processTagFragments(CompilationUnit cu, String sourceFile, TagElement parentTag, UMLTagElement parentTagElement) {
		List fragments = parentTag.fragments();
		for(IDocElement docElement : fragments) {
			LocationInfo docElementLocationInfo = generateLocationInfo(cu, sourceFile, (ASTNode)docElement, CodeElementType.DOC_ELEMENT);
			if(docElement instanceof TagElement) {
				TagElement nestedTag = (TagElement)docElement;
				UMLTagElement nestedTagElement = new UMLTagElement(nestedTag.getTagName(), docElementLocationInfo);
				processTagFragments(cu, sourceFile, nestedTag, nestedTagElement);
				parentTagElement.addNestedTag(nestedTagElement);
			}
			else if(docElement instanceof JavaDocRegion) {
				//TODO support JavaDocRegion
			}
			else {
				UMLDocElement umlDocElement = new UMLDocElement(docElement.toString(), docElementLocationInfo);
				if(docElement instanceof Name) {
					umlDocElement.setName(true);
				}
				else if(docElement instanceof MemberRef) {
					umlDocElement.setMemberRef(true);
				}
				else if(docElement instanceof MethodRef) {
					umlDocElement.setMethodRef(true);
				}
				else if(docElement instanceof TagProperty) {
					umlDocElement.setTagProperty(true);
				}
				parentTagElement.addFragment(umlDocElement);
			}
		}
	}

	private boolean generatedCode(UMLJavadoc javadoc) {
		if(javadoc != null)
			return javadoc.contains(FREE_MARKER_GENERATED) || javadoc.contains(FREE_MARKER_GENERATED_2) ||
					javadoc.contains(ANTLR_GENERATED) || javadoc.contains(XTEXT_GENERATED);
		return false;
	}

	private void processRecordDeclaration(CompilationUnit cu, RecordDeclaration recordDeclaration, UMLPackage umlPackage, String packageName, String sourceFile,
			List importedTypes, UMLJavadoc packageDoc, List comments, String javaFileContent) {
		UMLJavadoc javadoc = generateJavadoc(cu, recordDeclaration, sourceFile, javaFileContent);
		if(generatedCode(javadoc)) {
			return;
		}
		String recordName = recordDeclaration.getName().getFullyQualifiedName();
		LocationInfo locationInfo = generateLocationInfo(cu, sourceFile, recordDeclaration, CodeElementType.RECORD_DECLARATION);
		UMLClass umlClass = new UMLClass(packageName, recordName, locationInfo, recordDeclaration.isPackageMemberTypeDeclaration(), importedTypes);
		umlClass.setJavadoc(javadoc);
		if(recordDeclaration.isPackageMemberTypeDeclaration()) {
			umlClass.setPackageDeclaration(umlPackage);
			umlClass.setPackageDeclarationJavadoc(packageDoc);
			for(UMLComment comment : comments) {
				if(comment.getLocationInfo().before(locationInfo)) {
					umlClass.getPackageDeclarationComments().add(comment);
				}
			}
			comments.removeAll(umlClass.getPackageDeclarationComments());
		}
		umlClass.setRecord(true);
		
		int startSignatureOffset = processModifiers(cu, sourceFile, recordDeclaration, umlClass);
		if(startSignatureOffset == -1) {
			startSignatureOffset = recordDeclaration.getName().getStartPosition();
		}
    	List typeParameters = recordDeclaration.typeParameters();
		for(TypeParameter typeParameter : typeParameters) {
			UMLTypeParameter umlTypeParameter = new UMLTypeParameter(typeParameter.getName().getFullyQualifiedName(),
					generateLocationInfo(cu, sourceFile, typeParameter, CodeElementType.TYPE_PARAMETER));
			List typeBounds = typeParameter.typeBounds();
			for(Type type : typeBounds) {
				umlTypeParameter.addTypeBound(UMLType.extractTypeObject(cu, sourceFile, type, 0));
			}
			List typeParameterExtendedModifiers = typeParameter.modifiers();
			for(IExtendedModifier extendedModifier : typeParameterExtendedModifiers) {
				if(extendedModifier.isAnnotation()) {
					Annotation annotation = (Annotation)extendedModifier;
					umlTypeParameter.addAnnotation(new UMLAnnotation(cu, sourceFile, annotation));
				}
			}
    		umlClass.addTypeParameter(umlTypeParameter);
    	}
    	
    	List superInterfaceTypes = recordDeclaration.superInterfaceTypes();
    	for(Type interfaceType : superInterfaceTypes) {
    		UMLType umlType = UMLType.extractTypeObject(cu, sourceFile, interfaceType, 0);
    		UMLRealization umlRealization = new UMLRealization(umlClass, umlType.getClassType());
    		umlClass.addImplementedInterface(umlType);
    		getUmlModel().addRealization(umlRealization);
    	}
    	
    	List recordComponents = recordDeclaration.recordComponents();
    	for(SingleVariableDeclaration recordComponent : recordComponents) {
			Type parameterType = recordComponent.getType();
			String parameterName = recordComponent.getName().getFullyQualifiedName();
			UMLType type = UMLType.extractTypeObject(cu, sourceFile, parameterType, recordComponent.getExtraDimensions());
			if(recordComponent.isVarargs()) {
				type.setVarargs();
			}
			LocationInfo recordComponentLocationInfo = new LocationInfo(cu, sourceFile, recordComponent, CodeElementType.RECORD_COMPONENT);
			UMLRecordComponent umlRecordComponent = new UMLRecordComponent(parameterName, type, recordComponentLocationInfo);
			VariableDeclaration variableDeclaration = new VariableDeclaration(cu, sourceFile, recordComponent, umlRecordComponent, recordComponent.isVarargs());
			variableDeclaration.setAttribute(true);
			umlRecordComponent.setVariableDeclaration(variableDeclaration);
			umlRecordComponent.setClassName(umlClass.getName());
			umlClass.addAttribute(umlRecordComponent);
		}
    	
    	Map map = processBodyDeclarations(cu, recordDeclaration, umlPackage, packageName, sourceFile, importedTypes, umlClass, packageDoc, comments, javaFileContent);
    	
    	processAnonymousClassDeclarations(cu, recordDeclaration, umlPackage, packageName, sourceFile, recordName, importedTypes, packageDoc, comments, umlClass, javaFileContent);
    	
    	for(BodyDeclaration declaration : map.keySet()) {
    		if(declaration instanceof MethodDeclaration) {
				UMLOperation operation = (UMLOperation) map.get(declaration);
				processMethodBody(cu, sourceFile, (MethodDeclaration) declaration, operation, umlClass.getAttributes());
			}
			else if(declaration instanceof Initializer) {
				UMLInitializer initializer = (UMLInitializer) map.get(declaration);
				processInitializerBody(cu, sourceFile, (Initializer) declaration, initializer, umlClass.getAttributes());
			}
    	}
    	
    	int endSignatureOffset = recordDeclaration.bodyDeclarations().size() > 0 ?
    			((BodyDeclaration)recordDeclaration.bodyDeclarations().get(0)).getStartPosition() :
    				recordDeclaration.getStartPosition() + recordDeclaration.getLength();
		String text = javaFileContent.substring(startSignatureOffset, endSignatureOffset);
		if(text.contains("{"))
			text = text.substring(0, text.indexOf("{") + 1);
		if(!text.contains("record ")) {
			umlClass.setActualSignature("record " + text);
		}
		else {
			umlClass.setActualSignature(text);
		}
		this.getUmlModel().addClass(umlClass);
		distributeComments(comments, locationInfo, umlClass.getComments());
	}

	private void processAnnotationTypeDeclaration(CompilationUnit cu, AnnotationTypeDeclaration annotationDeclaration, UMLPackage umlPackage, String packageName, String sourceFile,
			List importedTypes, UMLJavadoc packageDoc, List comments, String javaFileContent) {
		UMLJavadoc javadoc = generateJavadoc(cu, annotationDeclaration, sourceFile, javaFileContent);
		if(generatedCode(javadoc)) {
			return;
		}
		String className = annotationDeclaration.getName().getFullyQualifiedName();
		LocationInfo locationInfo = generateLocationInfo(cu, sourceFile, annotationDeclaration, CodeElementType.ANNOTATION_TYPE_DECLARATION);
		UMLClass umlClass = new UMLClass(packageName, className, locationInfo, annotationDeclaration.isPackageMemberTypeDeclaration(), importedTypes);
		umlClass.setJavadoc(javadoc);
		if(annotationDeclaration.isPackageMemberTypeDeclaration()) {
			umlClass.setPackageDeclaration(umlPackage);
			umlClass.setPackageDeclarationJavadoc(packageDoc);
			for(UMLComment comment : comments) {
				if(comment.getLocationInfo().before(locationInfo)) {
					umlClass.getPackageDeclarationComments().add(comment);
				}
			}
			comments.removeAll(umlClass.getPackageDeclarationComments());
		}
		umlClass.setAnnotation(true);
		
		int startSignatureOffset = processModifiers(cu, sourceFile, annotationDeclaration, umlClass);
		if(startSignatureOffset == -1) {
			startSignatureOffset = annotationDeclaration.getName().getStartPosition();
		}
		Map map = processBodyDeclarations(cu, annotationDeclaration, umlPackage, packageName, sourceFile, importedTypes, umlClass, packageDoc, comments, javaFileContent);
		
		processAnonymousClassDeclarations(cu, annotationDeclaration, umlPackage, packageName, sourceFile, className, importedTypes, packageDoc, comments, umlClass, javaFileContent);

		for(BodyDeclaration declaration : map.keySet()) {
			if(declaration instanceof MethodDeclaration) {
				UMLOperation operation = (UMLOperation) map.get(declaration);
				processMethodBody(cu, sourceFile, (MethodDeclaration) declaration, operation, umlClass.getAttributes());
			}
			else if(declaration instanceof Initializer) {
				UMLInitializer initializer = (UMLInitializer) map.get(declaration);
				processInitializerBody(cu, sourceFile, (Initializer) declaration, initializer, umlClass.getAttributes());
			}
		}
		
		int endSignatureOffset = annotationDeclaration.bodyDeclarations().size() > 0 ?
    			((BodyDeclaration)annotationDeclaration.bodyDeclarations().get(0)).getStartPosition() :
    				annotationDeclaration.getStartPosition() + annotationDeclaration.getLength();
		String text = javaFileContent.substring(startSignatureOffset, endSignatureOffset);
		if(text.contains("{"))
			text = text.substring(0, text.indexOf("{") + 1);
		if(!text.contains("@interface ")) {
			umlClass.setActualSignature("@interface " + text);
		}
		else {
			umlClass.setActualSignature(text);
		}
		this.getUmlModel().addClass(umlClass);
		distributeComments(comments, locationInfo, umlClass.getComments());
	}

	private void processEnumDeclaration(CompilationUnit cu, EnumDeclaration enumDeclaration, UMLPackage umlPackage, String packageName, String sourceFile,
			List importedTypes, UMLJavadoc packageDoc, List comments, String javaFileContent) {
		UMLJavadoc javadoc = generateJavadoc(cu, enumDeclaration, sourceFile, javaFileContent);
		if(generatedCode(javadoc)) {
			return;
		}
		String className = enumDeclaration.getName().getFullyQualifiedName();
		LocationInfo locationInfo = generateLocationInfo(cu, sourceFile, enumDeclaration, CodeElementType.ENUM_DECLARATION);
		UMLClass umlClass = new UMLClass(packageName, className, locationInfo, enumDeclaration.isPackageMemberTypeDeclaration(), importedTypes);
		umlClass.setJavadoc(javadoc);
		if(enumDeclaration.isPackageMemberTypeDeclaration()) {
			umlClass.setPackageDeclaration(umlPackage);
			umlClass.setPackageDeclarationJavadoc(packageDoc);
			for(UMLComment comment : comments) {
				if(comment.getLocationInfo().before(locationInfo)) {
					umlClass.getPackageDeclarationComments().add(comment);
				}
			}
			comments.removeAll(umlClass.getPackageDeclarationComments());
		}
		umlClass.setEnum(true);
		
		List superInterfaceTypes = enumDeclaration.superInterfaceTypes();
    	for(Type interfaceType : superInterfaceTypes) {
    		UMLType umlType = UMLType.extractTypeObject(cu, sourceFile, interfaceType, 0);
    		UMLRealization umlRealization = new UMLRealization(umlClass, umlType.getClassType());
    		umlClass.addImplementedInterface(umlType);
    		getUmlModel().addRealization(umlRealization);
    	}
    	
    	List enumConstantDeclarations = enumDeclaration.enumConstants();
    	for(EnumConstantDeclaration enumConstantDeclaration : enumConstantDeclarations) {
			processEnumConstantDeclaration(cu, enumConstantDeclaration, sourceFile, umlClass, comments, javaFileContent);
		}
		
    	int startSignatureOffset = processModifiers(cu, sourceFile, enumDeclaration, umlClass);
    	if(startSignatureOffset == -1) {
			startSignatureOffset = enumDeclaration.getName().getStartPosition();
		}
		Map map = processBodyDeclarations(cu, enumDeclaration, umlPackage, packageName, sourceFile, importedTypes, umlClass, packageDoc, comments, javaFileContent);
		
		processAnonymousClassDeclarations(cu, enumDeclaration, umlPackage, packageName, sourceFile, className, importedTypes, packageDoc, comments, umlClass, javaFileContent);

		for(BodyDeclaration declaration : map.keySet()) {
			if(declaration instanceof MethodDeclaration) {
				UMLOperation operation = (UMLOperation) map.get(declaration);
				processMethodBody(cu, sourceFile, (MethodDeclaration) declaration, operation, umlClass.getAttributes());
			}
			else if(declaration instanceof Initializer) {
				UMLInitializer initializer = (UMLInitializer) map.get(declaration);
				processInitializerBody(cu, sourceFile, (Initializer) declaration, initializer, umlClass.getAttributes());
			}
		}
		
		int endSignatureOffset = enumDeclaration.bodyDeclarations().size() > 0 ?
    			((BodyDeclaration)enumDeclaration.bodyDeclarations().get(0)).getStartPosition() :
    				enumDeclaration.getStartPosition() + enumDeclaration.getLength();
		String text = javaFileContent.substring(startSignatureOffset, endSignatureOffset);
		if(text.contains("{"))
			text = text.substring(0, text.indexOf("{") + 1);
		if(!text.contains("enum ")) {
			umlClass.setActualSignature("enum " + text);
		}
		else {
			umlClass.setActualSignature(text);
		}
		this.getUmlModel().addClass(umlClass);
		distributeComments(comments, locationInfo, umlClass.getComments());
	}

	private Map processBodyDeclarations(CompilationUnit cu, AbstractTypeDeclaration abstractTypeDeclaration, UMLPackage umlPackage, String packageName,
			String sourceFile, List importedTypes, UMLClass umlClass, UMLJavadoc packageDoc, List comments, String javaFileContent) {
		Map map = new LinkedHashMap<>();
		List bodyDeclarations = abstractTypeDeclaration.bodyDeclarations();
		boolean interfaceOrAnnotation = umlClass.isInterface() || umlClass.isAnnotation();
		for(BodyDeclaration bodyDeclaration : bodyDeclarations) {
			if(bodyDeclaration instanceof FieldDeclaration) {
				FieldDeclaration fieldDeclaration = (FieldDeclaration)bodyDeclaration;
				List attributes = processFieldDeclaration(cu, fieldDeclaration, interfaceOrAnnotation, sourceFile, comments, javaFileContent);
	    		for(UMLAttribute attribute : attributes) {
	    			attribute.setClassName(umlClass.getName());
	    			umlClass.addAttribute(attribute);
	    		}
			}
			else if(bodyDeclaration instanceof MethodDeclaration) {
				MethodDeclaration methodDeclaration = (MethodDeclaration)bodyDeclaration;
				UMLOperation operation = processMethodDeclaration(cu, methodDeclaration, packageName, interfaceOrAnnotation, sourceFile, comments, javaFileContent);
	    		operation.setClassName(umlClass.getName());
	    		umlClass.addOperation(operation);
	    		map.put(methodDeclaration, operation);
			}
			else if(bodyDeclaration instanceof AnnotationTypeMemberDeclaration) {
				AnnotationTypeMemberDeclaration annotationTypeMemberDeclaration = (AnnotationTypeMemberDeclaration)bodyDeclaration;
				UMLOperation operation = processAnnotationTypeMember(cu, annotationTypeMemberDeclaration, packageName, interfaceOrAnnotation, sourceFile, comments, javaFileContent);
	    		operation.setClassName(umlClass.getName());
	    		umlClass.addOperation(operation);
	    		map.put(annotationTypeMemberDeclaration, operation);
			}
			else if(bodyDeclaration instanceof Initializer) {
				Initializer initializer = (Initializer)bodyDeclaration;
				UMLInitializer umlInitializer = processInitializer(cu, initializer, packageName, false, sourceFile, comments, javaFileContent);
				umlInitializer.setClassName(umlClass.getName());
				umlClass.addInitializer(umlInitializer);
				map.put(initializer, umlInitializer);
			}
			else if(bodyDeclaration instanceof TypeDeclaration) {
				TypeDeclaration typeDeclaration = (TypeDeclaration)bodyDeclaration;
				processTypeDeclaration(cu, typeDeclaration, umlPackage, umlClass.getName(), sourceFile, importedTypes, packageDoc, comments, javaFileContent);
			}
			else if(bodyDeclaration instanceof EnumDeclaration) {
				EnumDeclaration enumDeclaration = (EnumDeclaration)bodyDeclaration;
				processEnumDeclaration(cu, enumDeclaration, umlPackage, umlClass.getName(), sourceFile, importedTypes, packageDoc, comments, javaFileContent);
			}
			else if(bodyDeclaration instanceof AnnotationTypeDeclaration) {
        		AnnotationTypeDeclaration annotationDeclaration = (AnnotationTypeDeclaration)bodyDeclaration;
        		processAnnotationTypeDeclaration(cu, annotationDeclaration, umlPackage, umlClass.getName(), sourceFile, importedTypes, packageDoc, comments, javaFileContent);
        	}
			else if(bodyDeclaration instanceof RecordDeclaration) {
				RecordDeclaration recordDeclaration = (RecordDeclaration)bodyDeclaration;
        		processRecordDeclaration(cu, recordDeclaration, umlPackage, umlClass.getName(), sourceFile, importedTypes, packageDoc, comments, javaFileContent);
			}
		}
		return map;
	}

	private void processTypeDeclaration(CompilationUnit cu, TypeDeclaration typeDeclaration, UMLPackage umlPackage, String packageName, String sourceFile,
			List importedTypes, UMLJavadoc packageDoc, List comments, String javaFileContent) {
		UMLJavadoc javadoc = generateJavadoc(cu, typeDeclaration, sourceFile, javaFileContent);
		if(generatedCode(javadoc)) {
			return;
		}
		String className = typeDeclaration.getName().getFullyQualifiedName();
		if(className.equals("$")) {
			return;
		}
		LocationInfo locationInfo = generateLocationInfo(cu, sourceFile, typeDeclaration, CodeElementType.TYPE_DECLARATION);
		UMLClass umlClass = new UMLClass(packageName, className, locationInfo, typeDeclaration.isPackageMemberTypeDeclaration(), importedTypes);
		umlClass.setJavadoc(javadoc);
		if(typeDeclaration.isPackageMemberTypeDeclaration()) {
			umlClass.setPackageDeclaration(umlPackage);
			umlClass.setPackageDeclarationJavadoc(packageDoc);
			for(UMLComment comment : comments) {
				if(comment.getLocationInfo().before(locationInfo)) {
					umlClass.getPackageDeclarationComments().add(comment);
				}
			}
			comments.removeAll(umlClass.getPackageDeclarationComments());
		}
		if(typeDeclaration.isInterface()) {
			umlClass.setInterface(true);
    	}
    	
    	int startSignatureOffset = processModifiers(cu, sourceFile, typeDeclaration, umlClass);
    	if(startSignatureOffset == -1) {
			startSignatureOffset = typeDeclaration.getName().getStartPosition();
		}
    	List typeParameters = typeDeclaration.typeParameters();
		for(TypeParameter typeParameter : typeParameters) {
			UMLTypeParameter umlTypeParameter = new UMLTypeParameter(typeParameter.getName().getFullyQualifiedName(),
					generateLocationInfo(cu, sourceFile, typeParameter, CodeElementType.TYPE_PARAMETER));
			List typeBounds = typeParameter.typeBounds();
			for(Type type : typeBounds) {
				umlTypeParameter.addTypeBound(UMLType.extractTypeObject(cu, sourceFile, type, 0));
			}
			List typeParameterExtendedModifiers = typeParameter.modifiers();
			for(IExtendedModifier extendedModifier : typeParameterExtendedModifiers) {
				if(extendedModifier.isAnnotation()) {
					Annotation annotation = (Annotation)extendedModifier;
					umlTypeParameter.addAnnotation(new UMLAnnotation(cu, sourceFile, annotation));
				}
			}
    		umlClass.addTypeParameter(umlTypeParameter);
    	}
    	
    	Type superclassType = typeDeclaration.getSuperclassType();
    	if(superclassType != null) {
    		UMLType umlType = UMLType.extractTypeObject(cu, sourceFile, superclassType, 0);
    		UMLGeneralization umlGeneralization = new UMLGeneralization(umlClass, umlType.getClassType());
    		umlClass.setSuperclass(umlType);
    		getUmlModel().addGeneralization(umlGeneralization);
    	}
    	
    	List superInterfaceTypes = typeDeclaration.superInterfaceTypes();
    	for(Type interfaceType : superInterfaceTypes) {
    		UMLType umlType = UMLType.extractTypeObject(cu, sourceFile, interfaceType, 0);
    		UMLRealization umlRealization = new UMLRealization(umlClass, umlType.getClassType());
    		umlClass.addImplementedInterface(umlType);
    		getUmlModel().addRealization(umlRealization);
    	}
    	
    	Map map = processBodyDeclarations(cu, typeDeclaration, umlPackage, packageName, sourceFile, importedTypes, umlClass, packageDoc, comments, javaFileContent);
    	
    	processAnonymousClassDeclarations(cu, typeDeclaration, umlPackage, packageName, sourceFile, className, importedTypes, packageDoc, comments, umlClass, javaFileContent);
    	
    	for(BodyDeclaration declaration : map.keySet()) {
    		if(declaration instanceof MethodDeclaration) {
				UMLOperation operation = (UMLOperation) map.get(declaration);
				processMethodBody(cu, sourceFile, (MethodDeclaration) declaration, operation, umlClass.getAttributes());
			}
			else if(declaration instanceof Initializer) {
				UMLInitializer initializer = (UMLInitializer) map.get(declaration);
				processInitializerBody(cu, sourceFile, (Initializer) declaration, initializer, umlClass.getAttributes());
			}
    	}
    	
    	int endSignatureOffset = typeDeclaration.bodyDeclarations().size() > 0 ?
    			((BodyDeclaration)typeDeclaration.bodyDeclarations().get(0)).getStartPosition() :
    			typeDeclaration.getStartPosition() + typeDeclaration.getLength();
		String text = javaFileContent.substring(startSignatureOffset, endSignatureOffset);
		if(text.contains("{"))
			text = text.substring(0, text.indexOf("{") + 1);
		if(!text.contains("class ") && !text.contains("interface ")) {
			if(typeDeclaration.isInterface()) {
				umlClass.setActualSignature("interface " + text);
			}
			else {
				umlClass.setActualSignature("class " + text);
			}
		}
		else {
			umlClass.setActualSignature(text);
		}
    	this.getUmlModel().addClass(umlClass);
		distributeComments(comments, locationInfo, umlClass.getComments());
	}

	private void processAnonymousClassDeclarations(CompilationUnit cu, AbstractTypeDeclaration typeDeclaration,
			UMLPackage umlPackage, String packageName, String sourceFile, String className,
			List importedTypes, UMLJavadoc packageDoc, List allComments, UMLClass umlClass, String javaFileContent) {
		AnonymousClassDeclarationVisitor visitor = new AnonymousClassDeclarationVisitor();
    	typeDeclaration.accept(visitor);
    	Set anonymousClassDeclarations = visitor.getAnonymousClassDeclarations();
    	
    	Set typeDeclarationStatements = visitor.getTypeDeclarationStatements();
    	
    	for(TypeDeclarationStatement statement : typeDeclarationStatements) {
    		String methodNamePath = getMethodNamePath(statement);
    		String fullName = packageName + "." + className + "." + methodNamePath;
    		AbstractTypeDeclaration localTypeDeclaration = statement.getDeclaration();
			if(localTypeDeclaration instanceof TypeDeclaration) {
        		TypeDeclaration typeDeclaration2 = (TypeDeclaration)localTypeDeclaration;
        		processTypeDeclaration(cu, typeDeclaration2, umlPackage, fullName, sourceFile, importedTypes, packageDoc, allComments, javaFileContent);
        	}
        	else if(localTypeDeclaration instanceof EnumDeclaration) {
        		EnumDeclaration enumDeclaration = (EnumDeclaration)localTypeDeclaration;
        		processEnumDeclaration(cu, enumDeclaration, umlPackage, fullName, sourceFile, importedTypes, packageDoc, allComments, javaFileContent);
        	}
        	else if(localTypeDeclaration instanceof AnnotationTypeDeclaration) {
        		AnnotationTypeDeclaration annotationDeclaration = (AnnotationTypeDeclaration)localTypeDeclaration;
        		processAnnotationTypeDeclaration(cu, annotationDeclaration, umlPackage, fullName, sourceFile, importedTypes, packageDoc, allComments, javaFileContent);
        	}
        	else if(localTypeDeclaration instanceof RecordDeclaration) {
        		RecordDeclaration recordDeclaration = (RecordDeclaration)localTypeDeclaration;
        		processRecordDeclaration(cu, recordDeclaration, umlPackage, fullName, sourceFile, importedTypes, packageDoc, allComments, javaFileContent);
        	}
    	}
    	
    	DefaultMutableTreeNode root = new DefaultMutableTreeNode();
    	for(AnonymousClassDeclaration anonymous : anonymousClassDeclarations) {
    		insertNode(anonymous, root);
    	}
    	
    	List createdAnonymousClasses = new ArrayList();
    	Enumeration enumeration = root.postorderEnumeration();
    	while(enumeration.hasMoreElements()) {
    		DefaultMutableTreeNode node = (DefaultMutableTreeNode)enumeration.nextElement();
    		if(node.getUserObject() != null) {
    			AnonymousClassDeclaration anonymous = (AnonymousClassDeclaration)node.getUserObject();
    			boolean operationFound = false;
    			boolean attributeFound = false;
    			boolean initializerFound = false;
    			UMLOperation matchingOperation = null;
    			UMLAttribute matchingAttribute = null;
    			UMLInitializer matchingInitializer = null;
    			UMLEnumConstant matchingEnumConstant = null;
    			List comments = null;
				for(UMLOperation operation : umlClass.getOperations()) {
    				if(operation.getLocationInfo().getStartOffset() <= anonymous.getStartPosition() &&
    						operation.getLocationInfo().getEndOffset() >= anonymous.getStartPosition()+anonymous.getLength()) {
    					comments = operation.getComments();
    					operationFound = true;
    					matchingOperation = operation;
    					break;
    				}
    			}
    			if(!operationFound) {
	    			for(UMLAttribute attribute : umlClass.getAttributes()) {
	    				if(attribute.getLocationInfo().getStartOffset() <= anonymous.getStartPosition() &&
	    						attribute.getLocationInfo().getEndOffset() >= anonymous.getStartPosition()+anonymous.getLength()) {
	    					comments = attribute.getComments();
	    					attributeFound = true;
	    					matchingAttribute = attribute;
	    					break;
	    				}
	    			}
    			}
    			if(!operationFound && !attributeFound) {
    				for(UMLInitializer initializer : umlClass.getInitializers()) {
    					if(initializer.getLocationInfo().getStartOffset() <= anonymous.getStartPosition() &&
    							initializer.getLocationInfo().getEndOffset() >= anonymous.getStartPosition()+anonymous.getLength()) {
	    					comments = initializer.getComments();
	    					initializerFound = true;
	    					matchingInitializer = initializer;
	    					break;
    					}
    				}
    			}
    			if(!operationFound && !attributeFound && !initializerFound) {
    				for(UMLEnumConstant enumConstant : umlClass.getEnumConstants()) {
    					if(enumConstant.getLocationInfo().getStartOffset() <= anonymous.getStartPosition() &&
    							enumConstant.getLocationInfo().getEndOffset() >= anonymous.getStartPosition()+anonymous.getLength()) {
	    					comments = enumConstant.getComments();
	    					matchingEnumConstant = enumConstant;
	    					break;
    					}
    				}
    			}
    			if(matchingOperation != null || matchingAttribute != null || matchingInitializer != null || matchingEnumConstant != null) {
	    			String anonymousBinaryName = getAnonymousBinaryName(node);
	    			String anonymousCodePath = getAnonymousCodePath(node);
	    			UMLAnonymousClass anonymousClass = processAnonymousClassDeclaration(cu, anonymous, umlPackage, packageName + "." + className, anonymousBinaryName, anonymousCodePath, sourceFile, packageDoc, comments, umlClass.getImportedTypes(), javaFileContent);
	    			umlClass.addAnonymousClass(anonymousClass);
	    			if(matchingOperation != null) {
	    				matchingOperation.addAnonymousClass(anonymousClass);
	    				anonymousClass.addParentContainer(matchingOperation);
	    			}
	    			if(matchingAttribute != null) {
	    				matchingAttribute.addAnonymousClass(anonymousClass);
	    				anonymousClass.addParentContainer(matchingAttribute);
	    			}
	    			if(matchingInitializer != null) {
	    				matchingInitializer.addAnonymousClass(anonymousClass);
	    				anonymousClass.addParentContainer(matchingInitializer);
	    			}
	    			if(matchingEnumConstant != null) {
	    				matchingEnumConstant.addAnonymousClass(anonymousClass);
	    				anonymousClass.addParentContainer(matchingEnumConstant);
	    			}
	    			for(UMLOperation operation : anonymousClass.getOperations()) {
	    				for(UMLAnonymousClass createdAnonymousClass : createdAnonymousClasses) {
	    					if(operation.getLocationInfo().subsumes(createdAnonymousClass.getLocationInfo())) {
	    						operation.addAnonymousClass(createdAnonymousClass);
	    						createdAnonymousClass.addParentContainer(operation);
	    					}
	    				}
	    			}
	    			for(UMLAttribute attribute : anonymousClass.getAttributes()) {
	    				for(UMLAnonymousClass createdAnonymousClass : createdAnonymousClasses) {
	    					if(attribute.getLocationInfo().subsumes(createdAnonymousClass.getLocationInfo())) {
	    						attribute.addAnonymousClass(createdAnonymousClass);
	    						createdAnonymousClass.addParentContainer(attribute);
	    					}
	    				}
	    			}
	    			for(UMLInitializer initializer : anonymousClass.getInitializers()) {
	    				for(UMLAnonymousClass createdAnonymousClass : createdAnonymousClasses) {
	    					if(initializer.getLocationInfo().subsumes(createdAnonymousClass.getLocationInfo())) {
	    						initializer.addAnonymousClass(createdAnonymousClass);
	    						createdAnonymousClass.addParentContainer(initializer);
	    					}
	    				}
	    			}
	    			for(UMLEnumConstant enumConstant : anonymousClass.getEnumConstants()) {
	    				for(UMLAnonymousClass createdAnonymousClass : createdAnonymousClasses) {
	    					if(enumConstant.getLocationInfo().subsumes(createdAnonymousClass.getLocationInfo())) {
	    						enumConstant.addAnonymousClass(createdAnonymousClass);
	    						createdAnonymousClass.addParentContainer(enumConstant);
	    					}
	    				}
	    			}
	    			createdAnonymousClasses.add(anonymousClass);
	    			List bodyDeclarations = anonymous.bodyDeclarations();
	    			int i=0;
	    			int j=0;
	    			for(BodyDeclaration bodyDeclaration : bodyDeclarations) {
	    				if(bodyDeclaration instanceof MethodDeclaration) {
	    					MethodDeclaration methodDeclaration = (MethodDeclaration)bodyDeclaration;
	    					UMLOperation operation = anonymousClass.getOperations().get(i);
	    					processMethodBody(cu, sourceFile, methodDeclaration, operation, umlClass.getAttributes());
	    					i++;
	    				}
	    				else if(bodyDeclaration instanceof Initializer) {
	    					Initializer initializer = (Initializer)bodyDeclaration;
	    					UMLInitializer umlInitializer = anonymousClass.getInitializers().get(j);
	    					processInitializerBody(cu, sourceFile, initializer, umlInitializer, umlClass.getAttributes());
	    					j++;
	    				}
	    			}
    			}
    		}
    	}
	}

	private void processMethodBody(CompilationUnit cu, String sourceFile, MethodDeclaration methodDeclaration, UMLOperation operation, List attributes) {
		Block block = methodDeclaration.getBody();
		if(block != null) {
			OperationBody body = new OperationBody(cu, sourceFile, block, operation, attributes);
			operation.setBody(body);
		}
		else {
			operation.setBody(null);
		}
	}

	private void processInitializerBody(CompilationUnit cu, String sourceFile, Initializer initializer, UMLInitializer umlInitializer, List attributes) {
		Block block = initializer.getBody();
		if(block != null) {
			OperationBody body = new OperationBody(cu, sourceFile, block, umlInitializer, attributes);
			umlInitializer.setBody(body);
		}
		else {
			umlInitializer.setBody(null);
		}
	}

	private int processModifiers(CompilationUnit cu, String sourceFile, AbstractTypeDeclaration typeDeclaration, UMLClass umlClass) {
		int startSignatureOffset = -1;
		int modifiers = typeDeclaration.getModifiers();
    	if((modifiers & Modifier.ABSTRACT) != 0)
    		umlClass.setAbstract(true);
    	if((modifiers & Modifier.STATIC) != 0)
    		umlClass.setStatic(true);
    	if((modifiers & Modifier.FINAL) != 0)
    		umlClass.setFinal(true);
    	
    	if((modifiers & Modifier.PUBLIC) != 0)
    		umlClass.setVisibility(Visibility.PUBLIC);
    	else if((modifiers & Modifier.PROTECTED) != 0)
    		umlClass.setVisibility(Visibility.PROTECTED);
    	else if((modifiers & Modifier.PRIVATE) != 0)
    		umlClass.setVisibility(Visibility.PRIVATE);
    	else
    		umlClass.setVisibility(Visibility.PACKAGE);
    	
    	List extendedModifiers = typeDeclaration.modifiers();
		for(IExtendedModifier extendedModifier : extendedModifiers) {
			if(extendedModifier.isAnnotation()) {
				Annotation annotation = (Annotation)extendedModifier;
				umlClass.addAnnotation(new UMLAnnotation(cu, sourceFile, annotation));
			}
			else if(extendedModifier.isModifier()) {
				Modifier modifier = (Modifier)extendedModifier;
				umlClass.addModifier(new UMLModifier(cu, sourceFile, modifier));
				if(startSignatureOffset == -1) {
					startSignatureOffset = modifier.getStartPosition();
				}
			}
		}
		return startSignatureOffset;
	}

	private UMLInitializer processInitializer(CompilationUnit cu, Initializer initializer, String packageName, boolean isInterfaceMethod, String sourceFile, List comments, String javaFileContent) {
		UMLJavadoc javadoc = generateJavadoc(cu, initializer, sourceFile, javaFileContent);
		String name = "";
		if(initializer.getParent() instanceof AnonymousClassDeclaration && initializer.getParent().getParent() instanceof ClassInstanceCreation) {
			ClassInstanceCreation creation = (ClassInstanceCreation)initializer.getParent().getParent();
			name = stringify(creation.getType());
		}
		else if(initializer.getParent() instanceof AbstractTypeDeclaration) {
			AbstractTypeDeclaration typeDeclaration = (AbstractTypeDeclaration)initializer.getParent();
			name = typeDeclaration.getName().getIdentifier();
		}
		LocationInfo locationInfo = generateLocationInfo(cu, sourceFile, initializer, CodeElementType.INITIALIZER);
		UMLInitializer umlInitializer = new UMLInitializer(name, locationInfo);
		umlInitializer.setJavadoc(javadoc);
		distributeComments(comments, locationInfo, umlInitializer.getComments());
		
		int methodModifiers = initializer.getModifiers();
		if((methodModifiers & Modifier.STATIC) != 0)
			umlInitializer.setStatic(true);
		
		return umlInitializer;
	}

	private UMLOperation processAnnotationTypeMember(CompilationUnit cu, AnnotationTypeMemberDeclaration annotationTypeMemberDeclatation, String packageName, boolean isInterfaceMethod, String sourceFile, List comments, String javaFileContent) {
		UMLJavadoc javadoc = generateJavadoc(cu, annotationTypeMemberDeclatation, sourceFile, javaFileContent);
		String methodName = annotationTypeMemberDeclatation.getName().getFullyQualifiedName();
		LocationInfo locationInfo = generateLocationInfo(cu, sourceFile, annotationTypeMemberDeclatation, CodeElementType.ANNOTATION_TYPE_MEMBER_DECLARATION);
		
		UMLOperation umlOperation = new UMLOperation(methodName, locationInfo);
		umlOperation.setJavadoc(javadoc);
		distributeComments(comments, locationInfo, umlOperation.getComments());
		
		int methodModifiers = annotationTypeMemberDeclatation.getModifiers();
		if((methodModifiers & Modifier.PUBLIC) != 0)
			umlOperation.setVisibility(Visibility.PUBLIC);
		else if((methodModifiers & Modifier.PROTECTED) != 0)
			umlOperation.setVisibility(Visibility.PROTECTED);
		else if((methodModifiers & Modifier.PRIVATE) != 0)
			umlOperation.setVisibility(Visibility.PRIVATE);
		else if(isInterfaceMethod)
			umlOperation.setVisibility(Visibility.PUBLIC);
		else
			umlOperation.setVisibility(Visibility.PACKAGE);
		
		if((methodModifiers & Modifier.ABSTRACT) != 0)
			umlOperation.setAbstract(true);
		
		if((methodModifiers & Modifier.FINAL) != 0)
			umlOperation.setFinal(true);
		
		if((methodModifiers & Modifier.STATIC) != 0)
			umlOperation.setStatic(true);
		
		if((methodModifiers & Modifier.SYNCHRONIZED) != 0)
			umlOperation.setSynchronized(true);
		
		if((methodModifiers & Modifier.NATIVE) != 0)
			umlOperation.setNative(true);
		
		if((methodModifiers & Modifier.DEFAULT) != 0)
			umlOperation.setDefault(true);
		
		List extendedModifiers = annotationTypeMemberDeclatation.modifiers();
		for(IExtendedModifier extendedModifier : extendedModifiers) {
			if(extendedModifier.isAnnotation()) {
				Annotation annotation = (Annotation)extendedModifier;
				umlOperation.addAnnotation(new UMLAnnotation(cu, sourceFile, annotation));
			}
			else if(extendedModifier.isModifier()) {
				Modifier modifier = (Modifier)extendedModifier;
				umlOperation.addModifier(new UMLModifier(cu, sourceFile, modifier));
			}
		}
		
		Type returnType = annotationTypeMemberDeclatation.getType();
		if(returnType != null) {
			UMLType type = UMLType.extractTypeObject(cu, sourceFile, returnType, 0);
			UMLParameter returnParameter = new UMLParameter("return", type, "return", false);
			umlOperation.addParameter(returnParameter);
		}
		
		if(annotationTypeMemberDeclatation.getDefault() != null) {
			AbstractExpression defaultExpression = new AbstractExpression(cu, sourceFile, annotationTypeMemberDeclatation.getDefault(), CodeElementType.ANNOTATION_TYPE_MEMBER_DEFAULT_EXPRESSION, umlOperation);
			umlOperation.setDefaultExpression(defaultExpression);
		}
		return umlOperation;
	}

	private UMLOperation processMethodDeclaration(CompilationUnit cu, MethodDeclaration methodDeclaration, String packageName, boolean isInterfaceMethod, String sourceFile, List comments, String javaFileContent) {
		UMLJavadoc javadoc = generateJavadoc(cu, methodDeclaration, sourceFile, javaFileContent);
		String methodName = methodDeclaration.getName().getFullyQualifiedName();
		LocationInfo locationInfo = generateLocationInfo(cu, sourceFile, methodDeclaration, CodeElementType.METHOD_DECLARATION);
		UMLOperation umlOperation = new UMLOperation(methodName, locationInfo);
		umlOperation.setJavadoc(javadoc);
		distributeComments(comments, locationInfo, umlOperation.getComments());
		
		if(methodDeclaration.isConstructor())
			umlOperation.setConstructor(true);
		
		int methodModifiers = methodDeclaration.getModifiers();
		if((methodModifiers & Modifier.PUBLIC) != 0)
			umlOperation.setVisibility(Visibility.PUBLIC);
		else if((methodModifiers & Modifier.PROTECTED) != 0)
			umlOperation.setVisibility(Visibility.PROTECTED);
		else if((methodModifiers & Modifier.PRIVATE) != 0)
			umlOperation.setVisibility(Visibility.PRIVATE);
		else if(isInterfaceMethod)
			umlOperation.setVisibility(Visibility.PUBLIC);
		else
			umlOperation.setVisibility(Visibility.PACKAGE);
		
		if((methodModifiers & Modifier.ABSTRACT) != 0)
			umlOperation.setAbstract(true);
		
		if((methodModifiers & Modifier.FINAL) != 0)
			umlOperation.setFinal(true);
		
		if((methodModifiers & Modifier.STATIC) != 0)
			umlOperation.setStatic(true);
		
		if((methodModifiers & Modifier.SYNCHRONIZED) != 0)
			umlOperation.setSynchronized(true);
		
		if((methodModifiers & Modifier.NATIVE) != 0)
			umlOperation.setNative(true);
		
		if((methodModifiers & Modifier.DEFAULT) != 0)
			umlOperation.setDefault(true);
		
		List extendedModifiers = methodDeclaration.modifiers();
		int startSignatureOffset = -1;
		for(IExtendedModifier extendedModifier : extendedModifiers) {
			if(extendedModifier.isAnnotation()) {
				Annotation annotation = (Annotation)extendedModifier;
				umlOperation.addAnnotation(new UMLAnnotation(cu, sourceFile, annotation));
			}
			else if(extendedModifier.isModifier()) {
				Modifier modifier = (Modifier)extendedModifier;
				umlOperation.addModifier(new UMLModifier(cu, sourceFile, modifier));
				if(startSignatureOffset == -1) {
					startSignatureOffset = modifier.getStartPosition();
				}
			}
		}
		
		List typeParameters = methodDeclaration.typeParameters();
		if(startSignatureOffset == -1 && typeParameters.size() > 0) {
			startSignatureOffset = typeParameters.get(0).getStartPosition();
		}
		for(TypeParameter typeParameter : typeParameters) {
			UMLTypeParameter umlTypeParameter = new UMLTypeParameter(typeParameter.getName().getFullyQualifiedName(),
					generateLocationInfo(cu, sourceFile, typeParameter, CodeElementType.TYPE_PARAMETER));
			List typeBounds = typeParameter.typeBounds();
			for(Type type : typeBounds) {
				umlTypeParameter.addTypeBound(UMLType.extractTypeObject(cu, sourceFile, type, 0));
			}
			List typeParameterExtendedModifiers = typeParameter.modifiers();
			for(IExtendedModifier extendedModifier : typeParameterExtendedModifiers) {
				if(extendedModifier.isAnnotation()) {
					Annotation annotation = (Annotation)extendedModifier;
					umlTypeParameter.addAnnotation(new UMLAnnotation(cu, sourceFile, annotation));
				}
			}
			umlOperation.addTypeParameter(umlTypeParameter);
		}
		
		Type returnType = methodDeclaration.getReturnType2();
		if(returnType != null) {
			if(startSignatureOffset == -1) {
				startSignatureOffset = returnType.getStartPosition();
			}
			UMLType type = UMLType.extractTypeObject(cu, sourceFile, returnType, methodDeclaration.getExtraDimensions());
			UMLParameter returnParameter = new UMLParameter("return", type, "return", false);
			umlOperation.addParameter(returnParameter);
		}
		if(startSignatureOffset == -1) {
			startSignatureOffset = methodDeclaration.getName().getStartPosition();
		}
		List parameters = methodDeclaration.parameters();
		for(SingleVariableDeclaration parameter : parameters) {
			Type parameterType = parameter.getType();
			String parameterName = parameter.getName().getFullyQualifiedName();
			UMLType type = UMLType.extractTypeObject(cu, sourceFile, parameterType, parameter.getExtraDimensions());
			if(parameter.isVarargs()) {
				type.setVarargs();
			}
			UMLParameter umlParameter = new UMLParameter(parameterName, type, "in", parameter.isVarargs());
			VariableDeclaration variableDeclaration = new VariableDeclaration(cu, sourceFile, parameter, umlOperation, parameter.isVarargs());
			variableDeclaration.setParameter(true);
			umlParameter.setVariableDeclaration(variableDeclaration);
			umlOperation.addParameter(umlParameter);
		}
		List thrownExceptionTypes = methodDeclaration.thrownExceptionTypes();
		for(Type thrownExceptionType : thrownExceptionTypes) {
			UMLType type = UMLType.extractTypeObject(cu, sourceFile, thrownExceptionType, 0);
			umlOperation.addThrownExceptionType(type);
		}
		int endSignatureOffset = methodDeclaration.getBody() != null ?
				methodDeclaration.getBody().getStartPosition() + 1 :
				methodDeclaration.getStartPosition() + methodDeclaration.getLength();
		String text = javaFileContent.substring(startSignatureOffset, endSignatureOffset);
		umlOperation.setActualSignature(text);
		return umlOperation;
	}

	private void processEnumConstantDeclaration(CompilationUnit cu, EnumConstantDeclaration enumConstantDeclaration, String sourceFile, UMLClass umlClass, List comments, String javaFileContent) {
		UMLJavadoc javadoc = generateJavadoc(cu, enumConstantDeclaration, sourceFile, javaFileContent);
		LocationInfo locationInfo = generateLocationInfo(cu, sourceFile, enumConstantDeclaration, CodeElementType.ENUM_CONSTANT_DECLARATION);
		UMLEnumConstant enumConstant = new UMLEnumConstant(enumConstantDeclaration.getName().getIdentifier(), UMLType.extractTypeObject(umlClass.getName()), locationInfo);
		VariableDeclaration variableDeclaration = new VariableDeclaration(cu, sourceFile, enumConstantDeclaration, javaFileContent);
		enumConstant.setVariableDeclaration(variableDeclaration);
		enumConstant.setJavadoc(javadoc);
		distributeComments(comments, locationInfo, enumConstant.getComments());
		enumConstant.setFinal(true);
		enumConstant.setStatic(true);
		enumConstant.setVisibility(Visibility.PUBLIC);
		List arguments = enumConstantDeclaration.arguments();
		for(Expression argument : arguments) {
			enumConstant.addArgument(stringify(argument));
		}
		enumConstant.setClassName(umlClass.getName());
		umlClass.addEnumConstant(enumConstant);
	}

	private List processFieldDeclaration(CompilationUnit cu, FieldDeclaration fieldDeclaration, boolean isInterfaceField, String sourceFile, List comments, String javaFileContent) {
		UMLJavadoc javadoc = generateJavadoc(cu, fieldDeclaration, sourceFile, javaFileContent);
		List attributes = new ArrayList();
		Type fieldType = fieldDeclaration.getType();
		List fragments = fieldDeclaration.fragments();
		for(VariableDeclarationFragment fragment : fragments) {
			UMLType type = UMLType.extractTypeObject(cu, sourceFile, fieldType, fragment.getExtraDimensions());
			String fieldName = fragment.getName().getFullyQualifiedName();
			LocationInfo locationInfo = generateLocationInfo(cu, sourceFile, fragment, CodeElementType.FIELD_DECLARATION);
			UMLAttribute umlAttribute = new UMLAttribute(fieldName, type, locationInfo);
			umlAttribute.setFieldDeclarationLocationInfo(generateLocationInfo(cu, sourceFile, fieldDeclaration, CodeElementType.FIELD_DECLARATION));
			VariableDeclaration variableDeclaration = new VariableDeclaration(cu, sourceFile, fragment, umlAttribute, javaFileContent);
			variableDeclaration.setAttribute(true);
			umlAttribute.setVariableDeclaration(variableDeclaration);
			umlAttribute.setJavadoc(javadoc);
			distributeComments(comments, locationInfo, umlAttribute.getComments());
			
			int fieldModifiers = fieldDeclaration.getModifiers();
			if((fieldModifiers & Modifier.PUBLIC) != 0)
				umlAttribute.setVisibility(Visibility.PUBLIC);
			else if((fieldModifiers & Modifier.PROTECTED) != 0)
				umlAttribute.setVisibility(Visibility.PROTECTED);
			else if((fieldModifiers & Modifier.PRIVATE) != 0)
				umlAttribute.setVisibility(Visibility.PRIVATE);
			else if(isInterfaceField)
				umlAttribute.setVisibility(Visibility.PUBLIC);
			else
				umlAttribute.setVisibility(Visibility.PACKAGE);
			
			if((fieldModifiers & Modifier.FINAL) != 0)
				umlAttribute.setFinal(true);
			
			if((fieldModifiers & Modifier.STATIC) != 0)
				umlAttribute.setStatic(true);
			
			if((fieldModifiers & Modifier.VOLATILE) != 0)
				umlAttribute.setVolatile(true);
			
			if((fieldModifiers & Modifier.TRANSIENT) != 0)
				umlAttribute.setTransient(true);
			
			attributes.add(umlAttribute);
		}
		return attributes;
	}
	
	private UMLAnonymousClass processAnonymousClassDeclaration(CompilationUnit cu, AnonymousClassDeclaration anonymous, UMLPackage umlPackage, String packageName, String binaryName, String codePath, String sourceFile, UMLJavadoc packageDoc, List comments, List importedTypes, String javaFileContent) {
		List bodyDeclarations = anonymous.bodyDeclarations();
		LocationInfo locationInfo = generateLocationInfo(cu, sourceFile, anonymous, CodeElementType.ANONYMOUS_CLASS_DECLARATION);
		UMLAnonymousClass anonymousClass = new UMLAnonymousClass(packageName, binaryName, codePath, locationInfo, importedTypes);
		
		for(BodyDeclaration bodyDeclaration : bodyDeclarations) {
			if(bodyDeclaration instanceof FieldDeclaration) {
				FieldDeclaration fieldDeclaration = (FieldDeclaration)bodyDeclaration;
				List attributes = processFieldDeclaration(cu, fieldDeclaration, false, sourceFile, comments, javaFileContent);
	    		for(UMLAttribute attribute : attributes) {
	    			attribute.setClassName(anonymousClass.getCodePath());
	    			attribute.setAnonymousClassContainer(anonymousClass);
	    			anonymousClass.addAttribute(attribute);
	    		}
			}
			else if(bodyDeclaration instanceof MethodDeclaration) {
				MethodDeclaration methodDeclaration = (MethodDeclaration)bodyDeclaration;
				UMLOperation operation = processMethodDeclaration(cu, methodDeclaration, packageName, false, sourceFile, comments, javaFileContent);
				operation.setClassName(anonymousClass.getCodePath());
				operation.setAnonymousClassContainer(anonymousClass);
				anonymousClass.addOperation(operation);
			}
			else if(bodyDeclaration instanceof Initializer) {
				Initializer initializer = (Initializer)bodyDeclaration;
				UMLInitializer umlInitializer = processInitializer(cu, initializer, packageName, false, sourceFile, comments, javaFileContent);
				umlInitializer.setClassName(anonymousClass.getCodePath());
				umlInitializer.setAnonymousClassContainer(anonymousClass);
				anonymousClass.addInitializer(umlInitializer);
			}
			else if(bodyDeclaration instanceof TypeDeclaration) {
				TypeDeclaration typeDeclaration = (TypeDeclaration)bodyDeclaration;
				processTypeDeclaration(cu, typeDeclaration, umlPackage, anonymousClass.getName(), sourceFile, importedTypes, packageDoc, comments, javaFileContent);
			}
			else if(bodyDeclaration instanceof EnumDeclaration) {
				EnumDeclaration enumDeclaration = (EnumDeclaration)bodyDeclaration;
				processEnumDeclaration(cu, enumDeclaration, umlPackage, anonymousClass.getName(), sourceFile, importedTypes, packageDoc, comments, javaFileContent);
			}
			else if(bodyDeclaration instanceof AnnotationTypeDeclaration) {
        		AnnotationTypeDeclaration annotationDeclaration = (AnnotationTypeDeclaration)bodyDeclaration;
        		processAnnotationTypeDeclaration(cu, annotationDeclaration, umlPackage, anonymousClass.getName(), sourceFile, importedTypes, packageDoc, comments, javaFileContent);
        	}
			else if(bodyDeclaration instanceof RecordDeclaration) {
				RecordDeclaration recordDeclaration = (RecordDeclaration)bodyDeclaration;
				processRecordDeclaration(cu, recordDeclaration, umlPackage, anonymousClass.getName(), sourceFile, importedTypes, packageDoc, comments, javaFileContent);
			}
		}
		distributeComments(comments, locationInfo, anonymousClass.getComments());
		return anonymousClass;
	}
	
	private void insertNode(AnonymousClassDeclaration childAnonymous, DefaultMutableTreeNode root) {
		Enumeration enumeration = root.postorderEnumeration();
		DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(childAnonymous);
		
		DefaultMutableTreeNode parentNode = root;
		while(enumeration.hasMoreElements()) {
			DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode)enumeration.nextElement();
			AnonymousClassDeclaration currentAnonymous = (AnonymousClassDeclaration)currentNode.getUserObject();
			if(currentAnonymous != null && isParent(childAnonymous, currentAnonymous)) {
				parentNode = currentNode;
				break;
			}
		}
		parentNode.add(childNode);
	}

	private String getMethodNamePath(TypeDeclarationStatement statement) {
		String name = "";
		ASTNode parent = statement.getParent();
		while(parent != null) {
			if(parent instanceof MethodDeclaration) {
				String methodName = ((MethodDeclaration)parent).getName().getIdentifier();
				if(name.isEmpty()) {
					name = methodName;
				}
				else {
					name = methodName + "." + name;
				}
			}
			parent = parent.getParent();
		}
		return name;
	}

	private String getAnonymousCodePath(DefaultMutableTreeNode node) {
		AnonymousClassDeclaration anonymous = (AnonymousClassDeclaration)node.getUserObject();
		String name = "";
		ASTNode parent = anonymous.getParent();
		while(parent != null) {
			if(parent instanceof MethodDeclaration) {
				String methodName = ((MethodDeclaration)parent).getName().getIdentifier();
				if(name.isEmpty()) {
					name = methodName;
				}
				else {
					name = methodName + "." + name;
				}
			}
			else if(parent instanceof VariableDeclarationFragment &&
					(parent.getParent() instanceof FieldDeclaration ||
					parent.getParent() instanceof VariableDeclarationStatement)) {
				String fieldName = ((VariableDeclarationFragment)parent).getName().getIdentifier();
				if(name.isEmpty()) {
					name = fieldName;
				}
				else {
					name = fieldName + "." + name;
				}
			}
			else if(parent instanceof MethodInvocation) {
				String invocationName = ((MethodInvocation)parent).getName().getIdentifier();
				if(name.isEmpty()) {
					name = invocationName;
				}
				else {
					name = invocationName + "." + name;
				}
			}
			else if(parent instanceof SuperMethodInvocation) {
				String invocationName = ((SuperMethodInvocation)parent).getName().getIdentifier();
				if(name.isEmpty()) {
					name = invocationName;
				}
				else {
					name = invocationName + "." + name;
				}
			}
			else if(parent instanceof ClassInstanceCreation) {
				String invocationName = stringify(((ClassInstanceCreation)parent).getType());
				if(name.isEmpty()) {
					name = "new " + invocationName;
				}
				else {
					name = "new " + invocationName + "." + name;
				}
			}
			parent = parent.getParent();
		}
		return name.toString();
	}

	private String getAnonymousBinaryName(DefaultMutableTreeNode node) {
		StringBuilder name = new StringBuilder();
		TreeNode[] path = node.getPath();
		for(int i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy