0

There is a public service, and as far as I know, they have dozens or hundreds of clients. But I cannot generate classes from provided WSDL.

http://api.kartoteka.ru/search/v3/soap/search.wsdl

I tried wsimport from latest jdk8, and wsdl2java from axis1, axis2, cxf All apps fail. The most interesting thing is that SoapUI processed this WSDL without any errors.

I've "fixed" the first error about Duplicate keys by downloading wsdl and "patching" it, but next error is a bit complex for me:

[ERROR] undefined simple or complex type 'Error'
  line 15 of http://api.kartoteka.ru/core/v3/soap/core.wsdl

probably the first problem is also related to namespaces, and no duplicates really exist. The warning is rather verbose, but it's unclear what changes should I make.

[WARNING] src-resolve.4.1: Error resolving component 'Error'. It was detected that 'Error' has no namespace, but components with no target namespace are not referenceable from schema document 'http://api.kartoteka.ru/core/v3/soap/core.wsdl#types?schema1'. If 'Error' is intended to have a namespace, perhaps a prefix needs to be provided. If it is intended that 'Error' has no namespace, then an 'import' without a "namespace" attribute should be added to 'http://api.kartoteka.ru/core/v3/soap/core.wsdl#types?schema1'.
  line 15 of http://api.kartoteka.ru/core/v3/soap/core.wsdl#types?schema1

[WARNING] src-resolve: Cannot resolve the name 'Error' to a(n) 'type definition' component.
  line 15 of http://api.kartoteka.ru/core/v3/soap/core.wsdl#types?schema1

[WARNING] src-resolve.4.1: Error resolving component 'Error'. It was detected that 'Error' has no namespace, but components with no target namespace are not referenceable from schema document 'file:/tmp/kart/search.wsdl#types?schema3'. If 'Error' is intended to have a namespace, perhaps a prefix needs to be provided. If it is intended that 'Error' has no namespace, then an 'import' without a "namespace" attribute should be added to 'file:/tmp/kart/search.wsdl#types?schema3'.
  line 26 of file:/tmp/kart/search.wsdl#types?schema3

I found no options for namespaces in wsimport, so in general it looks like a wrong way to modify wsdl, maybe I'm missing something easy?

Oleg Gritsak
  • 548
  • 7
  • 26

1 Answers1

2

The problem is that the inline schema definitions in core.wsdl and search.wsdl do not have namespace defined for the target namespace (to which all defined elements belong to). The target namespace indicates that the vocabulary defined in this inline schema (talking about core.wsdl now only for simplicity) belong to a namespace "http://api.kartoteka.ru/core/v3/". So when the already defined vocabulary (complexType Error in this case) is referenced later on without any prefix it means that it should come from the default namespace. The default namespace is not defined in <xs:schema targetNamespace="http://api.kartoteka.ru/core/v3/">, but it should be taken from:

<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://api.kartoteka.ru/core/v3/" targetNamespace="http://api.kartoteka.ru/core/v3/">

Because as stated in the XML names spec, section 6.2, it should be inherited :

The scope of a default namespace declaration extends from the beginning of the start-tag in which it appears to the end of the corresponding end-tag, excluding the scope of any inner default namespace declarations. In the case of an empty tag, the scope is the tag itself.

A default namespace declaration applies to all unprefixed element names within its scope. Default namespace declarations do not apply directly to attribute names; the interpretation of unprefixed attributes is determined by the element on which they appear.

If there is a default namespace declaration in scope, the expanded name corresponding to an unprefixed element name has the URI of the default namespace as its namespace name. If there is no default namespace declaration in scope, the namespace name has no value. The namespace name for an unprefixed attribute name always has no value. In all cases, the local name is local part (which is of course the same as the unprefixed name itself).

I think that wsimport's behaviour is wrong as it does not take default namespace from the parent element. Adding default namespace is enough to "fix" this. So you only need to change one line for core.wsdl (line 8):

<xs:schema xmlns="http://api.kartoteka.ru/core/v3/" targetNamespace="http://api.kartoteka.ru/core/v3/">

