Using the object oriented exception concept I sometimes find myself in a situation that looks like the following.
I define a method that uses an exception class in its signature to indicate some kind of error. So for example this:
CLASS lcl_partner_finder DEFINITION FINAL CREATE PRIVATE. PUBLIC SECTION. CLASS-METHODS: "! Find a business partner id for a debtor "! @parameter iv_debtor | Debtor id "! @parameter rv_partner | Found business partner id "! @raising lcx_bp_not_found | No business partner exists for iv_debtor get_partner_from_debtor IMPORTING iv_debtor TYPE kunnr RETURNING VALUE(rv_partner) TYPE bu_partner RAISING lcx_bp_not_found. ENDCLASS.
According to the guidelines for exceptions I have to pick which of the 3 base classes my new exception class LCX_BP_NOT_FOUND uses. In this particular case I think that it would be reasonable to pick CX_STATIC_CHECK because the user of this method cannot validate beforehand if the partner exists, at least not using this class (so no reason for CX_DYNAMIC_CHECK). One could even argue that this method could be used for that exact reason. CX_NO_CHECK is out of the question in my opinion.
So I create the exception class:
"! Business partner not found exception CLASS lcx_bp_not_found DEFINITION FINAL CREATE PUBLIC INHERITING FROM cx_static_check. PUBLIC SECTION. METHODS: constructor IMPORTING ix_previous LIKE previous OPTIONAL iv_identification TYPE csequence OPTIONAL, get_text REDEFINITION. DATA: mv_identification TYPE string READ-ONLY. ENDCLASS.
Because of the static check any time I call get_partner_from_debtor without a try-catch that includes lcx_bp_not_found or propagation of the exception I will get a syntax warning. Which is what I want, because the probability of it happening is quite high, so the caller should be forced to handle this exception.
Later on in my implementation I define a new method to do something else.
"! Check if a business partner has a specified role (currently active) "! @parameter iv_partner | Partner id "! @parameter iv_role | Role to check "! @parameter rv_role_present | Role is present partner_has_role IMPORTING iv_partner TYPE bu_partner iv_role TYPE bu_role RETURNING VALUE(rv_role_present) TYPE abap_bool.
Now the first step in implementing it would be to validate the import parameters. So I would check if the partner specified in iv_partner exists. And if it does not I would not continue in the method and instead I would like to raise an exception indicating this error. Above I have already defined an exception class for the case that a business partner could not be found. But in this second method the perspective has changed. I would argue that because iv_partner is a direct importing parameter it is the responsibility of the caller to retrieve the bp id. Most of the users of this method would probably be annoyed if they got a warning to catch a LCX_BP_NOT_FOUND exception because they have implemented code before calling it that guarantees a valid iv_partner actual parameter. According to the guidelines this is the exact use case of CX_DYNAMIC_CHECK exceptions. But my exception is already inheriting from CX_STATIC_CHECK.
My question is, what is the recommended action in this situation? I have the same exception, with the same attributes, the same additional methods, maybe the same T100 message class behind it, but looked at from two different angles.
Approaches I have thought of so far:
I most of the time opt for the third approach. One does run into the risk of accidentally propagating the exception though, because the calling method might use LCX_ILLEGAL_ARGUMENT as well on its own. So I am not certain as to what is the ideal solution for this problem.
I am interested in any comments or recommendations.