#98 arrays don't handle polymorphism

2.0x
open
nobody
5
2008-10-06
2008-10-06
Anonymous
No

I'm trying to use a WSDL file from a 3rd party, and they define some of their objects as inheriting from a common base class.

I can't use the real example for IP reasons, so I'll make a simple toy example:

FooUser is a class with base class "FooObject",
FooGroup is another class with base class "FooObject".

There is a method that wants an array of FooObject.

If I call it as $moo->set_Objects([$fooUserObject]);
then it complains that the method wanted a FooObject and not a FooUser.

If I call it as $moo->set_Objects($fooUserObject) then it accepts that, but outputs xml that looks like this:

<moo ...><FooObjects><userAttrib1>Field from User</userAttrib1><userAttrib2>Another field from User</userAttrib2></FooObjects></moo>

Basically, polymorphism in arrays just doesn't sit well at all.

Discussion

  • Preben Hansen
    Preben Hansen
    2008-10-06

    I encountered the exact same problem. It appears that SOAP/WSDL/XSD/Typelib/ComplexType.pm doesn't check for subtypes when it encounters a sequence. The below patch fixes it for me.

    Best regards,
    Prutskovlen

    Index: lib/SOAP/WSDL/XSD/Typelib/ComplexType.pm

    --- lib/SOAP/WSDL/XSD/Typelib/ComplexType.pm (revision 743)
    +++ lib/SOAP/WSDL/XSD/Typelib/ComplexType.pm (working copy)
    @@ -192,7 +198,7 @@
    ref $_
    ? ref $_ eq 'HASH'
    ? $type->new($_)
    - : ref $_ eq $type
    + : ref $_ eq $type || (blessed $_ && $_->isa($type))
    ? $_
    : croak "cannot use " . ref($_) . " reference as value for $name - $type required"
    : $type->new({ value => $_ })

     
  • That patch seems to get me past the checking, but it's still casting it to the base class type to encode it.

     
  • Preben Hansen
    Preben Hansen
    2008-10-07

    I was afraid that was gonna be your next problem :)

    I'm on the Typemap branch, and the below is what it took to get my web service up and running (serialization + deserialization). Note that the serialize_attr hack is REALLY disgusting, but it'll have to work until Martin gets around to adding proper xsi:type support to the serializer.

    If you decide to try this out you'll have to switch to the Typemap branch, apply the patch and regenerate your perl classes using wsdl2perl.pl

    Best regards,
    Prutskovlen

    Index: lib/SOAP/WSDL/Expat/MessageParser.pm

    --- lib/SOAP/WSDL/Expat/MessageParser.pm (revision 743)
    +++ lib/SOAP/WSDL/Expat/MessageParser.pm (working copy)
    @@ -59,6 +59,15 @@
    return $self->{ class_resolver };
    }

    +sub prefix_resolver {
    + my $self = shift;
    + if (@_) {
    + $self->{ prefix_resolver } = shift
    + or return;
    + }
    + return $self->{ prefix_resolver };
    +}
    +
    sub load_classes {
    my $self = shift;
    return if $LOADED_OF{ $self->{ class_resolver } };
    Index: lib/SOAP/WSDL/Deserializer/XSD.pm
    ===================================================================
    --- lib/SOAP/WSDL/Deserializer/XSD.pm (revision 743)
    +++ lib/SOAP/WSDL/Deserializer/XSD.pm (working copy)
    @@ -43,8 +43,8 @@
    if ($caller->can('get_class_resolver'));

    # new style
    - $parser_of{ ${ $self } }->set_name_resolver( $caller->_get_name_resolver() )
    - if $caller->can('get_name_resolver');
    + $parser_of{ ${ $self } }->prefix_resolver( $caller->_get_name_resolver()->get_prefix_resolver() )
    + if $caller->can('_get_name_resolver');

    if (ref $method) {
    # set class resolver if serializer supports it
    Index: lib/SOAP/WSDL/XSD/Typelib/ComplexType.pm
    ===================================================================
    --- lib/SOAP/WSDL/XSD/Typelib/ComplexType.pm (revision 743)
    +++ lib/SOAP/WSDL/XSD/Typelib/ComplexType.pm (working copy)
    @@ -81,8 +81,13 @@
    }

    sub serialize_attr {
    - return q{} if not $xml_attr_of{ ${ $_[0] } };
    - return $xml_attr_of{ ${ $_[0] } }->serialize();
    + if (ref($_) =~ m/::([^:]+)$/) {
    + return qq{ xsi:type="$1"} if not $xml_attr_of{ ${ $_[0] } };
    + return qq{ xsi:type="$1"}.$xml_attr_of{ ${ $_[0] } }->serialize();
    + }else{
    + return if not $xml_attr_of{ ${ $_[0] } };
    + return $xml_attr_of{ ${ $_[0] } }->serialize();
    + }
    }

    # TODO: are complextypes are always true ?
    @@ -195,7 +200,7 @@
    ref $_
    ? ref $_ eq 'HASH'
    ? $type->new($_)
    - : ref $_ eq $type
    + : ref $_ eq $type || (blessed $_ && $_->isa($type))
    ? $_
    : croak "cannot use " . ref($_) . " reference as value for $name - $type required"
    : $type->new({ value => $_ })

     
  • Preben Hansen
    Preben Hansen
    2008-10-07

    Whoops, lib/SOAP/WSDL/XSD/Typelib/ComplexType.pm line 88 (after the patch) should have been:

    return q{} if not $xml_attr_of{ ${ $_[0] } };

    instead of

    return if not $xml_attr_of{ ${ $_[0] } };

    And this patch silences an annoying warning:

    Index: lib/SOAP/WSDL/Expat/MessageParser.pm

    --- lib/SOAP/WSDL/Expat/MessageParser.pm (revision 743)
    +++ lib/SOAP/WSDL/Expat/MessageParser.pm (working copy)
    @@ -95,7 +105,7 @@
    }

    return "SOAP::WSDL::XSD::Typelib::Builtin::$localname"
    - if ($namespace eq 'http://www.w3.org/2001/XMLSchema');
    + if (defined $namespace && $namespace eq 'http://www.w3.org/2001/XMLSchema');

    # resolve perl prefix
    my $perl_prefix = $self->{ prefix_resolver }->resolve_prefix('type', $namespace);