改进 GWT

如果您有兴趣了解 Google Web Toolkit (GWT) 的内部机制,从源代码构建,或为项目贡献想法或修改,那么本文档适合您。

  1. 介绍
    1. 许可
    2. 为什么 GWT 是开源的?
    3. 设计公理
  2. GWT 社区
    1. 请友善
    2. 在哪里讨论 GWT
    3. 如何报告错误
  3. 使用代码
    1. 签出源代码
    2. 从源代码编译
    3. 测试
  4. 贡献代码
    1. 代码风格
    2. 贡献者许可协议
    3. 提交补丁
    4. GWT 提交者
  5. 为网页和文档贡献

介绍

从基础开始,为什么 GWT 存在呢?简而言之,GWT 的存在是为了让网络对用户来说更好。我们已经将一个更长的答案融入我们的使命声明中。

GWT 的使命是通过使开发人员能够使用现有的 Java 工具为任何现代浏览器构建无妥协的 AJAX 来彻底改善用户的网络体验。

我们花了很多时间在这句话上,并尽力赋予它意义。所以,如果您能容忍我们,让我们解释一下为什么我们的使命声明以这种方式制定。

彻底改善
GWT 的非常规前提(即编译为 JavaScript)奠定了我们对能够产生重大影响的方法持开放态度的基调。我们愿意投入额外的考虑和工作来找到“数量级更好”的解决方案,而不是“足够好”的解决方案。
网络体验
我们想要优化的体验是网络体验。网络与桌面应用程序拥有不同的 DNA,GWT 被设计为属于网络传统,而不是提供一种在浏览器中机械地克隆桌面习惯用法的方式。当然,有一些重叠。但当存在冲突时,我们优先考虑简单、核心的网络概念,如超链接、历史记录、URL 和书签。
对用户
指的是最终用户。我们高度重视能够为最终用户带来最大差异的功能。显然,我们也希望让开发人员的生活更轻松,但绝不能以牺牲用户体验为代价。一个经典的例子:同步 RPC 是一个坏主意,即使它对开发人员来说方便得多。
通过使开发人员能够
GWT 是关于使开发人员能够做出伟大的事情,而不是一定地用勺子喂他们或将他们束缚起来。GWT 努力做到易于使用而不牺牲效率。我们通常优先确保 GWT 的基本功能运行良好,而不是添加数十个特殊用途的小部件。提供一个坚实的平台,以便其他出色的库可以在 GWT 之上构建,这比试图在开箱即用时满足所有人的需求要好得多。
现有的 Java 工具
我们不是为了技术本身而努力构建技术!我们选择 Java 语言的主要原因是,已经有如此多的优秀工具,更不用说大量的书籍、文章、库和专业知识了。GWT 应该通过与这些工具集成来利用它们,而不是试图取代它们。
无妥协的 AJAX
我们希望获得出色的成果,“出色”的定义是它对最终用户的好处。有时,我们开发人员方便的操作与最有利于最终用户的操作之间存在冲突。当两者发生冲突时,最终用户体验几乎总是获胜。

我们绝对不认为在 GWT 中的开发是一种妥协形式。我们坚信 GWT 应该生成比您手动编写的代码更好的 JavaScript 代码,并且通常会选择避免为了方便而做出让步,如果这样做会损害生成的 AJAX 代码的性能。

GWT 不打算成为一个孤岛。与 JavaScript 的良好集成是必不可少的,积极使用每个浏览器的最佳功能也是必不可少的,即使这需要糟糕的特例编码(在这种情况下,我们将尝试将其隐藏在没有开销的库后面)。
任何现代浏览器
我们希望 GWT 尽可能地可移植,只要它不涉及以任何显著方式牺牲用户体验。

这就是 GWT 的全部意义所在。说出 GWT不是关于哪些类型的事情也很有用……

