我有遗留源使用新的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.但是,再一次,即使那时也要注意交叉编译,这是一个经常被低估的棘手话题.