Scott Tiger Tech Blog

Blog technologiczny firmy Scott Tiger S.A.

GUAVA – integrujemy z GWT i MVP4G

Autor: Krzysztof Nielepkowicz o piątek 10. Luty 2012

    W poprzednim poście przedstawiłem sposób na szybkie i efektywne tworzenie aplikacji webowych dzięki tandemowi GWT i MVP4G. Jednak arsenał wspomagający jest o wiele większy. Kolejną rzeczą, którą chętnie by widział developer są generyczne operacje na kolekcjach. Parę miesięcy temu miałem okazję skorzystać z LambdaJ przy okazji poprzedniego projektu, chciałem skorzystać z tej biblioteki dla celów obecnego projektu opartego właśnie na GWT i MVP4G (oraz MyBatis). Niestety, spotkało mnie przykre rozczarowanie – LambaJ korzysta z aop’a i refleksji, co skutecznie uniemożliwia współpracę z GWT – na co również wskazuje  JRE Emulation Reference. Jakakolwiek próba użycia LambdaJ kończyła się wyjątkami. To zachęciło mnie to do zapoznania się z niejako zamiennikiem dla LambdaJ – z bibliotekami Google GUAVA.

    Potrzebne narzędzia/biblioteki :
    Zaczynamy zatem! Ze strony głównej projektu ściągamy interesujące nas JAR’y : guava-11.0.1.jar oraz guava-gwt-11.0.1.jar i umieszczamy je w podkatalogu lib. Teraz już posiadamy całą infrastrukturę, kolejnym krokiem jest modyfikacja deskryptora projektu – *.gwt.xml. Dla ułatwienia pokażę cały plik gdyż nie jest on i tak długi, podświetlone są 2 istotne linie kodu :

 

<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='tutek_mvp4g'>
  <!-- Inherit the core Web Toolkit stuff.                        -->
  <inherits name='com.google.gwt.user.User'/>

  <!-- Inherit the default GWT style sheet.  You can change       -->
  <!-- the theme of your GWT application by uncommenting          -->
  <!-- any one of the following lines.                            -->
  <inherits name='com.google.gwt.user.theme.clean.Clean'/>
  <!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/> -->
  <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
  <!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/>     -->  

  <!-- Other module inherits                                      -->
  <inherits name='com.mvp4g.Mvp4gModule' />
  <inherits name="com.google.common.collect.Collect" /> 
  <inherits name="com.google.common.base.Base"/> 

  <!-- Specify the app entry point class.                         -->
  <!-- <entry-point class='tutek.client.Tutek_MVP4G'/>      -->
  <entry-point class='com.mvp4g.client.Mvp4gEntryPoint'/>

  <!-- Specify the paths for translatable code                    -->
  <source path='client'/>
  <source path='shared'/>

</module>
    Podświetlone linie importują potrzebne moduły biblioteki GUAVA. Kolejnym krokiem jest modyfikacja eventBusa. Dodamy jedno zdarzenie – wybieranie wierszy po przez wartość jednej z kolumn. Definicja interfejsu eventBus nie jest zbyt obszerna więc ponownie zamieszczę cały kod zaznaczając istotne linie :

 

package tutek.client;

import tutek.client.bean.Person;
import tutek.client.presenter.TutekPresenter;

import com.google.gwt.view.client.ListDataProvider;
import com.mvp4g.client.annotation.Event;
import com.mvp4g.client.annotation.Events;
import com.mvp4g.client.annotation.Start;
import com.mvp4g.client.event.EventBus;

@Events(startPresenter = TutekPresenter.class)
public interface TutekEventBus extends EventBus
{

 @Start //obowiązkowe zdarzenie startowe
 @Event(handlers = {TutekPresenter.class})
 public void onStart();

