ABSTRACT SERIALIZABLE and inheritance

Posted by Simon L. Prinsloo on 06-May-2014 06:53

If you inherit from an ABSTRACT SERIALIZABLE class, the generated code is not automatically flagged as SERIALIZABLE.

I am wondering if that is a good default, or is it reasonable that if the base class is SERIALIZABLE, its descendants will most likely need to be too?

I am especially concerned with Progress.Lang.AppError descendants, who may end up, merely by accident, ans non-SERIALIZABLE, with the consequence that if they are thrown from the AppServer to the Client, they may get lost?

While I believe types declared by a Programmer should match exactly when serialised, I was wondering if a un-SERIALIZABLE Progress.Lang.AppError derivative should not SERIALIZABLE as the lowest super class be serialized instead? That way the client will get something, even if it is only a subset, when an error is thrown.

 

All Replies

Posted by Laura Stern on 06-May-2014 08:00

The reason to require that a class be marked SERIALIZABLE is to ensure that it was the intent of the programmer that the data in the class can be made available outside of the current session, i.e., that it can be sent to another program or,  in future, possibly written to disk.  This can be for security reasons or based on whether the particular data involved makes sense outside of its current context.  This decision must be made at every class level since the data at each class level has its own requirements.  This is standard behavior in other OO languages as well.

I'm not sure I understand your concern about AppError descendents.  Classes don't end up as non-SERIALIZABLE by accident.  The end up that way due to omission by the programmer.  I suppose you mean that the programmer just forgot to mark it.  But I'm still unclear what you mean in your last sentence.  Please clarify, if you will.  But I can say that you cannot serialize part of a class.  While there may be a hierarchy involved, a class instance is a single unit and cannot be treated as multiple parts. The whole thing must either be serialized or not.

Posted by Simon L. Prinsloo on 06-May-2014 09:36

I understand WHY we need to put SERIALIZABLE on each level, that was not my question.

I do not question the fact that PDSOE does not generally add SERIALIZABLE to the child class header when it generates it, since I agree that it should not.

My question concerns specifically PDSOE-generated code when the specified base class is both ABSTRACT and SERIALIZABLE.

It is my feeling that if the ABSTRACT has been marked as SERIALIZABLE, it would most likely be what is needed in the implementation as well. Thus I am asking: When PDSOE generate the class header for an implementation inheriting specifically from a serializable ABSTRACT class, would it not be better if the implementation was generated WITH the SERIALIZABLE  keyword? The programmer can always remove it in such a case.

Posted by Laura Stern on 06-May-2014 10:10

Yes, what you're saying makes some sense, but... the class that inherits from the ABSTRACT class can of course add its own data members and so the ability to serialize must be independently decided for this class.  As far as making it the default in PDSOE generated code, I'd say it is safer to assume that it should not be serialized than assume that it should be.  That is, in general, why you have to opt in to serialization rather than opt out of it.  

Sorry - I was confused (and still am) by your concern about the AppError and thus didn't answer your first question.

Posted by Simon L. Prinsloo on 06-May-2014 10:11

As for AppError - currently unhandled, thrown errors gets lost in oblivion when they reach the AS boundry, which is a maintenance nightmare.

Once 11.4 becomes commercial, any derived classes needs to be marked as SERIALIZABLE, otherwise the problem will persist, and if one is missed, it will "accidentally" not be serializable. The same will happen if a programmer forget to mark a new error implementation as such. Unlike normal classes that will fail in proper testing, many error conditions are hard to foresee and test properly, so a mistake with an error definition has the potential to only be apparent years later when the error gets thrown and goes unhandled - most likely in some unforeseen circumstances in production - and then it will most likely also go unnoticed by the client as well.

Besides, if the custom error's constuctors or methods reference the DB to build messages, it will never be natively serializable to a database-less client in any case, neither will that functionality be needed on the client .

It is better to receive a plain old AppError on the client containing at least the ReturnValue and the built-in message list, rather than letting it slip by unnoticed.

At the moment I contemplate to cater for this by hand. Any AppServer entry point .p file must have a catch-all Progress.Lang.Error CATCH block. If the error being caught is serializable, it gets throws to the client, if not, I instantiate a regular AppError, copy ReturnValue and all errors from the caught to the new, and throw that instead. This is messy and the cleanup on the AppServer now have to get rid of TWO error objects.

So if the programmer do not mark a custom error with custom context as SERIALIZABLE on 12/11/2014, nothing mysterious happens when that is thrown to the production client for a very specific data condition that occurs on 04/04/2021 on the 14043th operation of production user number 2144. We simply catch the AppError with the messages - minus the custom fields and methods - but at least a support call can be logged and the matter can be investigated with a proper starting point.

