GWT SuggestBox backed by DTO Model | PermGen error
Home > Google Web Toolkit > GWT SuggestBox backed by DTO Model

GWT SuggestBox backed by DTO Model

In this post I am writing a tutorial on how to use the Google Web Toolkit SuggestBox when you want it to provide Data Transfer Objects (DTO’s) suggestions.

According to GWT’s official docs you can Associate DTO objects with SuggestBox suggestions but I struggled to find any guiding tutorials on how to achieve this.

Having said this I have to give credit to Lombardi who went someway to helping me to work out how to do this. Good explanations are posted on their blog.

First of all lets make a simple Data Transfer Object

 
import com.google.gwt.user.client.rpc.IsSerializable;
 
public class PersonDTO implements IsSerializable
{
    private int id = 0;
    private String firstname = null;
    private String lastname = null;
 
    /**
     * @return the firstname
     */
     public String getFirstname()
     {
         return firstname;
     }
 
    /**
     * @param firstname the firstname to set
     */
     public void setFirstname(String firstname)
     {
         this.firstname = firstname;
     }
 
     /**
      * @return the lastname
      */
      public String getLastname()
      {
          return lastname;
      }
 
     /**
      * @param lastname the lastname to set
      */
      public void setLastname(String lastname)
      {
          this.lastname = lastname;
      }
 
     /**
      * @return the id
      */
      public int getId()
      {
          return id;
      }
 
     /**
      * @param id the id to set
      */
      public void setId(int id)
      {
          this.id = id;
      }
}

Thats the DTO object I’ll use throughout the tutorial.

Now we can make our Suggestion object as the following:

import com.google.gwt.user.client.ui.MultiWordSuggestOracle.MultiWordSuggestion;
 
/**
 * @author James Heggs - jheggs@axonbirch.com
 *
 */
public class PersonMultiWordSuggestion extends MultiWordSuggestion
{
    private PersonDTO personDTO = null;
 
    public PersonMultiWordSuggestion(PersonDTO user)
    {
        super(user.getFirstname() + " " + user.getLastname(), 
              user.getFirstname() + " " + user.getLastname() );
 
        this.personDTO = user;
    }
 
 
    /**
     * @return the personDTO
     */
     public PersonDTO getPersonDTO()
     {
         return personDTO;
     }
}

The super() call sets up the first parameter as the replacement String and the second parameter as the display string. You can of course change these.

Next we need to make our own Suggest Oracle. This is done relatively easy. My oracle is shown below:

 
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
 
import com.google.gwt.user.client.ui.SuggestOracle;
 
/**
 * @author James Heggs - jheggs@axonbirch.com
 *
 */
public class PersonNameSuggestOracle extends SuggestOracle
{
    private List<PersonMultiWordSuggestion> personSuggestions = null;
 
    @Override
    public void requestSuggestions(Request request, Callback callback)
    {
        Response resp = new Response( matchingPeople( request.getQuery(),
                                                      request.getLimit() ) );
 
        callback.onSuggestionsReady(request, resp);
    }
 
    /**
     * 
     * @param query The current text being entered into the suggest box
     * @param limit The maximum number of results to return 
     * @return A collection of people suggestions that match.
     */
     public Collection<PersonMultiWordSuggestion> matchingPeople(String query, int limit)
     {
         List<PersonMultiWordSuggestion> matchingPeople = new ArrayList<PersonMultiWordSuggestion>(limit);
 
         // only begin to search after the user has type two characters
         if ( query.length() >= 2 )
         {
             String prefixToMatch = query.toLowerCase();
 
             int i = 0;
             int s = personSuggestions.size();
 
             // Skip forward over all the names that don't match at the beginning of the array.
             while (i < s && !personSuggestions.get(i).getDisplayString().toLowerCase().startsWith(prefixToMatch) )
             {
                 i++;
             }
 
             // Now we are at the start of the block of matching names. Add matching names till we
             // run out of names, stop finding matches, or have enough matches.
             int count = 0;
 
             while (i < s && personSuggestions.get(i).getDisplayString().toLowerCase().startsWith(prefixToMatch) && count < limit) 
             {
                 matchingPeople.add( personSuggestions.get(i) );
                 i++;
                 count++;
             }
 
         }
 
             return matchingPeople;
     }
 
 
 
        /**
         * @param o 
         * @return
         * @see java.util.List#add(java.lang.Object)
         */
         public boolean add(PersonMultiWordSuggestion o)
         {
             if ( personSuggestions == null )
             {
                personSuggestions = new ArrayList<PersonMultiWordSuggestion>();
             }
 
             return personSuggestions.add(o);
         }
 
 
 
