Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

Handling general errors via class based exceptions

matt
Active Contributor
0 Kudos

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

8 REPLIES 8

Ramneek
Advisor
Advisor
0 Kudos

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

Clemenss
Active Contributor
0 Kudos

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

matt
Active Contributor
0 Kudos

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.

matt
Active Contributor
0 Kudos

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

pokrakam
Active Contributor
0 Kudos

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

matt
Active Contributor
0 Kudos

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.

pokrakam
Active Contributor
0 Kudos

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...

Clemenss
Active Contributor
0 Kudos

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