2010-04-08 11 views
13

używam JAXB dla moich konfiguracji aplikacjijak mogę wycofać w JAXB i cieszyć się sprawdzanie poprawności schematu bez używania wyraźnej plik schematu

czuję, że robię coś naprawdę krzywy i szukam sposobu na nie potrzebujesz rzeczywistego pliku lub tej transakcji.

Jak widać w kodzie I:

1.Create schemat do pliku z mojego JaxbContext (z mojej klasy adnotacji faktycznie) 2.Set ten plik schematu w celu umożliwienia prawdziwej walidacji kiedy 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(...); 

nie każdy z was wie, w jaki sposób można sprawdzić poprawność JAXB bez konieczności tworzenia pliku schematu, który siedzi w moim komputerze?

Czy muszę utworzyć schemat sprawdzania poprawności, wygląda na zbędny, gdy otrzymam go przez JaxbContect.generateSchema?

Jak to zrobić?

+0

Dlaczego nie czytasz schematu ze źródła classpath? – lexicore

+0

Nie jestem pewien, czy rozumiem, czy możesz rozwinąć? – ekeren

+0

Mogę załadować mój plik schematu z mojej ścieżki klas, ale staram się unikać tworzenia pliku schematu, jak widać powyżej, tworzę plik i używając go po chwili mogę go usunąć po skończeniu układania. Czy brakuje tu jakiegoś dużego obrazu? Dziękuję za pomoc. – ekeren

Odpowiedz

13

Odnośnie rozwiązania Ekeren za wyżej, to nie jest dobry pomysł, aby użyć PipedOutputStream/PipedInputStream w jednym wątku, abyście nie przepełnić bufor i przyczyny impas. ByteArrayOutputStream/ByteArrayInputStream działa, ale jeśli twoje klasy JAXB generują wiele schematów (w różnych przestrzeniach nazw), potrzebujesz wielu źródeł StreamSources.

skończyło się tak:

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

Dzięki, zmieniłem również moje rozwiązanie na byteArrayInputStream, ale nie wiedziałem o wielu schematach – ekeren

+1

@seanf. Twoje rozwiązanie działa dobrze, jednak sekwencja wygenerowanych wyników nie jest zgodna z kolejnością zależności. tj: out [0] może być zależne od outów [1]. W związku z tym podczas tworzenia newSchema (źródeł), nie powiedzie się, ponieważ nie znajduje niezbędne zależności określone przed użyciem. Czy istnieje sposób na zapewnienie, że zamówienie jest takie samo, jak jest wymagane w zależnościach? (tj: out [1] jest generowany przed outami [0])? Zobacz mój wątek na ten temat na http://stackoverflow.com/q/8842047/827480. –

1

Uważam, że wystarczy ustawić ValidationEventHandler na urządzeniu unmarshaller. Coś takiego:

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

I w kodzie:

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

Dziękuję za odpowiedź, jeśli chodzi o zrozumienie. Kiedy rozpiszę bez schematu, efektywnie nie sprawdzasz poprawności kodu XML. na przykład adnotacja @XmlElement (required = true) nie zostanie zweryfikowana bez schematu. czy się mylę? – ekeren

+0

Założono, że masz schemat na początek i wygenerowałeś swój obiekt JAXB z niego przy pomocy xjc. Czy tak nie jest? Nawet jeśli tak nie jest, wierzę, że unmarshaller może nadal sprawdzać poprawność, o ile wszystkie elementy są poprawnie opisane. –

+0

Nie zacząłem od klasy z adnotacjami, a nie schematu. Mogę utworzyć schemat poza klasą przy użyciu wywołania generateSchema w JaxbContext. Problem polega na tym, że jeśli nie dostarczę schematu, niemagodna walidacja jest słaba. Ostrzega przed nieoczekiwanymi elementami, ale nie ostrzega o duplikowaniu elementów i wymaganiach na przykład. – ekeren

1

miałem dokładnie problem i znalazł rozwiązanie w kodzie źródłowym Apache Axis 2:

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

i po tym, jak uzyskał listę DOMResults reprezentujący schematy, będziesz musiał przekształcić je w obiekty DOMSource, zanim będziesz mógł je wprowadzić do generatora schematów. Ten drugi etap może wyglądać tak:

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

Jeśli używasz Maven pomocą jaxb2-maven-plugin może pomóc. Generuje schematy w fazie generowania zasobów.

Powiązane problemy