 //zdarzenie wybierania osób po imieniu
 @Event(handlers = {TutekPresenter.class})
 public void selectByName(String name, ListDataProvider<Person> data);

}

 

    Zdarzenie „selectByName” jako parametr przyjmuje imię (name) wg. którego należy przefiltrować zawartość (data) tabelki. Jego obsługa jest zdefiniowana w klasie presentera – pojawi się nowa metoda o nazwie „onSelectByName” – nazwa zgodna z konwencją omówioną w poprzednim wpisie. Bezpośrednio w metodzie obsługującej zdarzenie modyfikujemy listę obiektów do wyświetlenia – przypomina to trochę funkcje statyczne. Klasa reprezentująca dane wyświetlane w tabeli – „Person” oraz klasa widoku („TutekView”) pozostają bez zmian w stosunku do poprzedniego wpisu. Zmienia się natomiast wnętrze klasy presentera :

 

 @Override
 public void bind()
 {
  GWT.log("bind");
  //tworzymy kolumny
  TextColumn<Person> name = new TextColumn<Person>() 
  {   
   @Override
   public String getValue(Person object)
   {
    return object.name;
   }
  };

  TextColumn<person> surName = new TextColumn<Person>() 
  {   
   @Override
   public String getValue(Person object)
   {
    return object.surName;
   }
  };

  //dodajemy kolumny
  view.cellTable.addColumn(name);
  view.cellTable.addColumn(surName);

  //obsługa zdarzeń
  view.btn_filter.addClickHandler(new ClickHandler() 
  {   
   @Override
   public void onClick(ClickEvent event)
   {   
    eventBus.selectByName("wacek", dataProvider);
   }
  });  
 }
    Zmiany nastąpiły w metodzie bind(). Dokładniej zmianie uległa obsługa zdarzeń – teraz zamiast dokonywać obsługi zdarzenia w kodzie tej metody odpalamy zdarzenie dla eventBusa. Definicja tego zdarzenia zapisana w eventBusie  mówi, że w prezenterze pojawi się nowa metoda, obsługująca zdarzenie będzie się nazywała „onSelectByName”, zatem przyjrzujmy się jej :

 

 public void onSelectByName(final String name, ListDataProvider<Person> data)
 {
  //Obiekt definiujący warunek
  Predicate<Person> nameCond = new Predicate<Person>() 
  {
   //nadpisana metoda szczegułowo definiujaca warunek filtrowania
   @Override
   public boolean apply(Person arg0)
   {
    return arg0.name.toLowerCase().equals(name);
   }   
  };
  data.setList( Lists.newArrayList( filter(data.getList(), nameCond) ) );    
 }

 

    To co jest ważne podczas filtrowania listy : zdefiniowanie predykatu – czyli warunku (pierwsze podświetlenie) następnie przefiltrowanie. Czujni zauważyli na pewno, że filtrowanie za pomocą funkcji „filter” wygląda tak jak by owa metoda została zdefiniowana w prezenterze – jednak to nie tak. Dzięki statycznemu importowi :

 

import static com.google.common.collect.Collections2.filter;

 

    Mozna używać funkcji „filter” z klasy „Collections2” tak jak by była zdefiniowana w naszej klasie. To wszystko – magia działa. Funkcja statyczna „filter” zwraca nową kolekcję, którą podstawiamy dla dataProvidera dostarczonego jako parametr – nie musieliśmy tego robić, jednak w moim odczuciu zwiększa to czytelność kodu. To wszystko…. Chyba nie – gdy wykorzystalem bibliotekę GUAVA w większym projekcie podczas kompilacji GWT (generowanie kodu js) dostalem nieoczekiwanie błędy, co najdziwniejsze, w bibliotece GUAVA.

 

[ERROR]
 Errors in 'jar:file:/C:/.../lib/guava-gwt-10.0.1.jar!/com/google/common/collect/BstBalancePolicy.java'
         [ERROR] Line 19: The import javax.annotation.Nullable cannot be resolved
         [ERROR] Line 36: Nullable cannot be resolved to a type
         [ERROR] Line 36: Nullable cannot be resolved to a type
         [ERROR] Line 43: Nullable cannot be resolved to a type
         [ERROR] Line 44: Nullable cannot be resolved to a type
         [ERROR] Line 44: Nullable cannot be resolved to a type
    Parę pytań do dr Google dało odpowiedź że brakuje biblioteki jsr305, uzupełniłem. Jednak to nadal nie dało rezultatu i błąd nadal się pojawiał. Dłuższe poszukiwania rozwiązania nie dały rezultatu aż w desperacji zacząłem próbować starszych wersji biblioteki GUAVA. Błąd pojawiał się również podczas używania wersji 10. Kolejna próba z wersją GUAVA 09 dała pozytywny rezulta – kompilacja GWT przebiegała bez błędów. Ciekawym jest fakt, iż błąd ujawniał się wewnątrz biblioteki, dodatkowo podczas zastosowania w większym projekcie. Zastosowanie zestawu GWT + MVP4G daje niezwykłą łatwość i porządek podczas tworzenia aplikacji. Dodanie do tego tandemu bibliotek GUAVA ułatwia manipulacje na danych (nie tylko!!) i dodatkowo zwiększa czytelność kod. Na koniec podaję link do gotowego projektu w Eclipse spakowanego rarem. Brakuje jedynie refleksji. Ale o tym już niebawem!
Share and Enjoy:
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Śledzik
  • Blip
  • Blogger.com
  • Gadu-Gadu Live
  • LinkedIn
  • MySpace
  • Wykop

Zostaw komentarz

XHTML: Możesz użyć następujących tagów: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>