2013-10-30 34 views
2

我有一个库是一个商业产品的直接扩展。该产品已有几年历史,并使用Sun的JAXB-2.0库。我可以预先取得课程路径吗?

我的图书馆使用JAXB,我有一个非常奇怪的错误。 What might cause "JAXBElement Does not have a no-arg default constructor"?

我发现这是由旧库中的一个错误引起的。我是否可以预先强制加载的类强制我的扩展使用该类的“正确”版本?

编辑:随着我的插件,我打包JAXB-2.2.5(它在我的插件的类路径中引用),但我怀疑现有的JVM已经加载了2.0版本的类,导致我的心痛。

+1

您可以使用自定义类加载器来隐藏加载的类路径,该自定义类加载器不会委托给其父类,而是尝试自行加载尽可能多的类。这样,你至少可以知道这是否是原因。 –

+0

@raphw我比我对JVM的理解稍深。你能稍微扩展一下吗? – InfernalRapture

+0

注释字段对于此目的有点短。请参阅下面的答案。 –

回答

2

每个Java ClassClassLoader加载。一旦加载了一个类,就不可能从类加载器中卸载这个类。 排除这一类的唯一可能性是将所有对此类加载器已加载的类的实例的所有引用全部引用到,对引用加载器本身

类加载器按层次结构组织。默认情况下,每个类加载器首先要求其父类加载器加载一个类。只有当父类加载器无法加载类时,原始类加载器才会尝试这样做。你可以重载这个行为来加载你的JAXB类。

虽然这并不容易:假设您有一个类MyObject,该类使用类加载器A加载。如果您使用类加载器B然后MyObject.class != MyObject.class加载了这两个类的相同类。这也会导致MyObject o = getMyObjectFromOtherClassLoader()抛出ClassCastException

Stackoverflow提供an example of a child first class loader。剩下的唯一事情就是在类加载器处于活动状态之前运行应用程序而不加载类。这一点,你可以做如下(待验证码):

class StartupWrapper { 

    public static void main(String[] args) throws Exception { 
    Class.forName("com.company.Main", true, 
     new ParentLastURLClassLoader(Arrays.asList(new URL("./new-JAXB.jar")))) 
     .getMethod("main", String[].class).invoke(null, args); 
    } 
} 

此包装将使用孩子一类加载器首先考虑您的图书馆启动类com.company.Name你的正常应用的public static void main(String[])方法。确保在显式加载之前不加载com.company.Main。 (因此,反射的方法。)

您是否使用像Maven这样的构建工具?你不能明确排除旧图书馆的依赖吗?遗留应用程序可能与新应用程序在旧JAXB中存在类似的问题。

+0

最终,我最终用更新后的版本替换了原来的库。然而这是一种破解,这是“正确的”解决方案;我很高兴你在这里分享这些信息。 – InfernalRapture

相关问题