Maven构建如何使用java版本1.6或之前的rt.jar

我有遗留源使用新的FtpClient(),并发现FtpClient是jre1.7中的抽象类.该代码适用于jre1.6或之前.

我正在使用maven来构建我的项目.我的JAVA_HOME指向jdk1.7,导致编译我的源代码失败.但是当我的JAVA_HOME指向jdk1.6时它很好.但是,我公司的jdk versioin默认为1.7,并且不会降级到1.6版本.

问题:如何在不更改JAVA_HOME的情况下编译我的源代码?

在相关的构建日志下面:

[INFO] Compiling 601 source files to C:\MyData\Project\A-Trunk\CCA\Online\branches\CCA_TabletAccess_Maven\Common_Source\target\classes
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Compilation failure

C:\MyData\Project\A-Trunk\CCA\Online\branches\CCA_TabletAccess_Maven\Common_Source\src\com\hhbb\cca\services\ens\util\FTPCommon.java:[44,9] error: FtpClient is abstract; cannot be instantiated

C:\MyData\Project\A-Trunk\CCA\Online\branches\CCA_TabletAccess_Maven\Common_Source\src\com\hhbb\cca\services\ens\util\FTPCommon.java:[45,6] error: cannot find symbol

could not parse error message:   symbol:   method openServer(String)
  location: variable aftp of type FtpClient
C:\MyData\Project\A-Trunk\CCA\Online\branches\CCA_TabletAccess_Maven\Common_Source\src\com\hhbb\cca\services\ens\util\FTPCommon.java:46: error: no suitable method found for login(String,String)
                aftp.login(user,psw);
                    ^

could not parse error message:     method FtpClient.login(String,char[],String) is not applicable
      (actual and formal argument lists differ in length)
    method FtpClient.login(String,char[]) is not applicable
      (actual argument String cannot be converted to char[] by method invocation conversion)
C:\MyData\Project\A-Trunk\CCA\Online\branches\CCA_TabletAccess_Maven\Common_Source\src\com\hhbb\cca\services\ens\util\FTPCommon.java:47: error: cannot find symbol
                aftp.ascii();
                    ^

could not parse error message:   symbol:   method ascii()
  location: variable aftp of type FtpClient
C:\MyData\Project\A-Trunk\CCA\Online\branches\CCA_TabletAccess_Maven\Common_Source\src\com\hhbb\cca\services\ens\util\FTPCommon.java:53: error: FtpClient is abstract; cannot be instantiated
                aftp = new FtpClient();
                       ^

C:\MyData\Project\A-Trunk\CCA\Online\branches\CCA_TabletAccess_Maven\Common_Source\src\com\hhbb\cca\services\ens\util\FTPCommon.java:[54,6] error: cannot find symbol

could not parse error message:   symbol:   method openServer(String,int)
  location: variable aftp of type FtpClient
C:\MyData\Project\A-Trunk\CCA\Online\branches\CCA_TabletAccess_Maven\Common_Source\src\com\hhbb\cca\services\ens\util\FTPCommon.java:55: error: no suitable method found for login(String,String)
                aftp.login(user,psw);
                    ^

could not parse error message:     method FtpClient.login(String,char[],String) is not applicable
      (actual and formal argument lists differ in length)
    method FtpClient.login(String,char[]) is not applicable
      (actual argument String cannot be converted to char[] by method invocation conversion)
C:\MyData\Project\A-Trunk\CCA\Online\branches\CCA_TabletAccess_Maven\Common_Source\src\com\hhbb\cca\services\ens\util\FTPCommon.java:56: error: cannot find symbol
                aftp.binary();
                    ^

could not parse error message:   symbol:   method binary()
  location: variable aftp of type FtpClient
C:\MyData\Project\A-Trunk\CCA\Online\branches\CCA_TabletAccess_Maven\Common_Source\src\com\hhbb\cca\services\ens\util\FTPCommon.java:62: error: cannot find symbol
                  aftp.closeServer();
                      ^

could not parse error message:   symbol:   method closeServer()
  location: variable aftp of type FtpClient
C:\MyData\Project\A-Trunk\CCA\Online\branches\CCA_TabletAccess_Maven\Common_Source\src\com\hhbb\cca\services\ens\util\FTPCommon.java:127: error: cannot find symbol
                        aftp.cd(RWFileDir);
                            ^

could not parse error message:   symbol:   method cd(String)
  location: variable aftp of type FtpClient
C:\MyData\Project\A-Trunk\CCA\Online\branches\CCA_TabletAccess_Maven\Common_Source\src\com\hhbb\cca\services\ens\util\FTPCommon.java:128: error: cannot find symbol
                        TelnetOutputStream outs = aftp.put(filename);
                                                      ^


[INFO] ------------------------------------------------------------------------
[INFO] For more information, run Maven with the -e switch
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8 seconds
[INFO] Finished at: Thu Mar 24 14:12:52 CST 2016

最佳答案 您在使用特殊情况时遇到了对Java交叉编译的常见误解:您希望使用sun.*类,这些类无法保证在Java版本之间兼容.从
official Oracle note

A Java program that directly calls into sun.* packages is not guaranteed to work on all Java-compatible platforms. In fact, such a program is not guaranteed to work even in future versions on the same platform.

在您的特定情况下,设置Maven编译器插件的源/目标是不够的.一般来说真的很危险. Java编译器只知道字节码,而不是Java API(rt.jar文件).因此,使用Java 7编译器编译仍然会使用Java 7的rt.jar,在您的情况下,它将破坏Java 6的代码(特别是因为sun.*用法).

检查this SO answer以获得更深入的解释.如果您对其内容有疑问,请查看Oracle的Stuart Marks的评论.

在您的特定情况下,您因此必须安装JDK 6,因为您需要指向Java 6 API的JDK 6 rt.jar文件,否则您的代码将永远无法正确编译.为此,您可以使用Maven编译器插件的executable选项指向要使用的不同JDK安装,以及fork选项.

但是,对于任何需要此切换的插件,您也必须对测试执行执行相同的操作.因此,更可靠的方法是在每次构建之前预先设置JAVA_HOME变量(指向JDK 6)或使用Maven toolchain并设置JDK以在一组Maven插件中使用.但是,同样,您需要在系统中安装JDK 6,否则它将无法工作.

您还可以考虑使用Maven profiles来隔离不同的JDK用法.在这样的配置文件中,我还建议添加Animal Sniffer Maven Plugin,如上述SO答案中所述.

作为一般考虑,上面的要点解释了为什么以及如何暂时解决它,但您的应用程序和构建可能很容易遇到维护问题.一个更结构化的方法肯定是修复sun.*包的使用,这是a really bad practice.但是,再一次,即使那时也要注意交叉编译,这是一个经常被低估的棘手话题.

点赞