It would however be nice if Progress could downgrade a custom error to an AppError and pass it back to the client in cases where the error itself cannot be sent back.

I can think of no use case where telling the user that something went wrong constitutes a security breach or is somehow worse than pretending that all is ***-dorey when it is not.

Posted by GregHiggins on 06-May-2014 11:21

I fail to see how remembering to implement a catch block, etc. is significantly different from remembering to make an object / error serializable.

Posted by Evan Bleicher on 06-May-2014 12:10

Laura has provided input on this thread from the Language / Runtime perspective.  As previously noted, the ABL runtime will not allow part of a hierarchy to be marked SERIALIZABLE.  The language team believes that this is the proper behavior and consistent with other OO languages.  Simon has noted how this can be problematic for AppErrors.   In this case, if a routine on an AppServer throws a customized error object (something that inherits from Progress.Lang.AppError) and the programmer does not mark this object as SERIALIZABLE, throwing this object cross the AppServer boundary will not work.  There will be a message in the AppServer log file noting this situation, and the caller on the ABL client will receive an ERROR but none of the data associated with the Progress.Lang.AppError will be available to the client.

Maybe this issue should be discussed not from the language perspective, but from a tooling perspective.  Should there be an option so that in PDSOE the class wizard defaults the SERIALIZABLE checkbox to the SERIALIZABLE value from the super class?  In this model, when defining a new class the default value for SERIALIZABLE will be the same as the class this class inherits from.  Since everything inherits from Progess.Lang.Object – which is also SERIALIZABLE – all objects by default will be SERIALIZABLE.  As noted previously, this would mean one would need to opt out of making a class SERIALIZABLE.  I don’t believe that this is correct, but wanted to see what others thought.

Posted by Laura Stern on 06-May-2014 12:21

What you're suggesting is not proper OO behavior.  Though I REALLY DO sympathize with what your saying.  However, there should be a relatively simple way to find all of your error classes so you can code them appropriately.  For example if all error objects have the word Error as part of the class name, you could do:

   grep Error *.cls | grep CLASS

Or perhaps you should be asking if the tooling (i.e., PDSOE) can help with this rather than asking for a language change.

Posted by Marian Edu on 06-May-2014 13:24

While Laura do have a point (I would rather not use serializable with an
abstract class to begin with), so does Simon because he's referring to a
very particular case and imho throwing an error is a bit different from
returning an object.

So it will be a different handling for errors but then again one can
only throw errors not any type of object :)


On 05/06/2014 06:12 PM, simon@vidisolve.com wrote:
>[collapse] From: simon@vidisolve.com
> Post: RE: ABSTRACT SERIALIZABLE and inheritance
> Posted in: Forum
> Link: http://community.progress.com/products/beta-eap/OE114-External/f/41/p/9955/37595.aspx#37595
>
> As for AppError - currently unhandled, thrown errors gets lost in oblivion when they reach the AS boundry, which is a maintenance nightmare.
> Once 11.4 becomes commercial, any derived classes needs to be marked as SERIALIZABLE, otherwise the problem will persist, and if one is missed, it will "accidentally" not be serializable. The same will happen if a programmer forget to mark a new error implementation as such. Unlike normal classes that will fail in proper testing, many error conditions are hard to foresee and test properly, so a mistake with an error definition has the potential to only be apparent years later when the error gets thrown and goes unhandled - most likely in some unforeseen circumstances in production - and then it will most likely also go unnoticed by the client as well.
> Besides, if the custom error's constuctors or methods reference the DB to build messages, it will never be natively serializable to a database-less client in any case, neither will that functionality be needed on the client .
> It is better to receive a plain old AppError on the client containing at least the ReturnValue and the built-in message list, rather than letting it slip by unnoticed.
> At the moment I contemplate to cater for this by hand. Any AppServer entry point .p file must have a catch-all Progress.Lang.Error CATCH block. If the error being caught is serializable, it gets throws to the client, if not, I instantiate a regular AppError, copy ReturnValue and all errors from the caught to the new, and throw that instead. This is messy and the cleanup on the AppServer now have to get rid of TWO error objects.
> So if the programmer do not mark a custom error with custom context as SERIALIZABLE on 12/11/2014, nothing mysterious happens when that is thrown to the production client for a very specific data condition that occurs on 04/04/2021 on the 14043th operation of production user number 2144. We simply catch the AppError with the messages - minus the custom fields and methods - but at least a support call can be logged and the matter can be investigated with a proper starting point.
> It would however be nice if Progress could downgrade a custom error to an AppError and pass it back to the client in cases where the error itself cannot be sent back.
> I can think of no use case where telling the user that something went wrong constitutes a security breach or is somehow worse than pretending that all is ***-dorey when it is not.
>
>
> --
> You were sent this email because you opted to receive email notifications when someone created a new thread.
>
> To unsubscribe[collapse] from:
> - ...only this thread, disable notifications at http://community.progress.com/products/beta-eap/OE114-External/f/41/p/9955/37595.aspx#37595.
> - ...all email notifications from Progress Community, navigate to "Settings", click on the "Email" tab, then under the "Email Configuration" section, set Send Notifications to "No".
>
>


