SlideShare uma empresa Scribd logo
1 de 41
Introduzione a GWT 2.0

    Luca Masini, 18.03.2010
Agenda


GWT in due minuti


I difetti di GWT 1.x


Le soluzioni adottate con GWT 2.0
GWT in 2 minuti
Java (compilato in JS) nel proprio IDE preferito......
......dove posso condividere codice tra client e server



@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "roomDisc", discriminatorType = DiscriminatorType.STRING)
public class Room {

    private RoomPK roomPk;

    @EmbeddedId
    public RoomPK getRoomPk() {
      return roomPk;
    }

    public void setRoomPk(final RoomPK roomPk) {
      this.roomPk = roomPk;
    }

    public void doSomeBusinessLogic(final String inputParameter) {
      ....
      ....
    }
}
Una "specie" di reflection per JS chiamata Deferred Binding



@RemoteServiceRelativePath("playgroundService")
 public interface PlaygroundService extends RemoteService {
   String[] cajole(String uri, String input);
   String getBuildInfo(); String fetch(String url);
 }
 GWT.create(PlaygroundService.class);
Una "specie" di reflection per JS chiamata Deferred Binding


 <generate-with class="com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator">
   <when-type-assignable class="com.google.gwt.user.client.rpc.RemoteService"/>
 </generate-with>

 public class ServiceInterfaceProxyGenerator extends Generator {
   @Override
   public String generate(TreeLogger logger, GeneratorContext ctx,   String requestedClass)
            throws UnableToCompleteException {

        TypeOracle typeOracle = ctx.getTypeOracle();
        ....
        ....
        ....

        return javaCode;
   }
Un meccanismo di integrazione con codice JavaScript (JSNI)



public native void bar(JSNIExample x, String s) /*-{
   var ret = this.@MyObject::instanceFoo(Ljava/lang/String;)(s);
   alert(ret);
}-*/;


                                                SmartGWT
Cosa non funziona con GWT ??
Scrivere codice UI è troppo complicato rispetto ad HTML (la
flessibilità costa !!)


<form method="POST" action="/writeForm">
   Nome: <input type="text" name="Nome" />
   Cognome: <input type="text" name="Cognome" />
   Indirizzo: <input type="text" name="Indirizzo" />
   Citt&agrave;: <input type="text" name="Citta" />
   <input type="submit" value="OK" />
</form>

La programmazione Swing-like di GWT è molto elegante ma costosa
in termini di righe di codice e complessità.

Anche chiamare il servizio, prendendo i valori dalla UI, ha un costo
notevole per il valore aggiunto che viene dato rispetto ad una normale
POST.
JavaScript cross-browser......
Ma il vero problema è il CSS !!!!!
Gestione a dir poco maldestra di JSON
 Se il nostro servizio non è un GWT-RPC, allora fare il parsing di
 JSON può farci perdere gran parte del vantaggio della tipizzazione di
 Java, oltre che essere molto noioso !!!
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET , url);
Request request = builder.sendRequest(null, new RequestCallback() {

  public void onResponseReceived(Request request, Response response) {
    JSONValue jsonValue = JSONParser.parse (response.getText());
    JSONArray jsonArray = jsonValue.isArray();

       for (int i = 0; i < jsonArray.size(); i++) {
         JSONObject jsObject = jsonArray.isObject();
         JSONString jsString = jsObject.isString();
         JSONNumber jsNumber = jsObject.isNumber();
       }
   }
});
Ambiente di sviluppo non integrato nel browser

  Durante lo sviluppo siamo integrati solo con Internet
  Explorer 7

  Come possiamo debuggare eventuali inconsistenze non
  ripetibili su IE ???

  Siamo costretti a numerose e lunghe sessioni di testing
  prima del rilascio in produzione, per eliminare le eventuali
  inconsistenze cross-browser.

  Dove finisce l'agilita dello strumento ?
Il compilatore genera un solo mega script scaricato
all'avvio dell'applicazione

   Un'applicazione di piccole dimensioni può occupare anche
   250kb
   L'aggiunta di poche librerie ad un'applicazione di medio-
   piccole dimensioni può far raggiungere i 500kb e più
   Questo non è un problema per applicazioni Intranet
   (caching efficace)
   E' sicuramente un problema invece per applicazioni Internet
   e Intranet PDA
Mapping non chiaro tra oggetti JavaScript e Java

Il passaggio dei parametri tra "mondo" Java e "mondo" JavaScript è
problematico:

   In hosted mode ad ogni passaggio viene allocato un wrapper
   JavaScriptObject, di fatto rendendo errate le identità

   Se possibile in web mode le cose possono andare ancora peggio,
   in quanto il runtime-type cambia durante l'esecuzione e esempi di
   riconoscimento con "instanceof" possono dipendere anche
   dall'ordine con cui il compilatore genera il JavaScript
Le soluzioni adottate con
        GWT 2.0
Out Of Process Hosted Mode

          (OOPHM)
Architettura nuova shell OOPHM
Il plugin per l'OOPHM

Il parametro "gwt.codesvr" serve come discriminante. Se
presente e non intercettato da un plugin locale fa generare alla
Shell un iframe con il codice per l'installazione:




Agli accessi successivi invece il parametro è usato per aprire
un "browser channel" verso la Shell stessa.
Strumenti Standard in Hosted Mode
UIBinder e Layouts
UIBinder: esempio

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
    xmlns:g="urn:import:com.google.gwt.user.client.ui"
    xmlns:v="urn:import:com.google.gwt.visualization.client.visualizations"
    xmlns:store="urn:import:net.lucamasini.client.view" >
    <ui:style type='net.lucamasini.client.view.StoreComposite.StoreStyle' >
        .important {
            font-weight: bold ;
        }

        .fullWidth {
             width: 100% ;
        }
    </ui:style>
    <g:HTMLPanel>
      <table>
          <tr>
             <td colspan='2' >
             <g:ListBox styleName="{style.important}" ui:field='tablesListBox' visibleItemCount='1' />
          </td>
          </tr>
          <tr>
          <td colspan='2' ><g:Button text="Ricarica" styleName="{style.important}" ui:field="button" /></td>
          </tr>
          <tr>
             <td colspan='2' ><store:FilterPanel ui:field="filterPanel" width='100%' /></td>
          </tr>
          <tr>
             <td colspan='2' >
                <g:DisclosurePanel open='false' width='100%' >
                  <g:header>Query</g:header>
                  <g:TextArea ui:field='textArea' visibleLines='5' styleName="{style.fullWidth}" />
                </g:DisclosurePanel>
             </td>
          </tr>
          <tr>
             <td colspan='2' ><v:Table ui:field="table" /></td>
          </tr>
          <tr>
             <td colspan='2' ><g:SimplePanel ui:field="detailsContainer" /></td>
          </tr>
          <tr>
             <td colspan='2' ><store:StatusBar ui:field="statusBar" /></td>
          </tr>
      </table>
    </g:HTMLPanel>
