Java 两个类具有相同的XML类型名称;“对象工厂”;

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实例,以便对

我们已经在系统中使用JAXB2.1很长时间了。我们有一个使用Ant构建的平台,它生成了一系列部署在OSGi运行时中的包。我们使用JavaSE6

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

在OSGi运行时中,我们有一个包,其中包含JAXB JAR并导出必要的包。我们使用生成的所有对象工厂的上下文路径创建一个JAXBContext实例,以便对所有数据类型进行marshall/unmarshall

到目前为止,这项技术一直有效,但现在我们正在尝试升级到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
其中,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
    文件,而不是用法)。可能是选错了注释

  • 如果这不起作用,请创建您自己的类加载器,它只能看到一个工厂。这应该没有必要,但谁知道呢

  • 尝试在JAXBContextImpl.java:436处设置一个断点,以查看它处理哪些类型以及原因


  • 我们终于找到了解决办法

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