2016-05-10 9 views
0

Ich habe ein GWT-Projekt, das die Google JavaScript Chart API verwendet, um Diagramme von Java-Objekten anzuzeigen. Ich konvertiere meine Java-Objekte in JSON und übermittle sie an die JavaScript-Diagramm-API über JSNI, und das funktioniert perfekt.Fehler beim Übergeben des Java-Objekts über GWT JSNI

Aber jetzt möchte ich einen Schritt weiter gehen und den anderen Weg gehen: Wenn ich innerhalb eines Diagramms klicke (was ich durch einen JavaScript-Listener erkennen kann), möchte ich dieses Java-Objekt zurück zu meinem Java-Code senden .

Ich glaube, ich alles in der JSNI Führung gemacht habe, aber wenn ich auf das Diagramm klicken, erhalte ich einen Fehler in der JavaScript-Konsole, die ich nicht einmal sicher bin, wie man lesen:

SCRIPT5022: Exception thrown and not caught 
File: eval code (21), Line: 5, Column: 7 

__gwt_javaInvokes[2] = 
    function(thisObj, dispId,p0,p1) { 
    var result = __static(dispId, thisObj,p0,p1); 
    if (result[0]) { 
     throw result[1]; 
    } else { 
     return result[1]; 
    } 
    } function(thisObj, dispId,p0,p1) { var result = __static(dispId, thisObj,p0,p1); if (result[0]) { throw result[1]; } else { return result[1]; } } 

hier ist meine hTML-Seite:

<!doctype html> 
<html> 
    <head> 
    <meta http-equiv="content-type" content="text/html; charset=UTF-8"> 
    <link type="text/css" rel="stylesheet" href="GwtTest.css"> 
    <title>GWT Test</title> 
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> 
    <script type="text/javascript" language="javascript" src="gwttest/gwttest.nocache.js"></script> 
    </head> 
    <body> 

    </body> 
</html> 

Das einzige, was von Interesse ist, dass ich die Google Chart API Script-Tag hinzugefügt haben.

Hier wird das Java-Objekt ist Ich versuche, von Java zu passieren, bis Sie JavaScript, um dann auf Java zurück:

package com.example.client; 

public class ChartData { 
    public String title = "test"; 

    public String labelOne = "thingOne"; 
    public String labelTwo = "thingTwo"; 
    public String labelThree = "thingThree"; 

    public int valueOne = 100; 
    public int valueTwo = 200; 
    public int valueThree = 300; 
} 

Schließlich, hier ist meine GWT-Client-Klasse:

package com.example.client; 

import com.google.gwt.core.client.EntryPoint; 
import com.google.gwt.core.client.JsArray; 
import com.google.gwt.core.client.JsonUtils; 
import com.google.gwt.event.dom.client.ClickEvent; 
import com.google.gwt.event.dom.client.ClickHandler; 
import com.google.gwt.user.client.ui.Button; 
import com.google.gwt.user.client.ui.RootLayoutPanel; 
import com.google.gwt.user.client.ui.SimplePanel; 
import com.google.gwt.user.client.ui.VerticalPanel; 

public class GwtTest implements EntryPoint { 

    public void onModuleLoad() { 

     RootLayoutPanel rootPanel = RootLayoutPanel.get(); 

     SimplePanel chartPanel = new SimplePanel(); 
     chartPanel.getElement().setId("chartDiv"); 
     chartPanel.setSize("500px", "500px"); 

     Button button = new Button("Click Me"); 
     button.addClickHandler(new ClickHandler(){ 

      @Override 
      public void onClick(ClickEvent event) { 
       ChartData chartData = new ChartData(); 
       String json = getChartJson(chartData); 
       JsArray<?> chartArrayData = JsonUtils.safeEval(json); 
       drawChart(chartArrayData, chartData); 
      } 
     }); 

     VerticalPanel vp = new VerticalPanel(); 
     vp.add(button); 
     vp.add(chartPanel); 

     rootPanel.add(vp); 

     loadChartLibrary(); 
    } 