</ui:UiBinder>
UIBinder: esempio

 interface StoreStyle extends CssResource {
     String important();
 }

 private static StoreCompositeUiBinder uiBinder = GWT
        .create (StoreCompositeUiBinder.class);

 interface StoreCompositeUiBinder
   extends UiBinder<Widget, StoreComposite> {
 }

 @UiField StoreStyle style;

 @UiField
 Button button;

 @UiHandler("button")
 void onClick(ClickEvent e) {
    …
    …
 }
UIBinder: Layouts e StyleInjection 1
<ui:UiBinder
 xmlns:ui='urn:ui:com.google.gwt.uibinder'
 xmlns:g='urn:import:com.google.gwt.user.client.ui'
 xmlns:mail='urn:import:com.google.gwt.sample.mail.client'>

 <ui:style>
 .shortcuts {
   border-left: 1px solid #999;
   border-right: 1px solid #999;
   border-bottom: 1px solid #999;
 }

 @sprite .stackHeader {
  gwt-image: 'gradient';
  background-color: #b4b6bc;
  cursor: pointer;

     text-shadow: rgba(255, 255, 255, 1) 0 1px 1px;
     font-size: 1.2em;
     font-weight: bold;
     color: #000;
     padding: .7em .5em 0 .6em;
     border-top: 1px solid #888;
 }

 @if user.agent ie6 {
     .mailboxesIcon {
       background-image: url(mailboxesgroup_ie6.gif);
       width: 31px;
       height: 22px;
       float: left;
     }

        .tasksIcon {
          background-image: url(tasksgroup_ie6.gif);
      width: 31px;
      height: 22px;
          float: left;
        }

       .contactsIcon {
         background-image: url(contactsgroup_ie6.gif);
    width: 31px;
    height: 22px;
         float: left;
       }
 } @else {
  @sprite .mailboxesIcon {
    gwt-image: 'mailboxesgroup';
    float: left;
  }
UIBinder: Layouts e StyleInjection 2
  @sprite .tasksIcon {
    gwt-image: 'tasksgroup';
    float: left;
  }

  @sprite .contactsIcon {
    gwt-image: 'contactsgroup';
    float: left;
  }
      }
 </ui:style>

 <ui:image field='mailboxesgroup' src='mailboxesgroup.png'/>
 <ui:image field='contactsgroup' src='contactsgroup.png'/>
 <ui:image field='tasksgroup' src='tasksgroup.png'/>
 <ui:image field='gradient' src='gradient_bg_dark.png' repeatStyle='Horizontal'/>

 <g:StackLayoutPanel styleName='{style.shortcuts}' unit='EM'>
  <g:stack>
   <g:header size='3'><div class='{style.stackHeader}'><div class='{style.mailboxesIcon}'/> Mailboxes</div></g:header>
   <mail:Mailboxes ui:field='mailboxes'/>
  </g:stack>

  <g:stack>
   <g:header size='3'><div class='{style.stackHeader}'><div class='{style.tasksIcon}'/> Tasks</div></g:header>
   <mail:Tasks ui:field='tasks'/>
  </g:stack>

  <g:stack>
    <g:header size='3'><div class='{style.stackHeader}'><div class='{style.contactsIcon}'/> Contacts</div></g:header>
    <mail:Contacts ui:field='contacts'/>
  </g:stack>
 </g:StackLayoutPanel>
</ui:UiBinder>
Overlay Type
Definizione di Overlay Type

DEF: un Overlay Type di GWT è un qualsiasi type per cui:

  type instanceof JavaScriptObject

è vero.

Attenzione !!!! Gli Overlay Type affiancano e non sostituiscono
JSNI, che rimane l'unico metodo valido per accedere a codice
nativo da GWT.
Overlay Type: esempio dalla documentazione ufficiale
var jsonData = [
   { "FirstName" : "Jimmy", "LastName" : "Webber" },
   { "FirstName" : "Alan", "LastName" : "Dayal" },
   { "FirstName" : "Keanu", "LastName" : "Spoon" },
   { "FirstName" : "Emily", "LastName" : "Rudnick" }
];

// An overlay type
class Customer extends JavaScriptObject {

    // Overlay types always have protected, zero-arg ctors
    protected Customer() { }

    // Typically, methods on overlay types are JSNI
    public final native String getFirstName() /*-{ return this.FirstName; }-*/;
    public final native String getLastName() /*-{ return this.LastName; }-*/;

    // Note, though, that methods aren't required to be JSNI
    public final String getFullName() {
      return getFirstName() + " " + getLastName();
    }
}


class MyModuleEntryPoint implements EntryPoint {
 public void onModuleLoad() {
   Customer c = getFirstCustomer();
   // Yay! Now I have a JS object that appears to be a Customer
   Window.alert("Hello, " + c.getFirstName());
 }

    // Use JSNI to grab the JSON object we care about
    // The JSON object gets its Java type implicitly
    // based on the method's return type
    private native Customer getFirstCustomer() /*-{
      // Get a reference to the first customer in the JSON array from earlier
      return $wnd.jsonData[0];
    }-*/;
}
Overlay Type: @SingleJSOImpl

   Per disaccoppiare meglio il codice client dal codice server a
   volte è opportuno far uso di Java interface.

   Purtroppo i JSO non hanno RTI e quindi due JSO che
   implementano la stessa interfaccia porterebbero ad un
   dispatching ambiguo dei metodi

   Allo scopo di permettere comunque l'uso di interface senza
   incorrere in questi inconvenienti si può far uso della
   annotation @SingleJSOImpl sul tipo che deve girare sul
   client GWT

   Le interface che dichiarano questa annotation sono gestite
   dal compilatore in modo da segnalare eventuali abusi dei
   JSO.
