Anfang des InhaltsbereichsDiese Grafik wird im zugehörigen Text erklärt Verbindung zu Objektreferenzen (Instanzen) Dokument im Navigationsbaum lokalisieren

Eine ABAP-Objektreferenz wird in JavaScript als Proxy-Objekt der vordefinierten Proxy-Klasse SAPAbapOrefClass abgebildet. Der JavaScript-Referenz kann über den Parameter NAME_PROP der Methode BIND ein (case-sensitiver) Name gegeben werden.

Die Komponenten eines Proxy-Objekts sind:

Das Proxy-Objekt kann in JavaScript nicht um weitere Properties oder Methoden erweitert werden. Bei Zuweisungen an gebundene Objektreferenzen in JavaScript oder wenn in JavaScript versucht wird, auf Attribute von nichtexistenten ABAP-Objekten zuzugreifen (die Referenzvariable in ABAP ist initial), wird die JavaScript-Verarbeitung abgebrochen.

Zugriff auf Instanzattribute

Zuweisungen an die Objektreferenzvariable in ABAP bewirken, dass danach auch in JavaScript mit den Attributen des ABAP-Objekts gearbeitet wird, auf das die Objektreferenzvariable nach der Zuweisung zeigt. Die Variable in JavaScript ist an die Objektreferenzvariable in ABAP gebunden und nicht an das ABAP-Objekt (siehe auch BIND_INSTANCE).

Das JavaScript-Objekt ist mit dem statischen Typ der Objektreferenzvariablen verknüpft. Wenn durch eine Zuweisung in ABAP ein Narrowing Cast durchgeführt wird, behält auch das JavaScript-Objekt seinen Typ und kann nicht auf hinzugekommene Attribute des dynamischen Typs zugreifen. Widening Casts sind ebenfalls nur in ABAP möglich und werden dort überprüft. Es kann in JavaScript deshalb nie die Situation geben, dass auf Attribute zugegriffen wird, die es im referierten Objekt nicht gibt.

Vorsicht ist geboten, wenn Properties der gebundenen Objektreferenzvariablen in JavaScript anderen Variablen zugewiesen werden. Wenn in ABAP das betreffende Objekt durch die Garbage Collection gelöscht wird, kommt es zu einem Laufzeitfehler, wenn versucht wird, die Zielvariable danach zu verwenden.

Beispiel

report DEMO_JAVA_SCRIPT_BIND_ATTRIBUT.

class C1 definition.
  public section.
    data ATTR type STRING.
    methods CONSTRUCTOR.
endclass.

class C1 implementation.
  method CONSTRUCTOR.
    ATTR = 'Hello '.
  endmethod.
endclass.

data OREF type ref to C1.

data RETURN_VALUE type STRING.

data SOURCE type STRING.

data JS_PROCESSOR type ref to CL_JAVA_SCRIPT.

start-of-selection.

  JS_PROCESSOR = CL_JAVA_SCRIPT=>CREATE( ).

  JS_PROCESSOR->BIND(  EXPORTING
                        NAME_OBJ  = 'abap'
                        NAME_PROP = 'Ref'
                       CHANGING
                         DATA      = OREF ).

  create object OREF.

concatenate  'if ( abap.Dref.notInitial() )  '
             '{ abap.Ref.attr += " World!"; }'
             INTO source.

  JS_PROCESSOR->EVALUATE( JAVA_SCRIPT = SOURCE ).
  write OREF->ATTR..

In diesem Beispiel verlängert JavaScript das Attribut OREF->ATTR von 'Hello' auf 'Hello World!'. Ein Zugriff in JavaScript auf 'oref.attr' vor der Anweisung CREATE OBJECT würde zum Abbruch der JavaScript-Verarbeitung führen.

Aufruf von Instanzmethoden

Um die öffentlichen Instanzmethoden des referierten Objekts in ABAP aus dem JavaScript aufzurufen, muß die Methode 'invoke' des betreffenden JavaScript-Objekts verwendet werden..

Die Methode invoke erwartet den Namen der ABAP-Instanzmethode als erstes Argument und in Kleinbuchstaben. Danach folgen die Übergabeparameter. Für jeden nicht-optionalen Schnittstellenparameter der ABAP-Instanzmethode muß ein durch Kommas getrenntes Paar bestehend aus Parametername und Aktualparameter angegeben werden. Die Reihenfolge der Paare ist beliebig. Optionale Parameter müssen nicht angegeben werden. Die in ABAP üblichen Zusätze EXPORTING, IMPORTING, CHANGING oder RETURNING werden ebenfalls nicht angegeben.

