2011-09-09 134 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構建腳本以從我添加的軟件包中排除其他類,以解決問題。

相關問題