and one line for search.wsdl (line 7):

<xs:schema xmlns="http://api.kartoteka.ru/search/v3/" targetNamespace="http://api.kartoteka.ru/search/v3/" elementFormDefault="qualified">

I am leaving other workarounds (below) which I wrote earlier but they are more complex (compared to this one) and aren't actually needed.


Maybe the simplest one is to make necessary changes to use namespaces in the embedded schema definitions.

  1. In search.wsdl make these changes (line 7 and line 26):

    <xs:schema xmlns:tns="http://api.kartoteka.ru/search/v3/" targetNamespace="http://api.kartoteka.ru/search/v3/" elementFormDefault="qualified">
    

    and

    <xs:element name="error" type="tns:Error"/>
    
  2. In core.wsdl make similar changes (line 8 and lines 15-18):

    <xs:schema xmlns:tns="http://api.kartoteka.ru/core/v3/" targetNamespace="http://api.kartoteka.ru/core/v3/">
    

    and

    <xs:element name="systemError" type="tns:Error" /> 
    <xs:element name="serviceRestriction" type="tns:Error" /> 
    <xs:element name="authorizationRestriction" type="tns:Error" /> 
    

Another way would be to define Error complexType outside of the wsdl file and import it in your core.wsdl and search.wsdl files.

  1. Create external schema file: common.xsd with contents like this:

    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
               xmlns="http://mycustomschema/common/"
               targetNamespace="http://mycustomschema/common/">
        <xs:complexType name="Error">
            <xs:sequence>
                <xs:element name="code" type="xs:positiveInteger"/>
                <xs:element name="msg" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:schema>
    
  2. Reference your custom complexType in search.wsdl:

    <xs:import namespace="http://mycustomschema/common/" schemaLocation="common.xsd"/>
    <xs:element name="sessionId" type="xs:string"/>
    <xs:element xmlns:common="http://mycustomschema/common/" name="error" type="common:Error"/>
    
  3. Reference your custom complexType in core.wsdl:

    <xs:import namespace="http://mycustomschema/common/" schemaLocation="common.xsd"/>
    <xs:element xmlns:common="http://mycustomschema/common/" name="systemError" type="common:Error" /> 
    <xs:element xmlns:common="http://mycustomschema/common/" name="serviceRestriction" type="common:Error" /> 
    <xs:element xmlns:common="http://mycustomschema/common/" name="authorizationRestriction" type="common:Error" /> 
    

One more method is to change element="error" to type="Error":

  1. Remove this line from search.wsdl:

    <xs:element name="error" type="Error"/>
    
  2. Change these lines in search.wsdl:

    <wsdl:message name="SearchError">
        <wsdl:part name="searchError" type="Error"/>
    </wsdl:message>
    <wsdl:message name="CardError">
        <wsdl:part name="cardError" type="Error"/>
    </wsdl:message>
    <wsdl:message name="ImportantFactsError">
        <wsdl:part name="importantFactsError" type="Error"/>
    </wsdl:message>
    <wsdl:message name="PledgeError">
        <wsdl:part name="pledgeError" type="Error"/>
    </wsdl:message>
    <wsdl:message name="VocabularyError">
        <wsdl:part name="vocabularyError" type="Error"/>
    </wsdl:message>
    <wsdl:message name="BoYearsRequest">
        <wsdl:part name="request" type="bo:orgBoYearsRequest"/>
    </wsdl:message>
    <wsdl:message name="BoYearsResponse">
        <wsdl:part name="response" type="bo:orgBoYearsResponse"/>
    </wsdl:message>
    <wsdl:message name="BoError">
        <wsdl:part name="boError" type="Error"/>
    </wsdl:message>
    
  3. Remove these lines from search.wsdl:

    <xs:element name="systemError" type="Error" /> 
    <xs:element name="serviceRestriction" type="Error" /> 
    <xs:element name="authorizationRestriction" type="Error" /> 
    
  4. Change these lines in search.wsdl:

    <wsdl:message name="SystemError">
        <wsdl:part name="systemError" type="Error"/>
    </wsdl:message>
    <wsdl:message name="ServiceRestriction">
        <wsdl:part name="serviceRestriction" type="Error"/>
    </wsdl:message>
    <wsdl:message name="AuthorizationRestriction">
        <wsdl:part name="authorizationRestriction" type="Error"/>
    </wsdl:message>
    

