Validace vstupu webových služeb


Potřeboval jsem validovat vstup webové služby na základě xsd šablony – a to jak typy, tak patterny a potřeboval jsem to pokud možno obecně a jednoduše. Postupně jsem se dobral řešení, které se pokusím níže popsat.

Měl jsem zadaný wsdl dokument, k němu definici typů v xsd a příkaz použít jax-ws. Takže jsem provedl wsimport a začal zkoušet. Na komplexní typy byl pomocí jaxb vytvořen binding, takže mi vznikla trochu poschoďovější struktura, která ovšem nebrala v úvahu definované simple typy a prostě je převedla na podobné typy jazyka Java. Pokud jsem tento projekt spustil na serveru, patterny těchto typů prostě zmizely a vygenerované xsd bylo úplně jiné, wsdl se jakž-takž podobalo. Stačilo ovšem přidat parametr k anotaci WebService, který specifikoval cestu k originálnímu wsdl.

[sourcecode language=“java“]@WebService(
name = "myServiceSei",
targetNamespace = "http://www.shmoula.cz/schema/myservice",
wsdlLocation = "META-INF/wsdl/myService.wsdl"
)[/sourcecode]

V tomto okamžiku jsem měl ovšem problém s bindingem, který jsem původně přiřazoval nějaké chybičce ve jmenných prostorech, a ten způsoboval, že mi služba předávala null hodnoty. Nakonec se ukázalo, že v zadaném wsdl se vyskytuje zpráva z názvem doSomeStuffRequest, který se kryl s elementem ve vlastním těle této zprávy (navíc jax-ws přidává postfix Request automaticky), takže stačilo tento název změnit a vše bylo v pořádku a já byl o krok blíže k validování.

První, co mě napadlo, bylo použití anotace SchemaValidation, tak jsem ji použil. Služba se ovšem chovala, jako by tam tato anotace vůbec nebyla a prošlo naprosto všechno. Tudíž nastoupilo řešení číslo dvě – použítí Marshalleru, který by měl při nesrovnalostech skončit s výjimkou. Končil, ovšem s výjimkou jinou, než jsem čekal.

unable to marshal type "cz.foo.bar.DoSomeStuffRequest" as an element because it is missing an @XmlRootElement annotation

Důvody jejího vzniku pěkně rozebral Kohsuke Kawaguchi ve svém blogpostu a protože jsem nechtěl do všech typů cpát XmlRootElement, řídil jsem se jí a dobral se funkčnosti – opravdu mi to validuje! Ještě jsem si s řešením trochu pohrál a především využil vygenerované ObjectFactory, abych nemusel vytvářet vlastní JAXBElement. Výsledek vypadá (zhruba) následovně a funguje na výbornou.

[sourcecode language=“java“]@WebMethod
public void doSomeStuff(DoSomeStuffRequest serviceParameters) {

ObjectFactory of = new ObjectFactory();
JAXBElement<DoSomeStuffRequest> element = of.createParcelImportRequest(serviceParameters);
SchemaFactory sf = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);

try {
URLClassLoader cl = (URLClassLoader) getClass().getClassLoader();
URL url = cl.findResource("META-INF/wsdl/myService.xsd");

Schema schema = sf.newSchema(url);

JAXBContext context = JAXBContext.newInstance(DoSomeStuffRequest.class);

Marshaller marshaller = context.createMarshaller();
marshaller.setSchema(schema);

marshaller.marshal(element, new DefaultHandler());

} catch (SAXException e) {
e.printStackTrace();
} catch (JAXBException e) {
e.printStackTrace();
}
}
[/sourcecode]

PS. Nic to ovšem nemění na tom, že SOAP není mrtvý, ale nemrtvý (a vůbec že je to fuj)!


Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *