cancel
Showing results for 
Search instead for 
Did you mean: 

Interesting phenomenon while re-raising a class-based exception

michał_badura
Participant
0 Kudos

Hi all,

I have encountered an interesting phenomenon while re-raising a class-based exception. To not waste your precious time, here's the code:

 

CLASS exception_1 DEFINITION INHERITING FROM cx_static_check.
ENDCLASS.

CLASS exception_2 DEFINITION INHERITING FROM cx_static_check.
ENDCLASS.

CLASS class_1 DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS
      do_something
        RAISING
          exception_1
          exception_2.
ENDCLASS.

CLASS class_2 DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS
      do_something
        RAISING
          exception_1
          exception_2.
ENDCLASS.


TRY.
    class_2=>do_something( ).
  CATCH exception_1
        exception_2 INTO DATA(exception).
    exception->get_source_position( IMPORTING source_line = DATA(source_line) ).

    BREAK-POINT.
ENDTRY.

CLASS class_1 IMPLEMENTATION.
  METHOD do_something.
    RAISE EXCEPTION TYPE exception_1.
  ENDMETHOD.
ENDCLASS.

CLASS class_2 IMPLEMENTATION.
  METHOD do_something.
    TRY.
        class_1=>do_something( ).
      CATCH exception_1
            exception_2 INTO DATA(exception).
        RAISE EXCEPTION exception.
    ENDTRY.
  ENDMETHOD.
ENDCLASS.

 

There are two problems with this code. Firstly, although it is syntactically correct and does not produce any side effects, at least not any I know, I get a warning from syntax checker, saying there is an exception of type CX_STATIC_CHECK, raised at line 49 (47 in above code), which is neither caught, nor is it declared in the RAISING clause.

raise exception.png

But there is no such exception! It will be either EXCEPTION_1 or EXCEPTION_2 and if you analyze the code and its flow, you will see that the reference is kept. This warning is however only then reported, when at least two exception classes are caught. First I thought, maybe because CX_STATIC_CHECK is the common super class for both EXCEPTION_1 and EXCEPTION_2. So I changed the inheritance of one of them to CX_NO_CHECK. I still get the same warning. Even if I change the inheritance of them both, the warning still says exception CX_STATIC_CHECK is not handled properly.

This "error" is reported with priority 1. I know, I can change the priorities in customizing, but 1 is okay for the real errors. And it can't be suppressed with pragma or pseudo comment. I would have to request an exemption. Or "correct" it by declaring CX_STATIC_CHECK in the RAISING clause, which however is not needed from the code perspective and would be wrong if not all declared exceptions inherit from CX_STATIC_CHECK.

I think it's a bug in syntax check, but am not quite sure, wanted to know your opinion first. I can reproduce it in 7.57 and 7.40.

The second problem I have with this code is that the original source position details get lost! The method GET_SOURCE_POSITION in the above example will give back line 47 and not 37. In the real case I wanted to work with RESUME. Here's the code:

 

CLASS exception_1 DEFINITION INHERITING FROM cx_dynamic_check.
ENDCLASS.

CLASS exception_2 DEFINITION INHERITING FROM cx_dynamic_check.
ENDCLASS.

CLASS class_1 DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS
      do_something
        IMPORTING
          input TYPE i
        RAISING
          RESUMABLE(exception_1)
          RESUMABLE(exception_2).
ENDCLASS.

CLASS class_2 DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS
      do_something
        IMPORTING
          input TYPE i
        RAISING
          RESUMABLE(exception_1)
          RESUMABLE(exception_2).
ENDCLASS.


TRY.
    class_2=>do_something( 1 ).
  CATCH exception_1
        exception_2 INTO DATA(exception).
    exception->get_source_position( IMPORTING source_line = DATA(source_line) ).

    BREAK-POINT.
ENDTRY.

CLASS class_1 IMPLEMENTATION.
  METHOD do_something.
    CASE input.
      WHEN 1.
        RAISE RESUMABLE EXCEPTION TYPE exception_1.
      WHEN 2.
        RAISE RESUMABLE EXCEPTION TYPE exception_2.
      WHEN 3.
        RAISE EXCEPTION TYPE exception_1.
      WHEN OTHERS.
        RAISE EXCEPTION TYPE exception_2.
    ENDCASE.
  ENDMETHOD.
ENDCLASS.

CLASS class_2 IMPLEMENTATION.
  METHOD do_something.
    TRY.
        class_1=>do_something( input ).
      CATCH BEFORE UNWIND exception_1
                          exception_2 INTO DATA(exception).
        IF exception->is_resumable = abap_true.
          RESUME.
        ELSE.
          RAISE EXCEPTION exception.
        ENDIF.
    ENDTRY.
  ENDMETHOD.
ENDCLASS.

 

In my real life scenario, the method which is causing an exception, couls sometimes proceed. Like for example getting an e-mail address for a business partner. If there is no valid address or only one, then it's clear. But if there are multiple valid addresses? The method could just proceed with any valid address. But it can't decide on its own. That's why a resumable exception, and if the caller resumes, then it's okay to use just any valid address. I don't want to pass the resumable exception up to the main program - it's to far, it can't decide whether it was okay, that the address was not unique or not. That's why I'm catching the exceptions and if they're resumable then I'm resuming, and if not, I would like to proceed with the original flow of RAISE EXCEPTION. But apparently I can't? 

Do you know any way to solve this problem?

I'll be glad to hear back from you, what's your idea on the two questions.

Many thanks in advance!

Best regards

Michał

Accepted Solutions (0)

Answers (0)