JSON Semplificato con i JSO
JSON con Overlay Type: esempio da documentazione
       String url = "http://www.google.com/calendar/feeds/developer-calendar@google.com/public/full"
               + "?alt=json-in-script";
       JsonpRequestBuilder jsonp = new JsonpRequestBuilder();
       jsonp.requestObject(url, new AsyncCallback<Feed>() {
           public void onFailure(Throwable throwable) {
               GWT.log ("Error: " + throwable, throwable);
           }

             public void onSuccess(Feed feed) {
                JsArray<Entry> entries = feed.getEntries();
                for (int i = 0; i < entries.length(); i++) {
                   Entry entry = entries.get(i);
                   GWT.log (entry.getTitle() + " (" + entry.getWhere() + "): "
                            + entry.getStartTime() + " -> "
                            + entry.getEndTime(), null);
                }
             }
       });
class Entry extends JavaScriptObject {
    protected Entry() {
    }

    public final native String getTitle() /*-{
        return this.title.$t;
    }-*/;

    public final native String getWhere() /*-{
        return this.gd$where[0].valueString;
    }-*/;

    public final native String getStartTime() /*-{
        return this.gd$when ? this.gd$when[0].startTime : null;
    }-*/;

    public final native String getEndTime() /*-{
        return this.gd$when ? this.gd$when[0].endTime : null;
    }-*/;
}

class Feed extends JavaScriptObject {
    protected Feed() {
    }

    public final native JsArray<Entry> getEntries() /*-{
        return this.feed.entry;
    }-*/;
}
Controllare il compilatore da
     codice applicativo
Code Splitting: esempio da documentazione
public class Hello implements EntryPoint {
 public void onModuleLoad() {
  Button b = new Button("Click me", new ClickHandler() {
    public void onClick(ClickEvent event) {
      Window.alert("Hello, AJAX");
    }
  });

        RootPanel.get().add(b);
    }
}

viene rifattorizzata con uno SplitPoint

public class Hello implements EntryPoint {
 public void onModuleLoad() {
  Button b = new Button("Click me", new ClickHandler() {
   public void onClick(ClickEvent event) {
     GWT.runAsync(new RunAsyncCallback() {
       public void onFailure(Throwable caught) {
         Window.alert("Code download failed");
       }

               public void onSuccess() {
                  Window.alert("Hello, AJAX");
               }
              });
          }
        });

        RootPanel.get().add(b);
    }
}
Code Splitting Iterativo
Capire i fragments

  L'Initial Download Fragment è caricato al bootstrap ed è
  quello da cui dobbiamo iniziare l'ottimizzazione per ottenere
  tempi di caricamento migliori
  Ad ogni Split Point è associato un Exclusive Fragment i
  quali possono essere caricati in qualsiasi ordine
  Se l'initial download fragment dipende da alcuni splitpoint,
  allora vengono creati anche degli Initial Fragment, da
  caricare in un ordine specifico (performance peggiori)
  Il Leftover Fragment invece contiene codice che non fa
  parte di alcuno Split Point in particolare ma a fattor comune
  e quindi deve essere caricato prima degli Exclusive.
Code Splitting: pattern
public class Module {
 // public APIs
 public doSomething() { /* ... */ }
 public somethingElse() { /* ... */ }

    // the module instance; instantiate it behind a runAsync
    private static Module instance = null;

    // A callback for using the module instance once it's loaded
    public interface ModuleClient {
      void onSuccess(Module instance);
      vaid onUnavailable();
    }

    /**
     * Access the module's instance. The callback
     * runs asynchronously, once the necessary
     * code has downloaded.
     */
    public static void createAsync(final ModuleClient client) {
      GWT.runAsync(new RunAsyncCallback() {
        public void onFailure(Throwable err) {
          client.onUnavailable();
        }

          public void onSuccess() {
            if (instance == null) {
              instance = new Module();
            }
            client.onSuccess(instance);
          }
        });
    }
}
SOYC

 Purtroppo l'uso produttivo degli split point non è banale, in
 quanto spesso finiamo per splittare uno script di 500kb in
 due da 450kb

 Questo è dovuto al fatto che in quasi tutte le parti di
 un'applicazione GWT usiamo il toolkit grafico e l'emulated
 JRE

 E' quindi necessario far generare al compilatore un report
 che ci permetta di capire meglio come ri-fattorizzare il
 codice per sfruttare questa caratteristica importante
SOYC

 In fase di ottimizzazione del tempo di startup e delle
 dimensioni di download è necessario ripetere spesso le
 iterazioni:
     genera report
     individua classi duplicate sui due script
     rifattorizza il codice

 Ovviamente per "classi duplicate" non significa che il
 programmatore sta scrivendo male il proprio codice, ma
 solo che ci sono degli accoppiamenti nella gerarchia o
 riferimenti che potrebbero essere rimossi senza
 compromettere le funzionalità applicative
Eliminare i metadati

  Abilitando durante la compilazione il flag

                    -XdisableClassMetadata

  ci può far risparmiare tempo in fase di compilazione e far
  diminuire la dimensione del nostro script

  Quando il compilatore non riesce a determinare bene per
  l'applicazione quali sono i metadati realmente usati questo
  può portare a risparmi anche 10% sulla dimensione del
  codice

  ATTENZIONE: chiamando object.getClass() senza metadati
  otteniamo sempre un new Class() !!!!!
Riferimenti


http://code.google.com/p/google-web-toolkit/wiki/AdvancedCompilerOptimizations
http://code.google.com/p/google-web-toolkit/wiki/DesignOOPHM
http://code.google.com/p/google-web-toolkit/wiki/ControllingPermutationExplosion
http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting
http://code.google.com/p/google-web-toolkit/wiki/OverlayTypes
http://code.google.com/p/google-web-toolkit/wiki/LayoutDesign
http://code.google.com/p/google-web-toolkit/wiki/NoClassMetadataOptimization
http://www.lucamasini.net/

Mais conteúdo relacionado

Destaque

Teaching Students with Emojis, Emoticons, & Textspeak
Teaching Students with Emojis, Emoticons, & TextspeakTeaching Students with Emojis, Emoticons, & Textspeak
Teaching Students with Emojis, Emoticons, & TextspeakShelly Sanchez Terrell
 
Hype vs. Reality: The AI Explainer
Hype vs. Reality: The AI ExplainerHype vs. Reality: The AI Explainer
Hype vs. Reality: The AI ExplainerLuminary Labs
 