Einschränkungen

Werteübernahme vom RETURNING-Parameter

Der Rückgabewert von invoke wird automatisch durch den RETURNING-Parameter der aufgerufenen Methode versorgt. Falls der Typ des RETURNING-Parameters elementar ist, ist dies tatsächlich der Rückgabewert der ABAP-Methode. In diesem Fall muß für den RETURNING-Parameter also nicht unbedingt ein Argument angegeben werden. Falls der Typ des RETURNING-Parameters komplex ist oder es keinen RETURNING-Parameter gibt, wird der Rückgabewert von invoke auf jsval_void gesetzt. Soll ein komplexer RETURNING-Parameter angenommen werden, muß also ein Argument angegeben werden.

Beispiel

report DEMO_JAVA_SCRIPT_BIND_METH_RET.

class COUNTER definition.
  public section.
    methods: SET importing VALUE(SET_VALUE) type I,
             INCREMENT,
             GET returning VALUE(GET_VALUE) type I.
  private section.
    data COUNT type I.
endclass.

class COUNTER implementation.
  method SET.
    COUNT = SET_VALUE.
  endmethod.
  method INCREMENT.
    COUNT = COUNT + 1.
  endmethod.
  method GET.
    GET_VALUE = COUNT.
  endmethod.
endclass.

data OREF type ref to COUNTER.
data RESULT type I.

data SOURCE type STRING.
data JS_PROCESSOR type ref to CL_JAVA_SCRIPT.

data GET_VALUE type STRING.

start-of-selection.

  JS_PROCESSOR = CL_JAVA_SCRIPT=>CREATE( ).

  JS_PROCESSOR->BIND( exporting NAME_OBJ  = 'abap'
                                NAME_PROP = 'Ref'
                      changing  DATA      = OREF ).

  create object OREF.

  concatenate
  'var start_value = 10 ;                                  '
  'var result = 0 ;                                        '
  'abap.Ref.invoke( "set", "set_value", start_value );       '
  'for (var i = 0; i < 5; i++)                              '
  '  {                                                     '
  '  abap.Ref.invoke( "increment" );                        '
  '  }                                                     '
  'result=abap.Ref.invoke( "get"  );                        '
* 'result=abap.Ref.invoke( "get", "get_value", result );     '
  into SOURCE separated by CL_ABAP_CHAR_UTILITIES=>CR_LF.

  JS_PROCESSOR->COMPILE(
                exporting
                  SCRIPT_NAME = 'COUNT.JS'
                  SCRIPT      = SOURCE ).

  JS_PROCESSOR->EXECUTE(
                exporting SCRIPT_NAME = 'COUNT.JS' ).

  GET_VALUE = JS_PROCESSOR->GET( NAME = 'result' ).

  RESULT = OREF->GET( ).

  write / GET_VALUE.
  write / RESULT.

In diesem Beispiel wird ein ABAP-Objekt der lokalen Klasse COUNTER über die Referenzvariable OREF an das JavaScript-Objekt abap.Ref gebunden. Im JavaScript werden über die Methode invoke die ABAP-Methoden SET, INCREMENT (fünf mal) und GET aufgerufen. Beim Aufruf der ABAP-Methode GET wird der RESULTING-Parameter GET_VALUE als Rückgabewert von invoke an die globale Variable result übergeben. Die kommentierte Zeile, in der Argumente angegeben sind, hätte das gleiche Ergebnis, die Argumentliste ist hier aber nicht notwendig bzw. überflüssig, da der RETURNING-Parameter der ABAP-Methode elementar ist.

result wird über die Methode GET der Klasse CL_JAVA_SCRIPT aus dem JavaScript-Kontext in die ABAP-Variable GET_VALUE ausgelesen. Weiterhin wird in ABAP die ABAP-Variable RESULT durch Aufruf der ABAP-Methode GET gefüllt. Die Werte von result in JavaScript und RESULT in ABAP sind gleich.

Werteübergabe bzw. -übernahme über Argumente

Wenn andere Parameter als elementare RETURNING-Parameter, also IMPORTING- EXPORTING- oder CHANGING-Parameter oder auch komplexe RETURNING-Parameter übergeben bzw. übernommen werden sollen, müssen die entsprechenden Argumente angegeben werden.

