常见问题解答 - 故障排除

  1. 编译器
    1. AssertionError: Element may only be set once
    2. 无法解析导入
    3. InternalError: 无法连接到 X11 窗口
    4. OutOfMemoryError: Java 堆空间
    5. 未定义的 DISPLAY 错误
  2. RPC
    1. 找不到资源
    2. ServletException: 内容类型必须为“text/plain”
  3. 历史记录
    1. Safari 2.0 中 GWT 历史记录功能已损坏
  4. 开发模式
    1. Failed to getGlobalExecState
    2. 找不到资源
    3. RuntimeException: 检测到安装问题,请重新安装 GWT
    4. 无法找到类型“com.foo.client.MyApp”
    5. 无效的内存访问位置 00000000 rip=01160767,或类似错误
    6. 页面导航已取消
    7. java.security.AccessControlException: 拒绝访问
  5. 图像包
    1. ImageBundle 图像未在 Internet Explorer 中显示
  6. 国际化
    1. 国际字符无法正确显示
  7. JUnit 测试
    1. JUnit 测试在 Mac 上失败

编译器

AssertionError: Element may only be set once

升级到 GWT 1.5 后,您可能会看到此异常

[ERROR] Uncaught exception escaped
java.lang.AssertionError: Element may only be set once

该消息表明某些小部件正在调用 setElement() 方法多次。尝试在小部件已初始化后在其上调用 setElement() 方法是非法的。

此断言在 GWT 1.4 中被放宽,但在 GWT 1.5 中恢复。将小部件的元素设置为任意的新元素将破坏大多数小部件所做出的各种假设;也就是说,它使小部件无法对底层元素的稳定性做出任何假设。如果元素可以任意更改,则各种事情都可能出错。

多次调用 setElement() 方法几乎总是无意中发生的(例如,扩展在构造函数中调用 setElement() 的小部件,然后从子类构造函数中再次调用它)。因此,该消息通常会揭示一个实际上正在被忽视的问题。

解决方法

与其从头开始编写新的 Widget,不如使用以下快捷方式从现有 DOM 元素构建 Widget。

首先,子类化 AbsolutePanel。然后,使用受保护的 AbsolutePanel(Element) 构造函数来更改底层元素。

无法解析导入

虽然您已成功在 IDE 中编译了项目的类文件,但在使用 GWT Google API 提供的 API 之一在新的项目上首次调用 GWT 编译器时,您遇到了类似以下错误

$ ./gearsTest-compile
Analyzing source in module 'com.example.gearsTest'
   [ERROR] Errors in '/Users/zundel/Documents/workspace2/galgwt-issue3/src/com/example/client/gearsTest.java'
      [ERROR] Line 9:  The import com.google.gwt.gears cannot be resolved
      [ERROR] Line 26:  Gears cannot be resolved

问题是,模块源路径上没有包 com.google.gwt.gears

解决方法

这可以通过以下两种方法之一更新模块 XML 文件(.gwt.xml)来解决。

  • 添加一个 <source> 标签,将该包添加到模块源路径。
  • 如果您的第三方库提供了一个,请添加一个 <inherits> 标签。

对于在 GWT Google API 中使用 Gears 包,适当的行是

<inherits name='com.google.gwt.gears.Gears'>

InternalError: 无法连接到 X11 窗口

GWT 编译器在 Linux 中是否需要 X11 窗口?不,GWT 编译器可以在“无头”模式下运行(即,访问 AWT 库而无需加载图形环境窗口)。

您可能会在最初遇到此问题,因为 ImageBundle 功能会触发 GWT 编译器在编译时连接到 X11 图形环境窗口。如果您没有设置 DISPLAY 环境变量,它将发出以下错误消息

java.lang.InternalError: Can't connect to X11 window server using ':0.0' as the value of the DISPLAY variable.

即使您在客户端代码中没有显式使用 ImageBundle,您仍然可能会遇到此错误消息,因为 GWT 在内部使用 ImageBundle 为小部件(如树小部件)进一步优化图像的 HTTP 往返次数,并加快 Web 应用程序的速度。这意味着,如果您使用任何在底层实现中使用 ImageBundle 的小部件,GWT 编译器将搜索 DISPLAY 环境变量并尝试连接到 X11 图形窗口。

解决方法

为避免此错误消息,请使用无头 AWT 选项运行 GWT 编译器。

-Djava.awt.headless=true
示例

Ant. 向 GWT 编译构建目标添加元素:<jvmarg value="-Djava.awt.headless=true"/>

命令行。 传递参数:-Djava.awt.headless=true

Eclipse. 在您的运行配置窗口中,选择参数选项卡,并在 VM 参数部分输入:-Djava.awt.headless=true

如果您使用自定义构建过程,您也可以在那里设置 AWT 无头选项。

OutOfMemoryError: Java 堆空间

