Java GWT是否在编译期间删除未使用的类?

Java GWT是否在编译期间删除未使用的类?,java,gwt,gwt-compiler,Java,Gwt,Gwt Compiler,假设我有一个大致如下的项目结构: {module-package}.webapp module.gwt.xml {module-package}.webapp.client Client.java UsedByClient.java NotUsedByClient.java 并且module.gwt.xml文件具有: <source path='client'/> <entry-point class='{module-package}.w

假设我有一个大致如下的项目结构:

{module-package}.webapp  
    module.gwt.xml
{module-package}.webapp.client
    Client.java
    UsedByClient.java
    NotUsedByClient.java
并且
module.gwt.xml
文件具有:

<source path='client'/>
<entry-point class='{module-package}.webapp.client.Client'/>

当我使用GWT编译这个项目时,有多少Java代码将被编译成Javascript

  • 即使入口点没有引用,
    NotUsedByClient.java
    也包括在内吗
  • UsedByClient.java
    是否全部或部分包含在内?例如,如果它有方法
    m()
    ,而
    客户端未调用该方法,是否编译
    m

其动机是,不幸的是,我使用的是一个遗留代码库,在同一个包中,服务器端代码与客户端代码共存,要将它们分开需要做一些工作。客户端不使用服务器端代码,但我担心GWT可能会将其编译为Javascript,有人可能会注意到它并尝试对其进行反向工程。

我不知何故偶然发现一位GWT工程师对编译器进行了“深入”的视频演示,其中有一个解释:

要点:

  • 其中一个编译器优化称为
    Pruner
    ,它将“从入口点遍历所有可访问的代码,删除所有其他内容(使用ControlFlowAnalyzer)”
  • 这实际上是一个重要的优化,因为如果没有它,所有GWT应用程序都需要完整地包含
    GWT user.jar
    ,这将大大增加应用程序的大小

因此,似乎GWT编译器确实删除了未使用的代码。

我不知何故偶然发现了一个GWT工程师在编译器上的“深入”视频演示,其中有一个解释:

要点:

  • 其中一个编译器优化称为
    Pruner
    ,它将“从入口点遍历所有可访问的代码,删除所有其他内容(使用ControlFlowAnalyzer)”
  • 这实际上是一个重要的优化,因为如果没有它,所有GWT应用程序都需要完整地包含
    GWT user.jar
    ,这将大大增加应用程序的大小

因此,GWT编译器似乎确实删除了未使用的代码。

以上所有情况以及更多情况都会发生:

  • 未引用的类将被删除
  • 将删除未引用的方法和字段
  • 常数可以是内联的
  • 对常数的各种操作(如!、=、+、&&等)可以简化(基于某些字段始终为null或true等)
  • 未重写的方法可能成为最终方法
  • …在某些情况下,最终方法可能是静态的(导致更小的调用站点,并且在该方法中没有“this”引用)
  • 小的、经常被称为静态的方法可能是内联的
这个过程会重复,我跳过了更多的优化,以进一步帮助删除大小代码。最后,所有类、方法、字段和局部变量都以一种进一步减小输出大小的方式重命名,包括对输出中的方法进行重新排序,以便它们按长度排序,从而使gzip在发送到客户端的过程中更有效地压缩内容


因此,虽然代码的某些方面可以进行反向工程(就像任何机器代码都可以进行反向工程一样),但没有引用的代码将不可用,甚至可能不可读的代码。

以上所有以及更多情况都会发生:

  • 未引用的类将被删除
  • 将删除未引用的方法和字段
  • 常数可以是内联的
  • 对常数的各种操作(如!、=、+、&&等)可以简化(基于某些字段始终为null或true等)
  • 未重写的方法可能成为最终方法
  • …在某些情况下,最终方法可能是静态的(导致更小的调用站点,并且在该方法中没有“this”引用)
  • 小的、经常被称为静态的方法可能是内联的
这个过程会重复,我跳过了更多的优化,以进一步帮助删除大小代码。最后,所有类、方法、字段和局部变量都以一种进一步减小输出大小的方式重命名,包括对输出中的方法进行重新排序,以便它们按长度排序,从而使gzip在发送到客户端的过程中更有效地压缩内容


因此,虽然您的代码的某些方面可以进行反向工程(就像任何机器代码都可以进行反向工程一样),但没有引用的代码将不可用,甚至可能不可读的代码。

谢谢Colin,有没有办法查看GWT在最终编译中保留的类型和成员?我很确定服务器端代码没有被引用,但是如果我能确认的话,那就太好了!查看SOYC功能:您的编译故事。这将告诉您每个包含的方法最终包含了多少字节,以及为什么它仍然包含在输出中。也就是说,避免服务器端代码的最佳方法是不将其包含在相同的指定包中(强制编译器根本不知道它存在),或者使用
@GwtIncompatible
对其进行注释。此外,如果您有无法翻译的代码,这可能会大大降低开发模式的速度,因为每次刷新都会重试编译。谢谢Colin,有没有办法查看GWT在最终编译中保留了哪些类型和成员?我很确定服务器端代码没有被引用,但是如果我能确认的话,那就太好了!查看SOYC功能:您的编译故事。这将告诉您每个包含的方法最终包含了多少字节,以及为什么它仍然包含在输出中。也就是说,避免服务器端代码的最佳方法是不将其包含在相同的指定包中(强制编译器根本不知道它存在),或者使用
@GwtIncompatible
对其进行注释。额外的