J'ai besoin de valider mes objets JAXB avant de les rassembler dans un fichier XML. Avant JAXB 2.0, on pouvait utiliser un javax.xml.bind.Validator. Mais cela a été déprécié, alors j'essaie de trouver la bonne façon de le faire. Je suis familier avec la validation au moment de marshall mais dans mon cas, je veux juste savoir si c'est valide. Je suppose que je pourrais rassembler un fichier temporaire ou une mémoire et le jeter, mais je me demande s'il existe une solution plus élégante.
Premièrement, javax.xml.bind.Validator
A été déprécié au profit de javax.xml.validation.Schema
( javadoc ). L'idée est que vous analysiez votre schéma via un javax.xml.validation.SchemaFactory
( javadoc ), et que vous injectiez cela dans le marshaller/unmarshaller.
En ce qui concerne votre question concernant la validation sans marshaling, le problème ici est que JAXB délègue réellement la validation à Xerces (ou quel que soit le processeur SAX que vous utilisez), et Xerces valide votre document en tant que flux d'événements SAX. Donc, pour valider, vous devez effectuer une sorte de marshalling.
L'implémentation à impact le plus faible serait d'utiliser une implémentation "/ dev/null" d'un processeur SAX. Le marshaling vers un OutputStream nul impliquerait toujours la génération XML, ce qui est inutile. Je suggère donc:
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(locationOfMySchema);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setSchema(schema);
marshaller.marshal(objectToMarshal, new DefaultHandler());
DefaultHandler
supprimera tous les événements et l'opération marshal()
lèvera une exception JAXBException si la validation par rapport au schéma échoue.
Vous pouvez utiliser un javax.xml.bind.util.JAXBSource
( javadoc ) et un javax.xml.validation.Validator
( javadoc ), ajoutez une implémentation de org.xml.sax.ErrorHandler
( javadoc ) et procédez comme suit:
import Java.io.File;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.util.JAXBSource;
import javax.xml.validation.*;
public class Demo {
public static void main(String[] args) throws Exception {
Customer customer = new Customer();
customer.setName("Jane Doe");
customer.getPhoneNumbers().add(new PhoneNumber());
customer.getPhoneNumbers().add(new PhoneNumber());
customer.getPhoneNumbers().add(new PhoneNumber());
JAXBContext jc = JAXBContext.newInstance(Customer.class);
JAXBSource source = new JAXBSource(jc, customer);
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new File("customer.xsd"));
Validator validator = schema.newValidator();
validator.setErrorHandler(new MyErrorHandler());
validator.validate(source);
}
}
Pour plus d'informations, consultez mon blog
Voilà comment nous l'avons fait. J'ai dû trouver un moyen de valider le fichier xml par rapport à un xsd correspondant à la version du xml car nous avons de nombreuses applications utilisant différentes versions du contenu xml.
Je n'ai pas vraiment trouvé de bons exemples sur le net et j'ai finalement fini avec ça. J'espère que cela vous aidera.
ValidationEventCollector vec = new ValidationEventCollector();
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
URL xsdURL = getClass().getResource("/xsd/" + xsd);
Schema schema = sf.newSchema(xsdURL);
//You should change your jaxbContext here for your stuff....
Unmarshaller um = (getJAXBContext(NotificationReponseEnum.NOTIFICATION, notificationWrapper.getEnteteNotification().getTypeNotification()))
.createUnmarshaller();
um.setSchema(schema);
try {
StringReader reader = new StringReader(xml);
um.setEventHandler(vec);
um.unmarshal(reader);
} catch (javax.xml.bind.UnmarshalException ex) {
if (vec != null && vec.hasEvents()) {
erreurs = new ArrayList < MessageErreur > ();
for (ValidationEvent ve: vec.getEvents()) {
MessageErreur erreur = new MessageErreur();
String msg = ve.getMessage();
ValidationEventLocator vel = ve.getLocator();
int numLigne = vel.getLineNumber();
int numColonne = vel.getColumnNumber();
erreur.setMessage(msg);
msgErreur.setCode(ve.getSeverity())
erreur.setException(ve.getLinkedException());
erreur.setPosition(numLigne, numColonne);
erreurs.add(erreur);
logger.debug("Erreur de validation xml" + "erreur : " + numLigne + "." + numColonne + ": " + msg);
}
}
}