de.gebit.integrity.ui.utils.JavadocUtil.java Source code

Java tutorial

Introduction

Here is the source code for de.gebit.integrity.ui.utils.JavadocUtil.java

Source

/*******************************************************************************
 * Copyright (c) 2013 Rene Schneider, GEBIT Solutions GmbH and others.
 * 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
 *******************************************************************************/
package de.gebit.integrity.ui.utils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.Javadoc;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.TagElement;
import org.eclipse.jdt.core.dom.TextElement;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.xtext.common.types.JvmField;
import org.eclipse.xtext.common.types.JvmOperation;
import org.eclipse.xtext.common.types.util.jdt.IJavaElementFinder;

/**
 * This utility class contains various helper functions to aid in the exploration of Javadoc data attached to classes.
 * Only for use inside Eclipse!
 * 
 * @author Rene Schneider - initial API and implementation
 * 
 */
public final class JavadocUtil {

    private JavadocUtil() {
        // nothing to do
    }

    /**
     * The options to use when parsing a Java Abstract Syntax Tree.
     */
    @SuppressWarnings("rawtypes")
    private static final Map ASTPARSER_OPTIONS = JavaCore.getDefaultOptions();

    private static MethodDeclaration getMethodDeclaration(JvmOperation aMethod,
            IJavaElementFinder anElementFinder) {
        IJavaElement tempSourceMethod = (IJavaElement) anElementFinder.findElementFor(aMethod);

        // That parent may also be an instance of org.eclipse.jdt.internal.core.ClassFile - in that case there's
        // no Javadoc anyway
        if (tempSourceMethod.getParent().getParent() instanceof ICompilationUnit) {
            ICompilationUnit tempCompilationUnit = (ICompilationUnit) tempSourceMethod.getParent().getParent();

            AbstractTypeDeclaration tempType = parseCompilationUnit(tempCompilationUnit);

            if (tempType instanceof TypeDeclaration) {
                for (MethodDeclaration tempMethod : ((TypeDeclaration) tempType).getMethods()) {
                    // We only check the plain method name and omit the full
                    // signature check here because fixture method names are
                    // required to be unique per class
                    if (aMethod.getSimpleName().equals(tempMethod.getName().getFullyQualifiedName())) {
                        return tempMethod;
                    }
                }
            }
        }

        return null;
    }

    /**
     * Returns a map of parameter names to Javadoc descriptions for a given Java method. This explores the @param
     * Javadoc parameter. Parameters which don't have such an information attached will not be put into the resulting
     * map.
     * 
     * @param aMethod
     *            the Java method to explore
     * @param anElementFinder
     *            the element finder to use for locating the {@link IJavaElement} to the given method
     * @return the result map, or null if there is no readable Javadoc at all
     */
    public static Map<String, String> getMethodParamJavadoc(JvmOperation aMethod,
            IJavaElementFinder anElementFinder) {
        MethodDeclaration tempMethodDeclaration = getMethodDeclaration(aMethod, anElementFinder);

        if (tempMethodDeclaration == null) {
            return null;
        }

        Javadoc tempJavaDoc = tempMethodDeclaration.getJavadoc();
        if (tempJavaDoc != null) {
            Map<String, String> tempResultMap = new HashMap<String, String>();
            for (Object tempTagObject : tempJavaDoc.tags()) {
                TagElement tempTag = (TagElement) tempTagObject;
                if (TagElement.TAG_PARAM.equals(tempTag.getTagName())) {
                    if (tempTag.fragments().size() >= 2) {
                        Object tempSimpleNameElement = tempTag.fragments().get(0);
                        Object tempTextElement = tempTag.fragments().get(1);
                        if ((tempSimpleNameElement instanceof SimpleName)
                                && (tempTextElement instanceof TextElement)) {
                            tempResultMap.put(((SimpleName) tempSimpleNameElement).getFullyQualifiedName(),
                                    ((TextElement) tempTextElement).getText());
                        }
                    }
                }
            }
            return tempResultMap;
        }

        return null;
    }

    /**
     * Returns the Javadoc text attached to a given Java Method.
     * 
     * @param aMethod
     *            the method to explore
     * @param anElementFinder
     *            the element finder to use for locating the {@link IJavaElement} for the given method
     * @return the Javadoc text, or null if none is available
     */
    public static String getMethodJavadoc(JvmOperation aMethod, IJavaElementFinder anElementFinder) {
        MethodDeclaration tempMethodDeclaration = getMethodDeclaration(aMethod, anElementFinder);

        if (tempMethodDeclaration == null) {
            return null;
        }

        Javadoc tempJavaDoc = tempMethodDeclaration.getJavadoc();
        if (tempJavaDoc != null) {
            return getJavadocMainText(tempJavaDoc);
        }

        return null;
    }

