You are on page 1of 9

Binding to Object References (Instances)

An ABAP object reference is mapped in JavaScript as a proxy object of the predefined proxy class
SAPAbapOrefClass. You can specify a – case-sensitive – name for the JavaScript reference using the
NAME_PROP parameter of the BIND method.

The components of the proxy object are:

• A predefined property, ‘Class’, based on the proxy class SAPAbapCrefClass and implicitly bound
to the class of the object. This allows you to access the static components of the object, as
described in Binding to Classes.
• The public instance attributes of the referenced ABAP object as properties (in lower case).
• A predefined method, ‘invoke’, which allows you to call the public instance methods of the
referenced ABAP object.
• A predefined method, ‘notInitial’, with no input parameters, that returns a Boolean value. The
return value is true if the ABAP object reference points to an instance, and false if the ABAP
object reference is blank.

You cannot add other properties or methods to the proxy object in JavaScript. If you assign ABAP object
references to bound object references in JavaScript, or if you try to access attributes to non-existent
ABAP objects in JavaScript (that is, if the reference variable in ABAP is blank), the JavaScript stops
processing.

Access to instance attributes


If you assign a JavaScript object to the object reference variable in ABAP, JavaScript also works with the
attributes of the ABAP object to which the object reference variable points after the assignment. The
variable in JavaScript is bound to the object reference variable in ABAP, not to the ABAP object (see also
BIND_INSTANCE).

The JavaScript object is linked to the static type of the object reference variable. If a narrowing cast is
performed using an assignment in ABAP, the JavaScript object retains its own type and cannot access
the added attributes of the dynamic type. Similarly, you can perform widening casts and have them
checked in ABAP only. For this reason, in JavaScript, you can never have the problem where you try to
access attributes that do not exist in the referenced object.

Process with care, if you want to assign properties of bound object reference variables in JavaScript to
other variables. If the relevant object is deleted in ABAP by the Garbage Collector, and you then try to use
the target variable, a runtime error occurs.

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 this example, JavaScript changes the attribute OREF->ATTR from 'Hello' to


'Hello World!'. If JavaScript tries to access 'oref.attr' before the CREATE OBJECT
assignment, processing terminates.

Calling instance methods


To call the public instance methods of the reference object in ABAP from JavaScript, use the ‘invoke’
method of the relevant JavaScript object.

The ‘invoke’ method expects the name of the ABAP instance method in lower case as the first argument,
following by the passed parameters. You must specify the parameter name and actual parameter as a
pair separated by commas, for each non-optional interface parameter of the ABAP instance method.
These pairs can be in any order. You do not have to specify optional parameters, or the usual ABAP
additions EXPORTING, IMPORTING, CHANGING, or RETURNING.

Constraints

• All the passed parameters in the interface of the ABAP method called must be fully typed. You
cannot use generic types, such as ANY or STANDARD TABLE.
• The methods called must be enabled for background processing – that is, they must expect any
user interaction.
• Each called method can have a maximum of 32 parameters (which corresponds to 65 arguments
for the ‘invoke’ method).
• The method call affects the system fields SY-SUBRC and SY-MSGV1 to SY-MSGV4, so that
there is no point accessing these fields in the method itself, or after the script has been executed.
• Class-based exceptions propagated in the interface of the method using RAISING cannot be
handled in JavaScript and lead to the script terminating. You can, however, handle them in an
TRY block in ABAP. You can handle classical exceptions in JavaScript.

Passing values using the RETURNING parameter

The return value from ‘invoke’ is automatically filled by the RETURNING parameter of the called method.
If the type of the RETURNING parameter is elementary, this is the actual return value of the ABAP
method. Thus in this case, you need not necessarily specify an argument for the RETURNING parameter.
If the type of the RETURNING parameter is complex or if there are no RETURNING parameters, the
returning value of invoke is set to jsval_void. If you specify a complex RETURNING parameter, you must
therefore specify an argument.

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 this example, an ABAP object of the local class COUNTER is bound to the
JavaScript object abap.Ref using the OREF reference variable. The JavaScript
calls the ABAP methods SET, INCREMENT (five times), and GET using the
‘invoke’ method. When it calls the (ABAP) GET method, the RESULTING
parameter GET_VALUE is passed to the global variable result as the return
value of invoke. The commented-out line specifying the arguments has the same
effect. However, the argument list is superfluous, since the RETURNING
parameter of the ABAP method.

