calling methods on deserialized objects

calling methods on deserialized objects

am 25.08.2006 22:32:31 von somone

Hello Perl Specialists,

i'm struggling with a weird problem ....

background:
I have stored an "object tree" in a CGI::Session. I want to make the whole
object model persistent, when the page has finished rendering and restore
all the stuff when the page is loaded by a new request. So far so good: The
object structure seems to be serialized correct. When looking at the
structure with Data::Dumper before and after the
serialization/deserialization step, I can see no difference. Even the
blessing and backpointers in the structure are maintained. But anyway an
error occurs when trying to call methods on the deserialzed objects.

problem:

I have a "restored" object like:

my $page = $session->param{page};

now I want to iterate through the child controls and call a method on them:

foreach my $controlName (keys (%{$page->{mControls}}))
{
my $childControl = $page->{mControls}->{$controlName };
$childControl->load(); # i've checked that $childControl is a valid
blessed reference at this point!
}

The "$childControl->load();" statement causes the following error:

"can't locate object method "load" via package SMDplus::Web::Controls::Form

As the error also shows, perl is well aware of the class where the load
method is implemented. Unfortunately it says that the package doesn't
contain the "load" method (which is not the case).

I can achieve what I want by transforming the statement

$childControl->load(); # generates error

into:

my $class = ref($childControl);
eval("$class\:\:load(\$childControl)"); # works fine

Since I don't want to use eval for several reasons, I am looking for a way
to make the "intuitive syntax" work. I should say that i'm using
"inheritance" as well.... I'm very confused about this behaviour and also
have the bad feeling, that I didn't understand some fundamentals of perl
"objects" :-(.

Can anybody please enlight me? This problem drives me mad by the time ...

kind regards
Michael

Re: calling methods on deserialized objects

am 25.08.2006 23:26:54 von mumia.w.18.spam+nospam.usenet

On 08/25/2006 03:32 PM, wrote:
> Hello Perl Specialists,
>
> i'm struggling with a weird problem ....
>
> background:
> I have stored an "object tree" in a CGI::Session. I want to make the whole
> object model persistent, when the page has finished rendering and restore
> all the stuff when the page is loaded by a new request. So far so good: The
> object structure seems to be serialized correct [ but method calls
> don't work ... ]

I've haven't used CGI::Session, but I don't think it'll work
for two reasons: 1) serialization and deserialization breaks
the internal connection between hashes and their associated
classes, and 2) after deserialization, objects referred to by
references may be in different locations.

I have three bits of advice: 1) bless the hashes back into
their respective classes after deserialization, 2) use custom
serialization and deserialization methods to reconstruct the
object tree for each request, and 3) make sure the objects'
package (class) files are loaded before deserializing.

This post is a WAG so forgive me if I'm totally off the wall.

PS.
The ref() function returns a string of text and, by itself, is
no indication that the internal bytecode that connects a hash
reference to a class is still there.

Re: calling methods on deserialized objects

am 26.08.2006 01:35:14 von somone

thanks for your reply ...

> I've haven't used CGI::Session, but I don't think it'll work for two
> reasons:
> 1) serialization and deserialization breaks the internal connection
> between hashes and their associated classes, and
What "internal connection" are you refering to? As far as i know, an object
is nothing more than a blessed hash reference!? So the "connection" between
hashref (object) and package (class) is the blessing (the packagename stored
with the hashref), or am I missing something here? If there IS actually
something more, this would explain the behaviour ...

> 2) after deserialization, objects referred to by references may be in
> different locations.
This is not a problem (at least in my case). The serialized structure looks
good (I had a look at the session text file), references are replaced by
their serialized target, no memory address pointers inside ...

> I have three bits of advice: 1) bless the hashes back into their
> respective classes after deserialization,
they do have the correct class! (since ref($hashref) returns the correct
name).

> 2) use custom serialization and deserialization methods to reconstruct the
> object tree for each request, and
would be an option ...
but I still hope to find a way to use the default session deserializer.

