【发布时间】:2015-09-04 04:36:08
【问题描述】:
我正在尝试使用 Java 中的 JAXB 将 XML 文件解组为生成的类结构。我遇到了一个令人困惑的问题,我交给JAXBContext.newInstance(packageName, classLoader) 的类加载器显然找不到一些必要的类来实例化模式类,但是当我手动搜索提供的类加载器以查找所需的类时,它们就在那里:
URLClassLoader cl = this.getJaxbClassloader();
try
{
cl.loadClass("org.postgresql.util.PGInterval");
Log.error("Found class [" + name + "] in provided classloader");
}
catch (ClassNotFoundException e)
{
Log.error("Unable to find class [" + name + "] in provided classloader");
}
JAXBContext ctx = JAXBContext.newInstance( "com.comp.gen", cl);
getJaxbClassloader() 方法只是创建了一个新的 URLClassLoader,加载了生成的类需要的一些特定的 jar,然后将系统类加载器设置为父级。生成的类使用我放入类加载器的一些 postgresql 库,这是我遇到问题的资源。 JAXB 在提供的包中正确找到了 ObjectFactory 类,问题似乎只是生成的类本身的实例化。
运行此代码的结果是手动调用cl.loadClass("org.postgresql.util.PGInterval"); 工作正常,它记录第一条语句说它找到了类,没有抛出异常。但是当 JAXBContext 被实例化时,它会在完全相同的资源上抛出一个 CNFE:
java.lang.ClassNotFoundException: org.postgresql.util.PGInterval
at java.net.URLClassLoader.findClass(URLClassLoader.java:600)
at java.lang.ClassLoader.loadClassHelper(ClassLoader.java:772)
at java.lang.ClassLoader.loadClass(ClassLoader.java:745)
at java.lang.ClassLoader.loadClass(ClassLoader.java:726)
... 78 more
更彻底的堆栈跟踪:
java.lang.NoClassDefFoundError: org.postgresql.util.PGInterval
at java.lang.Class.getDeclaredFieldsImpl(Native Method)
at java.lang.Class.getDeclaredFields(Class.java:740)
at com.sun.xml.bind.v2.model.nav.ReflectionNavigator.getDeclaredFields(ReflectionNavigator.java:249)
at com.sun.xml.bind.v2.model.nav.ReflectionNavigator.getDeclaredFields(ReflectionNavigator.java:58)
at com.sun.xml.bind.v2.model.impl.ClassInfoImpl.findFieldProperties(ClassInfoImpl.java:370)
at com.sun.xml.bind.v2.model.impl.RuntimeClassInfoImpl.getProperties(RuntimeClassInfoImpl.java:176)
at com.sun.xml.bind.v2.model.impl.ModelBuilder.getClassInfo(ModelBuilder.java:243)
at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:100)
at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:81)
at com.sun.xml.bind.v2.model.impl.ModelBuilder.getClassInfo(ModelBuilder.java:209)
at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:95)
at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:81)
at com.sun.xml.bind.v2.model.impl.ModelBuilder.getTypeInfo(ModelBuilder.java:315)
at com.sun.xml.bind.v2.model.impl.RegistryInfoImpl.<init>(RegistryInfoImpl.java:99)
at com.sun.xml.bind.v2.model.impl.ModelBuilder.addRegistry(ModelBuilder.java:357)
at com.sun.xml.bind.v2.model.impl.ModelBuilder.getTypeInfo(ModelBuilder.java:327)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:466)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:302)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1136)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:154)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:121)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:202)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:184)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:144)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:346)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:443)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:406)
有人知道这里出了什么问题吗?我的印象是(并且 JAXBContext 文档支持这一点)它会使用提供的类加载器来查找实例化类所需的实现类,因此鉴于资源似乎在我提供的类加载器中,为什么是 JAXB找不到?
编辑: 添加使用 PGInterval 资源的生成类的相关部分:
import org.postgresql.util.PGInterval;
...
...
...
@XmlElement(name = "time_to_live", required=false)
protected PGInterval time_to_live;
public PGInterval gettime_to_live()
{
return time_to_live;
}
public void settime_to_live(PGInterval time_to_live)
{
this.time_to_live = time_to_live;
}
我想值得注意的是,生成的类中唯一的导入不在 java 的标准库中。
【问题讨论】:
-
确实很有趣。你能分享一下有 PGInterval 属性的类吗?
-
不可能发布代码,生成的类是巨大的(不是按照我的设计我可能会添加......我正在使用其他人的代码库)。但是我可以找出使用 PGInterval 的 sn-ps。
-
让我们检查一下我们是否也可以这样做
cl.loadClass("org.postgresql.util.PGInterval").getDeclaredFields();问题可能是 PGInterval 本身。它似乎试图获取 PGInterval 的字段。 -
抱歉,回复晚了,但该电话工作正常。获取 PGInterval 类的声明字段有效。
-
你有什么理由不打电话给
JAXBContext.newInstance(TopLevelClass.class)吗?如果顶级类静态到达PGInterval类应该没问题。你也可以试试JAXBContext.newInstance("com.comp.gen", TopLevelClass.class.getClassLoader())。
标签: java jaxb classloader