在 GWT 1.5 或更高版本中编译项目时,您可能会遇到内存不足问题。

Compiling permutations
   Analyzing permutation #1
      [ERROR] An internal compiler exception occurred
com.google.gwt.dev.jjs.InternalCompilerException: Unexpected error during visit.
        at ...
Caused by: java.lang.OutOfMemoryError: Java heap space

GWT 1.5 提供了一个更大的库(在 gwt-user.jar 中),该库必须在编译期间进行分析,并且许多编译器优化需要更多的内存和处理能力。因此,GWT 编译器和开发模式在内部使用更多内存。这会导致编译器超过默认 JVM 堆大小。

某些项目需要增加 JVM 最大内存才能成功编译;其他项目可以通过增加限制来缩短编译时间。

解决方法

使用 Java VM 参数 -Xmx 以及以兆字节为单位指定内存量来增加 Java 堆限制。例如,java -Xmx512M -cp [args...] 将将堆最大值设置为 512 兆字节。

未定义的 DISPLAY 错误

在控制台或无头环境中编译或测试时,您可能会收到未定义的 DISPLAY 错误。

在 UNIX 环境中,GWT 测试(在某些情况下还有 GWT 编译器)需要 X 显示器。如果连续构建是从 cron 作业运行的,则运行的进程可能无法访问“真实”显示器。

解决方法

您可以通过使用名为 Xvfb 的程序来提供虚拟显示器。(Xvfb 代表 X11 虚拟帧缓冲区。)

要提供虚拟显示器

  • 安装 Xvfb。
  • 启动 Xvfb 服务器并设置环境变量 DISPLAY 以使用它。
export DISPLAY=:2
  • 在显示器 :2 上运行 Xvfb,没有访问控制

此命令将仅在 Xvfb 未启动时才启动它。任何 GWT 编译和测试都应将 DISPLAY 设置为 :2 以使用虚拟帧缓冲区。

ps -ef | grep Xvfb | grep -v grep >> /dev/null || Xvfb :2 -ac &

RPC

找不到资源

在开发模式下测试新的 RPC 接口时,收到“找不到资源”错误。

The development shell servlet received a request for 'rpcs/myService' in module 'com.example.RPCExample' 
   Resource not found: rpcs/myService

servlet 引擎找不到 RPC 方法的服务器端定义。

故障排除清单

  • 服务器端代码是否已定义,并且位于适当的目录中?

按照惯例,服务位于 标准项目结构 中的 server 目录中。

  • 模块 XML 文件 (_myApp_.gwt.xml) 中是否列出了服务器端代码路径?*
<!-- Example servlet loaded into development mode web server       -->
<servlet path="/myService" class="com.example.server.MyServiceImpl" />
  • 您是否编译了服务器端代码?

webAppCreator 工具 创建的 ant 构建脚本默认情况下应将所有源文件编译成字节码,但最好还是仔细检查一下。

  • 编译后的服务器类是否可供开发模式使用?

如果您的服务器类位于单独的 jar 文件或目录树中,则在启动开发模式 shell 时,您可能需要修改类路径(例如,通过编辑 ant 构建文件)。

ServletException: 内容类型必须为“text/plain”

如果您使用的是 GWT RPC,并且从 GWT 1.4 升级到 GWT 1.5,您可能会看到类似以下的堆栈跟踪

javax.servlet.ServletException: Content-Type must be 'text/plain' with 'charset=utf-8' (or unspecified charset)
        at com.google.gwt.user.server.rpc.RemoteServiceServlet.readPayloadAsUtf8(RemoteServiceServlet.java: 119)
        at com.google.gwt.user.server.rpc.RemoteServiceServlet.doPost(RemoteServiceServlet.java: 178)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java: 738)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java: 831)
        ...

在 GWT 1.5 中,RPC 内容类型从“text/plain”切换到“text/x-gwt-rpc”。

如果您收到此异常,则您的服务器仍在使用 GWT 1.4 gwt-servlet.jar。

解决方法

更新您的服务器以使用 GWT 1.5 gwt-servlet.jar。

历史记录

Safari 2.0 中 GWT 历史记录功能已损坏

  • 问:GWT 历史记录功能很棒,但它在 Safari 2.0 上一直让我抓狂。GWT 和 Safari 2.0 之间有什么历史渊源?
  • 答:不幸的是,GWT 历史记录系统与 Safari 2.0 不兼容。

Safari 2 中存在一些奇怪的错误,这些错误尤其难以解决,使得很难使用 GWT 在 IE 和 Firefox 中用于历史记录支持的相同技巧。确实存在一些凌乱的解决方案,但这些解决方案在许多重要的边缘情况下都会失败,而且不太可能成为良好的长期解决方案。

当前的实现为 Safari 2 提供了回退功能,因此库可以正常工作,但不会生成任何历史记录条目。

