2009-04-01 45 views
39

Đang cố gắng để vượt qua một lớp diễn viên ngoại lệ ở đây:Class Cast Ngoại lệ khi cố gắng unmarshall xml?

FooClass fooClass = (FooClass) unmarshaller.unmarshal(inputStream); 

ném ngoại lệ này:

java.lang.ClassCastException: javax.xml.bind.JAXBElement 

Tôi không hiểu điều này - như lớp được tạo ra bởi các công cụ xjc.bat - và các lớp mà nó tạo ra tôi đã không bị thay đổi chút nào - vì thế không có vấn đề gì ở đây - người unmarshaller thực sự sẽ đưa tôi trở lại một lớp có thể được chuyển sang FooClass.

Bất kỳ ý tưởng nào về những gì tôi đang làm sai?

Trả lời

93

FooClass có chú thích XmlRootElement không? Nếu không, hãy thử:

Source source = new StreamSource(inputStream); 
JAXBElement<FooClass> root = unmarshaller.unmarshal(source, FooClass.class); 
FooClass foo = root.getValue(); 

Dựa trên số Unofficial JAXB Guide.

+2

Tại sao có JAXB trình biên dịch không đặt một chú thích XmlRootElement trong lớp của tôi trong linh sam t nơi - như tôi không thể tìm thấy một. Mã của bạn hoạt động - nhưng tôi muốn biết thêm - tức là tại sao mã hoạt động? – Vidar

+0

Vượt qua - Tôi chỉ điều tra đủ xa để giải quyết vấn đề ban đầu :) Tôi không thực sự biết nhiều về JAXB ... –

+0

Công bằng - nhưng cảm ơn vì đã giúp tôi. – Vidar

1

Bạn có chắc chắn FooClass là phần tử gốc của nguồn đầu vào xml mà bạn đã truyền không? Unmarshall sẽ trả về một đối tượng của phần tử gốc được tạo bởi xjc.

3

Tôi sẽ xem tệp XML và đảm bảo rằng nó gần như những gì bạn mong đợi để xem.

Tôi cũng muốn tạm thời thay đổi mã để:

Object o = unmarshaller.unmarshal(inputStream); 
System.out.println(o.getClass()); 

Nếu một failes đầu tiên sau đó các diễn viên lớp đang xảy ra bên trong phương pháp unmarshal, nếu nó thành công thì bạn sẽ nhìn thấy lớp học thực tế rằng bạn đang quay trở lại và sau đó tìm ra lý do tại sao nó không phải là những gì bạn mong đợi nó được.

9

Để có giải thích đầy đủ, hãy đọc this article. Nó chỉ ra rằng XSD của bạn phải được thiết lập đúng, tức là phải có một số yếu tố gốc bao gồm tất cả các yếu tố khác.

XJC cố gắng đặt @XmlRootElement chú thích trên lớp mà chúng tôi tạo từ loại phức tạp. Điều kiện chính xác có phần xấu xí, nhưng ý tưởng cơ bản là nếu chúng ta có thể bảo đảm tĩnh rằng một loại phức tạp sẽ không được sử dụng bởi nhiều tên thẻ khác nhau, chúng tôi đặt @XmlRootElement.

+0

Liên kết mà bạn trỏ đến là câu trả lời hay nhất –

3

Chúng tôi đã dành quá nhiều giờ bồn chồn với lớp nhà máy JAXB để đáp ứng unmarshaller. Chúng tôi đã học được rằng sử dụng unmarshaller mà không cần gọi nhà máy đối tượng do JAXB tạo ra hoạt động ổn. Hy vọng mã mẫu sẽ làm cho người khác thất vọng:

System.out.println("Processing generic-type unmarshaller: "); 
MessageClass mcObject = unmarshalXml(MessageClass.class, msgQryStreamSource, 
    NAMESPACE + "." + "MessageClass"); 

public static <T> T unmarshalXml(Class<T> clazz, StreamSource queryResults, 
    String contextNamespace) 
    { 
     T resultObject = null; 
     try { 
      //Create instance of the JAXBContext from the class-name 
      JAXBContext jc; 
      jc = JAXBContext.newInstance(Class.forName(clazz.getName())); 
      Unmarshaller u = jc.createUnmarshaller(); 
      resultObject = clazz.cast(u.unmarshal(queryResults)); 
      } 
       //Put your own error-handling here. 
     catch(JAXBException e) 
     { 
      e.printStackTrace(); 
     } 
     catch (ClassCastException e) 
     { 
      e.printStackTrace(); 
     } 
     catch (ClassNotFoundException e) 
     { 
      e.printStackTrace(); 
     } 
     return clazz.cast(resultObject); 
    } 