--
m.edu
keep it simple
http://www.ganimede.ro
http://ro.linkedin.com/in/marianedu
medu@ganimede.ro
mobile: +40 740 036 212
skype: marian.edu[/collapse][/collapse]

Posted by Mike Fechner on 06-May-2014 16:05

Hi Evan,

IMHO serialization should be optional. Only a minority of classes will be intended to be passed across the wire. Most classes don't need to be serializable.

So when working on it from the tooling perspective, I could only imagine that it would be useful to exclude Progress.Lang.Object from what the tooling looks at. 

So when you actively select a super class (Progress.Lang.Object is typically not actively selected as a super class), the re-use the serializable flag of the super class.

Mit freundlichen Grüßen / Best regards,
 
Mike Fechner
Geschäftsführer / Director
 
Consultingwerk Ltd.
Unter Käster 1
50667 Köln / Germany
 
Tel.:  +49 221 / 6 77 88 55 0
Fax.: +49 221 / 6 77 88 55 5
Mobil: +49 171 / 4 357 484
 
 
Experts in OpenEdge & .NET

Am 06.05.2014 um 19:11 schrieb "Evan Bleicher" <bounce-bleicher@community.progress.com>:

Reply by Evan Bleicher

Laura has provided input on this thread from the Language / Runtime perspective.  As previously noted, the ABL runtime will not allow part of a hierarchy to be marked SERIALIZABLE.  The language team believes that this is the proper behavior and consistent with other OO languages.  Simon has noted how this can be problematic for AppErrors.   In this case, if a routine on an AppServer throws a customized error object (something that inherits from Progress.Lang.AppError) and the programmer does not mark this object as SERIALIZABLE, throwing this object cross the AppServer boundary will not work.  There will be a message in the AppServer log file noting this situation, and the caller on the ABL client will receive an ERROR but none of the data associated with the Progress.Lang.AppError will be available to the client.

Maybe this issue should be discussed not from the language perspective, but from a tooling perspective.  Should there be an option so that in PDSOE the class wizard defaults the SERIALIZABLE checkbox to the SERIALIZABLE value from the super class?  In this model, when defining a new class the default value for SERIALIZABLE will be the same as the class this class inherits from.  Since everything inherits from Progess.Lang.Object – which is also SERIALIZABLE – all objects by default will be SERIALIZABLE.  As noted previously, this would mean one would need to opt out of making a class SERIALIZABLE.  I don’t believe that this is correct, but wanted to see what others thought.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

Posted by Mike Fechner on 06-May-2014 16:09

The Language is perfectly, as it is right now!

As with returning error objects to the client, I see that as a framework challenge. There should only be a few entry points to the backed anyway. And in those you can CATCH all errors thrown on the AppServer in a central place, and if the error is serializable, re-throw to client, if not, throw an alternative error to the client (saving the messages and stack trace, but not additional properties)

Mit freundlichen Grüßen / Best regards,
 
Mike Fechner
Geschäftsführer / Director
 
Consultingwerk Ltd.
Unter Käster 1
50667 Köln / Germany
 
Tel.:  +49 221 / 6 77 88 55 0
Fax.: +49 221 / 6 77 88 55 5
Mobil: +49 171 / 4 357 484
 
 
Experts in OpenEdge & .NET

Am 06.05.2014 um 19:21 schrieb "Laura Stern" <bounce-stern@community.progress.com>:

Reply by Laura Stern

What you're suggesting is not proper OO behavior.  Though I REALLY DO sympathize with what your saying.  However, there should be a relatively simple way to find all of your error classes so you can code them appropriately.  For example if all error objects have the word Error as part of the class name, you could do:

   grep Error *.cls | grep CLASS

Or perhaps you should be asking if the tooling (i.e., PDSOE) can help with this rather than asking for a language change.

Stop receiving emails on this subject.

Flag this post as spam/abuse.

Posted by Thomas Mercer-Hursh on 06-May-2014 16:13

I think I am with Mike.  Most of the time, a subclass will want the same as the super.  The developer can handle any exceptions, if any.

Posted by Marian Edu on 07-May-2014 01:20

