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"

これで、の子要素にvalueができるようになりました〜

<?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>