How to set wsdl inner schema to Jaxb2Marshaller to validate each post i wold make?

后端 未结 1 1046
佛祖请我去吃肉
佛祖请我去吃肉 2021-01-28 14:38

I\'m consuming a SOAP webservice where I have to validate every xml post before call it.

So I\'m using:

  • The cxf-codegen-plugin to generate
1条回答
  •  说谎
    说谎 (楼主)
    2021-01-28 14:52

    finally I found an implementation that works for me.

    The idea is:

    • to extract the embedded schema's from the wsdl,
    • configure each schema namespace,
    • adding all posible namespaces non defined yet in it but that are defined on tag,
    • configure each schema import and locations,
    • store each schema into an implementing class of spring's Resource interface,
    • store all of them into an Resource array
    • and pass this array to the Jaxb2Marshaller through setSchema[s], instead of setSchema (as I have been doing).

    Based on the question, I had to modify the XxxxMarshallerProperties class and the applicationContext-xxxx-base.xml files, only.

    XxxxMarshallerProperties:

    @Component
    public class XxxxMarshallerProperties {
        @Autowired
        private ResourceLoader resourceLoader;
    
        /**
         * @return A new transformer.
         * @throws TransformerFactoryConfigurationError
         * @throws TransformerConfigurationException
         */
        private Transformer newTransformer()
            throws TransformerFactoryConfigurationError, TransformerConfigurationException {
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            return transformer;
        }
    
        /**
         * Load the wsdl into a dom Document. Used at:
    *     getSchemas * * @param wsdlUrl * url where the WSDL is located at * @param transformer * used to load the document * @return The wsdl dom Document * @throws ParserConfigurationException * @throws IOException * @throws TransformerException */ private Document loadWsdlDoc(URL wsdlUrl, Transformer transformer) throws ParserConfigurationException, IOException, TransformerException { DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder schemaBuilder = docFactory.newDocumentBuilder(); Document wsdlDoc = schemaBuilder.newDocument(); BufferedReader wsdlReader = new BufferedReader(new InputStreamReader(wsdlUrl.openStream())); Source source = new StreamSource(wsdlReader); transformer.transform(source, new DOMResult(wsdlDoc)); return wsdlDoc; } /** * Store into a map all namespaces defined on the wsdl. Used at:
    *     getSchemas * * @param defNode * <wsdl:definitions> dom node where to look * up. * @return A map of namespace definition attributes. Format: [(nodeName, * node)....] */ private Map getWsdlDefinedNamespaces(Element defNode) { Map namespaces = new TreeMap<>(); NamedNodeMap defNodeAtt = defNode.getAttributes(); int defNodeAttSz = defNodeAtt.getLength(); for (int attIndex = 0; attIndex < defNodeAttSz; attIndex++) { String ns = defNodeAtt.item(attIndex).getPrefix(); if ("xmlns".equals(ns)) { namespaces.put(// defNodeAtt.item(attIndex).getNodeName(), // defNodeAtt.item(attIndex)); } } return namespaces; } /** * Store into a map all the atributes present in a xsd schema node. Used at: *
    *     addDefinitionNamespaces * * @param wsdlSchemaNode * <s:schema> dom node where to look up. * @return A map of attributes. Format: [(nodeName, node)....] */ private Map getCurrentSchemaAtt(Node wsdlSchemaNode) { Map schemaXmlnss = new HashMap<>(); NamedNodeMap schemaNodeAtt = wsdlSchemaNode.getAttributes(); int schemaNodeAttSz = schemaNodeAtt.getLength(); for (int attIndex = 0; attIndex < schemaNodeAttSz; attIndex++) { String nodeAttName = schemaNodeAtt.item(attIndex).getNodeName(); Node nodeAtt = ((NamedNodeMap) schemaNodeAtt).item(attIndex); schemaXmlnss.put(nodeAttName, nodeAtt); } return schemaXmlnss; } /** * Adds all non existing namespace definition attributes to a schema node in * that schema node. If a namespace definition attribute name is found into * schema node, it's not added to the current schema node attributes. Used * at:
    *     getSchemas * * @param schemaNode * <s:schema> dom node where to add the * namespace definition attributes. * @param namespaces * map storing all namespace definition attributes. */ private void addDefinitionNamespaces(Node schemaNode, Map namespaces) { Map currSchemaAttMap = getCurrentSchemaAtt(schemaNode); for (Node xmlns : namespaces.values()) { String nodeName = xmlns.getNodeName(); if (!currSchemaAttMap.containsKey(nodeName)) { String namespaceURI = xmlns.getNamespaceURI(); String nodeValue = xmlns.getNodeValue(); ((Element) schemaNode).setAttributeNS(namespaceURI, nodeName, nodeValue); } } } /** * Update schema location by adding path. Used at:
    *     getSchemas * * @param schemaNode * <s:schema> dom node to update its * location. * @return The updated schema. */ private DOMSource updateSchemaLocationByAddingPath(Node schemaNode) { DOMSource schemaDomSource = new DOMSource(schemaNode); NodeList noteList = schemaDomSource.getNode().getChildNodes(); for (int j = 0; j < noteList.getLength(); j++) { if ("xsd:import".equals(noteList.item(j).getNodeName())) { NamedNodeMap nodeMap = noteList.item(j).getAttributes(); for (int attIndex = 0; attIndex < nodeMap.getLength(); attIndex++) { if ("schemaLocation".equals(nodeMap.item(attIndex).getNodeName())) { nodeMap.item(attIndex).setNodeValue(nodeMap.item(attIndex).getNodeValue()); } } } } return schemaDomSource; } /** * Transform a DOMSource schema into a spring's {@link Resource} to be * attached to a {@link Jaxb2Marshaller}. * * @param schemaDomSource * The schema to be transformed. * @param transformer * The transformer used. * @return A spring's {@link Resource} interface. * @throws TransformerException */ private Resource transformToResource(DOMSource schemaDomSource, Transformer transformer) throws TransformerException { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); Result result = new StreamResult(outStream); transformer.transform(schemaDomSource, result); ByteArrayResource schemaResource = new ByteArrayResource(outStream.toByteArray()); return schemaResource; } /** * Generate and retrieves all schemas contained into a wsdl file stored in * the classpath, in an {@link Resource} array, to be attached to a * {@link Jaxb2Marshaller} . * * @return An {@link Resource} array. * @throws IOException * @throws SAXException * @throws ParserConfigurationException * @throws TransformerException */ public Resource[] getSchemas() throws IOException, SAXException, ParserConfigurationException, TransformerException { Resource[] schemaResources = null; WebServiceClient wscAnnotation = Service.class.getAnnotation(WebServiceClient.class); String wsdlLocationPath = wscAnnotation.wsdlLocation(); Resource wsdlResource = resourceLoader.getResource(wsdlLocationPath); URL wsdlUri = wsdlResource.getURL(); Transformer transformer = newTransformer(); Document wsdlDoc = loadWsdlDoc(wsdlUri, transformer); NodeList schemaNodes = wsdlDoc.getElementsByTagNameNS(XMLConstants.W3C_XML_SCHEMA_NS_URI, "schema"); int nrSchemas = schemaNodes.getLength(); if (nrSchemas > 0) { Element defNode = wsdlDoc.getDocumentElement(); Map namespaces = getWsdlDefinedNamespaces(defNode); schemaResources = new Resource[nrSchemas]; for (int i = 0; i < nrSchemas; i++) { Node schemaNode = schemaNodes.item(i); addDefinitionNamespaces(schemaNode, namespaces); DOMSource schemaDomSource = updateSchemaLocationByAddingPath(schemaNode); schemaResources[i] = transformToResource(schemaDomSource, transformer); } } return schemaResources; } }

    applicationContext-xxxx-base.xml:

    
    
    
        
    
        
    
        
    
        
            
            
            
        
    
        
            
            
            
        
    
        
    
    
    
    

    Note that I'm using the Jaxb2Marshaller schemas, property (setSchemas), that allow me to set several schemas, instead of only one.

    0 讨论(0)
提交回复
热议问题