[howto] pass a byte array to a web service

Discussion in 'Ruby' started by aastanti@hotmail.com, Apr 5, 2005.

  1. Guest

    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
    , Apr 5, 2005
    #1
    1. Advertising

  2. <> schrieb im Newsbeitrag
    news:...
    > 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.

    >> require 'base64'

    => true
    >> Base64.encode64 "\001\002\003"

    => "AQID\n"
    >> Base64.encode64 "\001"

    => "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
    >
    Robert Klemme, Apr 5, 2005
    #2
    1. Advertising

  3. Guest

    Re: pass a byte array to a web service

    Robert Klemme wrote:
    > Withoug knowing web services inside out: The line above seems to

    indicate
    > that you have to send the bytes base64 encoded.
    >
    > >> require 'base64'

    > => true
    > >> Base64.encode64 "\001\002\003"

    > => "AQID\n"
    > >> Base64.encode64 "\001"

    > => "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
    , Apr 5, 2005
    #3
  4. Re: pass a byte array to a web service

    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!



    --
    Into RFID? www.rfidnewsupdate.com Simple, fast, news.
    Lyndon Samson, Apr 5, 2005
    #4
  5. Guest

    Re: pass a byte array to a web service

    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
    , Apr 6, 2005
    #5
  6. aa Guest

    Re: pass a byte array to a web service

    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
    aa, Apr 6, 2005
    #6
  7. Re: pass a byte array to a web service

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

    --
    Into RFID? www.rfidnewsupdate.com Simple, fast, news.
    Lyndon Samson, Apr 6, 2005
    #7
  8. Re: pass a byte array to a web service

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



    --
    Into RFID? www.rfidnewsupdate.com Simple, fast, news.
    Lyndon Samson, Apr 11, 2005
    #8
  9. Douglas Livingstone, Apr 11, 2005
    #9
  10. Re: pass a byte array to a web service

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

    Hello,

    Sorry for the late reply.

    aa wrote:
    > 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--
    NAKAMURA, Hiroshi, Apr 16, 2005
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    3
    Views:
    1,089
    Thomas 'PointedEars' Lahn
    Mar 20, 2006
  2. Kirby
    Replies:
    3
    Views:
    640
    Kirby
    Oct 8, 2004
  3. Replies:
    3
    Views:
    699
    Thomas 'PointedEars' Lahn
    Mar 20, 2006
  4. Replies:
    0
    Views:
    357
  5. Replies:
    3
    Views:
    144
    Thomas 'PointedEars' Lahn
    Mar 20, 2006
Loading...

Share This Page