2015-05-25 22 views
12

Tôi đang sử dụng jaxb để tạo các lớp java từ tệp xsd. Các xsd chứa một định nghĩa của một yếu tố trong đó nội dung là một danh sách các hằng số được xác định trong cùng một xsd như liệt kê.jaxb: ngoại lệ lớp học lạ trên danh sách enum

Khi các lớp được tạo bằng cách thực hiện tham chiếu JAXB từ oracle's jdk1.7 (v2.2.4-2), có thể lặp qua danh sách enums và gán cho chúng các biến cùng loại.

Tuy nhiên, khi các lớp được tạo bằng oracle của jdk1.8 (xây dựng 1.8.0_45-b15 - mới nhất của đăng ngày) thực hiện chiếu JAXB (v2.2.8-b130911.1802) nó không còn có thể gán các yếu tố của danh sách để biến kiểu enum.

Bất kỳ cố gắng để gán hoặc lặp bằng cách sử dụng tăng cường cho vòng kết thúc bằng một ClassCastException

java.lang.ClassCastException: java.lang.String cannot be cast to so.jaxb.enums.generated.GConstNameType 
    at so.jaxb.enums.domain.TestReader.readTest(TestReader.java:36) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309) 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) 

Danh sách chính nó là trong cả hai trường hợp tham số với kiểu enum chính xác.

Dưới đây là một mã tái tạo vấn đề đã nêu ở trên:

tập tin XSD

<?xml version="1.0" encoding="UTF-8" ?> 
<xs:schema xmlns="http://www.w3.org/2001/XMLSchema" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:tns="http://www.foo.com/xmlns/test" 
    targetNamespace="http://www.foo.com/xmlns/test" 
    attributeFormDefault="unqualified" 
    elementFormDefault="qualified"> 

    <xs:simpleType name="GConstType"> 
     <xs:list itemType="tns:GConstNameType" /> 
    </xs:simpleType> 
    <xs:simpleType name="GConstNameType"> 
     <xs:restriction base="xs:string"> 
      <xs:enumeration value="FOO" /> 
      <xs:enumeration value="BAR" /> 
      <xs:enumeration value="BAZ" /> 
     </xs:restriction> 
    </xs:simpleType> 

    <xs:complexType name="TestType"> 
     <xs:all> 
      <xs:element name="const-name-list" 
       type="tns:GConstType" minOccurs="0" maxOccurs="1" /> 
     </xs:all> 
    </xs:complexType> 

    <xs:element name="test" type="tns:TestType" /> 

</xs:schema> 

Kiểm tra tập tin XML

<?xml version="1.0" encoding="UTF-8"?> 
<t:test xmlns="http://www.w3.org/2001/XMLSchema" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:t="http://www.foo.com/xmlns/test" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 

    <t:const-name-list>FOO BAR</t:const-name-list> 

</t:test> 

đọc thử

public class TestReader { 

    @Test 
    public void readTest() throws IOException { 
     try (InputStream xml = TestReader.class 
       .getResourceAsStream("/so/jaxb/enums/resources/test.xml"); 
      InputStream xsd = TestReader.class 
       .getResourceAsStream("/so/jaxb/enums/resources/test.xsd")) { 
      TestType testType = fromXML(TestType.class, xml, xsd); 
      List<GConstNameType> constNameList = testType.getConstNameList(); 
      for(Object constName : constNameList) { 
       System.out.println(constName.getClass().getName()); 
      } 
      for(GConstNameType constName : constNameList) { 
       System.out.println(constName); 
      } 
     } 
    } 

    public static <T> T fromXML(Class<T> _class, InputStream xml, InputStream xsd) { 
     XMLStreamReader xsr = null; 
     try { 
      Source xmlSource = new StreamSource(xml); 
      Source xsdSource = new StreamSource(xsd); 
      JAXBContext jaxbContext = JAXBContext.newInstance(_class); 
      Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); 
      Schema schema = SchemaFactory 
       .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(xsdSource); 
      unmarshaller.setSchema(schema); 
      xsr = XMLInputFactory.newInstance().createXMLStreamReader(xmlSource); 
      JAXBElement<T> jaxbElement = unmarshaller.unmarshal(xsr, _class); 
      return jaxbElement.getValue(); 
     } catch (JAXBException | SAXException | XMLStreamException | FactoryConfigurationError e) { 
      throw new RuntimeException(e); 
     } finally { 
      try { 
       if(xsr != null) { 
        xsr.close(); 
       } 
      } catch(XMLStreamException e) { 
       throw new RuntimeException(e); 
      } 
     } 
    } 
} 

jdk1.7 Output

so.jaxb.enums.generated.GConstNameType 
so.jaxb.enums.generated.GConstNameType 
FOO 
BAR 

Output jdk1.8

java.lang.String 
java.lang.String 
<ClassCastException> 

Từ đầu ra ở trên rõ ràng là yếu tố của các loại java.lang.String được nhập lậu vào danh sách List<GConstNameType> hoặc Danh sách String s được đặt thay vì Danh sách GConstNameType s. Dù sao tên của các enums String từ tệp xml không được ánh xạ tới hằng số enum java.