虽然当前的 GWT 历史记录支持解决方案在 Safari 3 beta 版上并不完全有效,但它已在最新的 nightly WebKit 构建中经过测试,并且效果良好。

所以,请戴好帽子!Safari 3 正式发布后,Safari 的历史记录支持将正常工作。

开发模式

无法获取全局执行状态

在 Mac 上启动开发模式时,会收到错误“无法获取全局执行状态”。

此问题与 Google Gears 启用程序有关。

解决方法

检查 /Library/InputManagers 文件夹。如果存在名为 GearsEnabler.bundle 的文件,删除它应该可以解决此问题。

RuntimeException: 检测到安装问题,请重新安装 GWT

启动 GWT 编译器或开发模式时,您可能会看到以下异常。

Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.RuntimeException: Installation problem detected, please reinstall GWT
    at com.google.gwt.util.tools.Utility.computeInstallationPath(Utility.java:322)
    at com.google.gwt.util.tools.Utility.getInstallPath(Utility.java:223)
    at com.google.gwt.util.tools.ToolBase.<clinit>(ToolBase.java:55)
Caused by: java.io.IOException: Cannot determine installation directory; apparently not running from a jar
    at com.google.gwt.util.tools.Utility.computeInstallationPath(Utility.java:307)
  ...

此消息表示无法找到 GWT 的运行时二进制安装程序。通常,运行时二进制安装程序路径应与 gwt-dev-<platform>.jar 文件所在的目录相同。

GWT 安装路径嵌入到脚本中(从 applicationCreator 和 projectCreator 创建),作为指定给 gwt-dev-<platform>.jar 文件的路径。如果您查看此目录,它应该不仅包含 gwt-user.jar 和 gwt-dev-<platform>.jar 文件,还包含特定平台的共享库文件,例如 libgwt_ll.so 或 libgwt_ll.jnilib。

解决方法

确保指定给 gwt-dev-<platform>.jar 文件的 Java 类路径仍然包含共享库。如果不是,您可能需要重新下载并解压缩 GWT 分发版,确保您的下载完整。

贡献者注意事项

如果您是贡献者并通过 svn 签出了源代码,那么如果您从源代码运行 GWT,您可能会遇到此问题。

确保您拥有

  • 解压缩的二进制分发版或已编译的分发版
  • 在启动配置中配置了系统属性 gwt.devjar,如 eclipse/README.txt 文件中所述。

无法找到类型“com.foo.client.MyApp”

在开发模式下运行时,会收到错误:无法找到类型“com.foo.client.MyApp”。

Starting HTTP on port 8888
Finding entry point classes
  Unable to find type 'com.google.gwt.sample.stockwatcher.client.StockWatcher'
    Hint: Check that the type name 'com.google.gwt.sample.stockwatcher.client.StockWatcher' is really what you meant
    Hint: Check that your classpath includes all required source roots
Failure to load module 'com.google.gwt.sample.stockwatcher.StockWatcher'

此问题最常出现在手动创建启动配置时。Eclipse 的 Google 插件 会自动将源根添加到类路径中。

在 GWT 中手动创建启动配置时,最常见的问题之一是省略应用程序源代码路径,使其不在 Java 类路径中。GWT 编译器开发模式 shell 依赖于模块源代码来构建您的应用程序,并且两者都使用 Java 类路径来查找 .java 源文件。

解决方法

如果您使用的是 Eclipse,请打开启动配置,导航到类路径选项卡,并使用高级按钮将 src 文件夹添加到类路径中。

如果您是从命令行启动,请将 src 文件夹添加到 Java 命令的 -cp 参数后的路径列表中。

无效的内存访问位置 00000000 rip=01160767,或类似错误

如果您使用的是 GWT 2.0 之前的版本,以及 Mac 平台上的 Java 6,则在尝试运行托管模式时,您可能会看到此错误消息。此问题在 GWT 2.0 的 开发模式 中已不再存在。

出现这种情况的原因是,托管模式使用 32 位 SWT 绑定,这些绑定与 Mac 平台上的 Carbon 紧密耦合。不幸的是,Mac 上的 Java 6 使用的是 64 位 JVM,而 Carbon 目前不支持 64 位。这意味着要在 Mac 上使用 GWT 托管模式,您需要坚持使用 Java 5 来获得 32 位 JVM 支持。

解决方法

对于任何其他平台,使用 64 位 JVM 将在尝试启动托管模式时导致类似的错误消息。幸运的是,Java 6 在这些平台上提供了 32 位版本,因此您可以继续使用 64 位 JVM 进行 GWT 编译,并使用 32 位 JVM 进行托管模式。

页面导航已取消

一些开发人员在 Windows Vista 上运行 GWT 1.6 托管模式时遇到了此问题。出现这种情况的原因是,对于在 Windows Vista 上运行的许多应用程序和服务,IPv6 约定被使用,包括为 localhost 定义的端点 IP 地址。

