Perl から JAX-WS な Web サービスへマルチバイト文字列を送信

PerlSOAP::Lite を使用して、JAX-WS な Web サービスに対して日本語の文字列を送信した所、Web サービス側で正しく受信できなかった。

Java

Web サービス側はこんな感じ。

package me.org.echo;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
@WebService()
public class EchoWS {
    @WebMethod(operationName = "echo")
    public String echo(@WebParam(name = "params")String params) {
        Logger logger = Logger.getLogger(CalculatorWS.class.getName());
        logger.log(Level.INFO, params);
        return params;
    }
    @WebMethod(operationName = "echoList")
    public List<String> echoList(@WebParam(name = "params")List<String> params) {
        Logger logger = Logger.getLogger(CalculatorWS.class.getName());
        for (String param : params) {
            logger.log(Level.INFO, param);
        }
        return params;
    }
}

マルチバイトを含まない文字列を送信した場合、正しくログに表示される。

#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
use SOAP::Lite;
my $client = SOAP::Lite->service('http://localhost:8084/EchoWSApplication/EchoWS?wsdl');
$client->readable(1);
$client->ns('http://schemas.xmlsoap.org/soap/envelope/', 'ns');
my $str    = SOAP::Data->name('params')->value('Hello');
my $result = $client->echo($str);
2010/08/05 15:12:24 me.org.echo.EchoWS echo
情報: Hello!

日本語(マルチバイト文字)を送信した場合。

#!/usr/bin/env perl
use strict;
use warnings;
use utf8;
use Data::Dumper;
use SOAP::Lite;
my $client = SOAP::Lite->service('http://localhost:8084/EchoWSApplication/EchoWS?wsdl');
$client->readable(1);
$client->ns('http://schemas.xmlsoap.org/soap/envelope/', 'ns');
my $str    = SOAP::Data->name('params')->value('こんにちはこんにちは');
my $result = $client->echo($str);
2010/08/05 15:21:18 me.org.echo.EchoWS echo
情報: 44GT44KT44Gr44Gh44Gv44GT44KT44Gr44Gh44Gv

バイナリっぽい文字列になっとる…。


送信したリクエストをデバッグモードで表示してみたら、以下のように送信されている。

<?xml version="1.0" encoding="UTF-8"?>
<ns:Envelope
    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
    xmlns:wsp="http://www.w3.org/ns/ws-policy"
    xmlns:ns="http://schemas.xmlsoap.org/soap/envelope/"
    ns:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
    xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:tns="http://org.me.echo/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ns:Body>
    <tns:echo>
      <params xsi:type="xsd:base64Binary">44GT44KT44Gr44Gh44Gv44GT44KT44Gr44Gh44Gv</params>
    </tns:echo>
  </ns:Body>
</ns:Envelope>

base64Binary…だと…?
Base64 エンコードとか色々試したけど、どうやってもダメだった。


色々調べた結果、ヒントが見つかったので試した。
XMLRPC::Lite (SOAP::Lite) で base64 エンコーディングさせない: blog.bulknews.net

#!/usr/bin/env perl
use strict;
use warnings;
use utf8;
use Data::Dumper;
use SOAP::Lite +trace => [qw(debug)];

my $client = SOAP::Lite->service('http://localhost:8084/CalculatorWSApplication/CalculatorWS?wsdl');
$client->readable(1);
$client->ns('http://schemas.xmlsoap.org/soap/envelope/', 'ns');

my $data   = SOAP::Data->name('params')->type(string => 'こんにちはこんにちは');
my $result = $client->echo($data);
warn Dumper $result;
2010/08/05 15:29:36 me.org.echo.EchoWS echo
情報: こんにちはこんにちは

リクエストの中身。

<?xml version="1.0" encoding="UTF-8"?>
<ns:Envelope
    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
    xmlns:wsp="http://www.w3.org/ns/ws-policy"
    xmlns:ns="http://schemas.xmlsoap.org/soap/envelope/"
    ns:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
    xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:tns="http://org.me.echo/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ns:Body>
    <tns:echo>
      <params xsi:type="xsd:string">こんにちはこんにちは</params>
    </tns:echo>
  </ns:Body>
</ns:Envelope>

引数の型が List の場合は、

$data = SOAP::Data->name('params')->value(
    'hello!',
    SOAP::Data->type(string => 'こんにちは'),
    SOAP::Data->type(string => 'こんにちはこんにちは'),
);
$result = $client->echoList($data);

とすれば正しく送信できた。