语言战争
为什么 GWT 支持 Java 编程语言而不是语言 X?简而言之,工具。有很多好的 Java 工具。这就是全部解释。并不是说我们不喜欢语言 X,或者认为 Java 编程语言在某种程度上优于其他语言。我们只是喜欢这些工具。
成为一个单体框架
我们不喜欢那些非此即彼的沉重的“应用程序框架”,就像您不喜欢一样。这就是我们设计 GWT 由独立有用的部分组成的原因。
隐藏浏览器编程模型
GWT 并非试图将浏览器从您身边抽象出来。GWT 也并非试图阻止您在需要时编写 JavaScript。GWT 只是为我们开发人员提供一些额外杠杆作用,以形式上提供生产力工具和能够在有用时创建更高级别的抽象。如果您是 JavaScript 大师,我们希望您能发现 GWT 是一个很好的方法,您可以将您最好的 JavaScript 作品打包起来,并使其易于重用。
诱饵和转换
希望现在这一点已经不言而喻。我们从一开始就说我们没有打算为 GWT 收费,但希望现在您知道我们说到做到。
将传统的桌面 UI 克隆到网络上
我们希望培养良好的 UI,这些 UI 可能与现有的桌面 UI 相同,也可能不同。我们试图对“仅仅因为”它们经常用于桌面应用程序而引入功能持谨慎态度。

许可

所有 GWT 源代码和预构建的二进制文件均在Apache 2.0 许可证下提供。

为什么 GWT 是开源的?

第一个好问题是,“为什么 GWT 最初不是开源的?”自从 GWT 于 2006 年 5 月在 JavaOne 上发布以来,我们一直努力将构建 AJAX 应用程序的门槛降至最低。我们当时还没有准备好立即开源所有内容,因为我们知道我们对主要的基础设施工作(如 Mac OS X 托管模式)有计划,并且我们真的希望鼓励每个人专注于产品的理念本身以及如何编写应用程序,而不是造成与 GWT 的开源性相关的干扰。

GWT 的发展速度远远超过我们的预期,很快就变得很明显,推进 GWT 的最明智方式是早点开源而不是晚点开源。虽然我们从未真正感到特别吝啬于将源代码封闭起来,但现在,所有针对 GWT Java 到 JavaScript 编译器、托管模式浏览器等的代码都可以尽收眼底。我们非常期待您对想法、错误报告和补丁的贡献。

设计公理

我们在 2006 年 2 月 17 日采纳了这些公理。

  • 用户体验至关重要
  • 简化 AJAX 开发
    • Java 调试不可协商
    • 开箱即用的关键功能:历史记录、RPC、本地化和单元测试
  • 大部件必须独立有用
    • 简单的浏览器抽象(即使用 DOM 而不使用小部件类)
    • 小部件类可用,但不是必需的(即使用 DOM 和/或 JSNI)
    • 应用程序管理可用,但不是必需的(例如,历史记录支持是可选的)
    • RPC 可用,但不是必需的
    • Java 到 JavaScript 编译器在没有其他用户库的情况下也很有用(这意味着 JSNI 和调试与 gwt-user 没有纠缠在一起)
  • 与现有网页互操作
    • 除了 RPC 之外,组件在没有 GWT 特定服务器的情况下运行
    • 从 JavaScript 脚本化,反之亦然
    • 使用 CSS 进行样式设置
  • 促进 AJAX 代码的重用
    • 通过自包含的 JAR 文件共享整个组件和应用程序
    • 能够从 Java 类发布类似 Google 地图的 JavaScript API
  • 积极优化性能
    • 不要在运行时做可以在编译时完成的事情
    • 阻止不可优化模式
  • 默认情况下保持安全
    • 不要自动公开服务

GWT 社区

GWT 社区主要通过邮件列表、问题跟踪器,以及在较小程度上,源代码控制存储库来维护。我们鼓励您积极参与讨论,您也可以通过遵循和推广此处列出的指南,帮助我们提高这些群体的效率。

请保持友好

对他人表示礼貌和尊重是 Google 文化的重要组成部分,我们强烈鼓励所有参与 GWT 开发的人加入我们,接受任何不逊的行为。当然,礼貌并不意味着不能对彼此进行建设性的争论,但它确实意味着我们应该在列举某个提议可能不是最佳选择的原因时,相互尊重。永远不要对任何真诚地试图为讨论做出贡献的人表现出敌意或轻视。

