我正在努力将一个大型代码库从一个版本的API移植到另一个版本(特定于Hadoop CDH3到Hadoop CDH4)。
在这些库的“升级”期间,有人决定将常用的具体类(JobContext)更改为接口,并将其所有功能移动到子类(JobContextImpl)中。通常这将是一个相当直接的主张。但是,我们仍然需要保持对旧版本库的支持,从而支持该类作为具体和接口。
我们显然可以根据我们正在使用的hadoop版本更换两套不同的罐子,但这会给我们带来许多不必要的头疼。我想创建一个可以针对两个hadoop版本运行的版本。
当然,工厂模式会首先浮现在你的脑海中,但问题是新版本中的实现类在以前的版本中不存在,因此代码只能针对一组中的一次只能运行一个库。
接下来,我尝试使用groovyscript和一些聪明的反射来检测类路径中哪个版本的库。我能够实例化这些对象,但是使用一个我没有编译过的库给了我:
IncompatibleClassChangeError:找到接口org.pain.MyContext,但是预期了类
编辑: 总之,我需要能够实例化一个可以是具体类或接口的类。我可以检测它是什么,如果它是一个接口,我知道实现在哪里,但如果具体那么实现类就不存在。
答案 0 :(得分:1)
没有办法让JVM忽略二进制不兼容性;即相同类型的矛盾定义。
可能可以解决问题,但这会非常尴尬。
您需要做的是:
JobContext
类的所有直接和间接引用
JobContext
类型的所有变量替换为Object
JobContext
作为参数的方法和构造函数的所有调用替换为使用反射方法或构造函数调用返回结果,使用Class<?>
获取JobContext
Class.forName(...)
。简而言之,如果您可以摆脱代码使用的所有位置或依赖于静态加载的JobContext
,那么您将不会获得该类的任何IncompatibleClassChangeError
例外。
老实说,我认为最好只针对两个Hadoop API分别编译代码库。