ch.acanda.eclipse.pmd.java.resolution.design.UseUtilityClassQuickFix.java Source code

Java tutorial

Introduction

Here is the source code for ch.acanda.eclipse.pmd.java.resolution.design.UseUtilityClassQuickFix.java

Source

// =====================================================================
//
// Copyright (C) 2012 - 2016, Philip Graf
//
// 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 ch.acanda.eclipse.pmd.java.resolution.design;

import java.util.List;

import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IExtendedModifier;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.text.Position;

import ch.acanda.eclipse.pmd.java.resolution.ASTUtil;
import ch.acanda.eclipse.pmd.java.resolution.Finders;
import ch.acanda.eclipse.pmd.java.resolution.NodeFinder;
import ch.acanda.eclipse.pmd.java.resolution.ASTRewriteQuickFix;
import ch.acanda.eclipse.pmd.marker.PMDMarker;
import ch.acanda.eclipse.pmd.ui.util.PMDPluginImages;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;

/**
 * Quick fix for the rule <a
 * href="http://pmd.sourceforge.net/rules/java/design.html#UseUtilityClass">UseUtilityClass</a>. It makes the class
 * final and adds a private constructor.
 *
 * @author Philip Graf
 */
public final class UseUtilityClassQuickFix extends ASTRewriteQuickFix<TypeDeclaration> {

    public UseUtilityClassQuickFix(final PMDMarker marker) {
        super(marker);
    }

    @Override
    protected ImageDescriptor getImageDescriptor() {
        return PMDPluginImages.QUICKFIX_CHANGE;
    }

    @Override
    public String getLabel() {
        return "Convert to utility class";
    }

    @Override
    public String getDescription() {
        return "Makes the class final and adds a private constructor.";
    }

    @Override
    protected NodeFinder<CompilationUnit, TypeDeclaration> getNodeFinder(final Position position) {
        return Finders.positionWithinNode(position, getNodeType());
    }

    /**
     * Makes the class final and adds a private constructor.
     */
    @Override
    protected boolean rewrite(final TypeDeclaration typeDeclaration, final ASTRewrite rewrite)
            throws JavaModelException {
        addFinalIfNecessary(typeDeclaration, rewrite);
        addPrivateConstructor(typeDeclaration, rewrite);
        return true;
    }

    private void addFinalIfNecessary(final TypeDeclaration typeDeclaration, final ASTRewrite rewrite) {
        @SuppressWarnings("unchecked")
        final List<IExtendedModifier> modifiers = typeDeclaration.modifiers();
        if (!Iterables.any(modifiers, isFinal())) {
            final ListRewrite modifierRewrite = rewrite.getListRewrite(typeDeclaration,
                    TypeDeclaration.MODIFIERS2_PROPERTY);
            final Modifier modifier = (Modifier) typeDeclaration.getAST().createInstance(Modifier.class);
            modifier.setKeyword(ModifierKeyword.FINAL_KEYWORD);
            modifierRewrite.insertLast(modifier, null);
        }
    }

    @SuppressWarnings("unchecked")
    private void addPrivateConstructor(final TypeDeclaration typeDeclaration, final ASTRewrite rewrite) {
        final AST ast = typeDeclaration.getAST();
        final MethodDeclaration constructor = (MethodDeclaration) ast.createInstance(MethodDeclaration.class);
        constructor.setConstructor(true);

        final Modifier modifier = (Modifier) ast.createInstance(Modifier.class);
        modifier.setKeyword(ModifierKeyword.PRIVATE_KEYWORD);
        constructor.modifiers().add(modifier);

        constructor.setName(ASTUtil.copy(typeDeclaration.getName()));

        final Block body = (Block) ast.createInstance(Block.class);
        constructor.setBody(body);

        final ListRewrite statementRewrite = rewrite.getListRewrite(body, Block.STATEMENTS_PROPERTY);
        final ASTNode comment = rewrite.createStringPlaceholder("// hide constructor of utility class",
                ASTNode.EMPTY_STATEMENT);
        statementRewrite.insertFirst(comment, null);

        final int position = findConstructorPosition(typeDeclaration);
        final ListRewrite bodyDeclarationRewrite = rewrite.getListRewrite(typeDeclaration,
                TypeDeclaration.BODY_DECLARATIONS_PROPERTY);
        bodyDeclarationRewrite.insertAt(constructor, position, null);
    }

    private Predicate<? super IExtendedModifier> isFinal() {
        return new Predicate<IExtendedModifier>() {
            @Override
            public boolean apply(final IExtendedModifier modifier) {
                return modifier.isModifier() && ((Modifier) modifier).isFinal();
            }
        };
    }

    /**
     * The new private constructor should be inserted before the first method declaration.
     */
    private int findConstructorPosition(final TypeDeclaration typeDeclaration) {
        @SuppressWarnings("unchecked")
        final List<BodyDeclaration> bodyDeclarations = typeDeclaration.bodyDeclarations();
        for (int i = 0; i < bodyDeclarations.size(); i++) {
            if (bodyDeclarations.get(i) instanceof MethodDeclaration) {
                return i;
            }
        }
        return bodyDeclarations.size();
    }

}