SAPGUI not displaying long_text or text for unhandled custom exceptions - oop

In SAP NetWeaver 7.52 I created an ABAP classed based exception that works fine while executing within a try catch clause in the report/program. But the custom message is not displayed in SAPGUI when the exception is not handled by a try catch clause.
What I'm looking for is that when no try catch is defined the exporting message used at the moment of the raise statements is shown in the "UNCAUGHT_EXCEPTION". I have tried redefining the get_text( ) and get_longtext( ) methods. But the ABAP Run time error does not give any useful information to the developer about the cause (which is stored in the "attr_message" attribute of the exception).
When using the "try catch" the message can be retrieved without problems, but the idea is that SAPGUI presents the developer the right message in the "ABAP Runtime Error" report.
zcx_adk_exception.abap
"! Base exception for all ABAP Development Kit (ADK) exceptions
class zcx_adk_exception definition public create public inheriting from cx_dynamic_check.
public section.
"! Initializes the exception message
"! #parameter message | Message related to the reason of the exception
methods constructor
importing value(message) type zadk_str optional.
"! Returns the message associated to the exception
methods get_message
returning value(result) type zadk_str.
methods if_message~get_text redefinition.
methods if_message~get_longtext redefinition.
private section.
data attr_message type zadk_str value ''.
endclass.
class zcx_adk_exception implementation.
method constructor ##ADT_SUPPRESS_GENERATION.
super->constructor( ).
if message is not initial.
me->attr_message = message.
endif.
endmethod.
method get_message.
result = me->attr_message.
endmethod.
method if_message~get_text.
result = me->get_message( ).
endmethod.
method if_message~get_longtext.
result = me->get_message( ).
endmethod.
endclass.
What works fine:
try.
raise exception type zcx_adk_exception exporting message = 'Base_Exception_Error'.
catch zcx_adk_exception into data(ex).
write: / 'Example 1:', ex->get_message( ).
write: / 'Example 2:', ex->get_text( ).
write: / 'Example 2:', ex->get_longtext( ).
endtry.
And the output is this:
What does not work:
" Not Catching the exception
raise exception type zcx_adk_exception exporting message = 'Base_Exception_Error'.
This results in the following message being displayed instead

Following the previously proposed idea of using a message I came up with the following code that allows the exception to be raised with a message. This allows the exception to show the right message when called within a "try catch" block and display a useful message in the "Error analysis" section of the dump generated by SAPGUI.
Solution:
"! Program to test functionalities and utilities
REPORT zsandbox_tests.
" Exception Class
CLASS lcl_exception DEFINITION INHERITING FROM cx_dynamic_check.
PUBLIC SECTION.
INTERFACES if_t100_dyn_msg.
METHODS if_message~get_text REDEFINITION.
METHODS constructor
IMPORTING VALUE(message) TYPE string.
PRIVATE SECTION.
DATA attr_message TYPE string VALUE ''.
ENDCLASS.
CLASS lcl_exception IMPLEMENTATION.
METHOD if_message~get_text.
result = attr_message.
ENDMETHOD.
METHOD constructor.
super->constructor( ).
me->attr_message = message.
ENDMETHOD.
ENDCLASS.
" Class that raises the exception
CLASS lcl_main DEFINITION.
PUBLIC SECTION.
CLASS-METHODS main RAISING lcl_exception.
ENDCLASS.
CLASS lcl_main IMPLEMENTATION.
METHOD main.
DATA raise_message TYPE string VALUE 'Custom Message for the Exception'.
RAISE EXCEPTION TYPE lcl_exception
MESSAGE e000(lcl_exception) WITH raise_message '' '' '' " The if_t100_dyn_msg supports 4 attributes: V1, V2, V3 and V4 but I only use the first one
EXPORTING message = raise_message.
ENDMETHOD.
ENDCLASS.
" Call to Main Method
START-OF-SELECTION.
TRY.
lcl_main=>main( ).
CATCH lcl_exception INTO DATA(ex).
WRITE ex->get_text( ).
ENDTRY.
This generates the following output:
When no try catch is used:
" Call to Main Method
start-of-selection.
lcl_main=>main( ).
This is the output:

TL;DR : SAP did not plan to permit the customization of a short dump by the developer.
A "short dump" is a report which is generated by the ABAP kernel when an unexpected error occurs in an ABAP program, i.e. an error due to a bug in the program (usually an uncaught exception, or non-catchable errors) or to a system failure (input/output resources, memory resources, etc.)
It's intended to help the developer analyze the cause of the error and correct it.
It's not intended to be generated on purpose, except in a situation that the developer has made theoretically impossible, but actually happens, and which is thought to require many information to analyze if it happens, hence a short dump.
If it's really your intention to generate a short dump with a message, for some purpose, there are two ways:
MESSAGE 'message text' TYPE 'X'. (often used in standard SAP programs, especially in update function modules)
RAISE SHORTDUMP ... or ... THEN THROW SHORTDUMP ... in conditional expression. Both exist since ABAP 7.53. For instance RAISE SHORTDUMP TYPE zcx_adk_exception EXPORTING message = 'Base_Exception_Error'.
The short dump will contain the message text in the Analysis section.

Related

CALL METHOD with dynamic method name, RuntimeException