当然,Web 开发是一项严肃的工作,但它也充满了乐趣。让我们保持这种状态。让我们努力成为所有开源社区中最友好的社区之一。

在哪里讨论 GWT

与往常一样,在 官方 GWT (GWT) 开发者讨论组 中讨论使用 GWT。还有一个额外的组,供人们讨论本文档中的任何内容(例如,如何构建、如何提交补丁),称为 GWT 贡献者。您无需实际提交代码即可注册。您的参与本身就是宝贵的贡献。

如何报告错误

查看 问题跟踪

使用代码

如果您想直接接触 GWT 内部的代码,本节适合您。

签出源代码

如果您计划自己编译 GWT,签出 GWT 源代码最有帮助。预构建的 GWT 发行版已经包含所有 Java 源代码,因此您实际上无需从存储库签出它,只需调试它。只需调整您的 IDE 以从 GWT jar 中读取源代码即可。

GWT 托管在 gwt.googlesource.com 上,因此您可以使用 Git 客户端签出 GWT 的源代码,就像处理任何其他 Git 项目一样

git clone https://gwt.googlesource.com/gwt trunk

从源代码编译

除了几个本机库之外,所有内容都是 Java 源代码,可以在任何支持的平台上使用包含的 GWT Ant 构建文件进行构建。目前,您只能在 Linux 上构建本机代码二进制文件,而且即使这样,也需要付出一些努力,目前超出了本文档的范围。为了简化操作,我们已经签入了预构建的本机二进制文件。(是的,我们知道这很不寻常。但是源代码和 makefile 都在那里……只是记录所有这些内容并使其以跨平台方式构建很麻烦。)

  1. 安装 Apache Ant 1.7.0 或更高版本。我们假设 ant 命令位于您的路径中。
  2. 签出 GWT 先决条件工具和第三方库:~/gwt$ git clone https://github.com/gwtproject/tools.git tools
  3. 签出 GWT 源代码:~/gwt$ git clone https://gwt.googlesource.com/gwt trunk
  4. 可选地,设置一个环境变量,其中包含您刚刚签出工具的目录的完整路径。(如果 tools 目录与 GWT 源代码目录是兄弟目录,则无需指定 GWT_TOOLS。)在本例中,您从 ~/gwt 目录执行了上一个命令,因此您将键入:~/gwt$ export GWT_TOOLS=~/gwt/tools
  5. 切换到您签出 GWT 源代码的目录。假设您将其签出到 ~/gwt/trunk 中。确保您位于该目录中……~/gwt$ cd ~/gwt/trunk,然后只需调用 Ant ant
  6. GWT 构建会在源代码根目录的 build/dist 子目录中创建每个二进制发行版。在本例中,发行版将位于 ~/gwt/trunk/build 中。

测试

测试对于维护 GWT 的质量非常重要。单元测试 应为任何新代码编写,并且应在提交以供审核之前验证更改不会破坏现有测试。要执行测试,只需运行 ant test 并验证没有错误。

Ant JUnit 问题

ant.apache.org 上详细说明了 ant 无法找到 JUnit 类的问题。简单的解决方法是:

  • 从 ant lib 目录(例如,/usr/share/ant/lib/)中删除 ant-junit.jar
  • 将 junit.jar 复制到您的 ant lib 目录

贡献代码

现在 GWT 已经开源,我们很高兴我们的用户现在可以更轻松地修复错误和创建新功能,我们希望从社区获得很棒的补丁。但是,在您启动您最喜欢的 IDE 并开始疯狂地敲击新功能之前,请花点时间阅读本节内容并了解流程。虽然看起来很严格,但我们希望保持代码库的高质量标准。

代码风格

为了使源代码保持一致、可读、可差异化和易于合并,我们使用相当严格的编码风格,所有补丁都应符合此处概述的风格。为了使事情尽可能简单,许多这些风格规则将由 GWT 构建自动验证;构建系统无法捕获的风格问题应在代码审查期间解决。

为了更容易正确格式化您的 GWT 代码,请为 Eclipse 使用 GWT 风格格式化程序(首选项 | Java > 代码风格 > 格式化程序 | 导入…)。

