soap4rを使ってRailsでSOAPクライアント(SOAPリクエスト型指定編)
送信されるSOAPリクエストで型の不一致で苦しんだが、一応解決。
Ruby<->SOAP<->Javaの型がアンマッチ
以下のエラーが発生。
org.jboss.ws.core.jaxrpc.binding.BindingException:
org.jboss.ws.core.jaxrpc.binding.jbossxb.UnmarshalException:
Failed to parse source: Failed to resolve class name for filters: com.attask.api.Array
このとき、送信しているSOAPリクエストのxmlをみてみると以下のようになっている。
filter要素のtypeが "n2:Array"となっているため、通常のarrayとみなされていない模様。
<env:Body>. <n1:getProjectsFromSearch xmlns:n1="http://www.attask.com/api". env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">. <sessionID xsi:type="xsd:string">145383022112166l482d912pgl2nvk</sessionID>. <filters n2:arrayType="n3:NameValueBean[2]". xmlns:n2="http://schemas.xmlsoap.org/soap/encoding/". xmlns:n3="http://www.attask.com/api/types". xsi:type="n2:Array">. <------------------------------------------★ <item>. <extRefID xsi:type="xsd:int">0</extRefID>. <name xsi:type="xsd:string">ID</name>. <value xsi:type="xsd:string">72268</value>. </item>. <item>. <extRefID xsi:type="xsd:int">0</extRefID>. <name xsi:type="xsd:string">ID_Mod</name>. <value xsi:type="xsd:string">eq</value>. </item>. </filters>. </n1:getProjectsFromSearch>. </env:Body>. </env:Envelope>
(解決方法)
生成したWSDLドライバに対して、generate_explicit_typeというのをtrue指定していたが、これをtrueにすると上記のようにxsi:typeなどが付与されたxmlが作られる。これをfalseにすることで型指定が無くなり、エラーにならなくなる。
(修正後rubyコード)
soapdriver = SOAP::WSDLDriverFactory.new(wsdlpath).create_rpc_driver #soapdriver.generate_explicit_type = true (修正前) soapdriver.generate_explicit_type = false
(修正後に実施した際のxml)
<?xml version="1.0" encoding="utf-8" ?> <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <env:Body> <n1:getProjectsFromSearch xmlns:n1="http://www.attask.com/api"> <sessionID>-1760211922201ch2c8a12pj9vrrf</sessionID> <filters> <item> <extRefID>0</extRefID> <name>ID</name> <value>62094</value> </item> <item> <extRefID>0</extRefID> <name>ID_Mod</name> <value>eq</value> </item> </filters> </n1:getProjectsFromSearch> </env:Body> </env:Envelope>
型の構造がアンマッチ
上記で
(解決方法)
wsdl2rubyで、クラス定義をしているAPI.rbと一緒に生成されたソースファイルのひとつにAPIMappingRegistry.rbがある。
これをみてみると以下のようにクラスの構造について定義している。
module APIMappingRegistry EncodedRegistry = ::SOAP::Mapping::EncodedRegistry.new LiteralRegistry = ::SOAP::Mapping::LiteralRegistry.new NsTypes = "http://www.attask.com/api/types" ・・(略)・・ EncodedRegistry.register( :class => NameValueBeanArray, :schema_type => XSD::QName.new(NsTypes, "NameValueBean.Array"), :schema_element => [ ["value", ["NameValueBean[]", XSD::QName.new(nil, "value")], [0, nil]] ] )
今まで、APIMappingRegistry.rbは置いてあったけど使っていなかったので、requireで読み込むように修正。
(rubyのソース)
class AtTask::AtTaskPortalController < ApplicationController define_page uses_component_template_root require 'soap/wsdlDriver' require 'APIMappingRegistry.rb' <----★ def block_sample username = "hoge" password = "age" order_number = "62094" wsdlpath = File.join(RubricksLib::COMPONENT_DIR,"at_task","ws_api.wsdl") soapdriver = SOAP::WSDLDriverFactory.new(wsdlpath).create_rpc_driver soapdriver.generate_explicit_type = false sessionID = soapdriver.login(username, password) # プロジェクト検索用 NameValueBean の設定 nv = NameValueBeanArray.new nv[0] = NameValueBean.new nv[0].extRefID = 0 nv[0].name = "ID" nv[0].value = order_number nv[1] = NameValueBean.new nv[1].extRefID = 0 nv[1].name = "ID_Mod" nv[1].value = "eq"
これで、
<?xml version="1.0" encoding="utf-8" ?> <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <env:Body> <n1:getProjectsFromSearch xmlns:n1="http://www.attask.com/api"> <sessionID>1805085722228-56dfdi12pjipfup</sessionID> <filters> <value> <extRefID>0</extRefID> <name>ID</name> <value>62094</value> </value> <value> <extRefID>0</extRefID> <name>ID_Mod</name> <value>eq</value> </value> </filters> </n1:getProjectsFromSearch> </env:Body> </env:Envelope>