    /**
     * Returns the Javadoc description attached to a given {@link IField}.
     * 
     * @param aField
     *            the field to explore
     * @return the Javadoc String, or null if there is none
     */
    public static String getFieldJavadoc(IField aField) {
        ICompilationUnit tempCompilationUnit = aField.getCompilationUnit();
        AbstractTypeDeclaration tempType = parseCompilationUnit(tempCompilationUnit);

        if (tempType instanceof TypeDeclaration) {
            List<TypeDeclaration> tempTypes = new ArrayList<TypeDeclaration>();
            tempTypes.add((TypeDeclaration) tempType);
            // also visit all subtypes (inner classes!)
            Collections.addAll(tempTypes, ((TypeDeclaration) tempType).getTypes());

            for (TypeDeclaration tempTypeDeclaration : tempTypes) {
                for (FieldDeclaration tempField : tempTypeDeclaration.getFields()) {
                    if (compareFields(tempField, aField)) {
                        Javadoc tempJavadoc = tempField.getJavadoc();
                        if (tempJavadoc != null) {
                            return getJavadocMainText(tempJavadoc);
                        } else {
                            break;
                        }
                    }
                }
            }
        }

        return null;
    }

    /**
     * Returns the Javadoc text attached to a given field.
     * 
     * @param aField
     *            the field
     * @param anElementFinder
     *            the element finder
     * @return the Javadoc text or null if there is none
     */
    public static String getJvmFieldJavadoc(JvmField aField, IJavaElementFinder anElementFinder) {
        IJavaElement tempElement = anElementFinder.findElementFor(aField);

        if (tempElement instanceof IField) {
            return getFieldJavadoc((IField) tempElement);
        }

        return null;
    }

    /**
     * Returns the main text part from the given Javadoc.
     * 
     * @param aJavadoc
     *            the Javadoc object to explore
     * @return the text, or null if there is none
     */
    protected static String getJavadocMainText(Javadoc aJavadoc) {
        for (Object tempTagObject : aJavadoc.tags()) {
            TagElement tempTag = (TagElement) tempTagObject;
            if (tempTag.getTagName() == null) {
                StringBuffer tempText = new StringBuffer();
                for (Object tempPossibleTextElement : tempTag.fragments()) {
                    if (tempPossibleTextElement instanceof TextElement) {
                        tempText.append(((TextElement) tempPossibleTextElement).getText());
                        tempText.append(' ');
                    }
                }
                if (tempText.length() > 0) {
                    return tempText.toString();
                }
            }
        }

        return null;
    }

    /**
     * This checks whether a given {@link FieldDeclaration} and {@link IField} refer to the same field.
     * 
     * @param aFieldDeclaration
     *            the field declaration
     * @param aField
     *            the field
     * @return true if both refer to the same field, false otherwise
     */
    protected static boolean compareFields(FieldDeclaration aFieldDeclaration, IField aField) {
        @SuppressWarnings("unchecked")
        List<VariableDeclarationFragment> tempFragments = aFieldDeclaration.fragments();
        for (VariableDeclarationFragment tempVariableDeclarationFragment : tempFragments) {
            if (tempVariableDeclarationFragment.getName().getIdentifier().equals(aField.getElementName())) {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns the {@link AbstractTypeDeclaration} for the given {@link ICompilationUnit}. This basically parses the
     * given compilation unit into an Abstract Syntax Tree, using the parser provided by the JDT for the job.
     * 
     * @param aCompilationUnit
     *            the compilation unit to parse
     * @return the AST
     */
    protected static AbstractTypeDeclaration parseCompilationUnit(ICompilationUnit aCompilationUnit) {
        ASTParser tempParser = ASTParser.newParser(AST.JLS4);
        tempParser.setSource(aCompilationUnit);
        tempParser.setIgnoreMethodBodies(true);
        tempParser.setKind(ASTParser.K_COMPILATION_UNIT);
        tempParser.setCompilerOptions(ASTPARSER_OPTIONS);
        CompilationUnit tempNode = (CompilationUnit) tempParser.createAST(null);

        return (AbstractTypeDeclaration) tempNode.types().get(0);
    }

}