not all applications uses a framework, not all frameworks have a single (few) entry points, not everyone is using PSDOE (yeah, there is life outside of earth... bah, meant windowze)

stackoverflow.com/.../why-my-exception-class-needs-to-be-serialized

imho having 'throwable' (aka all errors) serializable is a good thing but there is also the .net approach and given the tight integration with 4gl that will probably win :(

stackoverflow.com/.../are-all-net-exceptions-serializable

Posted by Simon L. Prinsloo on 07-May-2014 06:24

[quote user="GregHiggins"]

I fail to see how remembering to implement a catch block, etc. is significantly different from remembering to make an object / error serializable.

[/quote]

Exactly. Someone forget both and somewhere down the line someone else like me end up being the fool hunting weird ghosts, simply because the message got lost due to the fact that the default error handling is not quite robust.

Errors, or exceptions, are quite different from other objects. The condition that cause them to be constructed can be a foreseen problem or it can be an unforeseen, exceptional case. Hence  there is not properly guaranteed and complete set of test cases to put them through.

Nothing except errors can be thrown, because errors are an exceptional case, and therefore I feel that an exception to the rule of not "downgrading" and serialising will warrant more robust exception handling.

Posted by andrew.may on 07-May-2014 07:04

I agree.

For non-serializable error subclasses thrown across the appserver boundary, I feel that the nicest behaviour would be:

  • Error cast to closest serializable parent (which will be a subclass of Progress.Lang.AppError) before being thrown across the boundary.
  • Warning message written to server's log-manager to log the implicit cast.
  • Possibly add a message entry to the thrown (cast) error to note the casting.

As Simon's said, throwables are a very different kind of class & it isn't unreasonable to have custom code for them.

I can't think of a scenario where losing a thrown error because it wasn't serializable would be desirable behaviour.

If no such scenario exists, it would be better for the language to handle this automatically on appserver calls, rather than making it the responsibility of tooling/devs to add boilerplate to each backend procedure.

Posted by Thomas Mercer-Hursh on 07-May-2014 09:09

Just to play devils advocate for a moment, why isn't the error being handled on the server side?  Then, if appropriate to send some message to the client, do so, but not in object form.  Certainly, this is a requirement with any non-ABL client, so why not use it for ABL clients too?

Posted by Simon L. Prinsloo on 07-May-2014 14:44

[quote user="Thomas Mercer-Hursh"]

Just to play devils advocate for a moment, why isn't the error being handled on the server side?  Then, if appropriate to send some message to the client, do so, but not in object form.  Certainly, this is a requirement with any non-ABL client, so why not use it for ABL clients too?

[/quote]

Correct. In an ideal world - huge systems generates no  unforeseen exceptions and programmers makes no mistakes, unit tests are 100% comprehensive and fool proof and therefore all errors are properly handled on the server.

But some of us live in the world of the maintenance programmer:

On the one end you wonder how and when the data got this way, on the other end a critical process is stuck, the CEO is on the CFO's back who is on the CIO's back who is on your back about something that flushed unseen to a since recycled log 9.878 financial months ago when the user shrugged about a "funny" message that popped up but everything SEEMED to have worked so he did not mention it, all because a long gone inexperienced guy or girl failed to properly handle the error when the code was written four years ago during an extreme late night session when everyone rushed for a deadline and code review was a fairy tale....

Posted by Thomas Mercer-Hursh on 07-May-2014 15:00

Well, now, just wait a minute.  What we are talking about here is a new capability.  By definition, we have never been able to pass these errors back to the client before and now we will be able to do.  So, my question is, do we actually want to.  If we pass the error object itself back to the client, we are locking ourselves into ABL clients and creating a future maintenance headache should we decide to move to a different kind of client later.  But, if we catch and handle the error on the server, sending back a message as needed to the client, a non-object message, then we are setting ourselves up to be client-technology independent in the future.  Moreover, we are handling the error in the context of where the error occurred, rather than depending on some client code, which might well be written by someone else, to handle an error from our context.  If anything, we are going to create a maintenance nightmare dealing with client code which has not been used to getting error objects back from the AppServer, suddenly needing to deal with such objects, often having little idea of what is going on in the AppServer code.

Posted by gus on 07-May-2014 15:17

so maybe the thing to do would be to have the server should tell the
client there was an error, giving back the error code. the client could
then request the error object if it wanted it.

Posted by Thomas Mercer-Hursh on 07-May-2014 15:24

What can the client do with the error object that it can't do with a sufficiently rich message?  

To me, crossing the AppServer boundary is an absolute domain boundary and I think that messages across such boundaries should be technology neutral since one can't count on another domain being in the same technology.  Might be today; might not be tomorrow.

This thread is closed