2011-09-09 29 views
5

Chúng tôi đã sử dụng JAXB 2.1 trong một thời gian dài trong hệ thống của chúng tôi. Chúng tôi có một nền tảng được xây dựng với Ant và tạo ra một loạt các gói được triển khai trong thời gian chạy OSGi. Chúng tôi sử dụng Java SE 6.Hai lớp có cùng tên kiểu XML "objectFactory"

Chúng tôi sử dụng JAXB trong quá trình xây dựng để tạo ra kiểu dữ liệu từ các lược đồ khác nhau. Các lớp đó được đóng gói trong các gói và được sử dụng trong thời gian chạy để tuần tự hóa/deserialize nội dung. Ngoài ra, chúng tôi sử dụng JAXB trong nền tảng của chúng tôi trong thời gian chạy để tạo các kiểu dữ liệu từ các lược đồ khác do người dùng cung cấp (nó là một loại nền tảng MDA).

Trong thời gian chạy OSGi, chúng tôi có một gói có các lọ JAXB và xuất các gói cần thiết. Chúng ta tạo một cá thể JAXBContext với đường dẫn ngữ cảnh của tất cả các nhà máy đối tượng được tạo ra, vì vậy chúng ta có thể marshall/unmarshall tất cả các kiểu dữ liệu của chúng ta.

Điều đó đã hoạt động cho đến nay nhưng hiện tại chúng tôi đang cố gắng nâng cấp lên phiên bản ổn định mới nhất của JAXB (2.2.4) và chúng tôi đang gặp sự cố khi cố gắng tạo ngữ cảnh trong thời gian chạy. Chúng tôi nhận được ngoại lệ sau đây:

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 

Các lỗi Hai lớp học có cùng tên kiểu XML "objectFactory" được in ra cho mỗi người trong số các nhà máy đối tượng được tạo ra trong quá trình xây dựng.

Chúng tôi đã thấy một số bài đăng trong SO có cùng lỗi nhưng áp dụng cho các loại được tạo, không áp dụng cho nhà máy đối tượng. Chúng tôi nghĩ rằng JAXB có thể không xác định được lớp ObjectFactory như một nhà máy đối tượng mà là một kiểu dữ liệu.

Một khả năng là chúng tôi đã sử dụng phiên bản nội bộ của JAXB trong Java 6, vì vậy chúng tôi quyết định sử dụng tài sản Hệ thống -Djava.endorsed.dirs và đưa ba lọ (jaxb-api-2.2.4 .jar, jaxb-impl-2.2.4.jar và jaxb-xjc-2.2.4.jar) trong đường dẫn đó, nhưng vẫn không hoạt động.

Chúng tôi nghĩ rằng vấn đề có thể là chúng tôi đang sử dụng một phiên bản JAXB khác trong thời gian chạy OSGi và trong quá trình xây dựng, do đó mã được tạo không tương thích. Nhưng có lẽ chúng ta sai và có một vấn đề khác.

Bạn có ý tưởng nào không?

Xin cảm ơn trước.

(Edit: thêm chi tiết về vấn đề này)

Chúng tôi tạo ra các JAXBContext theo cách này:

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

nơi contextPath là một chuỗi có chứa tất cả các nhà máy đối tượng của chúng tôi cách nhau bởi ':', và JAXBServiceClassLoader là:

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; 
    } 
    } 

(chỉnh sửa: sau khi đăng bài của Aaron)

Tôi đã gỡ lỗi tất cả nội bộ của JAXBContextImpl và điều này là JAXBContextImpl đang cố gắng lấy thông tin kiểu từ lớp ObjectFactory của chúng tôi, điều này là sai. Trong thực tế, trong com.sun.xml.internal.bind.v2.model.impl.ModelBuilder: 314, hàm getClassAnnotation() trả về null nhưng khi tôi nhìn thấy cá thể tôi có thể thấy chú thích XmlRegistry.

Vấn đề là tại thời điểm đó XmlRegistry.class.getClassLoader() trả về null, nhưng nếu tôi chạy ((Class) c) .getAnnotations() [0] .annotationType(). GetClassLoader() nó trả về classLoader của gói OSGi "lib.jaxb" có chứa các JAXB jars của tôi, đó là chính xác.

Vì vậy, tôi đoán rằng chúng tôi đang tải cùng một lúc hai phiên bản khác nhau của XmlRegistry, một từ JDK và một phiên bản khác từ JAXB 2.2.4 lọ. Câu hỏi đặt ra là: tại sao?

Và thậm chí nhiều hơn, thay vì tải tất cả các lớp com.sun.xml.internal. * (Như JAXBContextImpl), không được tải và thực thi com.sun.xml.bind.v2.runtime.JAXBContextImpl từ JAXB lọ? Trong quá trình gỡ lỗi, tôi có thể thấy rằng nó đang làm một số công cụ với sự phản ánh nhưng tôi không hiểu tại sao làm điều đó.

+0

Sử dụng Java SE 6 Tôi khuyên bạn nên sử dụng bản vá lỗi mới nhất của JAXB impl hỗ trợ JAXB 2.1 trừ khi có một tính năng JAXB 2.2 cụ thể mà bạn đang cố gắng sử dụng. –

