How to Create an Ajax Autocomplete Text Field: Part 3 [con't]
The "complete" Action
Before we can start the search, we have to verify that the searchString isn't empty. At the bottom of the following code snippet, there's a line that sets the HTTP header status to 204, indicating that the request succeeded but that there was no new information to return. After verifying that the searchString isn't empty, we remove both leading and trailing whitespace characters and convert the searchString to lower case so that the matching will be case insensitive. The search itself is contained within a try/catch block because the JSONObject.put()
method throws a JSONException. As a result, the IDE will display the following error: "Unreachable catch block for JSONException. This exception is never thrown from the try statement body." Once we add the method call that throws this error, it will stop.
The variables that we'll need to do the search are a JSONObject to hold each fund, an Iterator and the matches member variable that we declared earlier. It can now be instantiated to an empty JSONArray object:
The iterator is used to loop through each fund in the HashMap. Each fund that matches the searchString is stored in a new JSONObject. The put()
method is used so we can specify exactly which fields we want. Two of our delegate getters fund.getPrice().doubleValue()
and fund.getJsonDate()
are used. Finally, the JSONObject is added to the JSONArray:
The following code will appear at the bottom of the class:
Insert the following code to perform a case insensitive test against the Fund symbol and name fields and return the results:
Getting back the the "complete" action of the doGet()
method, all
that remains is to return the matches to the browser.
We can tell how many hits we got by using the length()
method, which is inherited
from the ArrayList class. If the matches array has more than one element, we
set the content type to "text/plain" because the JSON objects are
not HTML or XML. We also instruct the browser to not cache the results by setting
the "Cache-Control" header field to "no-cache." To return
the matches, we call the getWriter()
method of the HttpServletResponse
Object
to get the instance of the writer and call its write()
method, passing in a
String using the JSONArray's toString()
method. There are two versions of this
method. The first is called without any parameters and returns the Array as
one long String. The one that accepts an integer parameter returns a "pretty"
String, complete with carriage returns and indentations of the number of spaces
passed to it:
Comparison Between the JSONArray toString()
and toString(int indentFactor)
Methods
We supply an indentFactor because it makes debugging easier:
That covers the "complete" action. Let's move on to the "lookupbyname" one.
The "lookupbyname" Action
The search part is much like the "complete" action except
that we're storing the funds in an ArrayList this time. We don't need the JSONObjects
because the fund properties will be accessed directly within the JSP page rather
than by a script. Therefore, instead of sending the data back to the browser,
we create a new request parameter called funds and forward it to the Funds.jsp
page:
The "lookup" Action
The "lookup" action is the simplest of the three. It's only used
to retrieve a fund directly based on the symbol. Hence, no matching is required
other than to verify that it exists in the HashMap. Once that we confirm that
it is, we set the "fund" request attribute and forward the information
to the Fund.jsp
page to display:
The serialVersionUID
Your class should now be good to go, but there's still one warning displayed at the top of the class. If you hover over it , the following message is displayed in a tool tip: "The serializable class AutocompleteServlet does not declare a static final serialVersionUID field of type long." According to the Serializable Interface Sun documentation, a serializable class isn't required to explicitly declare a serialVersionUID. Since a default one will be calculated at runtime, they strongly recommended that serializable classes explicitly declare serialVersionUID values because the runtime version cannot be guaranteed. Therefore, "to guarantee a consistent serialVersionUID value across different Java compiler implementations, a serializable class must declare an explicit serialVersionUID value."
We can see what Eclipse suggests by clicking the warning icon (See Figure 10)
The first two are most useful to us. The first choice would just add a quick and dirty variable for us to set ourselves. The second one, however, does all the work for us, so that's what we'll select! Here's what was generated for me:
Here's the source for the AutocompleteServlet.java file that we just built.
That concludes the Java portion of the Autocomplete control. We'll have to wait until we have some browser components in place to see it in action. We'll be delving into those next time.
References
- The Servlet life cycle
- Java Sun documentation on Generics
- Strict Equality Operators article on WebReference
- Practical Guidelines for Java Serial Version ID and Serialization
Original: April 9, 2008