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

在DEA(Digital Evolution Algorithm)中使用ECJ(Evolutionary Computation in Java)进行编译时,如果出现java.lang.illegalargumentexception异常,通常表示传递给方法的参数不合法。 java.lang.illegalargumentexception异常是IllegalArgumentException类的子类,它表示非法或不合适的参数。它是运行时异常,意味着在程序执行期间可能会抛出该异常。 要解决这个异常,我们需要检查传递给方法的参数是否符合方法的要求,包括参数的类型、范围或其他限制条件。可以检查以下几个方面: 1. 参数的类型:确保传递给方法的参数的类型与方法定义中的参数类型匹配。如果参数类型不匹配,可以尝试将其转换为正确的类型。 2. 参数的范围:如果参数有范围限制,例如必须在特定的范围内(如0到100之间),请确保传递的参数值在合法范围之内。 3. 参数的有效性:如果方法对参数值有其他限制条件(例如非空),请确保传递的参数值满足这些条件。 在使用ECJ编译过程中出现java.lang.illegalargumentexception异常时,可以根据异常的具体信息来判断参数的错误位置并进行调试。根据异常堆栈跟踪,可以定位到引发异常的代码行,并检查涉及的参数。 根据这些检查,我们可以修复参数错误,确保传递给方法的参数是合法的。修改后,再次进行编译时就不会再出现java.lang.illegalargumentexception异常了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值