[howto] pass a byte array to a web service

A

aastanti

Hello all,

I have a web service developed in java with axis and I'd like to invoke
it by means of SOAP4R. The problem is that I don't know how to pass an
array of bytes, without starting from the WSDL. I tried with
String#pack, an array with numbers or chars (ie: [121] or ['a'] or
[65.chr]), but they all fail.

On customer side I always get:
SOAP::FaultError: java.lang.IllegalArgumentException: argument type
mismatch
from #<SOAP::Mapping::Object:0x2bc5468>

Please consider that the argument is defined in wsdl as:
<wsdl:part name="x" type="xsd:base64Binary"/>
("x" is obviously a fake name)

I tried simply with String as well, but I get:
SOAP::FaultError: org.xml.sax.SAXException: Bad types (class
java.lang.String ->
class [B)
from #<SOAP::Mapping::Object:0x2cec320>

We tried calling the web service in the following way:
require 'soap/rpc/driver'
s =
SOAP::RPC::Driver.new('http://localhost:8080/fake/services/BigFake',
'http://www.fake.com/fake')
s.add_method_with_soapaction("fakeMethod",
'http://localhost:8080/fake/services/BigFake/fakeMethod', ['in', 'x'])
x = ['a']
p s.fakeMethod(x)

Of course in reality we are calling a more complex method, with 8 input
parameters, 1 output parameter and a return value, but we have problem
only with the byte[] one.

The equivalent java version (the one that works) is a lot more complex,
hence it is not useful to post it here, but consider that the parameter
is passed to an axis call client as a native byte[].

We have tried to invoke the web service starting from the WSDL, and
surprisingly it works passing a String, which is not so understandable
to me:
require 'soap/wsdlDriver'
WSDL_URL = "http://localhost:8080/fake/services/BigFake?wsdl"
s = SOAP::WSDLDriverFactory.new(WSDL_URL).createDriver
x = "abc"
p s.fakeMethod(x)

Why the latter works, but the former, even passing a String, doesn't
work? Can anybody shed some light on this?

TIA
 
R

Robert Klemme

Hello all,

I have a web service developed in java with axis and I'd like to invoke
it by means of SOAP4R. The problem is that I don't know how to pass an
array of bytes, without starting from the WSDL. I tried with
String#pack, an array with numbers or chars (ie: [121] or ['a'] or
[65.chr]), but they all fail.

On customer side I always get:
SOAP::FaultError: java.lang.IllegalArgumentException: argument type
mismatch
from #<SOAP::Mapping::Object:0x2bc5468>

Please consider that the argument is defined in wsdl as:
<wsdl:part name="x" type="xsd:base64Binary"/>
("x" is obviously a fake name)

Withoug knowing web services inside out: The line above seems to indicate
that you have to send the bytes base64 encoded.
=> "AQ==\n"

Kind regards

robert