    private String getChartJson(ChartData chartData){ 
     String json = "["; 
     json += "[\"time\", \"" + chartData.title + "\"]"; 

     json += ","; 
     json += "[\"" + chartData.labelOne + "\"," + chartData.valueOne + "]"; 

     json += ","; 
     json += "[\"" + chartData.labelTwo + "\"," + chartData.valueTwo + "]"; 

     json += ","; 
     json += "[\"" + chartData.labelThree + "\"," + chartData.valueThree + "]"; 

     json += "]"; 
     return json; 
    } 

    private native void loadChartLibrary()/*-{ 
     $wnd.google.charts.load('current', {packages: ['corechart']}); 
    }-*/; 

    private native void drawChart(JsArray<?> dataArray, ChartData chartData)/*-{ 
     var data = $wnd.google.visualization.arrayToDataTable(dataArray); 
     var chart = new $wnd.google.visualization.ColumnChart($wnd.document.getElementById('chartDiv')); 
     chart.draw(data, null); 

     $wnd.google.visualization.events.addListener(chart, 'select', selectHandler); 

     function selectHandler(e) { 
      var selectionArray = chart.getSelection(); 
      if(selectionArray.length == 0){ 

      } 
      else{ 
      var row = selectionArray[0].row; 
      console.log(row); 
      [email protected]::printChartData(Lcom/example/client/ChartData;I)(chartData, row); 
      console.log("here"); 
      } 
     } 

    }-*/; 

    public void printChartData(ChartData chartData, int i){ 
     System.out.println(i + ": " + chartData.valueThree); 
    } 
} 

Wenn Sie diesen Code ausführen, sollten Sie eine Schaltfläche sehen, die Click Me sagt. Klicken Sie auf diese Schaltfläche, um das Diagramm anzuzeigen. Klicken Sie dann auf eine Leiste im Diagramm. Ich würde erwarten, dass dies meinen Java-Code in der printChartData()-Funktion auslöst, aber stattdessen erhalte ich einen Fehler in der JavaScript-Konsole.

Ich habe das Problem auf dieses Stück Code verengt:

var row = selectionArray[0].row; 
console.log(row); 
[email protected]::printChartData(Lcom/example/client/ChartData;I)(chartData, row); 
console.log("here"); 

Die Zeile an die Konsole richtig gedruckt wird, so dass ich weiß, dass mein JavaScript funktioniert. Aber dann wird die "here" nie auf der Konsole gedruckt, daher weiß ich, dass der Fehler in meiner JSNI-Zeile ist.

Fehle ich etwas mit meinem JSNI-Setup? Was bedeutet der JavaScript-Fehler?

Antwort

1

Ich denke, dass das Problem darin besteht, this in einem Handler zu verwenden. Sie erwarten wahrscheinlich this als Instanz der GwtTest Klasse, aber innerhalb eines Handlers verwendet, zeigt es auf den Handler. Und deshalb schlägt der Anruf zu [email protected]::printChartData fehl.

Sie können eine Variable außerhalb des Handlers deklarieren und this zuweisen und sie dann im Handler verwenden.

Versuchen:

var instance = this; 
function selectHandler(e) { 
     var selectionArray = chart.getSelection(); 
     if(selectionArray.length == 0){ 

     } 
     else{ 
     var row = selectionArray[0].row; 
     console.log(row); 
     [email protected]::printChartData(Lcom/example/client/ChartData;I)(chartData, row); 
     console.log("here"); 
     } 
    } 
+0

Wow, danke. Ich kann nicht glauben, dass es so einfach war. –

-1

ChartData ist, die sich nicht JavaScriptObject, so dass es eine ClassCastException wirft, wenn Sie
rufen printChartData.
Auch Adam hat Recht. Die Verwendung von this innerhalb des Handlers funktioniert nicht ...
Hier ist ein Beispiel, wie es funktionieren kann, außer Kraft setzt nur Ihre ganze GwtTest Klasse ..