解决方法

如果您查看 C:\Windows\System32\drivers\etc\hosts 文件,您会注意到 hosts 文件中定义的端点 ::1 localhost。要使 localhost 在 IPv4 案例中工作(在托管模式中使用),只需将此行更改为 127.0.0.1 localhost

java.security.AccessControlException: 拒绝访问

如果您使用 Eclipse 的 Google 插件 创建了应用程序,您可能遇到过以下堆栈跟踪

WARNING: Nested in java.lang.ExceptionInInitializerError:
java.security.AccessControlException: access denied
(java.lang.RuntimePermission modifyThreadGroup)
       at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323)
       at java.security.AccessController.checkPermission(AccessController.java:546)
       at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
       at com.google.appengine.tools.development.DevAppServerFactory

如果您在创建项目时错误地为您的项目启用了 Google App Engine 功能,或者是在开发过程中启用了该功能,并且您的 GWT 应用程序 war 文件夹中包含了与 Java App Engine 沙箱 冲突的服务器端库或类,则会出现此问题。

解决方法

如果您不打算在项目中使用 Google App Engine,只需按照以下步骤从项目中删除 Google App Engine 功能

  1. 在 Eclipse 中,右键单击您的项目并选择**Google > App Engine 设置…**
  2. 在 App Engine 属性菜单中,取消选中**使用 Google App Engine** 复选框。
  3. 单击**确定**。

如果您打算使用 Google App Engine,则需要从项目中删除任何违反 App Engine 沙箱安全限制的服务器端库的使用。有关 App Engine 沙箱中可用支持的更多信息,请查看 App Engine 文档。

图像捆绑包

Internet Explorer 中未显示 ImageBundle 图像

ImageBundle 图像在 Firefox、Opera 和 Safari 中显示,但在 Internet Explorer 中未显示。

安全性

首先要验证的是,您的 Web 应用程序是否使用 HTTPS,或者生成图像捆绑包文件中包含的任何图像是否受安全约束。

如果是这种情况,您可能遇到一个问题,根源在于您的 Web 服务器设置了一些响应标头(例如 Pragma: No-cache, Expires: Thu, 1 Jan 1970 00:00:00,…)并且 Internet Explorer 在使用 HTTPS 协议时会尊重这些标头。

解决方法

您可以在 API 参考中阅读有关此安全问题的更多详细信息以及如何解决此问题,图像捆绑包和 HTTPS 协议

大小

另一方面,如果您没有使用 HTTPS,但仍然遇到此问题,请查看您的图像捆绑包文件的大小。

许多开发人员遇到了 Internet Explorer 在从较大的图像捆绑包中提取图像时消耗大量内存的问题,随后无法正确显示图像。

解决方法

您可能需要考虑将一个大型图像捆绑包拆分成几个较小的捆绑包。这种方法对大多数遇到此问题的开发人员都有效。

国际化

国际字符无法正确显示

如果您将国际字符嵌入到 Java 源文件中,那么在运行应用程序并在 Web 浏览器中查看时,这些字符可能无法正确显示。

Java 要求包含国际字符的源代码文件使用 UTF-8 编码。通常,用于生成文件的编辑器(例如 IDE)未配置为将文件保存为 UTF-8。因此,您的源文件没有正确地使用 UTF-8 编码。

故障排除清单

  • 检查您的编辑器,看看它是否能够将文件保存为 UTF-8 以及它是否当前配置为这样做。
  • 如果您已将国际字符直接嵌入到 Java 源文件中,请检查它们是否以 UTF-8 格式保存。
  • 检查任何关联的 Java 属性文件(或您存储翻译的其他文件),看看它们是否以 UTF-8 格式保存。
  • 检查 HTML 主页。如果您的网页内容包含本地化数据,请通过将以下标记添加到 <head> 元素中将其编码为 UTF-8。
<meta http-equiv="content-type" content="text/html;charset=utf-8" />`

JUnit 测试

JUnit 测试在 Mac 上失败

一些 JUnit 测试在 Mac 平台上失败。

当 Safari/Webkit Web 浏览器以无头模式运行时,它能够优化一些渲染操作。这些优化的结果之一是,在运行单元测试时,某些元素的位置或大小可能与运行实际应用程序时不同。常见症状是看到小部件的位置或大小设置为 (0,0)

解决方法

要解决此问题,请在 -Dgwt.args= 系统属性设置中传递 -notHeadless 参数。注意:在使用 ant 构建时,从 GWT 1.5 版本开始,默认情况下启用此参数。

当为运行单元测试指定 -notHeadless 时,日志窗口和托管模式浏览器将在测试运行时弹出到屏幕上。关闭或操作这些窗口中的元素可能会导致单元测试失败。