I tried simply with String as well, but I get:
SOAP::FaultError: org.xml.sax.SAXException: Bad types (class
java.lang.String ->
class [B)
from #<SOAP::Mapping::Object:0x2cec320>

We tried calling the web service in the following way:
require 'soap/rpc/driver'
s =
SOAP::RPC::Driver.new('http://localhost:8080/fake/services/BigFake',
'http://www.fake.com/fake')
s.add_method_with_soapaction("fakeMethod",
'http://localhost:8080/fake/services/BigFake/fakeMethod', ['in', 'x'])
x = ['a']
p s.fakeMethod(x)

Of course in reality we are calling a more complex method, with 8 input
parameters, 1 output parameter and a return value, but we have problem
only with the byte[] one.

The equivalent java version (the one that works) is a lot more complex,
hence it is not useful to post it here, but consider that the parameter
is passed to an axis call client as a native byte[].

We have tried to invoke the web service starting from the WSDL, and
surprisingly it works passing a String, which is not so understandable
to me:
require 'soap/wsdlDriver'
WSDL_URL = "http://localhost:8080/fake/services/BigFake?wsdl"
s = SOAP::WSDLDriverFactory.new(WSDL_URL).createDriver
x = "abc"
p s.fakeMethod(x)

Why the latter works, but the former, even passing a String, doesn't
work? Can anybody shed some light on this?

TIA
 
A

aastanti

Robert said:
Withoug knowing web services inside out: The line above seems to indicate
that you have to send the bytes base64 encoded.

=> "AQ==\n"

Thanks Robert, but it doesn't work: it doesn't seem to be a matter of
encoding, it seems to be a matter of type conversion. Infact, if a try
to encode it like x = Base64.encode("abc") I get again:
Bad types (class java.lang.String -> class [B)

Please also note that starting from the WSDL it works perfectly passing
a plain simple string. I really don't understand.

AA
 
L

Lyndon Samson

Run a HTTP monitor in between the client and server.
Compare and contrast the working and failing code.

All java Strings are 16 bit Unicode, I'm pretty sure ruby uses 8 bit ascii.

good luck!
 
A

aastanti

Unfortunately that doesn't work either, I always get the same error as
expected:
SOAP::FaultError: org.xml.sax.SAXException: Bad types (class
java.lang.String -> class [B)
from #<SOAP::Mapping::Object:0x2c3e848>

I'll try to speculate. The point seems to be that working with RPC
Driver makes certain assumptions about types: while this is somewhat
irrelevant in ruby world, it becomes relevant when working with web
services in general and java in particular. The SAX parser argues about
the type of that parameter: it expects an array of B (I have to check
what B is), while I'm passing a ruby string that is recognized as a
java string after unmarshaling.

Evidently working with WSDLDriverFactory I get an exact stub, with
precise types for every parameters
I'll try with Lyndon Samson suggestion, it seems worth spending some
more time.
Thanks
AA
 
A

aa

Ok, I have used an HTTP monitor to check what's going on. The result is
that working with SOAP::RPC::Driver and add_method_with_soapaction a
type is automatically attached to every parameter. Infact, in the SOAP
message I see:
<inx xsi:type="xsd:string">YWJj</inx>
while using WSDLDriverFactory:
<x>YWJj</x>

That's it! Of course needs to be compatible with a byte[], that is to
say that if a type is specified it better be xsd:base64Binary. Infact,
if I rollback to pass an array like [65, 66] I can understand why I get
an IllegalArgumentExcep­tion ==> instead of xsd:base64Binary the SOAP
message contains
<inx n2:arrayType="xsd:anyType[2]"
xmlns:n2="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="n2:Array">
<item xsi:type="xsd:int">65</item>
<item xsi:type="xsd:int">66</item>
</inx>

Now the question is: why add_method_with_soapaction causes (sometimes
erronous) types to be passed with SOAP parameters?

Thx
AA
 
L

Lyndon Samson

Now the question is: why add_method_with_soapaction causes (sometimes
erronous) types to be passed with SOAP parameters?

Possibly something to do with the following

a="hello"
puts a[0]
puts a[0..0]

104
h

that is, a single character is a byte, yet a range is a substring.

I haven't quite grokked the ruby rules around this yet.
 
L

Lyndon Samson

that is, a single character is a byte, yet a range is a substring.
I haven't quite grokked the ruby rules around this yet.

Whys www.poignantguide.net/ruby/print.html says

str = "A string is a long shelf of letters and spaces."
puts str[0] # prints 'A'

but ruby 1.8.2

irb(main):001:0> str = "A string is a long shelf of letters and spaces."
=> "A string is a long shelf of letters and spaces."
irb(main):002:0> puts str[0]
65

So I guess the behaviour changed between 1.6 and 1.8? Or why made a typo?
 
N

NAKAMURA, Hiroshi

--------------enigBBA4C92B4239D3F5723F36A9
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable

Hello,

Sorry for the late reply.
Ok, I have used an HTTP monitor to check what's going on. The result is=
that working with SOAP::RPC::Driver and add_method_with_soapaction a
type is automatically attached to every parameter. Infact, in the SOAP
message I see:
<inx xsi:type=3D"xsd:string">YWJj</inx>
while using WSDLDriverFactory:
<x>YWJj</x>
=20
That's it! Of course needs to be compatible with a byte[], that is to
say that if a type is specified it better be xsd:base64Binary. Infact, [snip]
Now the question is: why add_method_with_soapaction causes (sometimes
erronous) types to be passed with SOAP parameters?

That's because without WSDL information, a driver cannot know the
defined type of passing parameters. To specify its type directly at
runtime, you can use SOAP/OM layer object (SOAP::*) such as;

def test_echoBase64_xsd_base64Binary
log_test
str =3D "Hello (=C6=FC=CB=DC=9E=ECJapanese) =80=B3=80=F3=80=CB=80=C1=80=
=CF"
arg =3D SOAP::SOAPBase64.new(str)
arg.as_xsd # Force xsd:base64Binary instead of soap-enc:base64=

var =3D drv.echoBase64(arg)
assert_equal(str, var)
end

def test_echoBase64_SOAP_ENC_base64
log_test
str =3D "Hello (=C6=FC=CB=DC=9E=ECJapanese) =80=B3=80=F3=80=CB=80=C1=80=
=CF"
arg =3D SOAP::SOAPBase64.new(str)
var =3D drv.echoBase64(arg)
assert_equal(str, var)
end

(excerpted from
http://dev.ctor.org/soap4r/file/trunk/test/interopR2/client.rb)

You WSDL seems to define the parameter as xsd:base64Binary, so use the
former one.

There's also another solution. To escape from this kind of Ruby
<-(SOAP)-> Java type mapping problem, you can let Java module to
inference its type by removing type attribute for each element, if the
Java side is utilizing a WSDL.

drv.generate_explicit_type =3D false

As a fact, your WSDLDriver sample does it implicitly.

Regards,
// NaHi


--------------enigBBA4C92B4239D3F5723F36A9
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.0 (Cygwin)

iD8DBQFCYEkIf6b33ts2dPkRAtWyAJ0d4uYIf+cu6QnFf/MJeXuZwCIxhQCglrpu
wTmVlM5xSLd9590xKZr48ho=
=hWwf
-----END PGP SIGNATURE-----

--------------enigBBA4C92B4239D3F5723F36A9--
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,480
Members
44,900
Latest member
Nell636132

Latest Threads

Top