Study: The Future of VR, AR and Self-Driving Cars
Study: The Future of VR, AR and Self-Driving CarsStudy: The Future of VR, AR and Self-Driving Cars
Study: The Future of VR, AR and Self-Driving CarsLinkedIn
 

Destaque (6)

You trail
You trailYou trail
You trail
 
Introduzione a Gwt
Introduzione a GwtIntroduzione a Gwt
Introduzione a Gwt
 
Inaugural Addresses
Inaugural AddressesInaugural Addresses
Inaugural Addresses
 
Teaching Students with Emojis, Emoticons, & Textspeak
Teaching Students with Emojis, Emoticons, & TextspeakTeaching Students with Emojis, Emoticons, & Textspeak
Teaching Students with Emojis, Emoticons, & Textspeak
 
Hype vs. Reality: The AI Explainer
Hype vs. Reality: The AI ExplainerHype vs. Reality: The AI Explainer
Hype vs. Reality: The AI Explainer
 
Study: The Future of VR, AR and Self-Driving Cars
Study: The Future of VR, AR and Self-Driving CarsStudy: The Future of VR, AR and Self-Driving Cars
Study: The Future of VR, AR and Self-Driving Cars
 

Semelhante a Luca Masini: Introduzione a GWT 2.0

Asp.Net MVC 3 - Il Model View Controller secondo Microsoft
Asp.Net MVC 3 - Il Model View Controller secondo MicrosoftAsp.Net MVC 3 - Il Model View Controller secondo Microsoft
Asp.Net MVC 3 - Il Model View Controller secondo MicrosoftStefano Benedetti
 
jQuery - 1 | WebMaster & WebDesigner
jQuery - 1 | WebMaster & WebDesignerjQuery - 1 | WebMaster & WebDesigner
jQuery - 1 | WebMaster & WebDesignerMatteo Magni
 
E suap - tecnologie client
E suap - tecnologie client E suap - tecnologie client
E suap - tecnologie client Sabino Labarile
 
Introduzione a jQuery
Introduzione a jQueryIntroduzione a jQuery
Introduzione a jQuerySandro Marcon
 
jQuery - 1 | WebMaster & WebDesigner
jQuery - 1 | WebMaster & WebDesignerjQuery - 1 | WebMaster & WebDesigner
jQuery - 1 | WebMaster & WebDesignerMatteo Magni
 
Javascript - 7 | WebMaster & WebDesigner
Javascript - 7 | WebMaster & WebDesignerJavascript - 7 | WebMaster & WebDesigner
Javascript - 7 | WebMaster & WebDesignerMatteo Magni
 
Seam unifies Java EE by Massimiliano Ciccazzo
Seam unifies Java EE by Massimiliano CiccazzoSeam unifies Java EE by Massimiliano Ciccazzo
Seam unifies Java EE by Massimiliano CiccazzoJava User Group Roma
 
April 2010 - Seam unifies JEE5
April 2010 - Seam unifies JEE5April 2010 - Seam unifies JEE5
April 2010 - Seam unifies JEE5JBug Italy
 
Matteo Bicocchi - Introducing HTML5
Matteo Bicocchi - Introducing HTML5Matteo Bicocchi - Introducing HTML5
Matteo Bicocchi - Introducing HTML5Pietro Polsinelli
 
Dominare il codice legacy
Dominare il codice legacyDominare il codice legacy
Dominare il codice legacyTommaso Torti
 
Javascript - 8 | WebMaster & WebDesigner
Javascript - 8 | WebMaster & WebDesignerJavascript - 8 | WebMaster & WebDesigner
Javascript - 8 | WebMaster & WebDesignerMatteo Magni
 
Qt Lezione4 Parte2: creare un custom widget plugin per Qt Designer
Qt Lezione4 Parte2: creare un custom widget plugin per Qt DesignerQt Lezione4 Parte2: creare un custom widget plugin per Qt Designer
Qt Lezione4 Parte2: creare un custom widget plugin per Qt DesignerPaolo Sereno
 
PyPaPi Qt Java Framework
PyPaPi Qt Java FrameworkPyPaPi Qt Java Framework
PyPaPi Qt Java FrameworkTiziano Lattisi
 
Javascript - 4 | WebMaster & WebDesigner
Javascript - 4 | WebMaster & WebDesignerJavascript - 4 | WebMaster & WebDesigner
Javascript - 4 | WebMaster & WebDesignerMatteo Magni
 
Non Conventional Android Programming (Italiano)
Non Conventional Android Programming (Italiano)Non Conventional Android Programming (Italiano)
Non Conventional Android Programming (Italiano)Davide Cerbo
 
jQuery e i suoi plugin
jQuery e i suoi pluginjQuery e i suoi plugin
jQuery e i suoi pluginPasquale Puzio
 

Semelhante a Luca Masini: Introduzione a GWT 2.0 (20)

Asp.Net MVC 3 - Il Model View Controller secondo Microsoft
Asp.Net MVC 3 - Il Model View Controller secondo MicrosoftAsp.Net MVC 3 - Il Model View Controller secondo Microsoft
Asp.Net MVC 3 - Il Model View Controller secondo Microsoft
 
Wcmil2018
Wcmil2018Wcmil2018
Wcmil2018
 
jQuery - 1 | WebMaster & WebDesigner
jQuery - 1 | WebMaster & WebDesignerjQuery - 1 | WebMaster & WebDesigner
jQuery - 1 | WebMaster & WebDesigner
 
E suap - tecnologie client
E suap - tecnologie client E suap - tecnologie client
E suap - tecnologie client
 
Introduzione a jQuery
Introduzione a jQueryIntroduzione a jQuery
Introduzione a jQuery
 
Oo Javascript
Oo JavascriptOo Javascript
Oo Javascript
 
jQuery - 1 | WebMaster & WebDesigner
jQuery - 1 | WebMaster & WebDesignerjQuery - 1 | WebMaster & WebDesigner
jQuery - 1 | WebMaster & WebDesigner
 
Javascript - 7 | WebMaster & WebDesigner
Javascript - 7 | WebMaster & WebDesignerJavascript - 7 | WebMaster & WebDesigner
Javascript - 7 | WebMaster & WebDesigner
 
Seam unifies Java EE by Massimiliano Ciccazzo
Seam unifies Java EE by Massimiliano CiccazzoSeam unifies Java EE by Massimiliano Ciccazzo
Seam unifies Java EE by Massimiliano Ciccazzo
 
April 2010 - Seam unifies JEE5
April 2010 - Seam unifies JEE5April 2010 - Seam unifies JEE5
April 2010 - Seam unifies JEE5
 
Matteo Bicocchi - Introducing HTML5
Matteo Bicocchi - Introducing HTML5Matteo Bicocchi - Introducing HTML5
Matteo Bicocchi - Introducing HTML5
 
Dominare il codice legacy
Dominare il codice legacyDominare il codice legacy
Dominare il codice legacy
 
Js intro
Js introJs intro
Js intro
 
Javascript - 8 | WebMaster & WebDesigner
Javascript - 8 | WebMaster & WebDesignerJavascript - 8 | WebMaster & WebDesigner
Javascript - 8 | WebMaster & WebDesigner
 
Qt Lezione4 Parte2: creare un custom widget plugin per Qt Designer
Qt Lezione4 Parte2: creare un custom widget plugin per Qt DesignerQt Lezione4 Parte2: creare un custom widget plugin per Qt Designer
Qt Lezione4 Parte2: creare un custom widget plugin per Qt Designer
 
PyPaPi Qt Java Framework
PyPaPi Qt Java FrameworkPyPaPi Qt Java Framework
PyPaPi Qt Java Framework
 
Javascript - 4 | WebMaster & WebDesigner
Javascript - 4 | WebMaster & WebDesignerJavascript - 4 | WebMaster & WebDesigner
Javascript - 4 | WebMaster & WebDesigner
 
Django
DjangoDjango
Django
 
Non Conventional Android Programming (Italiano)
Non Conventional Android Programming (Italiano)Non Conventional Android Programming (Italiano)
Non Conventional Android Programming (Italiano)
 
jQuery e i suoi plugin
jQuery e i suoi pluginjQuery e i suoi plugin
jQuery e i suoi plugin
 

Mais de firenze-gtug

Html5 apps - GWT oriented
Html5 apps - GWT orientedHtml5 apps - GWT oriented
Html5 apps - GWT orientedfirenze-gtug
 
Android ndk - ottimizzazione su dispositivi Intel
Android ndk - ottimizzazione su dispositivi IntelAndroid ndk - ottimizzazione su dispositivi Intel
Android ndk - ottimizzazione su dispositivi Intelfirenze-gtug
 
Gwt kickoff - Alberto Mancini & Francesca Tosi
Gwt kickoff - Alberto Mancini & Francesca TosiGwt kickoff - Alberto Mancini & Francesca Tosi
Gwt kickoff - Alberto Mancini & Francesca Tosifirenze-gtug
 
Youtube broadcast live - Massimiliano D'Ambrosio
Youtube broadcast live - Massimiliano D'AmbrosioYoutube broadcast live - Massimiliano D'Ambrosio
Youtube broadcast live - Massimiliano D'Ambrosiofirenze-gtug
 
Intro BeagleBone Black - Massimiliano D'Ambrosio
Intro BeagleBone Black - Massimiliano D'AmbrosioIntro BeagleBone Black - Massimiliano D'Ambrosio
Intro BeagleBone Black - Massimiliano D'Ambrosiofirenze-gtug
 
Arduino - Massimiliano D'Ambrosio
Arduino - Massimiliano D'AmbrosioArduino - Massimiliano D'Ambrosio
Arduino - Massimiliano D'Ambrosiofirenze-gtug
 
Introduzione a GAE - Alessandro Aglietti e Lorenzo Bugiani
Introduzione a GAE - Alessandro Aglietti e Lorenzo BugianiIntroduzione a GAE - Alessandro Aglietti e Lorenzo Bugiani
Introduzione a GAE - Alessandro Aglietti e Lorenzo Bugianifirenze-gtug
 
RFID: What & Why - Stefano Coluccini
RFID: What & Why - Stefano ColucciniRFID: What & Why - Stefano Coluccini
RFID: What & Why - Stefano Coluccinifirenze-gtug
 
GWT - AppDays - (25 aprile 2014, pordenone)
GWT - AppDays - (25 aprile 2014, pordenone)GWT - AppDays - (25 aprile 2014, pordenone)
GWT - AppDays - (25 aprile 2014, pordenone)firenze-gtug
 
Presentazione Google App Engine
Presentazione Google App EnginePresentazione Google App Engine
Presentazione Google App Enginefirenze-gtug
 
Android chat in the cloud
Android chat in the cloudAndroid chat in the cloud
Android chat in the cloudfirenze-gtug
 
Clean android code
Clean android codeClean android code
Clean android codefirenze-gtug
 
Intel ndk - a few Benchmarks
Intel ndk - a few BenchmarksIntel ndk - a few Benchmarks
Intel ndk - a few Benchmarksfirenze-gtug
 
EE Incremental Store
EE Incremental StoreEE Incremental Store
EE Incremental Storefirenze-gtug
 
Programming objects with android
Programming objects with androidProgramming objects with android
Programming objects with androidfirenze-gtug
 
Apertura "Mobile & Embedded" - 13 febbraio 2014
Apertura "Mobile & Embedded" - 13 febbraio 2014Apertura "Mobile & Embedded" - 13 febbraio 2014
Apertura "Mobile & Embedded" - 13 febbraio 2014firenze-gtug
 
Maven from dummies
Maven from dummiesMaven from dummies
Maven from dummiesfirenze-gtug
 
Dev fest android application case study
Dev fest android application   case studyDev fest android application   case study
Dev fest android application case studyfirenze-gtug
 

Mais de firenze-gtug (20)

Html5 apps - GWT oriented
Html5 apps - GWT orientedHtml5 apps - GWT oriented
Html5 apps - GWT oriented
 
Android ndk - ottimizzazione su dispositivi Intel
Android ndk - ottimizzazione su dispositivi IntelAndroid ndk - ottimizzazione su dispositivi Intel
Android ndk - ottimizzazione su dispositivi Intel
 
Gwt kickoff - Alberto Mancini & Francesca Tosi
Gwt kickoff - Alberto Mancini & Francesca TosiGwt kickoff - Alberto Mancini & Francesca Tosi
Gwt kickoff - Alberto Mancini & Francesca Tosi
 
