Java Hint in NetBeans for Identifying JOptionPanes

Posted by Geertjan on Oracle Blogs See other posts from Oracle Blogs or by Geertjan
Published on Sun, 8 Jul 2012 09:57:57 +0000 Indexed on 2012/07/08 15:20 UTC
Read the original article Hit count: 395

Filed under:

I tend to have "JOptionPane.showMessageDialogs" scattered through my code, for debugging purposes. Now I have a way to identify all of them and remove them one by one, since some of them are there for users of the application so shouldn't be removed, via the Refactoring window:


Identifying instances of code that I'm interested in is really trivial:

import org.netbeans.spi.editor.hints.ErrorDescription;
import org.netbeans.spi.java.hints.ConstraintVariableType;
import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
import org.netbeans.spi.java.hints.Hint;
import org.netbeans.spi.java.hints.HintContext;
import org.netbeans.spi.java.hints.TriggerPattern;
import org.openide.util.NbBundle.Messages;

@Hint(
        displayName = "#DN_ShowMessageDialogChecker",
        description = "#DESC_ShowMessageDialogChecker",
        category = "general")
@Messages({
    "DN_ShowMessageDialogChecker=Found \"ShowMessageDialog\"",
    "DESC_ShowMessageDialogChecker=Checks for JOptionPane.showMes"
})
public class ShowMessageDialogChecker {

    @TriggerPattern(value = "$1.showMessageDialog", constraints =
    @ConstraintVariableType(variable = "$1", type = "javax.swing.JOptionPane"))
    @Messages("ERR_ShowMessageDialogChecker=Are you sure you need this statement?")
    public static ErrorDescription computeWarning(HintContext ctx) {
        return ErrorDescriptionFactory.forName(
                ctx,
                ctx.getPath(),
                Bundle.ERR_ShowMessageDialogChecker());
    }
    
}

Stick the above class, which seriously isn't much code at all, in a module and run it, with this result:

Bit trickier to do the fix, i.e., add a bit of code to let the user remove the statement, but I looked in the NetBeans sources and used the System.out fix, which does the same thing: 

import com.sun.source.tree.BlockTree;
import com.sun.source.tree.StatementTree;
import com.sun.source.util.TreePath;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.netbeans.api.java.source.CompilationInfo;
import org.netbeans.api.java.source.WorkingCopy;
import org.netbeans.spi.editor.hints.ErrorDescription;
import org.netbeans.spi.editor.hints.Fix;
import org.netbeans.spi.java.hints.ConstraintVariableType;
import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
import org.netbeans.spi.java.hints.Hint;
import org.netbeans.spi.java.hints.HintContext;
import org.netbeans.spi.java.hints.JavaFix;
import org.netbeans.spi.java.hints.TriggerPattern;
import org.openide.util.NbBundle.Messages;

@Hint(
        displayName = "#DN_ShowMessageDialogChecker",
        description = "#DESC_ShowMessageDialogChecker",
        category = "general")
@Messages({
    "DN_ShowMessageDialogChecker=Found \"ShowMessageDialog\"",
    "DESC_ShowMessageDialogChecker=Checks for JOptionPane.showMes"
})
public class ShowMessageDialogChecker {

    @TriggerPattern(value = "$1.showMessageDialog", constraints =
    @ConstraintVariableType(variable = "$1", type = "javax.swing.JOptionPane"))
    @Messages("ERR_ShowMessageDialogChecker=Are you sure you need this statement?")
    public static ErrorDescription computeWarning(HintContext ctx) {
        Fix fix = new FixImpl(ctx.getInfo(), ctx.getPath()).toEditorFix();
        return ErrorDescriptionFactory.forName(
                ctx,
                ctx.getPath(),
                Bundle.ERR_ShowMessageDialogChecker(),
                fix);
    }

    private static final class FixImpl extends JavaFix {

        public FixImpl(CompilationInfo info, TreePath tp) {
            super(info, tp);
        }

        @Override
        @Messages("FIX_ShowMessageDialogChecker=Remove the statement")
        protected String getText() {
            return Bundle.FIX_ShowMessageDialogChecker();
        }

        @Override
        protected void performRewrite(TransformationContext tc) throws Exception {
            WorkingCopy wc = tc.getWorkingCopy();
            TreePath statementPath = tc.getPath();
            TreePath blockPath = tc.getPath().getParentPath();
            while (!(blockPath.getLeaf() instanceof BlockTree)) {
                statementPath = blockPath;
                blockPath = blockPath.getParentPath();
                if (blockPath == null) {
                    return;
                }
            }
            BlockTree blockTree = (BlockTree) blockPath.getLeaf();
            List<? extends StatementTree> statements = blockTree.getStatements();
            List<StatementTree> newStatements = new ArrayList<StatementTree>();
            for (Iterator<? extends StatementTree> it = statements.iterator(); it.hasNext();) {
                StatementTree statement = it.next();
                if (statement != statementPath.getLeaf()) {
                    newStatements.add(statement);
                }
            }
            BlockTree newBlockTree = wc.getTreeMaker().Block(newStatements, blockTree.isStatic());
            wc.rewrite(blockTree, newBlockTree);
        }
        
    }
    
}

Aside from now being able to use "Inspect & Refactor" to identify and fix all instances of JOptionPane.showMessageDialog at the same time, you can also do the fixes per instance within the editor:

© Oracle Blogs or respective owner

Related posts about /NetBeans IDE