ant2009
ant2009

Reputation: 22556

consuming xml webservice using retrofit Parameter `soap12:Body` does not have a match in class

Android Studio 3.4

I am testing the HolidayService2 endpoint and I want to consume that endpoint using retrofit.

This is the request endpoint:

POST /HolidayService_v2/HolidayService2.asmx HTTP/1.1
Host: www.holidaywebservice.com
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
  <soap12:Body>
    <GetCountriesAvailable xmlns="http://www.holidaywebservice.com/HolidayService_v2/" />
  </soap12:Body>

and the response endpoint:

<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
  <soap12:Body>
    <GetCountriesAvailableResponse xmlns="http://www.holidaywebservice.com/HolidayService_v2/">
      <GetCountriesAvailableResult>
        <CountryCode />
        <CountryCode />
      </GetCountriesAvailableResult>
    </GetCountriesAvailableResponse>
  </soap12:Body>
</soap12:Envelope>

The classes I have created for the request is:

@Root(name = "Envelope")
@NamespaceList(value = [
    Namespace(prefix = "xsi", reference = "http://www.w3.org/2001/XMLSchema-instance"),
    Namespace(prefix = "xsd", reference = "http://www.w3.org/2001/XMLSchema"),
    Namespace(prefix = "soap12", reference = "http://www.w3.org/2003/05/soap-envelope")
])
data class CountriesAvailableRequestEnvelope(
    @Element(name = "Body", required = false) val countriesAvailableRequest: CountriesAvailableRequest)

@Root(name = "GetCountriesAvailable", strict = false)
@NamespaceList(value = [
Namespace(reference = "http://www.holidaywebservice.com"),
Namespace(reference="http://www.w3.org/2003/05/soap-envelope")])
data class CountriesAvailableRequest(
    @Element(name = "GetCountriesAvailable", required = false) val code: String)

And for the response classes I have done the following:

@Root(name = "Envelope")
@NamespaceList(value = [
    Namespace(prefix = "xsi", reference = "http://www.w3.org/2001/XMLSchema-instance"),
    Namespace(prefix = "xsd", reference = " http://www.w3.org/2001/XMLSchema"),
    Namespace(prefix = "soap12", reference = "http://www.w3.org/2003/05/soap-envelope")])
data class CountriesAvailableResponseEnvelope(
    @Element(required = false, name = "Body") val countryCode: CountryCode)

@Root(name = "Body", strict = false)
@Namespace(reference="http://www.w3.org/2003/05/soap-envelope")
data class CountryCode(
    @Element(name = "description", required = false) val description: String?,
    @Element(name = "code", required = false) val code: String?)

This is the first time I am consuming web service and parsing xml. However, I am not sure if my classes I have setup reflect the xml.

This is my endpoint:

interface WebServices {
    @Headers("Content-Type: text/xml")
    @POST("/HolidayService_v2/HolidayService2.asmx")
    fun getAvailableCountries(@Body countriesAvailableRequest: CountriesAvailableRequestEnvelope): Observable<CountriesAvailableResponseEnvelope>
}

For calling the endpoint using rxJava:

fun requestFromWebService() {    webServices.getAvailableCountries(CountriesAvailableRequestEnvelope(CountriesAvailableRequest("UK")))
            .subscribeOn(Schedulers.io())
            .observeOn(Schedulers.trampoline())
            .subscribeWith(object : Observer<CountriesAvailableResponseEnvelope> {
                override fun onComplete() {
                    println("onComplete")
                }

                override fun onNext(t: CountriesAvailableResponseEnvelope) {
                    println(t.countryCode)
                }

                override fun onError(e: Throwable) {
                    println(e.message)
                }
            })
    }