Youtube broadcast live - Massimiliano D'Ambrosio
Youtube broadcast live - Massimiliano D'AmbrosioYoutube broadcast live - Massimiliano D'Ambrosio
Youtube broadcast live - Massimiliano D'Ambrosio
 
Intro BeagleBone Black - Massimiliano D'Ambrosio
Intro BeagleBone Black - Massimiliano D'AmbrosioIntro BeagleBone Black - Massimiliano D'Ambrosio
Intro BeagleBone Black - Massimiliano D'Ambrosio
 
Arduino - Massimiliano D'Ambrosio
Arduino - Massimiliano D'AmbrosioArduino - Massimiliano D'Ambrosio
Arduino - Massimiliano D'Ambrosio
 
Introduzione a GAE - Alessandro Aglietti e Lorenzo Bugiani
Introduzione a GAE - Alessandro Aglietti e Lorenzo BugianiIntroduzione a GAE - Alessandro Aglietti e Lorenzo Bugiani
Introduzione a GAE - Alessandro Aglietti e Lorenzo Bugiani
 
RFID: What & Why - Stefano Coluccini
RFID: What & Why - Stefano ColucciniRFID: What & Why - Stefano Coluccini
RFID: What & Why - Stefano Coluccini
 
GWT - AppDays - (25 aprile 2014, pordenone)
GWT - AppDays - (25 aprile 2014, pordenone)GWT - AppDays - (25 aprile 2014, pordenone)
GWT - AppDays - (25 aprile 2014, pordenone)
 
Presentazione Google App Engine
Presentazione Google App EnginePresentazione Google App Engine
Presentazione Google App Engine
 
Android chat in the cloud
Android chat in the cloudAndroid chat in the cloud
Android chat in the cloud
 
Clean android code
Clean android codeClean android code
Clean android code
 
#Html2Native
#Html2Native#Html2Native
#Html2Native
 
Intel ndk - a few Benchmarks
Intel ndk - a few BenchmarksIntel ndk - a few Benchmarks
Intel ndk - a few Benchmarks
 
EE Incremental Store
EE Incremental StoreEE Incremental Store
EE Incremental Store
 
Programming objects with android
Programming objects with androidProgramming objects with android
Programming objects with android
 
Apertura "Mobile & Embedded" - 13 febbraio 2014
Apertura "Mobile & Embedded" - 13 febbraio 2014Apertura "Mobile & Embedded" - 13 febbraio 2014
Apertura "Mobile & Embedded" - 13 febbraio 2014
 
Maven from dummies
Maven from dummiesMaven from dummies
Maven from dummies
 
Apps fuel oct2012
Apps fuel oct2012Apps fuel oct2012
Apps fuel oct2012
 
Dev fest android application case study
Dev fest android application   case studyDev fest android application   case study
Dev fest android application case study
 

