2011-09-09 136 views
5

我们在系统中长期使用JAXB 2.1。我们有一个使用Ant构建的平台,并生成一堆部署在OSGi运行时的捆绑包。我们使用Java SE 6.两个类具有相同的XML类型名称“objectFactory”

我们在构建过程中使用JAXB从不同模式生成数据类型。这些类打包在捆绑包中,并在运行时用于序列化/反序列化内容。另外我们在运行时在我们的平台中使用JAXB来从用户提供的其他模式(它是一种MDA平台)生成数据类型。

在OSGi运行时,我们有一个包含JAXB jar包并导出必需包的包。我们使用生成的所有对象工厂的上下文路径创建一个JAXBContext实例,因此我们可以编组/解组所有数据类型。

到目前为止,我们正在努力升级到JAXB (2.2.4)的最新稳定版本,并且我们在尝试在运行时创建上下文时遇到问题。我们得到以下异常:

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 

错误两个类具有相同的XML类型名称“objectFactory对象”打印每个在生成过程中产生的对象工厂。

我们已经在SO中看到了几个帖子,但是应用于生成的类型而不是对象工厂。我们认为JAXB可能不会将ObjectFactory类标识为对象工厂,而是将其标识为数据类型。

一种可能性是,我们在Java中使用6 JAXB的内部版本是,所以我们决定使用系统属性-Djava.endorsed.dirs,并把三个罐子(JAXB的API-2.2.4 .jar,jaxb-impl-2.2.4.jar和jaxb-xjc-2.2.4.jar)在该路径中,但仍然无法正常工作。

我们认为这个问题可能是因为我们在OSGi运行时和构建过程中使用了不同版本的JAXB,所以生成的代码不兼容。但也许我们错了,还有另一个问题。

你有什么想法吗?

在此先感谢。

(编辑:更多关于这方面的详细信息)

我们以这种方式创建的JAXBContext:

ClassLoader classLoader = new JAXBServiceClassLoader(getParentClassLoader(), 
                 Collections.unmodifiableMap(objectFactories)); 
    context = JAXBContext.newInstance(contextPath.toString(), classLoader); 

其中的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; 
    } 
    } 

(编辑:后阿龙的职位)

我一直在调试JAXBContextImpl的所有内部,事情是JAXBContextImpl试图从我们的ObjectFactory类获取类型信息,这是错误的。实际上,在com.sun.xml.internal.bind.v2.model.impl.ModelBuilder:314中,getClassAnnotation()调用返回null,但是当我看到该实例时,我可以看到注释XmlRegistry。如果我运行((Class)c).getAnnotations()[0] .annotationType()。getClassLoader(),它将返回该对象的值。包含我的JAXB JARB的OSGi包“lib.jaxb”的classLoader,它是正确的。

所以,我想,我们正在加载在同一时间两个不同版本XmlRegistry的,一个从JDK和JAXB 2.2.4罐子另一个。问题是:为什么?

而且,更重要的是,而不是加载所有com.sun.xml.internal。*类(如JAXBContextImpl),而不是加载并执行com.sun.xml.bind.v2.runtime.JAXBContextImpl JAXB罐子?在调试过程中,我可以看到它正在做一些反射,但我不明白为什么要这样做。

+0

使用Java SE 6我建议使用支持JAXB 2.1的JAXB impl的最新修补程序版本,除非您尝试使用特定的JAXB 2.2功能。 –

+0

对不起,我没有提到。升级到JAXB 2.2.4的原因是我们正在将我们的JAX-WS版本升级到2.2.5,并取决于该版本的JAXB(http://jax-ws.java.net/2.2.5/docs/ ReleaseNotes.html)。否则,我们可以使用JAXB 2.1。 – Denian

+0

它看起来像您的JAXB impl错误地将'ObjectFactory'视为一个域类。这很可能是由于@ XmlRegistry注释由于您的域类和JAX-WS实现之间的ClassLoader差异而未被识别。您是直接创建'JAXBContext',还是使用JAX-WS实现? –

回答

2

我们终于找到了解决方案。

从JAXB文档(发现JAXB实现段):

http://jaxb.java.net/nonav/2.2.4-1/docs/api/javax/xml/bind/JAXBContext.html

我们试图在META-INF添加资源/服务/ javax.xml.bind.JAXBContext在为了强制使用com.sun.xml.bind.v2.ContextFactory而不是Sun的内部工厂。这没有用,可能是因为我们正在使用OSGi包。

无论如何,我们使用我们自己的classloader,我们覆盖的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时才使用该类加载器,它应该没问题。

2
  1. 确保只有一个@XmlRegistry在类路径注释(搜索XmlRegistry.class文件,不使用)。也许错误的注释被拾取。

  2. 如果不工作,创建自己的ClassLoader它认为只有一个工厂。这应该不是必要的,但谁知道。

  3. 尝试在JAXBContextImpl.java:436设置断点,看看它处理哪些类型和原因。

+0

嗨, 对不起,延迟回复。 1.在jaxb-api-2.2.4.jar(它位于我的包“lib.jaxb”中)和Java 1.6 classes.jar中有一个XmlRegistry.class。 2.难以改变的实现,我会尝试,如果我不成功与3. 3.我一直在调试内部,但让我添加我的评论在主帖。 – Denian

+0

感谢您的巨大努力。不幸的是,我现在脱离了我的联盟,现在:-(我非常确定这是因为OSGi/Java的类加载方式(规则是首先从父CL加载,所以Java代码优先于类OSGi添加到类路径中)作为测试,尝试在** boot **类路径中指定JAXB实现(请参阅文档如何设置:http://download.oracle.com/javase/1.3/docs/ tooldocs/win32/migration.html#bootcp) –

+0

嗨,Aaron,感谢您的回复。 我试着将jar添加到bootclasspath,但没有区别,抛出同样的异常。 – Denian

0

我有同样的问题,但不同的原因。即使它可能无法解决作者的问题,我会为所有人发布这个答案,稍后阅读这篇文章,并与我有同样的问题。

我用这个编译器插件配置,它从编译排除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> 

工作配置:

<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> 
0

我尝试部署基于弹簧的SOAP Web服务时也有类似的问题。我在org.springframework.oxm.jaxb.Jaxb2Marshaller spring bean的contextPaths中添加了一个包。问题在于同一个班级包含在同一个contextPaths中。我更改了Ant构建脚本以从我添加的软件包中排除其他类,以解决问题。

相关问题