My retrofit setup looks like this:

  @Reusable
    @Provides
    fun provideRetrofit(context: Context, okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .baseUrl(http://www.holidaywebservice.com)
            .client(okHttpClient)
            .addConverterFactory(SimpleXmlConverterFactory.createNonStrict(Persister(AnnotationStrategy())))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build()
    }

Not sure if this is the reason why but I get this message in OnError:

I/System.out: org.simpleframework.xml.core.ConstructorException: Parameter 'soap12:Body' does not have a match in class nz.org.westforce.data.entities.holidaytest.CountriesAvailableRequestEnvelope

Many thanks for any suggestions

Upvotes: 6

Views: 1241

Answers (3)

fancyyou
fancyyou

Reputation: 965

request

@Root(name = "soap:Envelope")
@NamespaceList(
    value = [
        Namespace(prefix = "xsi", reference = "http://www.w3.org/2001/XMLSchema-instance"),
        Namespace(prefix = "xsd", reference = "http://www.w3.org/2001/XMLSchema"),
        Namespace(prefix = "soap", reference = "http://www.w3.org/2003/05/soap-envelope")
    ]
)
class CountriesAvailableRequestEnvelope(
    @field:Path("soap:Body")
    @field:Element(name ="GetCountriesAvailable")
    @param:Element(name ="GetCountriesAvailable")
    @field:Namespace(reference = "http://www.holidaywebservice.com/HolidayService_v2/")
    val getCountries: String = ""
)

use

val result = webServices.getAvailableCountries(CountriesAvailableRequestEnvelope())
...

response

@Root(name = "soap:Envelope")
@NamespaceList(
    value = [
        Namespace(prefix = "xsi", reference = "http://www.w3.org/2001/XMLSchema-instance"),
        Namespace(prefix = "xsd", reference = " http://www.w3.org/2001/XMLSchema"),
        Namespace(prefix = "soap", reference = "http://www.w3.org/2003/05/soap-envelope")]
)
class CountriesAvailableResponseEnvelope {
    @field:Path("soap:Body")
    @field:Element(name = "GetCountriesAvailableResponse")
    @field:Namespace(reference = "http://www.holidaywebservice.com/HolidayService_v2/")
    var response: GetCountriesAvailableResponse? = null
}

@Element
class GetCountriesAvailableResponse {
    var GetCountriesAvailableResult: List<CountryCode>? = null
}

class CountryCode {
    @field:Element(name = "Description")
    var description: String? = null
    @field:Element(name = "Code")
    var code: String? = null
}

logcat

2019-04-08 12:00:23.989 22722-22748/nz.org.westforce.mobileui D/OkHttp: --> POST http://www.holidaywebservice.com/HolidayService_v2/HolidayService2.asmx
2019-04-08 12:00:23.989 22722-22748/nz.org.westforce.mobileui D/OkHttp: Content-Type: text/xml
2019-04-08 12:00:23.989 22722-22748/nz.org.westforce.mobileui D/OkHttp: Content-Length: 329
2019-04-08 12:00:23.989 22722-22748/nz.org.westforce.mobileui D/OkHttp: <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
2019-04-08 12:00:23.989 22722-22748/nz.org.westforce.mobileui D/OkHttp:    <soap:Body>
2019-04-08 12:00:23.989 22722-22748/nz.org.westforce.mobileui D/OkHttp:       <GetCountriesAvailable xmlns="http://www.holidaywebservice.com/HolidayService_v2/"></GetCountriesAvailable>
2019-04-08 12:00:23.989 22722-22748/nz.org.westforce.mobileui D/OkHttp:    </soap:Body>
2019-04-08 12:00:23.989 22722-22748/nz.org.westforce.mobileui D/OkHttp: </soap:Envelope>
2019-04-08 12:00:23.990 22722-22748/nz.org.westforce.mobileui D/OkHttp: --> END POST (329-byte body)
2019-04-08 12:00:24.363 22722-22748/nz.org.westforce.mobileui D/OkHttp: <-- 200 OK http://www.holidaywebservice.com/HolidayService_v2/HolidayService2.asmx (372ms)
2019-04-08 12:00:24.363 22722-22748/nz.org.westforce.mobileui D/OkHttp: Cache-Control: private, max-age=0
2019-04-08 12:00:24.363 22722-22748/nz.org.westforce.mobileui D/OkHttp: Content-Type: application/soap+xml; charset=utf-8
2019-04-08 12:00:24.363 22722-22748/nz.org.westforce.mobileui D/OkHttp: Server: Microsoft-IIS/8.5
2019-04-08 12:00:24.363 22722-22748/nz.org.westforce.mobileui D/OkHttp: X-AspNet-Version: 4.0.30319
2019-04-08 12:00:24.363 22722-22748/nz.org.westforce.mobileui D/OkHttp: X-Powered-By: ASP.NET
2019-04-08 12:00:24.363 22722-22748/nz.org.westforce.mobileui D/OkHttp: X-Powered-By-Plesk: PleskWin
2019-04-08 12:00:24.363 22722-22748/nz.org.westforce.mobileui D/OkHttp: Date: Mon, 08 Apr 2019 03:48:45 GMT
2019-04-08 12:00:24.363 22722-22748/nz.org.westforce.mobileui D/OkHttp: Content-Length: 983
2019-04-08 12:00:24.368 22722-22748/nz.org.westforce.mobileui D/OkHttp: <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><GetCountriesAvailableResponse xmlns="http://www.holidaywebservice.com/HolidayService_v2/"><GetCountriesAvailableResult><CountryCode><Code>Canada</Code><Description>Canada</Description></CountryCode><CountryCode><Code>GreatBritain</Code><Description>Great Britain and Wales</Description></CountryCode><CountryCode><Code>IrelandNorthern</Code><Description>Northern Ireland</Description></CountryCode><CountryCode><Code>IrelandRepublicOf</Code><Description>Republic of Ireland</Description></CountryCode><CountryCode><Code>Scotland</Code><Description>Scotland</Description></CountryCode><CountryCode><Code>UnitedStates</Code><Description>United States</Description></CountryCode></GetCountriesAvailableResult></GetCountriesAvailableResponse></soap:Body></soap:Envelope>
2019-04-08 12:00:24.369 22722-22748/nz.org.westforce.mobileui D/OkHttp: <-- END HTTP (983-byte body)

Upvotes: 1

kiran Biradar
kiran Biradar

Reputation: 12742

You are missing one more class to to hold Body for request.

That is Envelope will contain Body object and Body will contain GetCountriesAvailable object.

Example:

@Root(name = "Envelope")
@NamespaceList(value = [
    Namespace(prefix = "xsi", reference = "http://www.w3.org/2001/XMLSchema-instance"),
    Namespace(prefix = "xsd", reference = "http://www.w3.org/2001/XMLSchema"),
    Namespace(prefix = "soap12", reference = "http://www.w3.org/2003/05/soap-envelope")
])
data class CountriesAvailableRequestEnvelope(
    @Element(name = "Body", required = false)
    @Namespace(reference="http://www.w3.org/2003/05/soap-envelope", prefix:"soap12")
    val Body: Body)


@Root(name = "Body", strict = false)
@Namespace(reference="http://www.w3.org/2003/05/soap-envelope", prefix:"soap12")
data class Body(
    @Element(name = "GetCountriesAvailable", required = false)
    val countriesAvailableRequest: CountriesAvailableRequest)



@Root(name = "GetCountriesAvailable", strict = false)
@Namespace(reference = "http://www.holidaywebservice.com")
data class CountriesAvailableRequest(
    @Element(name = "GetCountriesAvailable", required = false) val code: String)

Upvotes: 4

kiran Biradar
kiran Biradar

Reputation: 12742

Do not include prefix as part of element name.

Change

@Root(name = "soap12:Envelope")
@NamespaceList(value = [
    Namespace(prefix = "xsi", reference = "http://www.w3.org/2001/XMLSchema-instance"),
    Namespace(prefix = "xsd", reference = "http://www.w3.org/2001/XMLSchema"),
    Namespace(prefix = "soap12", reference = "http://www.w3.org/2003/05/soap-envelope")
])

to

@Root(name = "Envelope")
@NamespaceList(value = [
    Namespace(prefix = "xsi", reference = "http://www.w3.org/2001/XMLSchema-instance"),
    Namespace(prefix = "xsd", reference = "http://www.w3.org/2001/XMLSchema"),
    Namespace(prefix = "soap12", reference = "http://www.w3.org/2003/05/soap-envelope")
])

And for Body element change as below.

@Root(name = "Body", strict = false)
 @Namespace(reference="http://www.w3.org/2003/05/soap-envelope")
data class CountryCode(
    @Element(name = "description", required = false) val description: String?,
    @Element(name = "code", required = false) val code: String?)

Upvotes: 2

Related Questions