Written by

Cofounder at snext
Question Blaise ZARKA · Dec 19, 2019

%New error handling

Hi,

On a persistent class, I have defined an %OnNew method that validate some properties with appropriate status code for each kind of error. Question is: how do you catch the specific error when %New is called on this class?

Surrounding %New method with a try-catch not seems to work.

Thanks

Comments

Warlin Garcia · Dec 19, 2019

The error should be in the %objlasterror variable. You would have to check: if %New() returned a new instance, if not then check the value of %objlasterror. Then perform any error handling you'd like to do. 

try/catch doesn't work because %New() doesn't throw any exceptions.

0
Blaise ZARKA  Dec 19, 2019 to Jenna Makin

Interesting point Jenna. Thanks.
I'll try that!

0
Warlin Garcia  Dec 19, 2019 to Jenna Makin

While this is certainly possible, you'd be breaking the "contract". %OnNew() is expected to return a %Status that will be handled by %New().  This means the exception will be thrown by %OnNew()  but %New() won't care about it and still return an object (unless something else prevents it from doing so). 

0
Joel Solon  Jan 30, 2020 to Joel Solon

I've changed my recommendation on this a little. Return the result of %ValidateObject() as the final argument, but don't return that status as the return value of the method. That way, if there are any required properties, and the call to %New() doesn't supply them, %OnNew() still works. Here's the updated example:

/// constructor
Method %OnNew(name As %String = "", phone As %String = "", dob as %Date, Output valid As %Status) As %Status [Private]
{
    set valid = $$$OK
    set ..Name = name
    set ..Phone = phone
    set ..DOB = dob
    set valid = ..%ValidateObject() // validate the new object
    return $$$OK
}
0
Jenna Makin · Dec 19, 2019

The proper way to do this would be

if the %OnNew is going to error you should throw an exception-  If you did this, the thrown exception should be caught by your try/catch block that calls the %New() method.  Then in the catch block you can examine either %objlasterror or perhaps some specific error variable you create for your purposes.

0
Joel Solon · Dec 23, 2019

%OnNew() must return a %Status to %New(). But the code that calls %New() also needs the %Status. I think a "best practice" is simply to add an Output  %Status argument to %OnNew() that will therefore be returned to %New(). So the %Status is being returned using return (for %New()) and by using a pass-by-reference argument (for the code that calls %New()).

/// constructor
Method %OnNew(name As %String = "", phone As %String = "", dob as %Date, Output st As %Status) As %Status [Private]
{
    set st = $$$OK
    set ..Name = name
    set ..Phone = phone
    set ..DOB = dob
    set st = ..%ValidateObject() // validate the new object
    return st
}
0
Guillaume Rongier · Jan 30, 2020

Hi Blaise,

You can pass %OnNew expection to %New with this code snippet :

ClassTest.PersitenceTestExtends%Persistent
{

 

PropertymandatoryAs%String [ Required ];

 

Method%OnNew(mandatoryAs%String = "") As%Status
{

 

set ..mandatory = mandatory

 

$$$ThrowOnError(..%ValidateObject())

 

Quit$$$OK
}

 

}

 Now when you call the new method :

USER>set test = ##class(Test.PersitenceTest).%New()

  If $isobject($get(newerror))=1 Throw newerror
                                 ^
<THROW>%Construct+9^Test.PersitenceTest.1 *%Exception.StatusException ERROR #5659: Property 'Test.PersitenceTest::mandatory(10@Test.PersitenceTest,ID=)' required

Now you can catch you %OnNew expection anywhere :

ClassMethodtest() As%Status
{
try {
settest = ##class(Test.PersitenceTest).%New()
}
catchex {
Returnex.AsStatus()
}
Return$$$OK
}
0