Dabei ist folgendes zu beachten:

Beispiel

report DEMO_JAVA_SCRIPT_BIND_METH_VAL.

class C_ABAP definition.
  public section.
    methods SET_VALUE exporting P_ABAP type I.
endclass.

class C_ABAP implementation.
  method SET_VALUE.
    P_ABAP = 111.
  endmethod.
endclass.

data OREF type ref to C_ABAP.
data RESULT type I.

data SOURCE type STRING.
data JS_PROCESSOR type ref to CL_JAVA_SCRIPT.

data GET_VALUE type STRING.

start-of-selection.

  JS_PROCESSOR = CL_JAVA_SCRIPT=>CREATE( ).

  JS_PROCESSOR->BIND( exporting NAME_OBJ  = 'abap'
                                NAME_PROP = 'Ref'
                      changing  DATA      = OREF ).

  create object OREF.

  concatenate
  'var result_abap_val  =  0;                                '
  'var result_js_val    =  0;                                '
  'var result_abap_ref   = new SAPAbapMethParam(0);          '
  'var result_js_ref     = new SAPAbapMethParam(0);          '
  'var result_abap_ref_prop   = 0                            '
  'var result_js_ref_prop     = 0                            '
  'function set_value_val(p_js) { p_js = 666 };              '
  'function set_value_ref(p_js) { p_js.value = 666 };        '
  'abap.Ref.invoke( "set_value", "p_abap", result_abap_val );'
  'set_value_val(result_js_val);                             '
  'abap.Ref.invoke( "set_value", "p_abap", result_abap_ref );'
  'set_value_ref(result_js_ref);                             '
  'result_abap_ref_prop   = result_abap_ref.value;       '
  'result_js_ref_prop     = result_js_ref.value;         '
   into SOURCE separated by CL_ABAP_CHAR_UTILITIES=>CR_LF.

  JS_PROCESSOR->COMPILE(
                exporting
                  SCRIPT_NAME = 'VALUES.JS'
                  SCRIPT      = SOURCE ).

  JS_PROCESSOR->EXECUTE(
                exporting SCRIPT_NAME = 'VALUES.JS' ).

  GET_VALUE = JS_PROCESSOR->GET( NAME = 'result_abap_val' ).
  write: /  'result_abap_val' , 40 GET_VALUE.

  GET_VALUE = JS_PROCESSOR->GET( NAME = 'result_js_val' ).
  write: /  'result_js_val' , 40 GET_VALUE.

  GET_VALUE = JS_PROCESSOR->GET(
                            NAME = 'result_abap_ref_prop' ).
  write: /  'result_abap_ref.value' , 40 GET_VALUE.

  GET_VALUE = JS_PROCESSOR->GET(
                            NAME = 'result_js_ref_prop' ).
  write: /  'result_js_ref.value' , 40 GET_VALUE.

In diesem Beispiel wird ein ABAP-Objekt der lokalen Klasse C_ABAP über die Referenzvariable OREF an das JavaScript-Objekt abap.Ref gebunden. Im JavaScript werden zwei einfache Variable result_abap_val und js_abap_val, sowie zwei Objekte der Klasse SAPAbapMethParam result_abap_ref und result_js_ref definert. Weiterhin sind zwei JavaScript-Funktionen set_value_val und set_value_ref definiert.

Die ABAP-Methode SET_VALUE und die JavaScript-Funktionen werden mit verschiedenen Argumenten aufgerufen. Die Werteübergabe an die Argumente wird mit der Methode GET im ABAP-Programm überprüft. Da GET nicht auf die Properties eines Objekts zugreifen kann, wird das Property value der Objekte von SAPAbapMethParam an zwei Hilfsvariablen zugewiesen.

Das Programm zeigt, dass result_abap_val und js_abap_val vom Methoden- bzw. Funktionsaufruf nicht beeinflusst werden, während die Wertübergabe an das Property value der Klasse SAPAbapMethParam möglich ist.

Behandlung klassischer Ausnahmen

Klassische Ausnahmen, die bei der Methodendefinition mit EXCEPTIONS deklariert und in der Methode mit RAISE ausgelöst werden, können in JavaScript behandelt werden, und führen dann nicht zum Abbruch der JavaScript-Verarbeitung. Hierfür muß der optionale Parameter EXCEPTION (in Großbuchstaben und Anführungszeichen) gefolgt von einem Aktualparameter angegeben werden, der eine Instanz der vordefinierten Klasse SAPAbapMethParam ist.