总的来说,GWT 风格基于 标准 Java 约定,除了下面列出的差异。

为了记录,我们知道编码风格通常是一个有争议的话题。我们承认那里存在很多很棒的方法。我们只是试图选择一个至少与 Oracle 的 Java 编码约定在某种程度上保持一致的方法,对其进行良好编码,并坚持下去。

注释和 Javadoc

每个文件都应在顶部包含 Apache 许可证头,并在其前面加上版权声明。包语句和导入语句应紧随其后,每个块之间用空行隔开。接下来是类或接口声明。在 Javadoc 注释中,描述类或接口的作用。

/*
 * Copyright 2006 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.foo;

import com.google.bar.Blah;
import com.google.bar.Yada;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Does X and Y and provides an abstraction for Z.
 */
public class Foo {
  ...
}

类结构和成员排序

Java 类型应具有以下成员顺序

  1. 嵌套类型(混合内部类和静态类是可以的)
  2. 静态字段
  3. 静态初始化器
  4. 静态方法
  5. 实例字段
  6. 实例初始化器
  7. 构造函数
  8. 实例方法

属于同一类别的成员(例如,静态方法)也应根据可见性按此顺序排序

  1. public
  2. protected
  3. default
  4. private

所有方法应按字母顺序排序。字段的排序是可选的,但建议这样做。例如,以下类摘录排序正确

public abstract class Foo {
  // Type declarations.
  public class FooBaz {
  }
 
  private class FooBar {
  }

  // Static field declarations.
  // Remember, fields do NOT need to be sorted.
  static String B;
  static String A;

  // Static initializer declarations.
  static {
  }

  // Static methods declarations.
  // Remember, methods do need to be sorted.
  static void aStatic() {
  }

  static void bStatic() {
  }

  // Instance field declaration.
  String bField;
  String aField;

  // Instance Initializer declarations.
  {
  }

  // Constructors declaration.
  public Foo() {
  }

  protected Foo(String s) {
  }

  Foo(int i) {
  }

  private Foo(boolean b) {
  }

  // Instance method declaration.
  public void b() {
  }

  public void c() {
  }

  protected void a() {
  }

  protected void d() {
  }

  protected void e() {
  }

  protected void f() {
  }

  String h() {
  }

  // The "abstract" keyword does not modify the position of the method.
  abstract String i();

  void j() {
  }

  private void g() {
  }
}

缩进

我们对块使用 2 个空格的缩进。任何地方都不要使用制表符。

我们在换行后使用 4 个空格的缩进,包括函数调用和赋值。例如,这是正确的(换行后 4 个空格)

Instrument i =
    new Instrument();

这不是正确的(换行后 2 个空格)

Instrument i =
  new Instrument();

导入

导入语句的排序是

  • GWT 导入
  • 来自第三方的导入(com、junit、net、org)
  • java 和 javax

为了完全匹配 IDE 设置,导入应为

  • 每个分组内按字母顺序排列。大写字母被认为在小写字母之前(例如,Z 在 a 之前)。
  • 每个主要分组(google、com、junit、net、org、java、javax)之间应有空行。

行长和换行

代码中的每一行文本长度不应超过 100 个字符。使用换行符来换行(Unix 风格)。有一些例外

  • JSNI 方法 中引用的 Java 标识符可能非常长,如果跨行拆分,则无法解析。
  • 例外:如果注释行包含一个示例命令或一个长度超过 100 个字符的字面 URL,则该行可能长于 100 个字符,以方便剪切和粘贴。
  • 例外:导入行可以超出限制,因为人类很少看到它们。这也简化了工具编写。

名称中的缩略语

将缩略语和缩写视为单词。名称更易读

XmlHttpRequest XMLHTTPRequest
getCustomerId getCustomerID

此风格规则也适用于缩略语或缩写是整个名称的情况

class Html class HTML
String url; String URL;
long id; long ID;

请注意,这是对早期错误决策的逆转,GWT 中的许多代码都违反了此规则。虽然不值得为了风格问题而破坏现有 API,但所有新代码都应将缩略语视为单词。