public class GwtTest implements EntryPoint { 

private ChartData chartData; 

public void onModuleLoad() { 
    RootLayoutPanel rootPanel = RootLayoutPanel.get(); 
    SimplePanel chartPanel = new SimplePanel(); 
    chartPanel.getElement().setId("chartDiv"); 
    chartPanel.setSize("500px", "500px"); 
    Button button = new Button("Click Me"); 
    button.addClickHandler(new ClickHandler() { 
     @Override 
     public void onClick(ClickEvent event) { 
      chartData= ChartData.createJSO("Time", "Time"); 
      for (int i = 0; i < 4; i++) { 
       RowData row = RowData.createJSO("label" + i, 100 + i); 
       chartData.add(row); 
      } 
      drawChart(chartData); 
     } 
    }); 
    VerticalPanel vp = new VerticalPanel(); 
    vp.add(button); 
    vp.add(chartPanel); 
    rootPanel.add(vp); 
    loadChartLibrary(); 
} 

public static class ChartData extends JavaScriptObject { 
    protected ChartData() { 
    } 

    public static native ChartData createJSO(String chartname, String rowTypeDescriton) /*-{ 
     return [ [ chartname, rowTypeDescriton ] ]; 
    }-*/; 

    public final native RowData get(int index) /*-{ 
     return this[index + 1]; 
    }-*/; 

    public final native void add(RowData data) /*-{ 
     this[this.length] = data; 
    }-*/; 

} 

public static class RowData extends JavaScriptObject { 

    protected RowData() { 
    } 

    public static native RowData createJSO(String label, int value) /*-{ 
     return [ label, value ]; 
    }-*/; 

    public final native String getLabelOne() /*-{ 
     return this[0]; 
    }-*/; 

    public final native int getValueOne() /*-{ 
     return this[1]; 
    }-*/; 

} 

private native void loadChartLibrary()/*-{ 
    $wnd.google.charts.load('current', { 
     packages : [ 'corechart' ] 
    }); 
}-*/; 

private native void drawChart(ChartData dataArray)/*-{ 
    var self = this; 
    var data = $wnd.google.visualization.arrayToDataTable(dataArray); 
    var chart = new $wnd.google.visualization.ColumnChart($wnd.document 
      .getElementById('chartDiv')); 
    chart.draw(data, null); 
    $wnd.google.visualization.events.addListener(chart, 'select', 
      selectHandler); 
    function selectHandler(e) { 
     var selection = chart.getSelection(); 
     for (var i = 0; i < selection.length; i++) { 
      var item = selection[i]; 
      if (item.row != null) { 
       [email protected]::printChartData(I)(item.row); 
      } 
     } 
    } 

}-*/; 

public void printChartData(int row) { 
    System.out.println(chartData.get(row)); 
} 
} 
+0

Ich glaube nicht, dass das korrekt ist. 'ChartData' muss ** JavaScript ** nicht erweitern, und ich bekomme keine' ClassCastException'. Außerdem wird dadurch der Punkt meiner Frage besiegt, da ich 'chartData' benötige, um meinen nativen JavaScript-Code zu durchlaufen, und ich kann keine Variable auf Klassenebene verwenden, wie Sie es getan haben. Danke für die Antwort, aber diese Antwort ist nicht korrekt. Adams Antwort scheint das Problem gelöst zu haben. –

+0

Wenn Sie ein Objekt von einer jsni-Methode an Java übergeben möchten, das nicht primitiv ist, muss JavaScriptObject erweitert werden. Aber Sie haben Recht, ChartData muss in diesem Fall JavaScriptObject nicht erweitern, da Sie nur den Index der Zeile benötigen ... aber das Erstellen der JSON-Zeichenfolge mit 'getChartJson' und die anschließende Verwendung von JSONUtils ist nicht sehr elegant. Wenn Sie 'instance. @ com.example.client.GwtTest :: printChartData (Lcom/example/client/ChartData; I) (chartData, row) verwenden,' übergeben Sie 'ChartData' von einer JSNI-Methode an die Java-Methode und a ClassCastException wird ausgelöst, da JavaScriptObject nicht erweitert wird – Tobika

+0

Nein, ich erhalte diese Ausnahme überhaupt nicht. Beachten Sie, dass das Objekt aus Java-Code und nicht aus JavaScript-Code stammt. So kann ich es ohne Probleme durch den systemeigenen Code übergeben, ohne JavaScriptObject zu erweitern. Hast du versucht, den Code in Adams Antwort auszuführen? Es funktioniert gut und löst keine Ausnahmen aus. –

Verwandte Themen