result is read from the JavaScript context and passed to the ABAP variable
GET_VALUE using the GET method of the class CL_JAVA_SCRIPT. Moreover,
the program fills the ABAP variable RESULT in ABAP by calling the ABAP
method GET. The values of result in JavaScript and RESULT in ABAP are
identical.
Passing and receiving values using arguments

If you want to pass or receive parameters other than elementary RETURNING parameters – that is,
complex RETURNING parameters, or IMPORTING EXPORTING, or CHANGING parameters – you must
specify the appropriate arguments.

Note:

• The types of the actual and formal parameters must be compatible.


• If you specify numbers, literals (strings) – or JavaScript variables that contain simple numbers or
strings – as actual parameters, they are passed as values and behave like constants. They are
not affected by the EXPORTING, CHANGING or RETURNING parameters of the ABAP method.
This is not a peculiarity of ABAP method calls from JavaScript – it also applies to calling
JavaScript functions (see the example DEMO_JAVA_SCRIPT_BIND_METH_VAL below). If
ABAP variables are bound to JavaScript variables with simple values, the same applies.
• To pass a value to a JavaScript variable by reference, you must use complex JavaScript
variables – that is, properties of classes.

In the contexts created by the CL_JAVA_SCRIPT class, there is a predefined class


SAPAbapMethParam, which has exactly one elementary attribute (with the type String) for this
purpose. You can call this attribute anything you want; we recommend the name ‘value’. After
creating an object of this class, its single attribute can be used to pass elementary values (see
the example DEMO_JAVA_SCRIPT_BIND_METH_REF). This use is not limited to ABAP method
calls – it also applies to JavaScript functions (see the example
DEMO_JAVA_SCRIPT_BIND_METH_VAL).

You can also use the properties of the JavaScript equivalents of the bound complex ABAP data
objects for passing references. If you do, you must again ensure that the types are compatible
when passing values.

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 this example, an ABAP object of the local class C_ABAP is bound to the
JavaScript object abap.Ref using the OREF reference variable. In JavaScript,
two simple variables are defined – result_abap_val and js_abap_val – as well as
two objects of the class SAPAbapMethParam – result_abap_ref and
result_js_ref. Moreover, two JavaScript functions are defined – set_value_val
and set_value_ref.

The ABAP method SET_VALUE and the JavaScript functions are called with
different arguments. The values passed to the arguments are checked using the
GET method in the ABAP program. Since GET cannot access the attributes of an
object, the ‘value’ property of the objects from SAPAbapMethParam is assigned
to two auxiliary variables.

The program shows that result_abap_val and js_abap_val are not affected by the
method or function call, and that it is possible to pass a value to the ‘value‘
attribute of the SAPAbapMethParam class.

Handling classical exceptions

You can handle classical exceptions that are declared in the method definition using EXCEPTIONS and
are raised in methods using RAISE in JavaScript. JavaScript does not then terminate. To handle
exceptions in this way, you need to specify the optional parameter EXCEPTION (in uppercase and
quotation marks) followed by an actual parameter, that is an instance of the predefined class
SAPAbapMethParam.

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 this example, an ABAP object of the local class C1 is bound to the JavaScript
object abap.Ref using the OREF reference variable. In JavaScript, an object
‘except’ of the class SAPAbapMethParam is defined.

The ABAP method TEST is called in JavaScript and its exception EXC is
handled. After the method call, the except.value property has the value EXC.

Handling class-based exceptions

You cannot handle class-based exceptions declared in the method definition using RAISING and are
raised in methods using RAISE EXCEPTION in JavaScript. They cause JavaScript to terminate without
filling the LAST_CONDITION_CODE and LAST_ERROR_MESSAGE attributes. Instead, the script can
be executed in a TRY block so that you can handle the exceptions using CATCH.

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.

If an exception occurs, JavaScript terminates and the exception is handled in the


CATCH block.

You might also like