有关此风格规则的更多理由,请参阅 Effective Java 第 56 项(第一版中的第 38 项)和 Java Puzzlers 第 68 号。

参数化类型名称

参数化类型名称应为一个大写字母。但是,如果可读性要求更长的名称(尤其是由于具有多个参数),则名称应大写并带有后缀“T”。简而言之,首选 <T><K, V>,如果必要,则退化为 <KeyT, ValueT>

可以容忍
Foo<T> Foo<FooClientType>
Bar<K, V> Bar<KeyType, ValueType>
Baz<V, E, X> Baz<EventType, ErrorType, ExpressionType> Baz<EventT, ErrorT, ExpressionT>

单元测试

单元测试非常重要,我们强烈鼓励包含它们的提交,为新功能添加新的单元测试,或为错误修复更新现有的单元测试。

Java 类的测试应放在 test 下的并行源代码树中,测试类名称应以 Test 作为后缀。例如

src/com/google/gwt/core/client/EntryPoint.java
test/com/google/gwt/core/client/EntryPointTest.java

使用并行测试树有两个主要优点

  • 您可以进行包范围测试(与 tests 子包相比)。
  • 生产代码和测试代码之间有明确的区分,使打包更容易。这减少了构建中断的数量以及花费在更新构建文件上的时间。

请注意,使用 JUnit 测试与 ant 存在问题——上面描述了 解决方法

提交补丁

请提交代码。欢迎对所有 GWT 子项目 的贡献。以下是您需要执行的操作

  1. 决定要提交的代码。一次提交应该是对存储库问题跟踪器中一个问题的更改集。对于 GWT SDK,您可以查看 其开放问题 的列表。请不要在一个提交中混合多个逻辑更改,因为这会使历史记录难以跟踪。如果您想进行没有对应问题跟踪器问题的更改,请创建一个。
  2. 此外,请与问题中列出的团队成员协调。这可以确保工作不会重复,并且及早沟通您的计划通常会导致更好的补丁。
  3. 对适当的存储库进行分支。
  4. 实施您的更改,确保您的代码符合 GWT 源代码样式
  5. 确保您的代码有单元测试。
  6. 将您的更改推送到分叉的存储库。
  7. 创建拉取请求,按照拉取请求模板中的建议进行操作。

代码审查

代码审查是开发过程中的重要组成部分。欢迎任何人士对任何 开放拉取请求 提交代码审查。与 GWT维护人员完成的最终审查一起,社区的代码审查对代码质量有积极影响。

GWT 提交者

目前,GWT 工程团队的现有成员是唯一的提交者。在吃自己狗粮的伟大传统中,我们将要求每个新的 GWT 工程团队成员按照本文档中的程序,编写始终如一的优秀代码,并反复证明他或她真正理解了 GWT 的精髓,才能获得成为提交者的资格。

为网页和文档做贡献

此网页和它所托管的文档完全用 Markdown 编写。如果您发现错误,想要改进,编写文章或对网页做任何操作,请随时这样做。

工作原理如下

所有代码都存储在 GitHub 上,可以通过单击“在 GitHub 上编辑我”按钮直接在网上进行编辑。这是进行更改的最简单方法,但如果您打算对网站进行更大的更改,并希望先在本地测试这些更改,则可以克隆存储库

git clone https://github.com/gwtproject/gwt-site

源代码位于 src/main/markdown 中。在 README 中可以找到在本地测试更改的说明。

如果您认为您的更改已准备好发布到 gwtproject.org 上,您可以通过拉取请求将更改发送给我们,拉取请求的目标是 https://github.com/gwtproject/gwt-site

如果您希望为网站上使用的 GWT 代码(以改进导航)做出贡献,那么您应该

git clone https://gwt.googlesource.com/gwt-site-webapp

全局 .gitignore

由于我们的 .gitignore 文件不包含 IDE 或特定于操作系统的 .gitignore 条目,因此您应该设置您的全局 .gitignore。

这里 是设置全局 .gitignore 的方法。

这里 您可以找到一个 IDE 特定的全局 .gitignore 文件列表。