> 3) make sure the objects' package (class) files are loaded before
> deserializing.
This is something I thought of too ...
I will check, if this helps. But anyway: if the packages would not have been
loaded, the "eval-way" of calling the method could not have worked, could
it?

> This post is a WAG so forgive me if I'm totally off the wall.
I don't know what WAG stands for, but i forgive you in any case and thank
you for your time :-)


> PS.
> The ref() function returns a string of text and, by itself, is no
> indication that the internal bytecode that connects a hash reference to a
> class is still there.
If there is some "internal bytecode" could you please give me a link to an
explanation? Cause I didn't find anything like this in my perl book.

kind regards
Michael

Re: calling methods on deserialized objects

am 26.08.2006 06:00:48 von mumia.w.18.spam+nospam.usenet

On 08/25/2006 06:35 PM, Michael Küper wrote:
> thanks for your reply ...
>
> Mumia W. wrote:
>> I've haven't used CGI::Session, but I don't think it'll work for two
>> reasons:
>> 1) serialization and deserialization breaks the internal connection
>> between hashes and their associated classes, and
> What "internal connection" are you refering to? As far as i know, an object
> is nothing more than a blessed hash reference!?

Again, my entire previous post was a Wild A$$ Guess (WAG);
take it with some grains of salt.

I imagined that invisible Perl bytecode establishes the
connection between a hash reference and it's class. I was
wrong, because I tried it with Data::Dumper and FreezeThaw,
and it worked.

Note, I didn't use CGI::Session but instead stored the data in
the __DATA__ section.

> So the "connection" between
> hashref (object) and package (class) is the blessing (the packagename stored
> with the hashref), or am I missing something here? If there IS actually
> something more, this would explain the behaviour ...
>
>> 2) after deserialization, objects referred to by references may be in
>> different locations.
> This is not a problem (at least in my case). The serialized structure looks
> good (I had a look at the session text file), references are replaced by
> their serialized target, no memory address pointers inside ...
>
>> I have three bits of advice: 1) bless the hashes back into their
>> respective classes after deserialization,
> they do have the correct class! (since ref($hashref) returns the correct
> name).
>

It should work, even without re-blessing.

>> 2) use custom serialization and deserialization methods to reconstruct the
>> object tree for each request, and
> would be an option ...
> but I still hope to find a way to use the default session deserializer.
>
>> 3) make sure the objects' package (class) files are loaded before
>> deserializing.
> This is something I thought of too ...
> I will check, if this helps. But anyway: if the packages would not have been
> loaded, the "eval-way" of calling the method could not have worked, could
> it?
>

At least in PHP, storing objects in sessions doesn't work if
the class definitions aren't loaded when the session data is
loaded by the interpreter (AFAIR). Although Perl is a
completely different language, the problem is (probably) the
same. How can you associate an object's data with a class if
the class' definition isn't loaded?


>> This post is a WAG so forgive me if I'm totally off the wall.
> I don't know what WAG stands for, but i forgive you in any case and thank
> you for your time :-)
>
>
>> PS.
>> The ref() function returns a string of text and, by itself, is no
>> indication that the internal bytecode that connects a hash reference to a
>> class is still there.
> If there is some "internal bytecode" could you please give me a link to an
> explanation? Cause I didn't find anything like this in my perl book.
>
> kind regards
> Michael
>
>

I can't test your program because you didn't post one.

Why don't you post a minimal but complete Perl script that
demonstrates your problem, so you can get some responses that
are better than WAGs :-)

Re: calling methods on deserialized objects

am 03.09.2006 11:41:36 von somone

I found workaround which works for me ...
I have implemented a method "revive" on the WebControl BaseClass and each
derived class. Because the hashRef is correctly blessed after
deserialization, the method doesn't need any other arguments. It simply
clones the object and "repairs" references to other objects. It returns a
reference to the new object. So, with one call of:

$newRoot = $rootObject->revive();

I can restore recursively the whole object tree after deserialisation.
Methods can be called again on each object in the cloned object tree.