I try to demonstrate a CALL METHOD statement with dynamic method name on a 7.40 system. I use the following test code and get an ABAP Runtime Error in line 27. The Error Analysis in the Description of Exception states ... in the class LCL, the method "m" could not be found. But the standalone method call succeeds in calling m.
REPORT ZUTEST10.
CLASS lcl DEFINITION.
PUBLIC SECTION.
METHODS m.
ENDCLASS.
CLASS lcl IMPLEMENTATION.
METHOD m.
write / 'success'.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
DATA oref TYPE REF TO lcl.
CREATE OBJECT oref.
oref->m( ). " works fine
DATA name TYPE c VALUE 'm'.
CALL METHOD oref->(name). " <-- Runtime Error
In the background all method names are uppercase, so you have to call the method like this:
DATA name TYPE c VALUE 'M'.
On the other hand you can catch this exception, so the program won't dump, even if the method does not exist:
TRY.
CALL METHOD oref->(name).
CATCH cx_sy_dyn_call_illegal_method
INTO DATA(lx_illegal_method).
"handle illegal method call
ENDTRY.

Chaining Promises with custom error types with Kovenant

I'm using Retrofit to access a REST API and I would like to use Kovenant's then function to chain several units of work. In other words, I want to feed the output of one API call as a parameter to another API call.
I've defined a custom error type that includes a property to contain API specific error codes defined as follows:
class ApiError(val statusCode: Int, val apiErrorCode: Int, val message: String)
If an error occurs during an API call, an instance of this class is created with the appropriate error codes.
According to Kovenant's documentation, I can create an instance of Deferred<V, E> to obtain a Promise<V, E>. I was hoping that I could supply ApiError for the generic parameter E. I didn't see any generic constraints in Kovenant's definition of Deferred that seem to require E to be an Exception.
That being said, when I attempt to chain two functions that return Promise<V, ApiError> using then, I receive a compiler error stating that the expected type for then is a Promise<V, Exception>.
Can I make Kovenant work with a custom error type and if not, is subclassing Exception to include the properties I need the correct solution for what I'm trying to achieve?
Some of the base definitions do not have generic bounds for E but almost all of the extension functions do indicate the E is of type Exception. Viewing the source code in Kovenant promises-api.kt shows that it is clear that most things have this expectation.
You can simply change your error class to be a descendant of Exception:
class ApiError(val statusCode: Int, val apiErrorCode: Int, message: String) : Exception(message)
Then you can throw it to fail the Promise or use it to call fail on the Deferred.

Literal description of object type

VB2010 with ArcObjects. Im having a problem recalling how to do this. I can test for an object type and then do something if it is the proper type. All else I want to display a message with the type that is not supported. So I have:
Dim pRasRenderer As IRasterRenderer
pRasRenderer = pRasterLayer.Renderer
If TypeOf pRasRenderer Is IRasterClassifyColorRampRenderer Then
'process the layer
Else
Debug.Print "Type not supported: " & pRasRenderer.ToString
End If
If not supported the print statement should read
"Type not supported: IRasterStretchColorRampRenderer"
or any of the other types that I do not process. But All I get back is
"Type not supported: System.__ComObject"
I tried GetType() and TypeName. Just cant remember if I can do this or not.
With COM, the type isn't IRasterStretchColorRampRenderer, it's some COM type that (most likely) implements quite a few distinctly different interfaces. Given that you're working from .NET, you'll get __ComObject any time you try to access the "type" of the object directly.
The actual "type" of the object which implements IRasterStretchColorRampRenderer, for example, is more than likely a native implementation of a COM CoClass. As such, you'll never get a "managed" type name from .NET code for this.
Unfortunately, this means that you're best solution is likely to report that the type passed in is not supported without trying to report the actual type passed into the method. This would likely be something like:
Debug.Print "Type not supported: Current layer is not using a Classify Color Ramp Renderer"

System.Runtime.InteropServices.MarshalDirectiveException occured

I wrote a very simple code that reads and writes from a card. I got an error:
An unhandled exception of type
'System.Runtime.InteropServices.MarshalDirectiveException' occured in
ReadandWrite.exe
Additional information: PInvoke restriction: can not return variants.
Code Snippet:
Console.WriteLine("Address = 0x3c3, Value = 0x", MX4.r_1byte(963).ToString)
I am trying to understand the error and how to fix it.
Sounds like you're forgetting to declare an Interop Type for one or more of your Public methods/properties. See this MSDN thread.

Serializing Exceptions WCF + Silverlight

I have a WCF service I use to submit bugs for my project. Snippet of the data class:
Private _exception As Exception
<DataMember()> _
Public Property Exception As Exception
Get
Return _exception
End Get
Set(ByVal value As Exception)
_exception = value
End Set
End Property
I have a Silverlight app that uses the WCF service to send any bugs home if and when they occur. This is the error I'm testing with:
Dim i As Integer = 5
i = i / 0
The problem is SL is banging on with this message:
System.ServiceModel.CommunicationException was unhandled by user code
Message=There was an error while trying to serialize parameter :bug. The InnerException message was 'Type 'System.OverflowException' with data contract name 'OverflowException:http://schemas.datacontract.org/2004/07/System' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.
Is there some trick to get a generic .NET Exception (any InnerException) to serialize properly? I'm not doing anything funky with the exception - it's just a plain 'ol exception
Thanks for any help.
I doubt very much that you can serialize a .NET-specific type like an Exception. I recommend you create your own class to hold the parts of the exception you want serialized.
This may be a problem with implicitly casting the OverflowException into a System.Exception.
The data contract serializer is very specific. This can be good and bad.
I would try just throwing a new System.Exception to see if this works OK.
If this is the case, you may need to dumb down the exception, creating a new System.Exception with the original exception message in it.
Or, like John said, you might have a better go of it if you create a custom error class that holds the exception info.