我們在系統中長期使用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罐子?在調試過程中,我可以看到它正在做一些反射,但我不明白爲什麼要這樣做。
使用Java SE 6我建議使用支持JAXB 2.1的JAXB impl的最新修補程序版本,除非您嘗試使用特定的JAXB 2.2功能。 –
對不起,我沒有提到。升級到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
它看起來像您的JAXB impl錯誤地將'ObjectFactory'視爲一個域類。這很可能是由於@ XmlRegistry註釋由於您的域類和JAX-WS實現之間的ClassLoader差異而未被識別。您是直接創建'JAXBContext',還是使用JAX-WS實現? –