Beispiel

report DEMO_JAVA_SCRIPT_BIND_METH_EXC.

class C1 definition.
  public section.
    methods TEST exceptions EXC.
endclass.

class C1 implementation.
  method TEST.
    raise exc.
  endmethod.
endclass.

data OREF type ref to C1.

data SOURCE type STRING.
data JS_PROCESSOR type ref to CL_JAVA_SCRIPT.

data RESULT type STRING.

start-of-selection.

  JS_PROCESSOR = CL_JAVA_SCRIPT=>CREATE( ).

  JS_PROCESSOR->BIND( exporting NAME_OBJ  = 'abap'
                                NAME_PROP = 'Ref'
                      changing  DATA      = OREF ).

  create object OREF.

  concatenate
  'var except = new SAPAbapMethParam();           '
  'abap.Ref.invoke( "test", "EXCEPTION", except );'
  'except.value;                                  '
  into SOURCE separated by CL_ABAP_CHAR_UTILITIES=>CR_LF.

  JS_PROCESSOR->COMPILE(
                exporting
                  SCRIPT_NAME = 'TEST.JS'
                  SCRIPT      = SOURCE ).

  RESULT = JS_PROCESSOR->EXECUTE( 'TEST.JS' ).
  write / result.

In diesem Beispiel wird ein ABAP-Objekt der lokalen Klasse C1 über die Referenzvariable OREF an das JavaScript-Objekt abap.Ref gebunden. Im JavaScript wird ein Objekt except der Klasse SAPAbapMethParam definert.

Die ABAP-Methode TEST wird im JavaSript aufgerufen und ihre Ausnahme EXC behandelt. Die Property except.value hat nach dem Methodenaufruf den Wert EXC.

Behandlung klassenbasierter Ausnahmen

Klassenbasierte Ausnahmen, die bei der Methodendefinition mit RAISING deklariert und in der Methode mit RAISE EXCEPTION ausgelöst werden, können nicht in JavaScript behandelt werden. Sie führen zum Abbruch der JavaScript-Verarbeitung, ohne die Attribute LAST_CONDITION_CODE. und LAST_ERROR_MESSAGE zu versorgen. Statt dessen kann das Skript in einem TRY-Block ausgeführt werden, um die Ausnahmen in ABAP mit CATCH zu behandeln.

Beispiel

report DEMO_JAVA_SCRIPT_BIND_METH_CX.

class C1 definition.
  public section.
    data    ATTR type STRING.
    methods TEST raising CX_SY_ZERODIVIDE.
endclass.

class C1 implementation.
  method TEST.
    raise  exception type CX_SY_ZERODIVIDE.
    ATTR = 'Hello World!'.
  endmethod.
endclass.

data OREF type ref to C1.
data SOURCE type STRING.
data JS_PROCESSOR type ref to CL_JAVA_SCRIPT.
data RESULT type STRING.

data EXCREF type ref to CX_ROOT.
data TEXT   type STRING.

start-of-selection.

  JS_PROCESSOR = CL_JAVA_SCRIPT=>CREATE( ).

  JS_PROCESSOR->BIND( exporting NAME_OBJ  = 'abap'
                                NAME_PROP = 'Ref'
                      changing  DATA      = OREF ).

  create object OREF.

  concatenate
  'abap.Ref.invoke( "test" );'
  'abap.Ref.attr;            '
  into SOURCE separated by CL_ABAP_CHAR_UTILITIES=>CR_LF.

  JS_PROCESSOR->COMPILE(
                exporting
                  SCRIPT_NAME = 'TEST.JS'
                  SCRIPT      = SOURCE ).

  try.
      RESULT = JS_PROCESSOR->EXECUTE( 'TEST.JS' ).
      write / JS_PROCESSOR->LAST_ERROR_MESSAGE.
      write / RESULT.
    catch CX_ROOT into EXCREF.
      TEXT = EXCREF->GET_TEXT( ).
      message TEXT type 'I'.
  endtry.

Beim Auftreten der Ausnahme wird die JavaScript-Verarbeitung abgebrochen und die Ausnahme im CATCH-Block behandelt.

 

 

Ende des Inhaltsbereichs