GWTクライアントをChrome上でデバッグする

2018年10月6日

ここでは、GWTのクライアント側をChrome上でデバッグする方法について説明する。Eclipseを使用することを前提としている。

ちなみに、サーバ側はEclipseのデバッグモードでごく普通にデバッグができるのだが、クライアント側は、当然ながらEclipse側では対応できない。ブラウザの機能を使用してデバッグすることになる。

サンプルプログラム

サンプルとしては単純なものだ。GWT Eclipse Pluginを導入すると、GWTサンプルの作成機能がついてくるが、これを使用するだけである。

作成方法としては、最新Eclipse(2018/1 Oxygen)でGWTサンプルを動かすまでに記述してある。

これを動作させると、ブラウザ側では以下のような画面が表示されるだけだ。

デベロッパーツールを表示する

Chrome上で表示させたら、デベロッパーツールを開く。これは、Ctrl+Shift+Iを押すか、画面を右クリックして「検証」を選択する。

すると、こんな画面になる。

コンソール

まずはコンソールを見てみる。ここには、キャッチされていない例外が表示されるほか、GWTクライアントからのメッセージも表示される。

とは言っても、System.out.println(“”)では表示されない。コンソールに出力するには、GWT.logを使う必要があるのだ。試しに、ボタンをクリックしたら、「clicked!!!」と表示させるには、以下のようにする。

(sampleパッケージのSampleというクラスを作ったという前提で)sample.client.Sampleの以下の部分を変更する。

import com.google.gwt.core.client.*; // これが必要
....

    // Create a handler for the sendButton and nameField
    class MyHandler implements ClickHandler, KeyUpHandler {
      /**
       * Fired when the user clicks on the sendButton.
       */
      public void onClick(ClickEvent event) {
        GWT.log("clicked!!!"); // これを追加
        sendNameToServer();
      }


ブラウザをリロードして、Sendボタンをクリックしてみると、以下の表示になる。

ソースレベルデバッグ

次にソースレベルデバッグを行ってみる。意外なことなのだが、Chrome上ではクライアントがJavaScriptで動作しているにも関わらず、Javaのソースレベルデバッグができるのである。

以下のようにSourcesタブに移動し、左側のsample下を開いていき、Sample.javaを表示させる。右側にはJavaのソース・ファイルが表示される。先に、変更したように「GWT.log(“clicked!!!”)」のあることがわかる。

このGWT.logのところにブレークポイントを設定してみよう。行番号を右クリックし、Add breakpointを選択する。

背景が青色になり、この行にブレークポイントが設定されたことを示す。

この状態で、Sendボタンをクリックしてみると、以下のようにブレークポイントで停止する。

続行やステップ実行が、左上や下のボタンで選択できる。

このようにして、GWT.logによるトレース出力とソースレベルでのブレークポイントでの停止やステップ実行ができる。

例外発生時のスタックトレース

上記で一通りのデバッグはできるのだが、しかし、思いがけない例外発生時には少々苦労する。

例えば、Sendボタンをクリックしたときに、わざと例外を発生されるため、次のようにコードを変更してみる。この場合はNullPointerExceptionが発生する。

    Integer value = null;

    // Create a handler for the sendButton and nameField
    class MyHandler implements ClickHandler, KeyUpHandler {
      /**
       * Fired when the user clicks on the sendButton.
       */
      public void onClick(ClickEvent event) {
        GWT.log("value " + value.intValue());
        sendNameToServer();
      }

すると、コンソールには次のような表示がされる。

通常のJavaのスタックトレースとは、全く異なるスタックトレースなのである。そして、この例外はSample.javaで起こっているにも関わらず、そのことが全くわからない。

※ちなみに、クライアント側でNullPointerException等が発生すると、「com.google.gwt.event.shared.UmbrellaException」という表示がなされる。NullPointerExceptionという名前も、どこにも現れない。

Debugging in GWT 2.7 Super Dev Mode, stackTrace is missing?に議論がある。これを参考にして、onModuleLoad()を以下のようにしてみる。

import java.util.logging.*;

....
 private static Logger LOGGER = Logger.getLogger("TEST");
....

  // このメソッドを追加
  private void setUncaughtExceptionHandler() {
    GWT.setUncaughtExceptionHandler(new GWT.UncaughtExceptionHandler() {
      @Override
      public void onUncaughtException(Throwable e) {
        Throwable unwrapped = unwrap(e);
        LOGGER.log(Level.SEVERE, "onUncaughtException " + e.getMessage(), unwrapped);
      }

      public Throwable unwrap(Throwable e) {
        if (e instanceof UmbrellaException) {
          UmbrellaException ue = (UmbrellaException) e;
          if (ue.getCauses().size() == 1) {
            return unwrap(ue.getCauses().iterator().next());
          }
        }
        return e;
      }
    });
  }

  /**
   * This is the entry point method.
   */
  public void onModuleLoad() {

    this.setUncaughtExceptionHandler(); // onModuleLoad()の先頭に追加。

この状態で例外を発生させてみると、以下の表示になる。

先ほどとは異なり、Javaソース・ファイル名と行番号が表示されている。