<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |
<html xmlns="http://www.w3.org/1999/xhtml"> | |
<head> | |
<!-- -*- xhtml -*- --> | |
<title>Java Hint Module Tutorial for the NetBeans Platform</title> | |
<link rel="stylesheet" type="text/css" href="https://netbeans.org/netbeans.css"/> | |
<meta name="AUDIENCE" content="NBUSER"/> | |
<meta name="TYPE" content="ARTICLE"/> | |
<meta name="EXPIRES" content="N"/> | |
<meta name="developer" content="gwielenga@netbeans.org"/> | |
<meta name="indexed" content="y"/> | |
<meta name="description" | |
content="A short guide to using the Java Hint API."/> | |
<!-- Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Oracle and/or its affiliates. All rights reserved. --> | |
<!-- Use is subject to license terms.--> | |
</head> | |
<body> | |
<h1>NetBeans Java Hint Module Tutorial</h1> | |
<p>This tutorial demonstrates how to create a NetBeans module that provides | |
one or more Java hints. At the end of the first scenario covered in this tutorial, whenever the user | |
types "<tt>JOptionPane.showMessageDialog</tt>", a Java hint will appear, asking the user | |
whether the statement is needed (or whether it is there because the user | |
needed it for debugging):</p> | |
<p><img alt="" src="../images/tutorials/hint/72/result-1.png"/></p> | |
<p>At the end of the second scenario, the user will be able to click the hint to delete the superfluous | |
statement:</p> | |
<p><img alt="" src="../images/tutorials/hint/72/result-7.png"/></p> | |
<p>In addition, the user will be able to find and replace multiple instances of the | |
superfluous statement, after using the "Inspect & Transform" dialog in the Refactor menu, | |
which displays all found instances in the Refactoring window:</p> | |
<p><img alt="" src="../images/tutorials/hint/72/result-3.png"/></p> | |
<p><b class="notes">Note:</b> This document is applicable to NetBeans IDE 8.0 and | |
NetBeans Platform 8.0. If you | |
are using an earlier version, see <a href="74/nbm-java-hint.html">the previous version | |
of this document</a>.</p> | |
<p><b>Contents</b></p> | |
<img src="../images/articles/81/netbeans-stamp.png" class="stamp" width="114" height="114" alt="Content on this page applies to NetBeans IDE 8.0" title="Content on this page applies to NetBeans IDE 8.0"/> | |
<ul class="toc"> | |
<li><a href="#learning">Learning About Java Hints</a></li> | |
<li><a href="#creatingthemoduleproject">Setting Up the Module Project</a></li> | |
<li><a href="#scenario-1">Scenario 1: Identifying Statements of Interest</a></li> | |
<li><a href="#scenario-2">Scenario 2: Fixing Identified Statements</a></li> | |
</ul> | |
<p><b>To follow this tutorial, you need the software and resources listed in the following | |
table.</b></p> | |
<table> | |
<tbody> | |
<tr> | |
<th class="tblheader" scope="col">Software or Resource</th> | |
<th class="tblheader" scope="col">Version Required</th> | |
</tr> | |
<tr> | |
<td class="tbltd1"><a href="https://netbeans.org/downloads/index.html">NetBeans IDE</a></td> | |
<td class="tbltd1">version 8.0 or above</td> | |
</tr> | |
<tr> | |
<td class="tbltd1"><a href="http://java.sun.com/javase/downloads/index.jsp">Java Developer Kit (JDK)</a></td> | |
<td class="tbltd1">version 7 or above</td> | |
</tr> | |
</tbody> | |
</table> | |
<p class="tips">For troubleshooting purposes, you are welcome to download the <a href="http://java.net/projects/nb-api-samples/sources/api-samples/show/versions/8.0/tutorials/MyCustomHints">completed tutorial source code</a>.</p> | |
<!-- ===================================================================================== --> | |
<h2 class="tutorial"><a name="learning"></a>Learning About Java Hints</h2> | |
<p>The best way to learn about the Java hint infrastructure is to read the sources | |
of the Java hints that are part of the IDE. Start by identifying a hint that | |
does something similar to what you would like to achieve, then check out the NetBeans sources, | |
and read the source code of the related hint.</p> | |
<div class="indent"> | |
<ol> | |
<li>Use Mercurial to clone the NetBeans sources: <a href="http://wiki.netbeans.org/DevFaqAccessSourcesUsingMercurial">http://wiki.netbeans.org/DevFaqAccessSourcesUsingMercurial</a></li> | |
<li><p>In the NetBeans sources, browse to the "java.hints" folder, expand it, and read the | |
sources relevant to the hint you want to create:</p> | |
<br/> | |
<img src="../images/tutorials/hint/72/hint-list.png" alt="Step 1 of New Hint wizard"/> | |
<p class="tips"> The list of classes you see above is only the tip of the iceberg!</p> | |
</li> | |
</li> | |
</ol> | |
</div> | |
<p>The remainder of the tutorial shows you how to put a Java hint together generally, from scratch, but | |
remember that the best place to look for useful snippets of code is in the sources above, | |
if there is anything specific that you don't know how to do.</p> | |
<!-- ===================================================================================== --> | |
<h2 class="tutorial"><a name="creatingthemoduleproject"></a>Setting Up the Module Project</h2> | |
<p>Before you start writing the module, you have to make sure you | |
that your project is set up correctly. The IDE provides a wizard that sets up all the basic files | |
needed for a module.</p> | |
<div class="indent"> | |
<ol> | |
<li>Choose File > New Project (Ctrl+Shift+N). Under Categories, select NetBeans Modules. | |
Under Projects, select Module. Click Next.</li> | |
<li>In the Name and Location panel, type <tt>MyCustomHints</tt> in the Project Name field. | |
Change the Project Location to any directory on your computer. Click Next.</li> | |
<li>In the Basic Module Configuration panel, type <tt>org.my.custom.hints</tt> | |
in Code Name Base. Click Finish.</li> | |
</ol> | |
</div> | |
<p> The IDE creates the <tt>MyCustomHints</tt> | |
project. The project contains all of your sources and | |
project metadata, such as the project's Ant build script. The project | |
opens in the IDE. You can view its logical structure in the Projects window (Ctrl-1) and its | |
file structure in the Files window (Ctrl-2).</p> | |
<!-- ===================================================================================== --> | |
<h2><a name="scenario-1"></a>Scenario 1: Identifying Statements of Interest</h2> | |
<p>In this section, you provide the Java code for the Java hint.</p> | |
<div class="indent"> | |
<ol> | |
<li>Right-click the project node and choose New > Other > Module Development > Java Hint: | |
<br/><br/> | |
<img src="../images/tutorials/hint/72/new-hint-1.png" alt="Step 1 of New Hint wizard"/> | |
<p>Click Next.</p> | |
</li> | |
<li>In the New Java Hint Description panel, fill out the fields as follows: | |
<br/><br/> | |
<img src="../images/tutorials/hint/72/new-hint-2.png" alt="Step 2 of New Hint wizard"/> | |
<p>Click Next.</p> | |
</li> | |
<li>In the New Java Hint Location panel, fill out the fields as follows: | |
<br/><br/> | |
<img src="../images/tutorials/hint/72/new-hint-3.png" alt="Step 2 of New Hint wizard"/> | |
<p>Click Finish.</p> | |
<br/> | |
<p>The newly created class has the content below:</p> | |
<pre class="examplecode">package org.my.custom.hints; | |
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; | |
<a href="http://bits.netbeans.org/dev/javadoc/org-netbeans-spi-java-hints/org/netbeans/spi/java/hints/Hint.html">@Hint</a>(displayName = "#DN_JOptionPaneHint", | |
description = "#DESC_JOptionPaneHint", | |
category = "general") | |
<a href="http://bits.netbeans.org/dev/javadoc/org-openide-util/org/openide/util/NbBundle.Messages.html">@Messages</a>({ | |
"DN_JOptionPaneHint=JOptionPane.showMessageDialog", | |
"DESC_JOptionPaneHint=Checks for JOptionPane.showMessageDialog." | |
}) | |
public class JOptionPaneHint { | |
<a href="http://bits.netbeans.org/dev/javadoc/org-netbeans-spi-java-hints/org/netbeans/spi/java/hints/TriggerPattern.html">@TriggerPattern</a>( | |
value = "$str.equals(\"\")", //Specify a pattern as needed | |
constraints = | |
<a href="http://bits.netbeans.org/dev/javadoc/org-netbeans-spi-java-hints/org/netbeans/spi/java/hints/ConstraintVariableType.html">@ConstraintVariableType</a>( | |
variable = "$str", | |
type = "java.lang.String")) | |
<a href="http://bits.netbeans.org/dev/javadoc/org-openide-util/org/openide/util/NbBundle.Messages.html">@Messages</a>("ERR_JOptionPaneHint=Is JOptionPane.showMessageDialog needed?") | |
public static <a href="http://bits.netbeans.org/dev/javadoc/org-netbeans-spi-editor-hints/org/netbeans/spi/editor/hints/ErrorDescription.html">ErrorDescription</a> computeWarning(<a href="http://bits.netbeans.org/dev/javadoc/org-netbeans-spi-java-hints/org/netbeans/spi/java/hints/HintContext.html">HintContext</a> ctx) { | |
return <a href="http://bits.netbeans.org/dev/javadoc/org-netbeans-spi-java-hints/org/netbeans/spi/java/hints/ErrorDescriptionFactory.html">ErrorDescriptionFactory</a>.forName( | |
ctx, | |
ctx.getPath(), | |
Bundle.ERR_JOptionPaneHint()); | |
} | |
}</pre> | |
</li> | |
<li>Replace the <tt>@TriggerPattern</tt> with the following: | |
<pre class="examplecode">@TriggerPattern( | |
value = "$1.showMessageDialog", | |
constraints = | |
@ConstraintVariableType( | |
variable = "$1", | |
type = "javax.swing.JOptionPane"))</pre> | |
</li> | |
<li><p>Right-click the module and choose Build. Open the Files window (Ctrl-2) and browse | |
to the generated layer file, which is shown below:</p> | |
<br/> | |
<img src="../images/tutorials/hint/72/layer-1.png" alt="Layer 1"/> | |
<br/><br/><p>Open the layer file and you should see that the following has been generated from the | |
annotations in the class:</p> | |
<pre class="examplecode"><folder name="org-netbeans-modules-java-hints"> | |
<folder name="code-hints"> | |
<folder name="org-my-custom-hints-JOptionPaneHint.class"> | |
<folder name="org-netbeans-spi-java-hints-Hint.annotation"> | |
<!--org.my.custom.hints.JOptionPaneHint--> | |
<attr | |
bundlevalue="org.my.custom.hints.Bundle#DN_JOptionPaneHint" name="displayName"/> | |
<attr | |
bundlevalue="org.my.custom.hints.Bundle#DESC_JOptionPaneHint" name="description"/> | |
<attr name="category" stringvalue="general"/> | |
</folder> | |
<folder name="computeWarning.method"> | |
<folder name="org-netbeans-spi-java-hints-TriggerPattern.annotation"> | |
<folder name="constraints"> | |
<folder name="item0"> | |
<folder name="org-netbeans-spi-java-hints-ConstraintVariableType.annotation"> | |
<!--org.my.custom.hints.JOptionPaneHint--> | |
<attr name="variable" stringvalue="$1"/> | |
<attr name="type" stringvalue="javax.swing.JOptionPane"/> | |
</folder> | |
<!--org.my.custom.hints.JOptionPaneHint--> | |
</folder> | |
<!--org.my.custom.hints.JOptionPaneHint--> | |
</folder> | |
<!--org.my.custom.hints.JOptionPaneHint--> | |
<attr name="value" stringvalue="$1.showMessageDialog"/> | |
</folder> | |
<!--org.my.custom.hints.JOptionPaneHint--> | |
</folder> | |
<!--org.my.custom.hints.JOptionPaneHint--> | |
</folder> | |
</folder> | |
</folder></pre> | |
</li> | |
<li><p>Switch back to the Projects window, right-click the module, and | |
choose Run. A new instance of the IDE starts up. The | |
module is installed automatically. Create a new Java application. Type | |
<tt>JOptionPane.showMessageDialog</tt> somewhere in your code. You should see the | |
<tt>showMessageDialog</tt> is underlined and you should also see the hint' | |
displayed:</p> | |
<p><img alt="" src="../images/tutorials/hint/72/result-1.png"/></p> | |
<p>When you click on the icon in the left sidebar, the popup below appears. Press the | |
Right key on the keyboard while the popup is shown | |
to expand it, so that you can configure it if necessary:</p> | |
<p><img alt="" src="../images/tutorials/hint/72/result-2.png"/></p> | |
<p>Go to Source | Inspect, click Single Inspection, and then click the Browse button. Use the | |
Search field to find your new inspection:</p> | |
<p><img alt="" src="../images/tutorials/hint/72/result-4.png"/></p> | |
<p>Set the Scope to "Open Projects", so that all projects will be searched for the statement | |
of interest, and check that your inspection is shown:</p> | |
<p><img alt="" src="../images/tutorials/hint/72/result-5.png"/></p> | |
<p>Click Inspect and notice that all instances of the statement of interest are found:</p> | |
<p><img alt="" src="../images/tutorials/hint/72/result-6.png"/></p> | |
<p>Double-click an item in the list above and the corresponding file opens, with | |
the cursor on the line where the statement of interest has been found.</p> | |
</li> | |
</ol> | |
<p>Though you are able to find statements throughout your projects, you're not able | |
to fix them yet. That topic is covered in the next scenario.</p> | |
</div> | |
<!-- ======================================================================================= --> | |
<h2><a name="scenario-2"></a>Scenario 2: Fixing Identified Statements</h2> | |
<p>In this section, you learn how to fix statements of interest that have been identified via | |
the instructions in the previous section.</p> | |
<div class="indent"> | |
<ol> | |
<li><p>Add the Java fix below as an inner class of the class created in the previous | |
section.</p> | |
<pre class="examplecode">private static final class FixImpl extends <a href="http://bits.netbeans.org/dev/javadoc/org-netbeans-spi-java-hints/org/netbeans/spi/java/hints/JavaFix.html">JavaFix</a> { | |
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); | |
} | |
}</pre> | |
<p class="tips"> The code above comes from the NetBeans sources, where it | |
is used in the SystemOut class, in the "java.hints" module, for removing | |
found instances of <tt>System.out</tt>.</p> | |
</li> | |
<li><p>Add the fix to the error description you defined in the previous section; you | |
only need to add the code highlighted below:</p> | |
<pre class="examplecode">public static ErrorDescription computeWarning(HintContext ctx) { | |
<b><a href="http://bits.netbeans.org/dev/javadoc/org-netbeans-spi-editor-hints/org/netbeans/spi/editor/hints/Fix.html?is-external=true">Fix</a> fix = new FixImpl(ctx.getInfo(), ctx.getPath()).toEditorFix();</b> | |
return ErrorDescriptionFactory.forName( | |
ctx, | |
ctx.getPath(), | |
Bundle.ERR_JOptionPaneHint(), | |
<b>fix</b>); | |
}</pre> | |
</li> | |
<li><p>Check that you have these import statements:</p> | |
<pre class="examplecode">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.JavaFix.TransformationContext; | |
import org.netbeans.spi.java.hints.TriggerPattern; | |
import org.openide.util.NbBundle.Messages;</pre> | |
</li> | |
<li>Install the module again and you will be able to click the hint to delete the superfluous | |
statement:</p> | |
<p><img alt="" src="../images/tutorials/hint/72/result-7.png"/></p> | |
<p>In addition, you should be able to find and replace multiple instances of the | |
superfluous statement, after using the "Inspect & Transform" dialog in the Refactor menu, | |
which displays all found instances in the Refactoring window:</p> | |
<p><img alt="" src="../images/tutorials/hint/72/result-3.png"/></p> | |
</ol> | |
</div> | |
<p>In this tutorial, you have been introduced to the NetBeans Java hint infrastructure. To obtain a deeper | |
understanding, see the sources referred to at the start of this tutorial, as well as the resources | |
referred to below.</p> | |
<div class="feedback-box"><a href="https://netbeans.org/about/contact_form.html?to=3&subject=Feedback:%20Java%20Hint%208.0%20Tutorial">Send Us Your Feedback</a></div> | |
<h2><a name="nextsteps"></a>See Also</h2> | |
<p>For more information about creating and developing NetBeans Module, see the following resources: </p> | |
<ul> | |
<li><a href="http://wiki.netbeans.org/Java_DevelopersGuide">Java Developer's Guide</a></li> | |
<li><a href="https://platform.netbeans.org/tutorials/nbm-copyfqn.html">NetBeans Java Language Infrastructure Tutorial</a></li> | |
<li><a href="http://wiki.netbeans.org/RetoucheDeveloperFAQ">Retouche Developer FAQ</a></li> | |
<li><a href="https://netbeans.org/kb/trails/platform.html">Other Related Tutorials</a></li> | |
<li><a href="https://netbeans.org/download/dev/javadoc/">NetBeans API Javadoc</a></li> | |
</ul> | |
<!-- ======================================================================================== --> | |
<!-- ======================================================================================== | |
<h2><a name="version"></a>Versioning </h2> | |
<table width="76%" border="1"> | |
<tbody> | |
<tr> | |
<td> | |
<div align="left"><b>Version</b></div> | |
</td> | |
<td> | |
<div align="left"><b>Date</b></div> | |
</td> | |
<td> | |
<div align="left"><b>Comments</b></div> | |
</td> | |
</tr> | |
<tr> | |
<td> | |
1 | |
</td> | |
<td> | |
15 November 2008 | |
</td> | |
<td> | |
Initial version. | |
</td> | |
</tr> | |
<tr> | |
<td> | |
2 | |
</td> | |
<td> | |
12 November 2011 | |
</td> | |
<td> | |
Updated for 7.1. | |
</td> | |
</tr> | |
<tr> | |
<td> | |
3 | |
</td> | |
<td> | |
8 and 9 July 2012 | |
</td> | |
<td> | |
Completely rewrote the tutorial for 7.2. | |
</td> | |
</tr> | |
<tr> | |
<td> | |
4 | |
</td> | |
<td> | |
1 July 2014 | |
</td> | |
<td> | |
Update for NetBeans IDE 8.0. | |
</td> | |
</tr> | |
</tbody> | |
</table>--> | |
</body> | |
</html> |