/******************************************************************************* * Copyright (c) 2010, 2011 Obeo. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Obeo - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.docs.intent.bridge.java.resource.factory; import java.util.Collection; import java.util.LinkedHashSet; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.ILocalVariable; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; import org.eclipse.mylyn.docs.intent.bridge.java.AbstractCapableElement; import org.eclipse.mylyn.docs.intent.bridge.java.Classifier; import org.eclipse.mylyn.docs.intent.bridge.java.ClassifierKind; import org.eclipse.mylyn.docs.intent.bridge.java.Field; import org.eclipse.mylyn.docs.intent.bridge.java.JavaFactory; import org.eclipse.mylyn.docs.intent.bridge.java.Javadoc; import org.eclipse.mylyn.docs.intent.bridge.java.Method; import org.eclipse.mylyn.docs.intent.bridge.java.Parameter; import org.eclipse.mylyn.docs.intent.bridge.java.VisibilityKind; import org.eclipse.mylyn.docs.intent.bridge.java.VisibleElement; /** * A class allowing to represent Java classes as models. * * @author <a href="mailto:alex.lagarde@obeo.fr">Alex Lagarde</a> */ public class JavaClassExplorer { /** * Constant identifying opening brackets. */ private static final String OPENING_BRACKET = "{"; /** * Constant identifying closing brackets. */ private static final String CLOSING_BRACKET = "}"; /** * Allows to represent all the {@link IType}s contained in the given {@link ICompilationUnit} as * {@link Classifier}s. * * @param path * the path of this element from the workspace root * @param javaClass * the {@link ICompilationUnit} to inspect * @return the {@link Classifier}s corresponding to the {@link IType}s contained in the given * {@link ICompilationUnit} * @throws JavaModelException * if errors occur while querying the java class */ public Collection<Classifier> getJavaClassAsModel(String path, ICompilationUnit javaClass) throws JavaModelException { Collection<Classifier> eClassifiers = new LinkedHashSet<Classifier>(); IType[] allTypes; allTypes = javaClass.getAllTypes(); for (IType iType : allTypes) { eClassifiers.add(getTypeAsModel(path, iType)); } return eClassifiers; } /** * Allows to represent the given {@link IType} as a {@link Classifier}. * * @param path * the path of this element from the workspace root * @param iType * the {@link IType} to inspect * @return a {@link Classifier} corresponding to the given {@link IType} * @throws JavaModelException * if errors occur while querying the type */ private Classifier getTypeAsModel(String path, IType iType) throws JavaModelException { Classifier eClassifier = JavaFactory.eINSTANCE.createClassifier(); eClassifier.setClassifierPath(path); eClassifier.setName(iType.getFullyQualifiedName()); updateAbstractInformations(eClassifier, iType); updateVisibilityInformations(eClassifier, iType); eClassifier.setJavadoc(getJavadocAsModel(iType)); // Is this class an implementation ? int flags = iType.getFlags(); if (Flags.isInterface(flags)) { eClassifier.setKind(ClassifierKind.INTERFACE); } else if (Flags.isEnum(flags)) { eClassifier.setKind(ClassifierKind.ENUM); } else { eClassifier.setKind(ClassifierKind.CLASS); } // class supertypes and implemented interfaces eClassifier.setExtends(iType.getSuperclassName()); for (String superInterface : iType.getSuperInterfaceNames()) { eClassifier.getImplements().add(superInterface); } for (IField field : iType.getFields()) { eClassifier.getFields().add(getFieldAsModel(path, field)); } for (IMethod method : iType.getMethods()) { eClassifier.getMethods().add(getMethodAsModel(path, method)); } return eClassifier; } /** * Allows to represent the given {@link IMethod} as a {@link Method}. * * @param path * the path of this element from the workspace root * @param method * the {@link IMethod} to inspect * @return a {@link Method} corresponding to the given {@link IMethod} * @throws JavaModelException * if errors occur while querying the method */ private Method getMethodAsModel(String path, IMethod method) throws JavaModelException { Method eMethod = null; if (method.isConstructor()) { eMethod = JavaFactory.eINSTANCE.createConstructor(); } else { eMethod = JavaFactory.eINSTANCE.createMethod(); } JavaFactory.eINSTANCE.createMethod(); eMethod.setSimpleName(method.getElementName()); updateAbstractInformations(eMethod, method); updateVisibilityInformations(eMethod, method); eMethod.setJavadoc(getJavadocAsModel(method)); eMethod.setReturnType(getTypeFromTypeSignature(method.getReturnType())); for (ILocalVariable parameter : method.getParameters()) { Parameter eParameter = JavaFactory.eINSTANCE.createParameter(); eParameter.setName(parameter.getElementName()); eParameter.setType(getTypeFromTypeSignature(parameter.getTypeSignature())); String attachedJavadoc = parameter.getAttachedJavadoc(new NullProgressMonitor()); if (attachedJavadoc != null && attachedJavadoc.length() > 0) { Javadoc paramJavaDoc = JavaFactory.eINSTANCE.createJavadoc(); paramJavaDoc.setContent(attachedJavadoc); eParameter.setJavadoc(paramJavaDoc); } eMethod.getParameters().add(eParameter); } for (String exceptionType : method.getExceptionTypes()) { eMethod.getExceptions().add(getTypeFromTypeSignature(exceptionType)); } // Setting method content if neither abstract or interface String methodContentWithoutJavaDoc = method.getSource(); if (methodContentWithoutJavaDoc.contains(OPENING_BRACKET) && methodContentWithoutJavaDoc.contains(CLOSING_BRACKET)) { if (method.getJavadocRange() != null) { methodContentWithoutJavaDoc = method.getSource().substring( method.getJavadocRange().getLength()); } String methodContentWithoutDeclaration = methodContentWithoutJavaDoc.trim(); if (methodContentWithoutDeclaration.contains(OPENING_BRACKET) && methodContentWithoutDeclaration.contains(CLOSING_BRACKET)) { methodContentWithoutDeclaration = methodContentWithoutJavaDoc .substring(methodContentWithoutJavaDoc.indexOf(OPENING_BRACKET) + 1); methodContentWithoutDeclaration = methodContentWithoutDeclaration.substring(0, methodContentWithoutDeclaration.lastIndexOf(CLOSING_BRACKET)).trim(); // Normalize line delimiters and tabulations String methodContent = ""; String[] methodLines = methodContentWithoutDeclaration.split("\n"); for (int i = 0; i < methodLines.length; i++) { methodContent += methodLines[i].trim().replace("\t", "") + "\n"; } methodContent = methodContent.trim(); eMethod.setContent(methodContent); } } eMethod.setName(getMethodID(method)); eMethod.setClassifierPath(path); return eMethod; } /** * Allows to represent the given {@link IField} as a {@link Field}. * * @param path * the path of this element from the workspace root * @param field * the {@link field} to inspect * @return a {@link Field} corresponding to the given {@link IField} * @throws JavaModelException * if errors occur while querying the field */ private Field getFieldAsModel(String path, IField field) throws JavaModelException { Field eField = JavaFactory.eINSTANCE.createField(); eField.setName(field.getElementName()); eField.setJavadoc(getJavadocAsModel(field)); eField.setType(getTypeFromTypeSignature(field.getTypeSignature())); eField.setClassifierPath(path); String fieldTypeSignature = Signature.toString(field.getTypeSignature()); if (fieldTypeSignature != null) { String[][] resolvedType = field.getDeclaringType().resolveType(fieldTypeSignature); if (resolvedType != null) { eField.setQualifiedType(Signature.toQualifiedName(resolvedType[0])); } } updateVisibilityInformations(eField, field); return eField; } /** * Allows to represent the javadoc of the given {@link IMember} as a {@link Javadoc}. * * @param iMember * the {@link IMember} to inspect * @return a {@link Javadoc} corresponding to the given {@link IMember}'s javadoc * @throws JavaModelException * if errors occur while querying the member */ private Javadoc getJavadocAsModel(IMember iMember) throws JavaModelException { Javadoc eJavaDoc = null; if (iMember.getJavadocRange() != null) { eJavaDoc = JavaFactory.eINSTANCE.createJavadoc(); eJavaDoc.setContent(iMember.getOpenable().getBuffer() .getText(iMember.getJavadocRange().getOffset(), iMember.getJavadocRange().getLength())); } return eJavaDoc; } /** * Sets the given{@link AbstractCapableElement} as abstract if the given {@link IMember} is abstract. * * @param abstactCapableElement * the {@link AbstractCapableElement} to update * @param iMember * the {@link IMember} to inspect * @throws JavaModelException * if errors occur while querying the member */ private void updateAbstractInformations(AbstractCapableElement abstactCapableElement, IMember iMember) throws JavaModelException { abstactCapableElement.setAbstract(Flags.isAbstract(iMember.getFlags())); } /** * Updates the visibility informations of the given {@link VisibleElement} (is it public ? final ? static * ?) * * @param visiblementElement * the {@link VisibleElement} to update * @param iMember * the {@link IMember} to inspect * @throws JavaModelException * if errors occur while querying the member */ private void updateVisibilityInformations(VisibleElement visiblementElement, IMember iMember) throws JavaModelException { int flags = iMember.getFlags(); visiblementElement.setFinal(Flags.isFinal(flags)); visiblementElement.setStatic(Flags.isStatic(flags)); if (Flags.isPublic(flags)) { visiblementElement.setVisibility(VisibilityKind.PUBLIC); } else if (Flags.isProtected(flags)) { visiblementElement.setVisibility(VisibilityKind.PROTECTED); } else if (Flags.isPrivate(flags)) { visiblementElement.setVisibility(VisibilityKind.PRIVATE); } else { visiblementElement.setVisibility(VisibilityKind.PACKAGE); } } /** * Returns a normalized form of the given type signature (e.g. transforms 'QExampleJavaClass;' in * 'ExampleJavaClass'. * * @param typeSignature * the type signature as given by JDT * @return the normalized form of the given type signature */ public static String getTypeFromTypeSignature(String typeSignature) { return Signature.toString(typeSignature); } /** * Returns the identifier used to identify the given {@link IMember}. * * @param member * the {@link IMember} to inspect * @return the identifier used to identify the given {@link IMember} * @throws JavaModelException * if errors occur while querying the member */ public static String getMemberID(IMember member) throws JavaModelException { if (member instanceof IMethod) { return getMethodID((IMethod)member); } else { return member.getElementName(); } } /** * Returns the identifier used to identify the given {@link IMethod}. * * @param method * the {@link IMethod} to inspect * @return the identifier used to identify the given {@link IMethod} * @throws JavaModelException * if errors occur while querying the member */ public static String getMethodID(IMethod method) throws JavaModelException { String methodSignature = method.getElementName() + "("; for (ILocalVariable parameter : method.getParameters()) { methodSignature += "," + getTypeFromTypeSignature(parameter.getTypeSignature()); } methodSignature = methodSignature.replaceFirst(",", "") + ")"; return methodSignature; } }