        /**
         * @param o
         * @return
         * @see java.util.List#remove(java.lang.Object)
         */
         public boolean remove(Object o)
         {
             if ( personSuggestions != null)
             {
                 return personSuggestions.remove(o);
             }
 
             return false;
          }
 
}

I think for most developers that enough code to get going but just to clear things up the following code snippets show the use of the DTO and SuggestBox as to how it could be used. Also in the code snippets I am assuming you are familar with GWT’s RPC architecture.

First an RPC call to fetch the DTO objects from a server (Production mode could ask for persistent objects from hibernate or something similar.)

 
PersonNameSuggestOracle oracle = new PersonNameSuggestOracle();
SuggestBox nameSuggestBox = new SuggestBox(oracle);
 
 
//fetch names
  MyServiceAsync serviceRPC = GWT.create(MyService.class);
  serviceRPC.fetchPeople(new AsyncCallback&lt; List&lt;PersonDTO&gt; &gt;()
  {
   public void onFailure(Throwable caught)
   {
    // TODO Auto-generated method stub
 
   }
 
   public void onSuccess(List&lt;PersonDTO&gt; results)
   {
    if ( results != null && results.size() &gt; 0 )
    {
     for ( PersonDTO person : results )
     {
      oracle.add(new PersonMultiWordSuggestion(person) );
     }
    }
 
   }
  });

Then for those interest snippet code on how to handle the selected suggestion

nameSuggestBox.addEventHandler(new SuggestionHandler()
{
    public void onSuggestionSelected(SuggestionEvent event)
    {
        PersonMultiWordSuggestion suggestion = (PersonMultiWordSuggestion)event.getSelectedSuggestion();
 
        // Do what you want with the suggestion and DTO
        // suggestion.getPersonDTO
 
 
    }
});

Thats basically it. If people have any questions or ideas please post them as a comment in order to help others.

  1. admin
    July 19th, 2010 at 09:09 | #1

    Hi there,

    I can however that is purely the server side code and thus is completely dependant on your architecture.

    For example you may or may not use Hibernate for ORM or you may just use an in memory model.

    What section of the code are you struggling with?

  2. cometta
    July 18th, 2010 at 16:39 | #2

    can you post MyServiceImpl.fetchPeople() method?

  3. cometta
    July 18th, 2010 at 13:17 | #3

    i want to add a submit button. how do i get the entries keyed into the suggestionbox by user?

    submitButton.addClickHandler(new ClickHandler() {
    @Override
    public void onClick(ClickEvent event) {

    // box.WhatMethodtocalltogetEntriesSelectedByUser..?

    }
    });

  4. June 17th, 2010 at 20:37 | #4

    Hi,

    That’s absolutely no problem. You were not too slow or too late :)

    I am writing a blogpost about how I solved the issue and I’m referencing your post. Thank you very much again.

    You can see the post here: http://altuginplainenglish.blogspot.com/2010/06/gwt-suggestbox-filled-with-any-object.html

    Best wishes,
    Altug

  5. admin
    June 11th, 2010 at 22:00 | #5

    Hi there,

    Sorry I haven’t replied sooner.

    Thank you for your comments glad you have got your issue sorted :)

  6. June 11th, 2010 at 11:54 | #6

    Hello again,

    I found the functionality solution. In the Oracle Class, the added items were too few. Now I changed it to “suggestions.get(i).getDisplayString().toLowerCase().contains(prefixToMatch)” and it also takes some other items in the suggestion.

    Thank you very much for your blogpost.

    Best wishes,
    Altug

  7. Altug
    June 10th, 2010 at 11:16 | #7

    Hello,

    first of all, thank you very much for your post. It helped me so much.

    My problem(s) is(are) as follows: I am filling my SuggestBox which takes some objects and they it is being filled correctly. Then, if I want to use it, it always shows me one suggestion at a time, despite extending MultiWordSuggestOracle. I do not get the other suggestions match with the query. Secondly, the white space does not work for me, I always get the first letters matching. And thirdly, I do not get the bold matching query in the suggestion’s displaystring.

    any idea how I can fix these?

    Thanks in advance,
    Altug

  8. admin
    January 6th, 2010 at 09:25 | #8

    Hi there,

    Glad you found it useful and thank you for the nice comments.

    I wrote the post when GWT was on version 1.4 – I think since then they have improved the event handling so well done for sorting that out

    Eggsy

  9. Ale
    January 5th, 2010 at 22:28 | #9

    Thanks very much, it’s work perfectly.
    I only change

    .addEventHandler(new SuggestionHandler()

    to
    .addSelectionHandler(new SelectionHandler()

    because the first was deprecated…

    thanks again!

  1. No trackbacks yet.