2011 Jan 14 4:19 PM
Fairly standard scenario: I've got this.
DATA: l_requester TYPE xubname.
CALL FUNCTION 'ENQUEUE_EZMYTAB'
EXPORTING
username = i_username
EXCEPTIONS
foreign_lock = 1
system_failure = 2
OTHERS = 3.
CASE sy-subrc.
WHEN 1.
l_requester = sy-msgv1.
RAISE EXCEPTION TYPE zcx_my_exception EXPORTING textid = zcx_my_exception=>lock_error
user = i_username
lockedby = l_requester.
WHEN 2.
RAISE EXCEPTION TYPE zcx_my_exception.
ENDCASE.
But what I really want for WHEN 2 is the class based exception of
MESSAGE sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1...
I.e., in my calling code, I want to catch the exception, and display whatever the original error message was as generated by the ENQUEUE function module.
I suppose I could do this
DATA: ls_error TYPE scx_t100key.
...
WHEN 2.
ls_error-msgid = sy-msgid.
ls_error-msgty = sy-msgty.
ls_error-msgno = sy-msgno.
...
RAISE EXCEPTION TYPE zcx_my_exception EXPORTING textid = ls_error
but I can't help feel I'm missing something staggeringly obvious...
matt
2011 Jan 14 4:59 PM
May not be the best of the solution but one way could be to use a string variable (lv_dummy) and then
MESSAGE sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1...INTO lv_dummy.
Now you could pass this string to an attribute in your exception class and use the same syntax
RAISE EXCEPTION TYPE zcx_my_exception EXPORTING textid = zcx_my_exception=>...
to raise the exception.
Thank you,
Ramneek
2011 Jan 15 12:09 AM
Hi Matt,
this may sound too simple:
For me the real advantage of class-based-exception is that they can be raised in an inner block and caught in an outer block at any level.
I never use the exception attributes to communicate any details, but use
IF SY-SUBRC NE 0.
MESSAGE sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1... INTO lv_string.
Raise Exception type zcx_my_exception.
ENDIF.
Catching the exception I may (roughly) know where it comes from. As the message variables are present, I can check their values or repeat the MESSAGE without INTO. The main function of MESSAGE INTO is for transparency, the ability to see the whole message in debugger in lv_string and the where-used-list if message is created by programmer..
If I really need different reaction for different SY-SUBRC ( = different untyped exception), I'd rather create different class-based exceptions. This helps transparency.
In other oo language you do not have an ABAP message concept with everywhere-present message variables. Why use this crutch of putting the message variable filled by functions exception into exception object attributes only to convert them back to message output?
I prefer [KISS|http://en.wikipedia.org/wiki/KISS_principle].
Regards,
Clemens
2011 Jan 15 7:16 AM
All I'm really interested in is returning the message back to the view, in the simplest way, without violating the MVC pattern.
In the CATCH, I've currently got:
CATCH zcx_my_exception INTO lx_error.
MESSAGE lx_Error TYPE 'I'.
I'd like to keep that. The trouble with EXPORTING a string to the exception when I raise it, is that I'm limited to 50 characters, as the string goes into MSGV1.
2011 Jan 15 11:53 AM
This is what I did in the end:
WHEN 1.
l_requester = sy-msgv1.
RAISE EXCEPTION TYPE zcx_myexception EXPORTING textid = zcx_myexception=>lock_error
user = me->username
lockedby = l_requester.
WHEN 2.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 INTO l_errmsg.
RAISE EXCEPTION TYPE zcx_myexception EXPORTING msg = l_errmsg.
In the catch, I do this.
DATA: lx_error TYPE REF TO zcx_myexception.
...
CATCH zcx_myexception INTO lx_error.
IF lx_error->msg IS INITIAL.
MESSAGE lx_error TYPE 'I'.
ELSE.
MESSAGE lx_error->msg TYPE 'I'.
ENDIF.
I'd forgotten the obvious point that the attributes of an exception object are directly available!
thanks
matt
2011 Jan 18 4:46 PM
Hi Matt,
Purely academic as it's after the fact, but isn't this the type of thing that message class based exception classes are supposed to do? I've never really seen the point of raising old-fashioned messages from an exception class , but it seems what you're trying to do.
You'd need to create an exception class for this purpose, but then you should be able to just raise the exception in the usual way and just map the exception attributes to the message variables in the exception class text definition rather than in your code.
Cheers,
Mike
2011 Jan 18 4:52 PM
The problem is that these fm are SAP provided. If they threw proper exceptions we won't have a problem. This particular fm only returns two errors - locked, or the locking system is broken. But other fm can return all sorts of error messages. I don't want them to return a message to the screen - as my methods are part of the model (MVC). I don't want to have to write an exception class for every possible scenario the SAP fm might throw up.
2011 Jan 18 5:25 PM
You don't need an exception class for each message. Either one class per message class or one per function module to keep some kind of logical division, or you could just lump it all into a big catchall class. You'd still need to create a text per message. Whether it's worthwhile depends on the number of messages I guess. Hmm, so in we're back to I can't see much point to message-based exception classes...
2011 Jan 18 6:45 PM
Hi,
my cent:
One if not the main advantage of class-based-exceptions is that they can be caught in any outer block as long as they are in the blocks interface.
As we can not have more than one exception occur at any given point of time in one LUW, I have no problem with using the SY-MSGxy variables to communicate exception details.
Between RAISING a class-based exception and catching it nothing is processed except the exception constructor.
I do not think this is a violation of MVC approach, take it as ABAP-specific specialization, very simple and fully transparent.
Regards,
Clemens