Thời gian chạy java trong cả hai trường hợp giống nhau, đó là số jre từ số jdk1.8.

Các lệnh sử dụng cho thế hệ:

C:\Oracle\Java\jdk1.7\bin\xjc.exe D:\dev\java\Tests\src\so\jaxb\enums\resources\test.xsd -b D:\dev\java\Tests\src\so\jaxb\enums\resources -d D:\dev\java\Tests/src -p so.jaxb.enums.generated -extension 

C:\Oracle\Java\jdk1.8\bin\xjc.exe D:\dev\java\Tests\src\so\jaxb\enums\resources\test.xsd -b D:\dev\java\Tests\src\so\jaxb\enums\resources -d D:\dev\java\Tests/src -p so.jaxb.enums.generated -extension 
  • như thế nào possibles này/Điều gì đang xảy ra ở đây?
  • Định nghĩa lược đồ được hiển thị ở trên không chính xác để xác định một điều tra?
  • Cách khắc phục sự cố này mà không phải sử dụng XmlAdapter (cách hoạt động trên mọi phiên bản jdk)?

EDIT

Sự khác biệt mã chỉ giữa hai gói tạo

The only code difference between both generated packages

Loại bỏ các chú thích

@XmlSchemaType(name = "anySimpleType") 

hiển thị mã được tạo ra jdk1.8 đầy đủ chức năng.

  • Tại sao mới hơn JAXB triển khai ánh xạ enum thành anySimpleType?
+0

Bạn đã cố gắng sử dụng * * thay của * *? Có vẻ như Java8 ít khoan dung hơn về chuỗi XML có thể hoặc không thể. – medveshonok117

+0

@ medveshonok117 đã thử với 'xs: token' như được đề xuất nhưng' xcj' vẫn tạo '@XmlSchemaType (name =" anySimpleType ")' dẫn đến 'ClassCastException'. – A4L

+0

Sự cố trong dự án GH JAXB: https://github.com/gf-metro/jaxb/issues/21 –

Trả lời

2

bạn có thể thay đổi XSD của bạn để:

<xs:complexType name="TestType"> 
    <xs:sequence> 
     <xs:element name="const-name-list"> 
      <xs:simpleType> 
       <xs:list itemType="tns:GConstNameType"/> 
      </xs:simpleType> 
     </xs:element> 
    </xs:sequence> 
</xs:complexType> 

<xs:simpleType name="GConstNameType"> 
    <xs:restriction base="xs:string"> 
     <xs:enumeration value="FOO"/> 
     <xs:enumeration value="BAR"/> 
     <xs:enumeration value="BAZ"/> 
    </xs:restriction> 
</xs:simpleType> 

này đang làm việc trên java 8.

phân tích cú pháp mới có một số restrications mới.

CẬP NHẬT: cho bình luận của bạn, bạn có thể sử dụng này:

<xs:complexType name="TestType"> 
    <xs:complexContent> 
     <xs:extension base="tns:ListType"> 
      <xs:sequence/> 
     </xs:extension> 
    </xs:complexContent> 
</xs:complexType> 

<xs:complexType name="ListType"> 
    <xs:sequence> 
     <xs:element name="const-name-list"> 
      <xs:simpleType> 
       <xs:list itemType="tns:GConstNameType"/> 
      </xs:simpleType> 
     </xs:element> 
    </xs:sequence> 
</xs:complexType> 

<xs:complexType name="SecondTestType"> 
    <xs:complexContent> 
     <xs:extension base="tns:ListType"> 
      <xs:sequence/> 
     </xs:extension> 
    </xs:complexContent> 
</xs:complexType> 

<xs:simpleType name="GConstNameType"> 
    <xs:restriction base="xs:string"> 
     <xs:enumeration value="FOO"/> 
     <xs:enumeration value="BAR"/> 
     <xs:enumeration value="BAZ"/> 
    </xs:restriction> 
</xs:simpleType> 

+0

Cảm ơn câu trả lời của bạn. Trong khi điều này làm việc xung quanh vấn đề, tôi thấy nó không phải là rất thông minh để phải xác định loại nội tuyến mỗi lần nó là cần thiết hơn là xác định một lần và tham chiếu nó bằng cách sử dụng thuộc tính _type = "..." _. Bạn có thể xây dựng thêm về những _restrictions_ đó không? Có bất kỳ đặc điểm kỹ thuật mà nói rằng danh sách enum bây giờ phải được định nghĩa như thế này (imho cả hai định nghĩa là tương đương)? Trong bất kỳ cách nào, tôi sẽ gọi thực tế là tạo ra một danh sách 'String' và tiêm vào một danh sách 'GConstNameType' là rathaer một lỗi hơn là một hạn chế. Hạn chế làm việc theo cách khác xung quanh ;-) – A4L

+0

@ A4L bạn có nghĩa là định nghĩa của danh sách? – igreen

+0

có, loại đơn giản 'GConstType' trong phiên bản của bạn là ẩn danh kể từ khi được gạch chân. – A4L

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