Luca Masini: Introduzione a GWT 2.0

  • 1. Introduzione a GWT 2.0 Luca Masini, 18.03.2010
  • 2. Agenda GWT in due minuti I difetti di GWT 1.x Le soluzioni adottate con GWT 2.0
  • 3. GWT in 2 minuti
  • 4. Java (compilato in JS) nel proprio IDE preferito......
  • 5. ......dove posso condividere codice tra client e server @Entity @Inheritance(strategy = InheritanceType.JOINED) @DiscriminatorColumn(name = "roomDisc", discriminatorType = DiscriminatorType.STRING) public class Room { private RoomPK roomPk; @EmbeddedId public RoomPK getRoomPk() { return roomPk; } public void setRoomPk(final RoomPK roomPk) { this.roomPk = roomPk; } public void doSomeBusinessLogic(final String inputParameter) { .... .... } }
  • 6. Una "specie" di reflection per JS chiamata Deferred Binding @RemoteServiceRelativePath("playgroundService") public interface PlaygroundService extends RemoteService { String[] cajole(String uri, String input); String getBuildInfo(); String fetch(String url); } GWT.create(PlaygroundService.class);
  • 7. Una "specie" di reflection per JS chiamata Deferred Binding <generate-with class="com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator"> <when-type-assignable class="com.google.gwt.user.client.rpc.RemoteService"/> </generate-with> public class ServiceInterfaceProxyGenerator extends Generator { @Override public String generate(TreeLogger logger, GeneratorContext ctx, String requestedClass) throws UnableToCompleteException { TypeOracle typeOracle = ctx.getTypeOracle(); .... .... .... return javaCode; }
  • 8. Un meccanismo di integrazione con codice JavaScript (JSNI) public native void bar(JSNIExample x, String s) /*-{ var ret = this.@MyObject::instanceFoo(Ljava/lang/String;)(s); alert(ret); }-*/; SmartGWT
  • 9. Cosa non funziona con GWT ??
  • 10. Scrivere codice UI è troppo complicato rispetto ad HTML (la flessibilità costa !!) <form method="POST" action="/writeForm"> Nome: <input type="text" name="Nome" /> Cognome: <input type="text" name="Cognome" /> Indirizzo: <input type="text" name="Indirizzo" /> Citt&agrave;: <input type="text" name="Citta" /> <input type="submit" value="OK" /> </form> La programmazione Swing-like di GWT è molto elegante ma costosa in termini di righe di codice e complessità. Anche chiamare il servizio, prendendo i valori dalla UI, ha un costo notevole per il valore aggiunto che viene dato rispetto ad una normale POST.
  • 12. Ma il vero problema è il CSS !!!!!
  • 13. Gestione a dir poco maldestra di JSON Se il nostro servizio non è un GWT-RPC, allora fare il parsing di JSON può farci perdere gran parte del vantaggio della tipizzazione di Java, oltre che essere molto noioso !!! RequestBuilder builder = new RequestBuilder(RequestBuilder.GET , url); Request request = builder.sendRequest(null, new RequestCallback() { public void onResponseReceived(Request request, Response response) { JSONValue jsonValue = JSONParser.parse (response.getText()); JSONArray jsonArray = jsonValue.isArray(); for (int i = 0; i < jsonArray.size(); i++) { JSONObject jsObject = jsonArray.isObject(); JSONString jsString = jsObject.isString(); JSONNumber jsNumber = jsObject.isNumber(); } } });
  • 14. Ambiente di sviluppo non integrato nel browser Durante lo sviluppo siamo integrati solo con Internet Explorer 7 Come possiamo debuggare eventuali inconsistenze non ripetibili su IE ??? Siamo costretti a numerose e lunghe sessioni di testing prima del rilascio in produzione, per eliminare le eventuali inconsistenze cross-browser. Dove finisce l'agilita dello strumento ?
  • 15. Il compilatore genera un solo mega script scaricato all'avvio dell'applicazione Un'applicazione di piccole dimensioni può occupare anche 250kb L'aggiunta di poche librerie ad un'applicazione di medio- piccole dimensioni può far raggiungere i 500kb e più Questo non è un problema per applicazioni Intranet (caching efficace) E' sicuramente un problema invece per applicazioni Internet e Intranet PDA
  • 16. Mapping non chiaro tra oggetti JavaScript e Java Il passaggio dei parametri tra "mondo" Java e "mondo" JavaScript è problematico: In hosted mode ad ogni passaggio viene allocato un wrapper JavaScriptObject, di fatto rendendo errate le identità Se possibile in web mode le cose possono andare ancora peggio, in quanto il runtime-type cambia durante l'esecuzione e esempi di riconoscimento con "instanceof" possono dipendere anche dall'ordine con cui il compilatore genera il JavaScript
  • 17. Le soluzioni adottate con GWT 2.0
  • 18. Out Of Process Hosted Mode (OOPHM)
  • 20. Il plugin per l'OOPHM Il parametro "gwt.codesvr" serve come discriminante. Se presente e non intercettato da un plugin locale fa generare alla Shell un iframe con il codice per l'installazione: Agli accessi successivi invece il parametro è usato per aprire un "browser channel" verso la Shell stessa.
  • 21. Strumenti Standard in Hosted Mode
  • 23. UIBinder: esempio <!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent"> <ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:v="urn:import:com.google.gwt.visualization.client.visualizations" xmlns:store="urn:import:net.lucamasini.client.view" > <ui:style type='net.lucamasini.client.view.StoreComposite.StoreStyle' > .important { font-weight: bold ; } .fullWidth { width: 100% ; } </ui:style> <g:HTMLPanel> <table> <tr> <td colspan='2' > <g:ListBox styleName="{style.important}" ui:field='tablesListBox' visibleItemCount='1' /> </td> </tr> <tr> <td colspan='2' ><g:Button text="Ricarica" styleName="{style.important}" ui:field="button" /></td> </tr> <tr> <td colspan='2' ><store:FilterPanel ui:field="filterPanel" width='100%' /></td> </tr> <tr> <td colspan='2' > <g:DisclosurePanel open='false' width='100%' > <g:header>Query</g:header> <g:TextArea ui:field='textArea' visibleLines='5' styleName="{style.fullWidth}" /> </g:DisclosurePanel> </td> </tr> <tr> <td colspan='2' ><v:Table ui:field="table" /></td> </tr> <tr> <td colspan='2' ><g:SimplePanel ui:field="detailsContainer" /></td> </tr> <tr> <td colspan='2' ><store:StatusBar ui:field="statusBar" /></td> </tr> </table> </g:HTMLPanel> </ui:UiBinder>
  • 24. UIBinder: esempio interface StoreStyle extends CssResource { String important(); } private static StoreCompositeUiBinder uiBinder = GWT .create (StoreCompositeUiBinder.class); interface StoreCompositeUiBinder extends UiBinder<Widget, StoreComposite> { } @UiField StoreStyle style; @UiField Button button; @UiHandler("button") void onClick(ClickEvent e) { … … }
  • 25. UIBinder: Layouts e StyleInjection 1 <ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui' xmlns:mail='urn:import:com.google.gwt.sample.mail.client'> <ui:style> .shortcuts { border-left: 1px solid #999; border-right: 1px solid #999; border-bottom: 1px solid #999; } @sprite .stackHeader { gwt-image: 'gradient'; background-color: #b4b6bc; cursor: pointer; text-shadow: rgba(255, 255, 255, 1) 0 1px 1px; font-size: 1.2em; font-weight: bold; color: #000; padding: .7em .5em 0 .6em; border-top: 1px solid #888; } @if user.agent ie6 { .mailboxesIcon { background-image: url(mailboxesgroup_ie6.gif); width: 31px; height: 22px; float: left; } .tasksIcon { background-image: url(tasksgroup_ie6.gif); width: 31px; height: 22px; float: left; } .contactsIcon { background-image: url(contactsgroup_ie6.gif); width: 31px; height: 22px; float: left; } } @else { @sprite .mailboxesIcon { gwt-image: 'mailboxesgroup'; float: left; }
  • 26. UIBinder: Layouts e StyleInjection 2 @sprite .tasksIcon { gwt-image: 'tasksgroup'; float: left; } @sprite .contactsIcon { gwt-image: 'contactsgroup'; float: left; } } </ui:style> <ui:image field='mailboxesgroup' src='mailboxesgroup.png'/> <ui:image field='contactsgroup' src='contactsgroup.png'/> <ui:image field='tasksgroup' src='tasksgroup.png'/> <ui:image field='gradient' src='gradient_bg_dark.png' repeatStyle='Horizontal'/> <g:StackLayoutPanel styleName='{style.shortcuts}' unit='EM'> <g:stack> <g:header size='3'><div class='{style.stackHeader}'><div class='{style.mailboxesIcon}'/> Mailboxes</div></g:header> <mail:Mailboxes ui:field='mailboxes'/> </g:stack> <g:stack> <g:header size='3'><div class='{style.stackHeader}'><div class='{style.tasksIcon}'/> Tasks</div></g:header> <mail:Tasks ui:field='tasks'/> </g:stack> <g:stack> <g:header size='3'><div class='{style.stackHeader}'><div class='{style.contactsIcon}'/> Contacts</div></g:header> <mail:Contacts ui:field='contacts'/> </g:stack> </g:StackLayoutPanel> </ui:UiBinder>
  • 28. Definizione di Overlay Type DEF: un Overlay Type di GWT è un qualsiasi type per cui: type instanceof JavaScriptObject è vero. Attenzione !!!! Gli Overlay Type affiancano e non sostituiscono JSNI, che rimane l'unico metodo valido per accedere a codice nativo da GWT.
  • 29. Overlay Type: esempio dalla documentazione ufficiale var jsonData = [ { "FirstName" : "Jimmy", "LastName" : "Webber" }, { "FirstName" : "Alan", "LastName" : "Dayal" }, { "FirstName" : "Keanu", "LastName" : "Spoon" }, { "FirstName" : "Emily", "LastName" : "Rudnick" } ]; // An overlay type class Customer extends JavaScriptObject { // Overlay types always have protected, zero-arg ctors protected Customer() { } // Typically, methods on overlay types are JSNI public final native String getFirstName() /*-{ return this.FirstName; }-*/; public final native String getLastName() /*-{ return this.LastName; }-*/; // Note, though, that methods aren't required to be JSNI public final String getFullName() { return getFirstName() + " " + getLastName(); } } class MyModuleEntryPoint implements EntryPoint { public void onModuleLoad() { Customer c = getFirstCustomer(); // Yay! Now I have a JS object that appears to be a Customer Window.alert("Hello, " + c.getFirstName()); } // Use JSNI to grab the JSON object we care about // The JSON object gets its Java type implicitly // based on the method's return type private native Customer getFirstCustomer() /*-{ // Get a reference to the first customer in the JSON array from earlier return $wnd.jsonData[0]; }-*/; }
  • 30. Overlay Type: @SingleJSOImpl Per disaccoppiare meglio il codice client dal codice server a volte è opportuno far uso di Java interface. Purtroppo i JSO non hanno RTI e quindi due JSO che implementano la stessa interfaccia porterebbero ad un dispatching ambiguo dei metodi Allo scopo di permettere comunque l'uso di interface senza incorrere in questi inconvenienti si può far uso della annotation @SingleJSOImpl sul tipo che deve girare sul client GWT Le interface che dichiarano questa annotation sono gestite dal compilatore in modo da segnalare eventuali abusi dei JSO.
  • 32. JSON con Overlay Type: esempio da documentazione String url = "http://www.google.com/calendar/feeds/developer-calendar@google.com/public/full" + "?alt=json-in-script"; JsonpRequestBuilder jsonp = new JsonpRequestBuilder(); jsonp.requestObject(url, new AsyncCallback<Feed>() { public void onFailure(Throwable throwable) { GWT.log ("Error: " + throwable, throwable); } public void onSuccess(Feed feed) { JsArray<Entry> entries = feed.getEntries(); for (int i = 0; i < entries.length(); i++) { Entry entry = entries.get(i); GWT.log (entry.getTitle() + " (" + entry.getWhere() + "): " + entry.getStartTime() + " -> " + entry.getEndTime(), null); } } }); class Entry extends JavaScriptObject { protected Entry() { } public final native String getTitle() /*-{ return this.title.$t; }-*/; public final native String getWhere() /*-{ return this.gd$where[0].valueString; }-*/; public final native String getStartTime() /*-{ return this.gd$when ? this.gd$when[0].startTime : null; }-*/; public final native String getEndTime() /*-{ return this.gd$when ? this.gd$when[0].endTime : null; }-*/; } class Feed extends JavaScriptObject { protected Feed() { } public final native JsArray<Entry> getEntries() /*-{ return this.feed.entry; }-*/; }
  • 33. Controllare il compilatore da codice applicativo
  • 34. Code Splitting: esempio da documentazione public class Hello implements EntryPoint { public void onModuleLoad() { Button b = new Button("Click me", new ClickHandler() { public void onClick(ClickEvent event) { Window.alert("Hello, AJAX"); } }); RootPanel.get().add(b); } } viene rifattorizzata con uno SplitPoint public class Hello implements EntryPoint { public void onModuleLoad() { Button b = new Button("Click me", new ClickHandler() { public void onClick(ClickEvent event) { GWT.runAsync(new RunAsyncCallback() { public void onFailure(Throwable caught) { Window.alert("Code download failed"); } public void onSuccess() { Window.alert("Hello, AJAX"); } }); } }); RootPanel.get().add(b); } }
  • 36. Capire i fragments L'Initial Download Fragment è caricato al bootstrap ed è quello da cui dobbiamo iniziare l'ottimizzazione per ottenere tempi di caricamento migliori Ad ogni Split Point è associato un Exclusive Fragment i quali possono essere caricati in qualsiasi ordine Se l'initial download fragment dipende da alcuni splitpoint, allora vengono creati anche degli Initial Fragment, da caricare in un ordine specifico (performance peggiori) Il Leftover Fragment invece contiene codice che non fa parte di alcuno Split Point in particolare ma a fattor comune e quindi deve essere caricato prima degli Exclusive.
  • 37. Code Splitting: pattern public class Module { // public APIs public doSomething() { /* ... */ } public somethingElse() { /* ... */ } // the module instance; instantiate it behind a runAsync private static Module instance = null; // A callback for using the module instance once it's loaded public interface ModuleClient { void onSuccess(Module instance); vaid onUnavailable(); } /** * Access the module's instance. The callback * runs asynchronously, once the necessary * code has downloaded. */ public static void createAsync(final ModuleClient client) { GWT.runAsync(new RunAsyncCallback() { public void onFailure(Throwable err) { client.onUnavailable(); } public void onSuccess() { if (instance == null) { instance = new Module(); } client.onSuccess(instance); } }); } }
  • 38. SOYC Purtroppo l'uso produttivo degli split point non è banale, in quanto spesso finiamo per splittare uno script di 500kb in due da 450kb Questo è dovuto al fatto che in quasi tutte le parti di un'applicazione GWT usiamo il toolkit grafico e l'emulated JRE E' quindi necessario far generare al compilatore un report che ci permetta di capire meglio come ri-fattorizzare il codice per sfruttare questa caratteristica importante
  • 39. SOYC In fase di ottimizzazione del tempo di startup e delle dimensioni di download è necessario ripetere spesso le iterazioni: genera report individua classi duplicate sui due script rifattorizza il codice Ovviamente per "classi duplicate" non significa che il programmatore sta scrivendo male il proprio codice, ma solo che ci sono degli accoppiamenti nella gerarchia o riferimenti che potrebbero essere rimossi senza compromettere le funzionalità applicative
  • 40. Eliminare i metadati Abilitando durante la compilazione il flag -XdisableClassMetadata ci può far risparmiare tempo in fase di compilazione e far diminuire la dimensione del nostro script Quando il compilatore non riesce a determinare bene per l'applicazione quali sono i metadati realmente usati questo può portare a risparmi anche 10% sulla dimensione del codice ATTENZIONE: chiamando object.getClass() senza metadati otteniamo sempre un new Class() !!!!!