2010-04-08 19 views
13

Tôi đang sử dụng jaxb cho các cấu hình ứng dụng của tôilàm thế nào tôi có thể unmarshall trong jaxb và tận hưởng xác nhận sơ đồ mà không cần sử dụng một file schema rõ ràng

tôi cảm thấy như tôi đang làm một cái gì đó thực sự quanh co và tôi đang tìm kiếm một cách để không cần một tập tin thực tế hoặc giao dịch này.

Như bạn thấy trong mã của tôi:

1.create một schema vào một tập tin từ JaxbContext của tôi (từ chú thích lớp học của tôi thực sự) 2.Set tập tin giản đồ này để cho phép xác nhận đúng khi tôi unmarshal

JAXBContext context = JAXBContext.newInstance(clazz); 
Schema mySchema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(schemaFile); 
jaxbContext.generateSchema(new MySchemaOutputResolver()); // ultimately creates schemaFile 
Unmarshaller u = m_context.createUnmarshaller(); 
u.setSchema(mySchema); 
u.unmarshal(...); 

Bạn có biết cách xác thực jaxb mà không cần tạo tệp sơ đồ nằm trong máy tính của mình không?

Tôi có cần phải tạo lược đồ để xác thực không, có vẻ như thừa khi tôi nhận được nó bằng JaxbContect.generateSchema?

Bạn làm như thế nào?

+0

Tại sao bạn không đọc lược đồ từ tài nguyên classpath? – lexicore

+0

Tôi không chắc chắn tôi hiểu, bạn có thể xây dựng? – ekeren

+0

Tôi có thể tải tệp lược đồ từ đường dẫn lớp của mình nhưng tôi đang cố gắng tránh tạo tệp sơ đồ, như bạn có thể thấy ở trên tôi đang tạo tệp và sử dụng tệp đó sau một giây tôi thực sự có thể xóa tệp đó sau khi kết thúc marshaling. Tôi có thiếu một số bức tranh lớn ở đây không? Cảm ơn sự giúp đỡ của bạn – ekeren

Trả lời

13

Về giải pháp ekeren của trên, nó không phải là một ý tưởng tốt để sử dụng PipedOutputStream/PipedInputStream trong một chủ đề duy nhất, kẻo bạn tràn bộ đệm và nguyên nhân bế tắc. ByteArrayOutputStream/ByteArrayInputStream hoạt động, nhưng nếu các lớp JAXB của bạn tạo ra nhiều lược đồ (trong các không gian tên khác nhau), bạn cần nhiều StreamSources.

tôi đã kết thúc với điều này:

JAXBContext jc = JAXBContext.newInstance(Something.class); 
final List<ByteArrayOutputStream> outs = new ArrayList<ByteArrayOutputStream>(); 
jc.generateSchema(new SchemaOutputResolver(){ 
    @Override 
    public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException { 
     ByteArrayOutputStream out = new ByteArrayOutputStream(); 
     outs.add(out); 
     StreamResult streamResult = new StreamResult(out); 
     streamResult.setSystemId(""); 
     return streamResult; 
    }}); 
StreamSource[] sources = new StreamSource[outs.size()]; 
for (int i=0; i<outs.size(); i++) { 
    ByteArrayOutputStream out = outs.get(i); 
    // to examine schema: System.out.append(new String(out.toByteArray())); 
    sources[i] = new StreamSource(new ByteArrayInputStream(out.toByteArray()),""); 
} 
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
m.setSchema(sf.newSchema(sources)); 
m.marshal(docs, new DefaultHandler()); // performs the schema validation 
+0

Cảm ơn, tôi cũng đã thay đổi giải pháp của mình thành byteArrayInputStream nhưng tôi không biết về nhiều lược đồ – ekeren

+1

@seanf. Giải pháp của bạn hoạt động tốt, tuy nhiên chuỗi kết quả được tạo không khớp với thứ tự phụ thuộc. tức là: outs [0] có thể phụ thuộc vào outs [1]. Do đó, khi tạo một newSchema (nguồn), nó không thành công vì nó không tìm thấy các phụ thuộc cần thiết được xác định trước khi sử dụng. Có cách nào để đảm bảo rằng thứ tự giống như được yêu cầu trong các phụ thuộc không? (tức là: outs [1] được tạo ra trước khi outs [0])? Xem chuỗi của tôi về vấn đề này tại http://stackoverflow.com/q/8842047/827480. –