+0

Xin lỗi vì tôi không đề cập đến điều đó. Lý do để nâng cấp lên JAXB 2.2.4 là chúng tôi đang nâng cấp phiên bản JAX-WS lên 2.2.5 và nó phụ thuộc vào phiên bản JAXB đó (http://jax-ws.java.net/2.2.5/docs/ ReleaseNotes.html). Nếu không, chúng ta có thể sử dụng JAXB 2.1. – Denian

+0

Dường như JAXB của bạn đang xử lý nhầm lẫn 'ObjectFactory' như một lớp miền. Điều này rất có thể là do chú thích '@ XmlRegistry' không được nhận ra do sự khác biệt' ClassLoader' giữa các lớp miền của bạn và việc triển khai JAX-WS. Bạn có đang tạo trực tiếp 'JAXBContext' hoặc thực hiện JAX-WS làm việc này không? –

Trả lời

2

Cuối cùng, chúng tôi đã tìm ra giải pháp cho việc này.

Từ các tài liệu JAXB (Discovery thực hiện JAXB mục):

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

Chúng tôi cố gắng thêm một nguồn tài nguyên trong META-INF/dịch vụ/javax.xml.bind.JAXBContext trong để thực thi việc sử dụng com.sun.xml.bind.v2.ContextFactory thay vì nhà máy nội bộ của Sun. Điều đó không có tác dụng, có lẽ vì chúng tôi đang sử dụng gói OSGi.

Dù sao, như chúng ta đang sử dụng classloader riêng của chúng tôi, chúng tôi ghi đè lên các phương pháp getResourceAsStream(), được gọi là từ 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); 
} 

Đây không phải là giải pháp đẹp nhất nhưng nó hoạt động đối với chúng tôi . Và trình nạp lớp đó chỉ được sử dụng khi chúng ta tạo JAXBContext, nó sẽ ổn thôi.

2
  1. Hãy chắc chắn rằng chỉ có một @XmlRegistry chú thích trong classpath của bạn (Tìm kiếm XmlRegistry.class tập tin, không sử dụng). Có thể chú thích sai được chọn.

  2. Nếu điều đó không hiệu quả, hãy tạo trình nạp lớp của riêng bạn chỉ xem một nhà máy. Điều đó không cần thiết nhưng ai biết được.

  3. Cố gắng đặt điểm ngắt tại JAXBContextImpl.java:436 để xem loại quy trình nào xử lý và lý do.

+0

Xin chào, Xin lỗi vì trả lời muộn. 1. Có một lớp XmlRegistry.class trong jaxb-api-2.2.4.jar (nằm bên trong gói "lib.jaxb") của tôi và trong Java 1.6 classes.jar. 2. Rất khó để thay đổi việc thực hiện, tôi sẽ cố gắng nếu tôi không thành công với 3. 3. Tôi đã gỡ lỗi nội bộ, nhưng hãy để tôi thêm nhận xét của tôi vào bài đăng chính. – Denian

+0

Cảm ơn vì nỗ lực tuyệt vời của bạn. Thật không may, tôi ra khỏi giải đấu của tôi, bây giờ :-(Tôi khá chắc chắn đó là vì cách OSGi/Java thực hiện nạp lớp (Quy tắc là tải từ CL mẹ đầu tiên, vì vậy mã Java được ưu tiên hơn các lớp OSGi thêm vào đường dẫn lớp) Là một thử nghiệm, hãy thử chỉ định việc thực thi JAXB của bạn trong đường dẫn lớp ** boot ** (xem tài liệu cách thiết lập: http://download.oracle.com/javase/1.3/docs/ tooldocs/win32/migration.html # bootcp) –

+0

Xin chào Aaron, cảm ơn câu trả lời của bạn Tôi đã cố gắng thêm các lọ vào bootclasspath nhưng nó không tạo ra sự khác biệt nào, cùng một ngoại lệ được ném ra. – Denian

0

Tôi có cùng một vấn đề, nhưng nguyên nhân khác. Ngay cả khi nó có thể không sửa chữa các vấn đề tác giả tôi đăng câu trả lời này cho tất cả những người, đọc bài đăng này sau này và có cùng một vấn đề như tôi.

Tôi đã sử dụng cấu hình trình biên dịch plugin này, loại trừ tệp package-info.java khỏi quá trình biên dịch. Sau khi loại bỏ các loại trừ tất cả mọi thứ làm việc như một say mê! Dường như JAXB bao gồm một số định nghĩa quan trọng trong các tệp này!

bị hỏng Config:

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

Working Config:

<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

Tôi đã có một vấn đề tương tự khi cố gắng triển khai một dịch vụ web xà phòng mùa xuân-based. Tôi đã thêm một gói vào số contextPaths của hạt đậu xuân org.springframework.oxm.jaxb.Jaxb2Marshaller. Vấn đề là cùng một lớp trong các gói khác được bao gồm trong cùng một contextPaths. Tôi đã thay đổi kịch bản xây dựng Ant để loại trừ các lớp khác khỏi gói mà tôi đã thêm, điều đó giải quyết được vấn đề.

Các vấn đề liên quan