blob: 1c0fe80c1b73647b0a0eadcd9ba3dd9bf8856517 [file] [log] [blame]
<!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 &gt; 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 &gt; Other &gt; Module Development &gt; 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">&lt;folder name="org-netbeans-modules-java-hints"&gt;
&lt;folder name="code-hints"&gt;
&lt;folder name="org-my-custom-hints-JOptionPaneHint.class"&gt;
&lt;folder name="org-netbeans-spi-java-hints-Hint.annotation"&gt;
&lt;!--org.my.custom.hints.JOptionPaneHint--&gt;
&lt;attr
bundlevalue="org.my.custom.hints.Bundle#DN_JOptionPaneHint" name="displayName"/&gt;
&lt;attr
bundlevalue="org.my.custom.hints.Bundle#DESC_JOptionPaneHint" name="description"/&gt;
&lt;attr name="category" stringvalue="general"/&gt;
&lt;/folder&gt;
&lt;folder name="computeWarning.method"&gt;
&lt;folder name="org-netbeans-spi-java-hints-TriggerPattern.annotation"&gt;
&lt;folder name="constraints"&gt;
&lt;folder name="item0"&gt;
&lt;folder name="org-netbeans-spi-java-hints-ConstraintVariableType.annotation"&gt;
&lt;!--org.my.custom.hints.JOptionPaneHint--&gt;
&lt;attr name="variable" stringvalue="$1"/&gt;
&lt;attr name="type" stringvalue="javax.swing.JOptionPane"/&gt;
&lt;/folder&gt;
&lt;!--org.my.custom.hints.JOptionPaneHint--&gt;
&lt;/folder&gt;
&lt;!--org.my.custom.hints.JOptionPaneHint--&gt;
&lt;/folder&gt;
&lt;!--org.my.custom.hints.JOptionPaneHint--&gt;
&lt;attr name="value" stringvalue="$1.showMessageDialog"/&gt;
&lt;/folder&gt;
&lt;!--org.my.custom.hints.JOptionPaneHint--&gt;
&lt;/folder&gt;
&lt;!--org.my.custom.hints.JOptionPaneHint--&gt;
&lt;/folder&gt;
&lt;/folder&gt;
&lt;/folder&gt;</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&lt;? extends StatementTree&gt; statements = blockTree.getStatements();
List&lt;StatementTree&gt; newStatements = new ArrayList&lt;StatementTree&gt;();
for (Iterator&lt;? extends StatementTree&gt; 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&amp;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>