1

Tôi tin rằng bạn chỉ cần đặt một số ValidationEventHandler trên trình gỡ xếp hạng của mình. Một cái gì đó như thế này:

public class JAXBValidator extends ValidationEventCollector { 
    @Override 
    public boolean handleEvent(ValidationEvent event) { 
     if (event.getSeverity() == event.ERROR || 
      event.getSeverity() == event.FATAL_ERROR) 
     { 
      ValidationEventLocator locator = event.getLocator(); 
      // change RuntimeException to something more appropriate 
      throw new RuntimeException("XML Validation Exception: " + 
       event.getMessage() + " at row: " + locator.getLineNumber() + 
       " column: " + locator.getColumnNumber()); 
     } 

     return true; 
    } 
} 

Và trong mã của bạn:

Unmarshaller u = m_context.createUnmarshaller(); 
u.setEventHandler(new JAXBValidator()); 
u.unmarshal(...); 
+0

Cảm ơn phản hồi của bạn, theo như hiểu Khi unmarshalling mà không có một lược đồ bạn có hiệu quả không xác nhận hợp lệ XML. ví dụ: chú thích @XmlElement (required = true) sẽ không được xác thực mà không có lược đồ. Liệu tôi có sai? – ekeren

+0

Tôi đã giả định rằng bạn đã có một lược đồ để bắt đầu và tạo đối tượng JAXB của bạn từ nó với xjc. đây không phải là trường hợp à? Mặc dù nó không phải là mặc dù, tôi tin rằng unmarshaller vẫn có thể xác nhận miễn là tất cả các yếu tố được chú thích một cách chính xác. –

+0

Tôi chưa bắt đầu với một lớp chú thích và không phải là một lược đồ. Tôi có thể tạo lược đồ ra khỏi lớp bằng cách sử dụng lệnh generateSchema trên JaxbContext. Vấn đề là nếu tôi không cung cấp một xác nhận hợp lệ lược đồ là người nghèo. Nó cảnh báo về các phần tử không mong muốn nhưng không cảnh báo về các phần tử sao chép và các phần tử được yêu cầu chẳng hạn. – ekeren

1

tôi đã có vấn đề chính xác và tìm ra giải pháp trong Apache Axis 2 mã nguồn:

protected List<DOMResult> generateJaxbSchemas(JAXBContext context) throws IOException { 
    final List<DOMResult> results = new ArrayList<DOMResult>(); 
    context.generateSchema(new SchemaOutputResolver() { 
     @Override 
     public Result createOutput(String ns, String file) throws IOException { 
      DOMResult result = new DOMResult(); 
      result.setSystemId(file); 
      results.add(result); 
      return result; 
     } 
    }); 
    return results; 
} 

và sau khi bạn đã mua danh sách các DOMResults đại diện cho các lược đồ, bạn sẽ cần phải chuyển đổi chúng thành các đối tượng DOMSource trước khi bạn có thể nạp chúng vào một trình tạo lược đồ. Bước thứ hai này có thể giống như thế này:

Unmarshaller u = myJAXBContext.createUnmarshaller(); 
List<DOMSource> dsList = new ArrayList<DOMSource>(); 
for(DOMResult domresult : myDomList){ 
    dsList.add(new DOMSource(domresult.getNode())); 
} 
String schemaLang = "http://www.w3.org/2001/XMLSchema"; 
SchemaFactory sFactory = SchemaFactory.newInstance(schemaLang); 
Schema schema = sFactory.newSchema((DOMSource[]) dsList.toArray(new DOMSource[0])); 
u.setSchema(schema);    
0

Nếu bạn sử dụng maven sử dụng jaxb2-maven-plugin có thể giúp bạn. Nó tạo ra các lược đồ trong giai đoạn tạo tài nguyên.

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