Java 两个类具有相同的XML类型名称;“对象工厂”;
我们已经在系统中使用JAXB2.1很长时间了。我们有一个使用Ant构建的平台,它生成了一系列部署在OSGi运行时中的包。我们使用JavaSE6 我们在构建过程中使用JAXB从不同的模式生成数据类型。这些类打包在包中,并在运行时用于序列化/反序列化内容。此外,我们在运行时的平台中使用JAXB从用户提供的其他模式生成数据类型(它是一种MDA平台) 在OSGi运行时中,我们有一个包,其中包含JAXB JAR并导出必要的包。我们使用生成的所有对象工厂的上下文路径创建一个JAXBContext实例,以便对所有数据类型进行marshall/unmarshall 到目前为止,这项技术一直有效,但现在我们正在尝试升级到JAXB的最新稳定版本(2.2.4),并且在尝试在运行时创建上下文时遇到问题。我们得到以下例外情况:Java 两个类具有相同的XML类型名称;“对象工厂”;,java,jaxb,jax-ws,osgi,jaxb2,Java,Jaxb,Jax Ws,Osgi,Jaxb2,我们已经在系统中使用JAXB2.1很长时间了。我们有一个使用Ant构建的平台,它生成了一系列部署在OSGi运行时中的包。我们使用JavaSE6 我们在构建过程中使用JAXB从不同的模式生成数据类型。这些类打包在包中,并在运行时用于序列化/反序列化内容。此外,我们在运行时的平台中使用JAXB从用户提供的其他模式生成数据类型(它是一种MDA平台) 在OSGi运行时中,我们有一个包,其中包含JAXB JAR并导出必要的包。我们使用生成的所有对象工厂的上下文路径创建一个JAXBContext实例,以便对
Two classes have the same XML type name "objectFactory". Use @XmlType.name and @XmlType.namespace to assign different names to them.
this problem is related to the following location:
at some.package.ObjectFactory
this problem is related to the following location:
at some.other.package.ObjectFactory
at com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:91)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:436)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:277)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1100)
at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:143)
at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:110)
at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:191)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:187)
... 76 more
其中,contextPath是一个字符串,包含所有由“:”分隔的对象工厂,JAXBServiceClassLoader是:
private static final class JAXBServiceClassLoader extends ClassLoader
{
@NotNull
private final Map<String, Object> objectFactories;
private JAXBServiceClassLoader(@NotNull ClassLoader parent, @NotNull Map<String, Object> objectFactories)
{
super(parent);
this.objectFactories = objectFactories;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException
{
Class<?> ret;
try
{
ret = super.loadClass(name);
}
catch (ClassNotFoundException e)
{
Object objectFactory = objectFactories.get(name);
if (objectFactory != null)
{
ret = objectFactory.getClass();
}
else
{
throw new ClassNotFoundException(name + " class not found");
}
}
return ret;
}
}
私有静态最终类JAXBServiceClassLoader扩展了ClassLoader
{
@NotNull
私人工厂;
私有JAXBServiceClassLoader(@NotNull ClassLoader父级,@NotNull映射对象工厂)
{
超级(家长);
this.objectFactories=objectFactories;
}
@凌驾
公共类loadClass(字符串名称)引发ClassNotFoundException
{
类ret;
尝试
{
ret=super.loadClass(名称);
}
catch(classnotfounde异常)
{
objectFactory=objectFactories.get(名称);
if(objectFactory!=null)
{
ret=objectFactory.getClass();
}
其他的
{
抛出新的ClassNotFoundException(名称+“未找到类”);
}
}
返回ret;
}
}
(编辑:在Aaron的帖子之后)
我一直在调试JAXBContextImpl的所有内部构件,问题是JAXBContextImpl试图从我们的ObjectFactory类中获取类型信息,这是错误的。事实上,在com.sun.xml.internal.bind.v2.model.impl.ModelBuilder:314中,getClassAnnotation()调用返回null,但当我看到实例时,我可以看到注释XmlRegistry
问题是,此时XmlRegistry.class.getClassLoader()返回null,但如果我运行((class)c).getAnnotations()[0].annotationType().getClassLoader(),它将返回包含jaxb JAR的OSGi包“lib.jaxb”的类加载器,这是正确的
因此,我猜我们同时加载了两个不同版本的XmlRegistry,一个来自JDK,另一个来自JAXB2.2.4JARS。问题是:为什么
而且,更重要的是,不应该从JAXB JAR加载和执行com.sun.xml.bind.v2.runtime.JAXBContextImpl,而不是加载所有那些com.sun.xml.internal.*类(如JAXBContextImpl)?在调试过程中,我可以看到它正在使用反射进行一些操作,但我不明白为什么要这样做
@XmlRegistry
注释(搜索XmlRegistry.class
文件,而不是用法)。可能是选错了注释我们终于找到了解决办法 从JAXB文档(发现JAXB实现部分): 我们试图在META-INF/services/javax.xml.bind.JAXBContext中添加一个资源,以便强制使用com.sun.xml.bind.v2.ContextFactory而不是sun的内部工厂。这不起作用,可能是因为我们使用的是OSGi捆绑包 无论如何,当我们使用自己的类加载器时,我们重写了getResourceAsStream()方法,该方法是从ContextFinder:343调用的:
@Override
public InputStream getResourceAsStream(String name)
{
if (name!=null && name.equals("META-INF/services/javax.xml.bind.JAXBContext"))
{
return new ByteArrayInputStream("com.sun.xml.bind.v2.ContextFactory".getBytes());
}
return super.getResourceAsStream(name);
}
这不是最漂亮的解决方案,但它对我们有效。只有在我们创建JAXBContext时才使用这个类加载器,应该没问题。我也有同样的问题,但原因不同。即使它可能无法解决作者的问题,我也为所有这些人发布了这个答案,稍后阅读这篇文章,发现了与我相同的问题 我使用了这个编译器插件配置,它将package-info.java文件排除在编译之外。在移除排斥后,一切都像一个符咒一样工作!JAXB似乎在这些文件中包含了一些重要的定义 断开的配置:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
<excludes>
<exclude>**/package-info.java</exclude>
</excludes>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
<fork>false</fork>
</configuration>
</plugin>
maven编译器插件
3
1.6
1.6
UTF-8
**/package-info.java
真的
真的
假的
工作配置:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
<fork>false</fork>
</configuration>
</plugin>
maven编译器插件
3
1.6
1.6
UTF-8
真的
真的
假的
我在尝试部署基于spring的soap web服务时遇到了类似的问题。我在org.springframework.oxm.jaxb.Jaxb2Marshaller
springbean的contextpath
中添加了一个包。问题是同一类存在于同一contextpath
中的其他包中。我更改了Ant构建脚本,将其他类从我添加的包中排除,这解决了问题。使用Java SE 6,我建议使用支持JAXB 2.1的JAXB impl的最新补丁版本,除非您尝试使用特定的JAXB 2.2功能。很抱歉,我没有提到这一点。升级到JAXB2.2.4的原因是,我们正在将JAX-WS版本升级到2.2.5,这取决于该版本
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
<fork>false</fork>
</configuration>
</plugin>