This way you can use the type defined in embedded schema definition directly and wsimport seems to understand the wsdl file this way.

Julius Zaldokas
  • 234
  • 2
  • 7
  • Julius, huge thanks for spending time on this. Unfortunately, after this error with namespaces another one arise. The most intriguing aspect of this situation for me is - who's to blame? I thought that java is very strong at SOAP field due to it's history. And so much pain with this service... – Oleg Gritsak Jun 27 '18 at 03:56
  • Next error is [ERROR] duplicate "message" entity: "SystemError" line 20 of file:/tmp/kar/core.wsdl it shows after both 1 and 2 solutions. Unfortunately there are no visible duplicates, so it's unclear what it wants :( – Oleg Gritsak Jun 27 '18 at 03:57
  • Might be that you made too many modfications to the core.wsdl file. Basically, all you need to change in core.wsdl (as compared to the original file) is line 8. Define default namespace like this: `` – Julius Zaldokas Jun 27 '18 at 07:05
  • I updated my answer with my opinion on why wsimport's behaviour (regarding namespaces) is wrong. I don't see any other problems when I try to import the wsdl file. Please, double check if you didn't make any other changes. Actually, all you need is to change two lines (line 8 in core.wsdl and line 7 in search.wsdl) by defining default namespace one more time. – Julius Zaldokas Jun 27 '18 at 07:45
  • Julius, I mean that problem with namespaces is not the only one :( Old options 1 and 2 both work. And new, short, also is OK. But after that I just get next error: [ERROR] duplicate "message" entity: "SystemError" in core.wsdl. And total number of errors is unknown :( – Oleg Gritsak Jun 27 '18 at 08:17
  • Actually, I've managed to generate classes with apache-cxf, it displayed only 2 errors (not with namespaces, but missing type and duplicate element "Value"). After patching wsdl classes were generated, but with missing methods. This situation is soo weird :( – Oleg Gritsak Jun 27 '18 at 08:19
  • I marked question as answered, because you've nicely solved the mentioned problem. Thank you! Unfortunately, it is only the first in long list. – Oleg Gritsak Jun 27 '18 at 08:22
  • Regarding the "[ERROR] duplicate "message" entity" I cannot reproduce this error. Can you post the wsimport command you are using and also the whole core.wsdl file? Regarding "duplicate element "Value", this is normal behaviour. JAXB cannot create two fields (one for attribute value, another for xs:string property) with the same name. There are case when you need to write JAXB bindings to map some elements to different names. This is such case. See this [link](https://stackoverflow.com/questions/4394134/jaxb-property-value-is-already-defined-use-jaxbproperty-to-resolve-this) for an example. – Julius Zaldokas Jun 27 '18 at 08:43
  • http://94.177.190.72/search.wsdl and http://94.177.190.72/core.wsdl , I start wsimport without options wsimport search.wsdl – Oleg Gritsak Jun 27 '18 at 09:34
  • Ok, so the problem is that it parses local core.wsdl as well as the one in the internet and so duplication arises. It happens because auth.wsdl contains the import with http URL. Actually, you can leave the original import in search.wsdl and create another file catalog.xml where you can map the url to your local file. As in: ` ` Then use: `wsimport -catalog catalog.xml search.wsdl` – Julius Zaldokas Jun 27 '18 at 10:04
  • That way, both auth.wsdl and search.wsdl will take local core.wsdl rather then the one from the internet and it should solve your problem. Then you will have to deal with other things by creating a JAXB bindings file ("Value" and later other problems which you will need to overcome by specifying different Java packages for different wsdl/xsd files). There are plenty of resources on how to do that, I hope you will be able to finally generate everything successfully. – Julius Zaldokas Jun 27 '18 at 10:14