idea2019.3使用ecj編譯處理bom字符

idea調用ecj方法

因爲工作項目中同事用的編譯器是eclipse,想移植用idea,發現項目中很多文件包含有UTF8格式的BOM字符,如果更改文件格式也可以解決,想到idea調用外部ecj.jar來進行編譯,如果能在編譯讀取文件時判斷一下讀取的字符,去掉包含的特殊bom字符,就能從根源上解決這個問題了,參照網上之前的修改ecj.jar裏Utils類裏的一個讀取方法,試了一下沒有效果,用舊版17年的idea是可以使用的,可能是idea後面更改了調用的方式,2019.3版本聽說性能有很大提升,所以決定查找一下idea是如何調用ecj的方法來進行編譯的。


  • 查看github上,有idea的社區版源碼,先clone下來;

  • 有4個多G的文件,克隆下來之後,導入idea,直接open根目錄;堆內存加到1.5G,索引20分鐘超時,生成了部分索引可以用來查找

  • 有很多報錯,不過沒事,目的不是啓動它,主要找編譯時調用ecj的方法

  • 查找關鍵字終於在JavaBuilder找到了構建項目的方法

    public ExitCode build(@NotNull CompileContext context,
                            @NotNull ModuleChunk chunk,
                            @NotNull DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder,
                            @NotNull OutputConsumer outputConsumer) throws ProjectBuildException, IOException {
        JavaCompilingTool compilingTool = COMPILING_TOOL.get(context);
        if (!IS_ENABLED.get(context, Boolean.TRUE) || compilingTool == null) {
          return ExitCode.NOTHING_DONE;
        }
        // 用於構建項目的方法
        return doBuild(context, chunk, dirtyFilesHolder, outputConsumer, compilingTool);
      }
    
  • 在doBuild方法裏,從變量裏的Map獲得編譯所需要的編譯器(ecj使用的是JavaCompilingTool的子類EclipseCompilerTool),還有對java版本的校驗,是否使用javac進行編譯;

搭建ecj的運行環境
  1. 去eclipse官網找到對應的ecj版本源碼,這裏用的是ecj-4.10.jar;需要同時下載這個版本的sdk,org.eclipse.jdt-4.10

在這裏插入圖片描述
2. 使用idea打開,下載需要依賴的jar然後添加進去,這裏需要下載ant的jar包;

  1. 這個版本的ecj,使用了一些java11的api,使用java8無法編譯,切換爲java11;

  2. 在代碼裏找有沒有可執行的Main方法,看項目還有沒有錯誤,執行,控制檯輸出

    Eclipse Compiler for Java(TM) bundle_qualifier, bundle_version
    Copyright IBM Corp 2000, 2015. All rights reserved.
     
     Usage: <options> <source files | directories>
     If directories are specified, then their source contents are compiled.
     Possible options are listed below. Options enabled by default are prefixed
     with '+'.
     
     Classpath options:
        -cp -classpath <directories and ZIP archives separated by ;>
                           specify location for application classes and sources.
                           Each directory or file can specify access rules for
                           types between '[' and ']' (e.g. [-X] to forbid
                           access to type X, [~X] to discourage access to type X,
                           [+p/X;-p/*] to forbid access to all types in package p
                           but allow access to p/X)
        .... 省略掉,意思就是調用這個方法,需要跟的一些args的解釋
        VMOption跟java文件夾路徑,會對文件夾裏的java文件進行編譯
    
  3. 查看org.eclipse.jdt.internal.compiler.tool.EclipseCompiler#getTask方法,如何調用,然後就能debug,查看調用的方法了

  4. 調用call之後,實際上是去調用EclipseCompilerImpl的call方法了

  5. 最後發現,getTask裏的代碼,讀取java文件確實用到了Util#getInputStreamAsCharArray,對Util的兩個讀取文件方法都做了bom移除處理。

  6. 執行ecj的Main方法,args跟一個java文件夾的路徑,會對文件夾的java文件進行編譯,自己創建一個bom文件,發現可以處理,重新打包,然後idea配置compile爲eclipse,關聯重新打包的ecj-4.10.jar,還是不能處理,GG。

卡了好一陣子,還是想用新版的,應該是調用了其他方法,重新換一個地方找調用的方法,先導入默認的ecj包,不處理,查看它打印錯誤日誌的方法,
在這裏插入圖片描述
debug找到另一個讀取內容的地方(org/eclipse/jdt/internal/compiler/parser/Parser.java),在前面處理一下bom字符
在這裏插入圖片描述
在這裏插入圖片描述

重新編譯,替換文件,在2019.3.1是可以處理bom的,設置編譯方式爲eclipse,關聯ecj的jar包,不要用默認的(替換掉默認的也可以)
在這裏插入圖片描述

最後一個問題

如果整體項目使用UTF-8編譯(setting->encoding裏設置),有一些GBK裏的字符無法識別,

如果整體項目使用GBK編譯,報”諾縫ublic“,debug發現是文件是UTF-8 bom類型的文件,當做GBK文件來處理,直接按char讀的,所以就讀成了這個不識別的字,在parse.java裏面,再處理一下這兩個字符設置爲空字符和p字符就好了;

Util.java裏的讀取字節流默認是處理了bom字符的,但是由於項目設置,這個encoding到這裏的時候可能是個空選項,反正就是最後把所有可能遇到的問題都處理一下,項目文件分支比較多,編碼雜亂,別人用eclipse是可以正常運行的,原則上就不改變文件默認的東西,往已有的上面適配就好了

// Do not keep first character for UTF-8 BOM encoding
int start = 0;
if (totalRead > 0 && UTF_8.equals(encoding)) { 
    if (contents[0] == 0xFEFF) { // if BOM char then skip
        totalRead--;
        start = 1;
    }
}

ecj.jar資源地址://download.csdn.net/download/qq_23747281/12077645

發佈了15 篇原創文章 · 獲贊 4 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章