Java Hint in NetBeans for Identifying JOptionPanes

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:

Comments:

Post a Comment:
  • HTML Syntax: NOT allowed
About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
12
13
14
23
24
25
26
27
28
29
30
   
       
Today