我有一个最初是为Java 1.4编写的项目,但我的Mac上只有Java 6,我无法安装Java 1.4。
通常情况下,我会使用这样的一行来编译:
javac -source=1.4 -target=1.4 MyClass.java
但是,MyClass.java
实现了java.sql.ResultSet
接口,它在Java 6中添加了几个新方法,因此我遇到了编译错误,如:
MyClass is not abstract and does not override abstract method
updateNClob(java.lang.String,java.io.Reader) in java.sql.ResultSet
我不能简单地实现缺少的方法,因为许多使用泛型,这在Java 1.4中是不可用的。
似乎解决方案是获取并编译Java 1.4 JAR。所以,我有几个问题:
javac
指定我想使用1.4 JAR而不是Java 6 JAR?谢谢!
答案 0 :(得分:4)
除非您是JDBC供应商,否则实现像这样的接口是不明智的。
考虑使用proxy来维护JVM版本之间的兼容性。
迁移到代理服务器如下完成。考虑这个ResultSet
实现:
public class ResultSetFoo implements ResultSet {
public String getString(int columnIndex) throws SQLException {
return "foobar";
}
// other Java 1.4 methods
这将被更改,因此没有类实现ResultSet
:
public class ResultBar {
public String getString(int columnIndex) throws SQLException {
return "foobar";
}
// other method signatures matching the 1.4 ResultSet, as before
然后,您需要在运行时构建两种类型之间的方法映射(鸭子类型的原始形式:)
private static final Map RESULT_SET_DUCK = initResultSet();
private static Map initResultSet() {
Map map = new HashMap();
Method[] methods = ResultSet.class.getMethods();
for (int i = 0; i < methods.length; i++) {
try {
Method match =
ResultBar.class.getMethod(methods[i].getName(),
methods[i].getParameterTypes());
map.put(methods[i], match);
} catch (SecurityException e) {
throw new IllegalStateException(e);
} catch (NoSuchMethodException e) {
// OK; not supported in 1.4
}
}
return map;
}
这允许您通过代理调用ResultBar
类型:
/** Create a java.sql.ResultSet proxy */
public static ResultSet proxy(final ResultBar duck) {
class Handler implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Method proxiedMethod = (Method) RESULT_SET_DUCK.get(method);
if (proxiedMethod == null) {
throw new UnsupportedOperationException("TODO: method detail");
} else {
return invoke(proxiedMethod, duck, args);
}
}
private Object invoke(Method m, Object target, Object[] args)
throws Throwable {
try {
return m.invoke(target, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
}
return (ResultSet) Proxy.newProxyInstance(null, RSET, new Handler());
}
这样的实现应该允许在一个JVM中编译的代码在未来的JVM中使用,即使添加了新方法。 现有方法签名不太可能改变,因为让数据库供应商做一些工作是一回事;让所有API消费者都改变的其他因素。
您可能需要更改类实例的创建方式。您不能再直接使用构造函数:
ResultSet nonPortable = new ResultSetFoo();
//becomes...
ResultSet portable = proxy(new ResultBar());
如果您已经雇用了工厂/建筑商/等。模式这个很容易。
尽管在最新的JVM中反射相对便宜,但在旧版本中反射较少;这可能会对绩效产生不利影响。
答案 1 :(得分:4)
你的情况似乎很人为。我会尽力简化问题。首先,我将忽略你关于Maven的问题。
所以让我首先陈述一些事实:
-source=1.4
表示:亲爱的编译器,请仅接受语言结构 ---不是库功能---这些功能可以在JDK 1.4的javac中使用。
-target=1.4
表示:亲爱的编译器,请以二进制文件格式编写类文件,该格式与JRE 1.4兼容。
我认为您对与JDK 1.4的加载时兼容性感兴趣,即您希望JDK 1.4可以加载您的设置中生成的类文件。是吗?
您是否也想支持源兼容性?即你想让其他人在JDK 1.4上编译你的代码吗?
如果上一个问题的答案是肯定的,我会尝试在OS X上安装JDK 1.4。它支持多个已安装的JDK。所以我很确定这是可能的。如果没有选择,请使用:
-source=1.4 -target=1.4 -bootclasspath=[path/to/1.4.jar]
注意,不要使用-Xbootclasspath。这会更改执行javac的jvm的引导类路径。
如果上述问题的答案是否定的。您可以处置-source=1.4
,允许您在代码中使用泛型和其他Java 5增强功能。但是您仍然必须使用以下方式提供二进制兼容性:
-target=1.4 -bootclasspath=[path/to/1.4.jar]
另一种选择是使用Retroweaver。
重新阅读你的问题之后,我想补充说你必须掌握jdbc类文件的JDK 1.4变体。否则,您将遇到问题中显示的编译器错误。
答案 2 :(得分:2)
如何向Java 1.6 javac指定我想使用1.4 JAR而不是Java 6 JAR?
胜利。 &安培; * nix将指定bootclasspath
选项。有关详细信息,请参阅javac: Cross-Compilation Options。