0

Chỉ định @XmlRootElement (name = "specifyName", namespace = "namespace") để chuyển đối tượng.

2

Xây dựng trên các bản xem trước câu trả lời từ đồng nghiệp, chỉ trong trường hợp bất kỳ ai vẫn đang tìm kiếm câu trả lời.

tôi đã vấn đề có yếu tố gốc của chương trình của tôi được định nghĩa là:

<schema> 
    <element name="foo" type="bar" /> 
    <complexType name="bar" /> 
</schema> 

Và do đó tôi đã nhận được một ngoại lệ Cast tại địa chỉ:

try {    
     javax.xml.bind.JAXBContext jaxbCtx = javax.xml.bind.JAXBContext.newInstance(mobilityConfigType.getClass().getPackage().getName());    
     javax.xml.bind.Unmarshaller unmarshaller = jaxbCtx.createUnmarshaller(); 
     File f = FileUtil.toFile(this.getPrimaryFile());    
     mobilityConfigType = (MobilityModelConfigType)unmarshaller.unmarshal(FileUtil.toFile(this.getPrimaryFile())); 
    } catch (javax.xml.bind.JAXBException ex) {    
     java.util.logging.Logger.getLogger("global").log(java.util.logging.Level.SEVERE, null, ex); //NOI18N 
    } 

Những gì tôi đã làm là phải thay đổi dòng đầu tiên của khối thử tới:

javax.xml.bind.JAXBContext jaxbCtx = javax.xml.bind.JAXBContext.newInstance(mobilityConfigType.getClass().getName()); 

Điều đó giải quyết được vấn đề cho tôi.

12

Sử dụng JAXBIntrospector trên JAXBElement để có được những schemaObject như >>

JAXBContext jaxbContext = JAXBContext.newInstance(Class.forName(className)); 
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); 
Object schemaObject = JAXBIntrospector.getValue(unmarshaller.unmarshal(new ByteArrayInputStream(xmlString.getBytes()))); 

Tham khảo: when does JAXB unmarshaller.unmarshal returns a JAXBElement<MySchemaObject> or a MySchemaObject?

+3

Giải pháp này chỉ đơn giản và hoạt động tốt cho dàn diễn viên – maoanz

+0

Cảm ơn bạn. Nó cũng là một giải pháp chung. –

+1

Và sau đó, những gì tôi phải làm với schemaObject này? – Line

0

Tôi cũng gặp phải những "Javax.xml.bind.JAXBElement không thể được đúc để" lỗi và thấy giải pháp rất đơn giản này:

FooClass fooClass = (FooClass) ((JAXBElement) u.unmarshal(new File("xml/foo.xml"))).getValue(); 

Vì, rõ ràng, một đối tượng kiểu JAXBElement được trả lại, bạn cần phải định kiểu giá trị thay thế.

Nguồn: https://forums.oracle.com/thread/1625944

1

Đôi khi bạn có một định nghĩa XSD với nhiều yếu tố gốc khác nhau (ví dụ XSD định nghĩa trong WSDL) và trong trường hợp đó các lớp được tạo ra đang thiếu @XmlRootElement. Vì vậy, như người sử dụng mbrauh đã viết bạn phải có được giá trị của JAXBElement. Trong trường hợp của tôi, tôi đã sử dụng:

FooClass request = ((JAXBElement<FooClass>) marshaller.unmarshal(new StreamSource(classPathResource.getInputStream()))).getValue(); 

Vì vậy, sử dụng generics bạn có thể dễ dàng tránh việc nhập kiểu kép.

11

Tôi đã gặp phải vấn đề tương tự ngày hôm nay, đã xem câu trả lời ở đây, đã thực hiện một số nghiên cứu và cho tôi thấy rằng giải pháp chung nhất là sử dụng JAXBIntrospector. Do đó -

FooClass fooClass = (FooClass) unmarshaller.unmarshal(inputStream); 

nên được viết như

FooClass fooClass = (FooClass) JAXBIntrospector.getValue(unmarshaller.unmarshal(inputStream)); 

Hoặc thậm chí tốt hơn, để làm cho nó chung chung hơn -

T t = (T) JAXBIntrospector.getValue(unmarshaller.unmarshal(inputStream)); 
0

Hãy thử điều này:

JAXBContext jc = JAXBContext.newInstance(Foo.class); 
Unmarshaller unmarshaller = jc.createUnmarshaller(); 
JAXBElement element = (JAXBElement) unmarshaller.unmarshal(new StringReader(xmlString)); 
Foo foo = (Foo)element; 
Các vấn đề liên quan