ajson, Automatic Update (#5966)

This commit is contained in:
github-actions[bot] 2023-01-03 14:47:44 +01:00 committed by GitHub
parent 0ea950c938
commit 95389c532b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1460 additions and 109 deletions

View File

@ -164,7 +164,9 @@
"cyclic_oo": false,
"fully_type_constants": true,
"keep_single_parameter_on_one_line": true,
"prefer_returning_to_exporting": true,
"prefer_returning_to_exporting": {
"exclude": ["/json/"]
},
"selection_screen_naming": true,
"sicf_consistency": true,
"sql_escape_host_variables": true,
@ -291,7 +293,7 @@
},
"line_length": {
"length": 120,
"exclude": ["zcl_abapgit_object_pdts.clas.testclasses.abap"]
"exclude": ["zcl_abapgit_object_pdts.clas.testclasses.abap", "/json/"]
},
"line_only_punc": {
"ignoreExceptions": true

View File

@ -26,12 +26,12 @@
]
},
"devDependencies": {
"@abaplint/cli": "^2.94.10",
"@abaplint/cli": "^2.94.13",
"@abaplint/database-sqlite": "^2.3.93",
"@abaplint/runtime": "^2.3.93",
"@abaplint/transpiler-cli": "^2.3.93",
"@abaplint/runtime": "^2.3.94",
"@abaplint/transpiler-cli": "^2.3.94",
"abapmerge": "^0.14.8",
"c8": "^7.12.0",
"eslint": "^8.30.0"
"eslint": "^8.31.0"
}
}

View File

@ -1,6 +1,6 @@
CLASS zcl_abapgit_ajson DEFINITION
PUBLIC
CREATE PRIVATE .
CREATE PUBLIC .
PUBLIC SECTION.
@ -24,6 +24,7 @@ CLASS zcl_abapgit_ajson DEFINITION
ALIASES:
clear FOR zif_abapgit_ajson~clear,
set FOR zif_abapgit_ajson~set,
setx FOR zif_abapgit_ajson~setx,
set_boolean FOR zif_abapgit_ajson~set_boolean,
set_string FOR zif_abapgit_ajson~set_string,
set_integer FOR zif_abapgit_ajson~set_integer,
@ -35,6 +36,11 @@ CLASS zcl_abapgit_ajson DEFINITION
push FOR zif_abapgit_ajson~push,
stringify FOR zif_abapgit_ajson~stringify.
ALIASES:
clone FOR zif_abapgit_ajson~clone,
filter FOR zif_abapgit_ajson~filter,
map FOR zif_abapgit_ajson~map.
ALIASES:
mt_json_tree FOR zif_abapgit_ajson~mt_json_tree,
keep_item_order FOR zif_abapgit_ajson~keep_item_order,
@ -51,33 +57,44 @@ CLASS zcl_abapgit_ajson DEFINITION
RAISING
zcx_abapgit_ajson_error .
CLASS-METHODS create_empty
CLASS-METHODS create_empty " Might be deprecated, prefer using new( ) or create object
IMPORTING
!ii_custom_mapping TYPE REF TO zif_abapgit_ajson_mapping OPTIONAL
iv_keep_item_order TYPE abap_bool DEFAULT abap_false
iv_format_datetime TYPE abap_bool DEFAULT abap_true
RETURNING
VALUE(ro_instance) TYPE REF TO zcl_abapgit_ajson.
" Experimental ! May change
CLASS-METHODS create_from
CLASS-METHODS create_from " TODO, rename to 'from' ?
IMPORTING
!ii_source_json TYPE REF TO zif_abapgit_ajson
!ii_filter TYPE REF TO zif_abapgit_ajson_filter OPTIONAL
!ii_filter TYPE REF TO zif_abapgit_ajson_filter OPTIONAL " Might be deprecated, use filter() instead
!ii_mapper TYPE REF TO zif_abapgit_ajson_mapping OPTIONAL " Might be deprecated, use map() instead
RETURNING
VALUE(ro_instance) TYPE REF TO zcl_abapgit_ajson
RAISING
zcx_abapgit_ajson_error .
METHODS constructor.
METHODS constructor
IMPORTING
iv_keep_item_order TYPE abap_bool DEFAULT abap_false
iv_format_datetime TYPE abap_bool DEFAULT abap_true.
CLASS-METHODS new
IMPORTING
iv_keep_item_order TYPE abap_bool DEFAULT abap_false
iv_format_datetime TYPE abap_bool DEFAULT abap_true
RETURNING
VALUE(ro_instance) TYPE REF TO zcl_abapgit_ajson.
PROTECTED SECTION.
PRIVATE SECTION.
DATA mv_read_only TYPE abap_bool.
DATA mi_custom_mapping TYPE REF TO zif_abapgit_ajson_mapping.
DATA mv_keep_item_order TYPE abap_bool.
DATA mv_format_datetime TYPE abap_bool.
" TODO restructure into zif_ajson=>ty_opts
CLASS-DATA go_float_regex TYPE REF TO cl_abap_regex.
DATA ms_opts TYPE zif_abapgit_ajson=>ty_opts.
DATA mi_custom_mapping TYPE REF TO zif_abapgit_ajson_mapping. " DEPRECATED, will be removed
METHODS get_item
IMPORTING
@ -107,44 +124,51 @@ ENDCLASS.
CLASS zcl_abapgit_ajson IMPLEMENTATION.
METHOD zif_abapgit_ajson~opts.
rs_opts-read_only = mv_read_only.
rs_opts-format_datetime = mv_format_datetime.
rs_opts-keep_item_order = mv_keep_item_order.
ENDMETHOD.
METHOD constructor.
format_datetime( abap_true ).
ms_opts-keep_item_order = iv_keep_item_order.
format_datetime( iv_format_datetime ).
ENDMETHOD.
METHOD create_empty.
CREATE OBJECT ro_instance.
CREATE OBJECT ro_instance
EXPORTING
iv_format_datetime = iv_format_datetime
iv_keep_item_order = iv_keep_item_order.
ro_instance->mi_custom_mapping = ii_custom_mapping.
ENDMETHOD.
METHOD create_from.
DATA lo_filter_runner TYPE REF TO lcl_filter_runner.
DATA lo_mutator_queue TYPE REF TO lcl_mutator_queue.
IF ii_source_json IS NOT BOUND.
zcx_abapgit_ajson_error=>raise( 'Source not bound' ).
ENDIF.
CREATE OBJECT ro_instance.
IF ii_filter IS BOUND.
CREATE OBJECT lo_filter_runner.
lo_filter_runner->run(
CREATE OBJECT ro_instance
EXPORTING
ii_filter = ii_filter
it_source_tree = ii_source_json->mt_json_tree
CHANGING
ct_dest_tree = ro_instance->mt_json_tree ).
ELSE.
iv_format_datetime = ii_source_json->opts( )-format_datetime
iv_keep_item_order = ii_source_json->opts( )-keep_item_order.
IF ii_filter IS NOT BOUND AND ii_mapper IS NOT BOUND.
ro_instance->mt_json_tree = ii_source_json->mt_json_tree.
" Copy keep order and custom mapping ???
ELSE.
CREATE OBJECT lo_mutator_queue.
IF ii_mapper IS BOUND.
" Mapping goes first. But maybe it should be a freely definable queue of processors ?
lo_mutator_queue->add( lcl_mapper_runner=>new( ii_mapper ) ).
ENDIF.
IF ii_filter IS BOUND.
lo_mutator_queue->add( lcl_filter_runner=>new( ii_filter ) ).
ENDIF.
lo_mutator_queue->lif_mutator_runner~run(
EXPORTING
it_source_tree = ii_source_json->mt_json_tree
IMPORTING
et_dest_tree = ro_instance->mt_json_tree ).
ENDIF.
ENDMETHOD.
@ -201,6 +225,14 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
ENDMETHOD.
METHOD new.
CREATE OBJECT ro_instance
EXPORTING
iv_format_datetime = iv_format_datetime
iv_keep_item_order = iv_keep_item_order.
ENDMETHOD.
METHOD parse.
DATA lo_parser TYPE REF TO lcl_json_parser.
@ -260,7 +292,7 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
METHOD read_only_watchdog.
IF mv_read_only = abap_true.
IF ms_opts-read_only = abap_true.
zcx_abapgit_ajson_error=>raise( 'This json instance is read only' ).
ENDIF.
ENDMETHOD.
@ -313,6 +345,11 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
ENDMETHOD.
METHOD zif_abapgit_ajson~clone.
ri_json = create_from( me ).
ENDMETHOD.
METHOD zif_abapgit_ajson~delete.
read_only_watchdog( ).
@ -334,14 +371,21 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
ENDMETHOD.
METHOD zif_abapgit_ajson~filter.
ri_json = create_from(
ii_source_json = me
ii_filter = ii_filter ).
ENDMETHOD.
METHOD zif_abapgit_ajson~format_datetime.
mv_format_datetime = iv_use_iso.
ms_opts-format_datetime = iv_use_iso.
ri_json = me.
ENDMETHOD.
METHOD zif_abapgit_ajson~freeze.
mv_read_only = abap_true.
ms_opts-read_only = abap_true.
ENDMETHOD.
@ -462,11 +506,18 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
METHOD zif_abapgit_ajson~keep_item_order.
mv_keep_item_order = abap_true.
ms_opts-keep_item_order = abap_true.
ri_json = me.
ENDMETHOD.
METHOD zif_abapgit_ajson~map.
ri_json = create_from(
ii_source_json = me
ii_mapper = ii_mapper ).
ENDMETHOD.
METHOD zif_abapgit_ajson~members.
DATA lv_normalized_path TYPE string.
@ -481,6 +532,11 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
ENDMETHOD.
METHOD zif_abapgit_ajson~opts.
rs_opts = ms_opts.
ENDMETHOD.
METHOD zif_abapgit_ajson~push.
DATA lr_parent TYPE REF TO zif_abapgit_ajson=>ty_node.
@ -507,7 +563,7 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
ls_new_path-name = |{ lv_new_index }|.
lt_new_nodes = lcl_abap_to_json=>convert(
iv_keep_item_order = mv_keep_item_order
is_opts = ms_opts
iv_data = iv_val
is_prefix = ls_new_path ).
READ TABLE lt_new_nodes INDEX 1 REFERENCE INTO lr_new_node. " assume first record is the array item - not ideal !
@ -547,16 +603,14 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
IF ls_split_path IS INITIAL. " Assign root, exceptional processing
IF iv_node_type IS NOT INITIAL.
mt_json_tree = lcl_abap_to_json=>insert_with_type(
iv_format_datetime = mv_format_datetime
iv_keep_item_order = mv_keep_item_order
is_opts = ms_opts
iv_data = iv_val
iv_type = iv_node_type
is_prefix = ls_split_path
ii_custom_mapping = mi_custom_mapping ).
ELSE.
mt_json_tree = lcl_abap_to_json=>convert(
iv_format_datetime = mv_format_datetime
iv_keep_item_order = mv_keep_item_order
is_opts = ms_opts
iv_data = iv_val
is_prefix = ls_split_path
ii_custom_mapping = mi_custom_mapping ).
@ -586,8 +640,7 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
IF iv_node_type IS NOT INITIAL.
lt_new_nodes = lcl_abap_to_json=>insert_with_type(
iv_format_datetime = mv_format_datetime
iv_keep_item_order = mv_keep_item_order
is_opts = ms_opts
iv_item_order = ls_deleted_node-order
iv_data = iv_val
iv_type = iv_node_type
@ -596,8 +649,7 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
ii_custom_mapping = mi_custom_mapping ).
ELSE.
lt_new_nodes = lcl_abap_to_json=>convert(
iv_format_datetime = mv_format_datetime
iv_keep_item_order = mv_keep_item_order
is_opts = ms_opts
iv_item_order = ls_deleted_node-order
iv_data = iv_val
iv_array_index = lv_array_index
@ -614,6 +666,74 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
ENDMETHOD.
METHOD zif_abapgit_ajson~setx.
DATA lv_path TYPE string.
DATA lv_val TYPE string.
DATA lv_int TYPE i.
DATA lv_dec TYPE decfloat34.
DATA lv_last TYPE i.
IF iv_param IS INITIAL.
RETURN.
ENDIF.
SPLIT iv_param AT ':' INTO lv_path lv_val.
CONDENSE lv_path.
CONDENSE lv_val.
IF lv_val IS INITIAL.
RETURN. " Hmm ? or empty string ? or null ?
ENDIF.
IF go_float_regex IS NOT BOUND.
CREATE OBJECT go_float_regex EXPORTING pattern = '^([1-9][0-9]*|0)\.[0-9]+$'.
" expects fractional, because ints are detected separately
ENDIF.
IF lv_val = 'null'.
zif_abapgit_ajson~set_null( lv_path ).
ELSEIF lv_val = 'true'.
zif_abapgit_ajson~set_boolean(
iv_path = lv_path
iv_val = abap_true ).
ELSEIF lv_val = 'false'.
zif_abapgit_ajson~set_boolean(
iv_path = lv_path
iv_val = abap_false ).
ELSEIF lv_val CO '0123456789'.
lv_int = lv_val.
zif_abapgit_ajson~set_integer(
iv_path = lv_path
iv_val = lv_int ).
ELSEIF lv_val CO '0123456789.' AND go_float_regex->create_matcher( text = lv_val )->match( ) = abap_true.
lv_dec = lv_val.
zif_abapgit_ajson~set(
iv_path = lv_path
iv_val = lv_dec ).
ELSEIF lv_val+0(1) = '{' OR lv_val+0(1) = '['.
"Expect object/array, but no further checks, parser will catch errors
zif_abapgit_ajson~set(
iv_path = lv_path
iv_val = parse( lv_val ) ).
ELSE. " string
lv_last = strlen( lv_val ) - 1.
IF lv_val+0(1) = '"' AND lv_val+lv_last(1) = '"'.
lv_val = substring(
val = lv_val
off = 1
len = lv_last - 1 ).
ENDIF.
zif_abapgit_ajson~set_string(
iv_path = lv_path
iv_val = lv_val ).
ENDIF.
ri_json = me.
ENDMETHOD.
METHOD zif_abapgit_ajson~set_boolean.
ri_json = me.
@ -733,7 +853,7 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
rv_json = lcl_json_serializer=>stringify(
it_json_tree = mt_json_tree
iv_keep_item_order = mv_keep_item_order
iv_keep_item_order = ms_opts-keep_item_order
iv_indent = iv_indent ).
ENDMETHOD.
@ -777,7 +897,7 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION.
ls_new_node-name = ls_split_path-name.
ls_new_node-type = zif_abapgit_ajson=>node_type-array.
IF mv_keep_item_order = abap_true AND ls_deleted_node IS NOT INITIAL.
IF ms_opts-keep_item_order = abap_true AND ls_deleted_node IS NOT INITIAL.
ls_new_node-order = ls_deleted_node-order.
ENDIF.

View File

@ -1073,8 +1073,7 @@ CLASS lcl_abap_to_json DEFINITION FINAL.
is_prefix TYPE zif_abapgit_ajson=>ty_path_name OPTIONAL
iv_array_index TYPE i DEFAULT 0
ii_custom_mapping TYPE REF TO zif_abapgit_ajson_mapping OPTIONAL
iv_keep_item_order TYPE abap_bool DEFAULT abap_false
iv_format_datetime TYPE abap_bool DEFAULT abap_false
is_opts TYPE zif_abapgit_ajson=>ty_opts OPTIONAL
iv_item_order TYPE i DEFAULT 0
RETURNING
VALUE(rt_nodes) TYPE zif_abapgit_ajson=>ty_nodes_tt
@ -1088,8 +1087,7 @@ CLASS lcl_abap_to_json DEFINITION FINAL.
is_prefix TYPE zif_abapgit_ajson=>ty_path_name OPTIONAL
iv_array_index TYPE i DEFAULT 0
ii_custom_mapping TYPE REF TO zif_abapgit_ajson_mapping OPTIONAL
iv_keep_item_order TYPE abap_bool DEFAULT abap_false
iv_format_datetime TYPE abap_bool DEFAULT abap_false
is_opts TYPE zif_abapgit_ajson=>ty_opts OPTIONAL
iv_item_order TYPE i DEFAULT 0
RETURNING
VALUE(rt_nodes) TYPE zif_abapgit_ajson=>ty_nodes_tt
@ -1226,8 +1224,8 @@ CLASS lcl_abap_to_json IMPLEMENTATION.
CREATE OBJECT lo_converter.
lo_converter->mi_custom_mapping = ii_custom_mapping.
lo_converter->mv_keep_item_order = iv_keep_item_order.
lo_converter->mv_format_datetime = iv_format_datetime.
lo_converter->mv_keep_item_order = is_opts-keep_item_order.
lo_converter->mv_format_datetime = is_opts-format_datetime.
lo_converter->convert_any(
EXPORTING
@ -1623,8 +1621,8 @@ CLASS lcl_abap_to_json IMPLEMENTATION.
CREATE OBJECT lo_converter.
lo_converter->mi_custom_mapping = ii_custom_mapping.
lo_converter->mv_keep_item_order = iv_keep_item_order.
lo_converter->mv_format_datetime = iv_format_datetime.
lo_converter->mv_keep_item_order = is_opts-keep_item_order.
lo_converter->mv_format_datetime = is_opts-format_datetime.
lo_converter->insert_value_with_type(
EXPORTING
@ -1689,20 +1687,35 @@ CLASS lcl_abap_to_json IMPLEMENTATION.
ENDCLASS.
**********************************************************************
* MUTATOR INTERFACE
**********************************************************************
INTERFACE lif_mutator_runner.
METHODS run
IMPORTING
it_source_tree TYPE zif_abapgit_ajson=>ty_nodes_ts
EXPORTING
et_dest_tree TYPE zif_abapgit_ajson=>ty_nodes_ts
RAISING
zcx_abapgit_ajson_error.
ENDINTERFACE.
**********************************************************************
* FILTER RUNNER
**********************************************************************
CLASS lcl_filter_runner DEFINITION FINAL.
PUBLIC SECTION.
METHODS run
INTERFACES lif_mutator_runner.
CLASS-METHODS new
IMPORTING
ii_filter TYPE REF TO zif_abapgit_ajson_filter
it_source_tree TYPE zif_abapgit_ajson=>ty_nodes_ts
CHANGING
ct_dest_tree TYPE zif_abapgit_ajson=>ty_nodes_ts
RAISING
zcx_abapgit_ajson_error.
RETURNING
VALUE(ro_instance) TYPE REF TO lcl_filter_runner.
METHODS constructor
IMPORTING
ii_filter TYPE REF TO zif_abapgit_ajson_filter.
PRIVATE SECTION.
DATA mi_filter TYPE REF TO zif_abapgit_ajson_filter.
@ -1721,14 +1734,20 @@ ENDCLASS.
CLASS lcl_filter_runner IMPLEMENTATION.
METHOD run.
METHOD new.
CREATE OBJECT ro_instance EXPORTING ii_filter = ii_filter.
ENDMETHOD.
METHOD constructor.
ASSERT ii_filter IS BOUND.
mi_filter = ii_filter.
CLEAR ct_dest_tree.
ENDMETHOD.
METHOD lif_mutator_runner~run.
CLEAR et_dest_tree.
GET REFERENCE OF it_source_tree INTO mr_source_tree.
GET REFERENCE OF ct_dest_tree INTO mr_dest_tree.
GET REFERENCE OF et_dest_tree INTO mr_dest_tree.
walk( iv_path = '' ).
@ -1788,3 +1807,187 @@ CLASS lcl_filter_runner IMPLEMENTATION.
ENDMETHOD.
ENDCLASS.
**********************************************************************
* MAPPER RUNNER
**********************************************************************
CLASS lcl_mapper_runner DEFINITION FINAL.
PUBLIC SECTION.
INTERFACES lif_mutator_runner.
CLASS-METHODS new
IMPORTING
ii_mapper TYPE REF TO zif_abapgit_ajson_mapping
RETURNING
VALUE(ro_instance) TYPE REF TO lcl_mapper_runner.
METHODS constructor
IMPORTING
ii_mapper TYPE REF TO zif_abapgit_ajson_mapping.
PRIVATE SECTION.
DATA mi_mapper TYPE REF TO zif_abapgit_ajson_mapping.
DATA mr_source_tree TYPE REF TO zif_abapgit_ajson=>ty_nodes_ts.
DATA mr_dest_tree TYPE REF TO zif_abapgit_ajson=>ty_nodes_ts.
METHODS process_deep_node
IMPORTING
iv_path TYPE string
iv_renamed_path TYPE string
iv_node_type TYPE zif_abapgit_ajson=>ty_node-type
RAISING
zcx_abapgit_ajson_error.
ENDCLASS.
CLASS lcl_mapper_runner IMPLEMENTATION.
METHOD new.
CREATE OBJECT ro_instance EXPORTING ii_mapper = ii_mapper.
ENDMETHOD.
METHOD constructor.
ASSERT ii_mapper IS BOUND.
mi_mapper = ii_mapper.
ENDMETHOD.
METHOD lif_mutator_runner~run.
FIELD-SYMBOLS <root> LIKE LINE OF it_source_tree.
READ TABLE it_source_tree WITH KEY path = `` name = `` ASSIGNING <root>.
IF sy-subrc <> 0 OR NOT ( <root>-type = zif_abapgit_ajson=>node_type-array OR <root>-type = zif_abapgit_ajson=>node_type-object ).
" empty or one-value-only tree
et_dest_tree = it_source_tree.
RETURN.
ENDIF.
CLEAR et_dest_tree.
GET REFERENCE OF it_source_tree INTO mr_source_tree.
GET REFERENCE OF et_dest_tree INTO mr_dest_tree.
INSERT <root> INTO TABLE et_dest_tree.
process_deep_node(
iv_path = `/`
iv_renamed_path = `/`
iv_node_type = <root>-type ).
ENDMETHOD.
METHOD process_deep_node.
FIELD-SYMBOLS <item> LIKE LINE OF mr_source_tree->*.
DATA ls_renamed_node LIKE <item>.
LOOP AT mr_source_tree->* ASSIGNING <item> WHERE path = iv_path.
ls_renamed_node = <item>.
IF iv_node_type <> zif_abapgit_ajson=>node_type-array.
" don't rename array item names -> they are numeric index
mi_mapper->rename_node(
EXPORTING
is_node = <item>
CHANGING
cv_name = ls_renamed_node-name ).
IF ls_renamed_node-name IS INITIAL.
zcx_abapgit_ajson_error=>raise(
iv_msg = 'Renamed node name cannot be empty'
is_node = <item> ).
ENDIF.
ENDIF.
ls_renamed_node-path = iv_renamed_path.
INSERT ls_renamed_node INTO TABLE mr_dest_tree->*.
IF sy-subrc <> 0. " = 4 ?
zcx_abapgit_ajson_error=>raise(
iv_msg = 'Renamed node has a duplicate'
is_node = ls_renamed_node ).
ENDIF.
" maybe also catch CX_SY_ITAB_DUPLICATE_KEY but secondary keys are not changed here, so not for now
IF <item>-type = zif_abapgit_ajson=>node_type-array OR <item>-type = zif_abapgit_ajson=>node_type-object.
process_deep_node(
iv_path = iv_path && <item>-name && `/`
iv_renamed_path = iv_renamed_path && ls_renamed_node-name && `/`
iv_node_type = <item>-type ).
ENDIF.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
**********************************************************************
* MUTATOR QUEUE
**********************************************************************
CLASS lcl_mutator_queue DEFINITION FINAL.
PUBLIC SECTION.
INTERFACES lif_mutator_runner.
CLASS-METHODS new
RETURNING
VALUE(ro_instance) TYPE REF TO lcl_mutator_queue.
METHODS add
IMPORTING
ii_mutator TYPE REF TO lif_mutator_runner
RETURNING
VALUE(ro_self) TYPE REF TO lcl_mutator_queue.
PRIVATE SECTION.
DATA mt_queue TYPE STANDARD TABLE OF REF TO lif_mutator_runner.
ENDCLASS.
CLASS lcl_mutator_queue IMPLEMENTATION.
METHOD add.
IF ii_mutator IS BOUND.
APPEND ii_mutator TO mt_queue.
ENDIF.
ro_self = me.
ENDMETHOD.
METHOD new.
CREATE OBJECT ro_instance.
ENDMETHOD.
METHOD lif_mutator_runner~run.
DATA li_mutator TYPE REF TO lif_mutator_runner.
DATA lv_qsize TYPE i.
FIELD-SYMBOLS <from> LIKE it_source_tree.
FIELD-SYMBOLS <to> LIKE it_source_tree.
DATA lr_buf TYPE REF TO zif_abapgit_ajson=>ty_nodes_ts.
lv_qsize = lines( mt_queue ).
IF lv_qsize = 0.
et_dest_tree = it_source_tree.
RETURN.
ENDIF.
LOOP AT mt_queue INTO li_mutator.
IF sy-tabix = 1.
ASSIGN it_source_tree TO <from>.
ELSE.
ASSIGN lr_buf->* TO <from>.
ENDIF.
IF sy-tabix = lv_qsize.
ASSIGN et_dest_tree TO <to>.
ELSE.
CREATE DATA lr_buf.
ASSIGN lr_buf->* TO <to>.
ENDIF.
li_mutator->run(
EXPORTING
it_source_tree = <from>
IMPORTING
et_dest_tree = <to> ).
ENDLOOP.
ENDMETHOD.
ENDCLASS.

View File

@ -1976,6 +1976,9 @@ CLASS ltcl_writer_test DEFINITION FINAL
METHODS set_with_type FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS overwrite_w_keep_order_touch FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS overwrite_w_keep_order_set FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS setx FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS setx_float FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS setx_complex FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS set_with_type_slice
IMPORTING
@ -3083,6 +3086,112 @@ CLASS ltcl_writer_test IMPLEMENTATION.
ENDMETHOD.
METHOD setx.
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a:1' )->stringify( )
exp = '{"a":1}' ).
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a : 1' )->stringify( )
exp = '{"a":1}' ).
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a:"1"' )->stringify( )
exp = '{"a":"1"}' ).
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a:abc' )->stringify( )
exp = '{"a":"abc"}' ).
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a:null' )->stringify( )
exp = '{"a":null}' ).
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a:true' )->stringify( )
exp = '{"a":true}' ).
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a:"true"' )->stringify( )
exp = '{"a":"true"}' ).
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a:false' )->stringify( )
exp = '{"a":false}' ).
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a/b:1' )->stringify( )
exp = '{"a":{"b":1}}' ).
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/:1' )->stringify( )
exp = '1' ). " Hmmm ?
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( ':1' )->stringify( )
exp = '1' ). " Hmmm ?
" TODO some negative tests like "/a:", ""
ENDMETHOD.
METHOD setx_float.
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a:1.123' )->stringify( )
exp = '{"a":1.123}' ).
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a:00.123' )->stringify( )
exp = '{"a":"00.123"}' ). " hmmm
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a:.123' )->stringify( )
exp = '{"a":".123"}' ).
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a:123.' )->stringify( )
exp = '{"a":"123."}' ).
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a:1..123' )->stringify( )
exp = '{"a":"1..123"}' ).
ENDMETHOD.
METHOD setx_complex.
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a:{"b" : 1}' )->stringify( )
exp = '{"a":{"b":1}}' ).
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a:{}' )->stringify( )
exp = '{"a":{}}' ).
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a:[1, 2]' )->stringify( )
exp = '{"a":[1,2]}' ).
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>new( )->setx( '/a:[]' )->stringify( )
exp = '{"a":[]}' ).
TRY.
zcl_abapgit_ajson=>new( )->setx( '/a:{"b" : 1' ).
cl_abap_unit_assert=>fail( ).
CATCH zcx_abapgit_ajson_error.
ENDTRY.
TRY.
zcl_abapgit_ajson=>new( )->setx( '/a:[1, 2' ).
cl_abap_unit_assert=>fail( ).
CATCH zcx_abapgit_ajson_error.
ENDTRY.
ENDMETHOD.
ENDCLASS.
@ -3999,3 +4108,400 @@ CLASS ltcl_filter_test IMPLEMENTATION.
ENDMETHOD.
ENDCLASS.
**********************************************************************
* MAPPER TEST
**********************************************************************
CLASS ltcl_mapper_test DEFINITION FINAL
FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PUBLIC SECTION.
INTERFACES zif_abapgit_ajson_mapping.
PRIVATE SECTION.
METHODS simple_test FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS array_test FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS duplication_test FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS empty_name_test FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS trivial FOR TESTING RAISING zcx_abapgit_ajson_error.
ENDCLASS.
CLASS ltcl_mapper_test IMPLEMENTATION.
METHOD zif_abapgit_ajson_mapping~rename_node.
IF cv_name+0(1) = 'a'.
cv_name = to_upper( cv_name ).
ENDIF.
IF cv_name = 'set_this_empty'.
CLEAR cv_name.
ENDIF.
" watch dog for array
IF is_node-index <> 0.
cl_abap_unit_assert=>fail( 'rename must not be called for direct array items' ).
ENDIF.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~to_abap.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~to_json.
ENDMETHOD.
METHOD simple_test.
DATA lo_json TYPE REF TO zcl_abapgit_ajson.
DATA lo_json_filtered TYPE REF TO zcl_abapgit_ajson.
DATA lo_nodes_exp TYPE REF TO lcl_nodes_helper.
lo_json = zcl_abapgit_ajson=>create_empty( ).
lo_json->set(
iv_path = '/ab'
iv_val = 1 ).
lo_json->set(
iv_path = '/bc'
iv_val = 2 ).
lo_json->set(
iv_path = '/c/ax'
iv_val = 3 ).
lo_json->set(
iv_path = '/c/by'
iv_val = 4 ).
lo_json->set(
iv_path = '/a/ax'
iv_val = 5 ).
lo_json->set(
iv_path = '/a/by'
iv_val = 6 ).
lo_json_filtered = zcl_abapgit_ajson=>create_from(
ii_source_json = lo_json
ii_mapper = me ).
CREATE OBJECT lo_nodes_exp.
lo_nodes_exp->add( ' | |object | | |4' ).
lo_nodes_exp->add( '/ |AB |num |1 | |0' ).
lo_nodes_exp->add( '/ |bc |num |2 | |0' ).
lo_nodes_exp->add( '/ |c |object | | |2' ).
lo_nodes_exp->add( '/c/ |AX |num |3 | |0' ).
lo_nodes_exp->add( '/c/ |by |num |4 | |0' ).
lo_nodes_exp->add( '/ |A |object | | |2' ).
lo_nodes_exp->add( '/A/ |AX |num |5 | |0' ).
lo_nodes_exp->add( '/A/ |by |num |6 | |0' ).
cl_abap_unit_assert=>assert_equals(
act = lo_json_filtered->mt_json_tree
exp = lo_nodes_exp->sorted( ) ).
ENDMETHOD.
METHOD array_test.
DATA lo_json TYPE REF TO zcl_abapgit_ajson.
DATA lo_json_filtered TYPE REF TO zcl_abapgit_ajson.
DATA lo_nodes_exp TYPE REF TO lcl_nodes_helper.
lo_json = zcl_abapgit_ajson=>create_empty( ).
lo_json->touch_array( iv_path = '/' ).
lo_json->set(
iv_path = '/1/ab'
iv_val = 1 ).
lo_json->set(
iv_path = '/1/bc'
iv_val = 2 ).
lo_json->set(
iv_path = '/2/ax'
iv_val = 3 ).
lo_json->set(
iv_path = '/2/by'
iv_val = 4 ).
lo_json_filtered = zcl_abapgit_ajson=>create_from(
ii_source_json = lo_json
ii_mapper = me ).
CREATE OBJECT lo_nodes_exp.
lo_nodes_exp->add( ' | |array | | |2' ).
lo_nodes_exp->add( '/ |1 |object | |1|2' ).
lo_nodes_exp->add( '/ |2 |object | |2|2' ).
lo_nodes_exp->add( '/1/ |AB |num |1 | |0' ).
lo_nodes_exp->add( '/1/ |bc |num |2 | |0' ).
lo_nodes_exp->add( '/2/ |AX |num |3 | |0' ).
lo_nodes_exp->add( '/2/ |by |num |4 | |0' ).
cl_abap_unit_assert=>assert_equals(
act = lo_json_filtered->mt_json_tree
exp = lo_nodes_exp->sorted( ) ).
ENDMETHOD.
METHOD duplication_test.
DATA lo_json TYPE REF TO zcl_abapgit_ajson.
DATA lx_err TYPE REF TO zcx_abapgit_ajson_error.
lo_json = zcl_abapgit_ajson=>create_empty( ).
lo_json->set(
iv_path = '/ab'
iv_val = 1 ).
lo_json->set(
iv_path = '/AB'
iv_val = 2 ).
TRY.
zcl_abapgit_ajson=>create_from(
ii_source_json = lo_json
ii_mapper = me ).
cl_abap_unit_assert=>fail( ).
CATCH zcx_abapgit_ajson_error INTO lx_err.
cl_abap_unit_assert=>assert_char_cp(
act = lx_err->get_text( )
exp = 'Renamed node has a duplicate @/AB' ).
ENDTRY.
ENDMETHOD.
METHOD trivial.
DATA lo_json TYPE REF TO zcl_abapgit_ajson.
DATA lo_json_filtered TYPE REF TO zcl_abapgit_ajson.
DATA lo_nodes_exp TYPE REF TO lcl_nodes_helper.
lo_json = zcl_abapgit_ajson=>create_empty( ).
lo_json_filtered = zcl_abapgit_ajson=>create_from(
ii_source_json = lo_json
ii_mapper = me ).
cl_abap_unit_assert=>assert_initial( lo_json_filtered->mt_json_tree ).
lo_json->set(
iv_path = '/'
iv_val = 1 ).
lo_json_filtered = zcl_abapgit_ajson=>create_from(
ii_source_json = lo_json
ii_mapper = me ).
CREATE OBJECT lo_nodes_exp.
lo_nodes_exp->add( ' | |num |1 | |0' ).
cl_abap_unit_assert=>assert_equals(
act = lo_json_filtered->mt_json_tree
exp = lo_nodes_exp->sorted( ) ).
ENDMETHOD.
METHOD empty_name_test.
DATA lo_json TYPE REF TO zcl_abapgit_ajson.
DATA lx_err TYPE REF TO zcx_abapgit_ajson_error.
lo_json = zcl_abapgit_ajson=>create_empty( ).
lo_json->set(
iv_path = '/set_this_empty'
iv_val = 1 ).
TRY.
zcl_abapgit_ajson=>create_from(
ii_source_json = lo_json
ii_mapper = me ).
cl_abap_unit_assert=>fail( ).
CATCH zcx_abapgit_ajson_error INTO lx_err.
cl_abap_unit_assert=>assert_char_cp(
act = lx_err->get_text( )
exp = 'Renamed node name cannot be empty @/set_this_empty' ).
ENDTRY.
ENDMETHOD.
ENDCLASS.
**********************************************************************
* CLONING TEST
**********************************************************************
CLASS ltcl_cloning_test DEFINITION FINAL
FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PUBLIC SECTION.
INTERFACES zif_abapgit_ajson_mapping.
INTERFACES zif_abapgit_ajson_filter.
PRIVATE SECTION.
METHODS clone_test FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS filter_test FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS mapper_test FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS mapper_and_filter FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS opts_copying FOR TESTING RAISING zcx_abapgit_ajson_error.
ENDCLASS.
CLASS ltcl_cloning_test IMPLEMENTATION.
METHOD clone_test.
DATA li_json TYPE REF TO zif_abapgit_ajson.
DATA li_json_new TYPE REF TO zif_abapgit_ajson.
DATA lo_nodes_exp TYPE REF TO lcl_nodes_helper.
li_json = zcl_abapgit_ajson=>create_empty( ).
li_json->set(
iv_path = '/ab'
iv_val = 1 ).
li_json->set(
iv_path = '/xy'
iv_val = 2 ).
li_json_new = li_json->clone( ).
CREATE OBJECT lo_nodes_exp.
lo_nodes_exp->add( ' | |object | | |2' ).
lo_nodes_exp->add( '/ |ab |num |1 | |0' ).
lo_nodes_exp->add( '/ |xy |num |2 | |0' ).
cl_abap_unit_assert=>assert_equals(
act = li_json->mt_json_tree
exp = lo_nodes_exp->sorted( ) ).
cl_abap_unit_assert=>assert_equals(
act = li_json_new->mt_json_tree
exp = lo_nodes_exp->sorted( ) ).
" ensure disconnection
li_json->set(
iv_path = '/ab'
iv_val = 5 ).
cl_abap_unit_assert=>assert_equals(
act = li_json->get_integer( '/ab' )
exp = 5 ).
cl_abap_unit_assert=>assert_equals(
act = li_json_new->get_integer( '/ab' )
exp = 1 ).
ENDMETHOD.
METHOD filter_test.
DATA li_json TYPE REF TO zif_abapgit_ajson.
DATA li_json_new TYPE REF TO zif_abapgit_ajson.
DATA lo_nodes_exp TYPE REF TO lcl_nodes_helper.
li_json = zcl_abapgit_ajson=>create_empty( ).
li_json->set(
iv_path = '/ab'
iv_val = 1 ).
li_json->set(
iv_path = '/xy'
iv_val = 2 ).
li_json_new = li_json->filter( me ).
CREATE OBJECT lo_nodes_exp.
lo_nodes_exp->add( ' | |object | | |1' ).
lo_nodes_exp->add( '/ |ab |num |1 | |0' ).
cl_abap_unit_assert=>assert_equals(
act = li_json_new->mt_json_tree
exp = lo_nodes_exp->sorted( ) ).
ENDMETHOD.
METHOD mapper_test.
DATA li_json TYPE REF TO zif_abapgit_ajson.
DATA li_json_new TYPE REF TO zif_abapgit_ajson.
DATA lo_nodes_exp TYPE REF TO lcl_nodes_helper.
li_json = zcl_abapgit_ajson=>create_empty( ).
li_json->set(
iv_path = '/ab'
iv_val = 1 ).
li_json->set(
iv_path = '/xy'
iv_val = 2 ).
li_json_new = li_json->map( me ).
CREATE OBJECT lo_nodes_exp.
lo_nodes_exp->add( ' | |object | | |2' ).
lo_nodes_exp->add( '/ |AB |num |1 | |0' ).
lo_nodes_exp->add( '/ |xy |num |2 | |0' ).
cl_abap_unit_assert=>assert_equals(
act = li_json_new->mt_json_tree
exp = lo_nodes_exp->sorted( ) ).
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~rename_node.
IF cv_name+0(1) = 'a'.
cv_name = to_upper( cv_name ).
ENDIF.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~to_abap.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~to_json.
ENDMETHOD.
METHOD zif_abapgit_ajson_filter~keep_node.
rv_keep = boolc( is_node-name IS INITIAL OR is_node-name+0(1) <> 'x' ).
ENDMETHOD.
METHOD mapper_and_filter.
DATA li_json TYPE REF TO zif_abapgit_ajson.
DATA li_json_new TYPE REF TO zif_abapgit_ajson.
DATA lo_nodes_exp TYPE REF TO lcl_nodes_helper.
li_json = zcl_abapgit_ajson=>new( ).
li_json->set(
iv_path = '/ab'
iv_val = 1 ).
li_json->set(
iv_path = '/bc'
iv_val = 2 ).
li_json->set(
iv_path = '/xy'
iv_val = 3 ).
li_json_new = zcl_abapgit_ajson=>create_from(
ii_source_json = li_json
ii_filter = me
ii_mapper = me ).
CREATE OBJECT lo_nodes_exp.
lo_nodes_exp->add( ' | |object | | |2' ).
lo_nodes_exp->add( '/ |AB |num |1 | |0' ).
lo_nodes_exp->add( '/ |bc |num |2 | |0' ).
cl_abap_unit_assert=>assert_equals(
act = li_json_new->mt_json_tree
exp = lo_nodes_exp->sorted( ) ).
ENDMETHOD.
METHOD opts_copying.
DATA li_json TYPE REF TO zif_abapgit_ajson.
DATA li_json_new TYPE REF TO zif_abapgit_ajson.
li_json = zcl_abapgit_ajson=>new( )->keep_item_order( ).
li_json->set(
iv_path = '/ab'
iv_val = 1 ).
li_json_new = li_json->clone( ).
cl_abap_unit_assert=>assert_equals(
act = li_json_new->opts( )-keep_item_order
exp = abap_true ).
ENDMETHOD.
ENDCLASS.

View File

@ -4,7 +4,16 @@ CLASS zcl_abapgit_ajson_mapping DEFINITION
CREATE PUBLIC.
PUBLIC SECTION.
CLASS-METHODS create_camel_case
CONSTANTS:
BEGIN OF rename_by,
attr_name TYPE i VALUE 0,
full_path TYPE i VALUE 1,
pattern TYPE i VALUE 2,
" regex type i value 3, " TODO add if needed in future
END OF rename_by.
CLASS-METHODS create_camel_case " DEPRECATED
IMPORTING
it_mapping_fields TYPE zif_abapgit_ajson_mapping=>ty_mapping_fields OPTIONAL
iv_first_json_upper TYPE abap_bool DEFAULT abap_true
@ -23,12 +32,38 @@ CLASS zcl_abapgit_ajson_mapping DEFINITION
RETURNING
VALUE(ri_mapping) TYPE REF TO zif_abapgit_ajson_mapping.
CLASS-METHODS create_field_mapping
CLASS-METHODS create_field_mapping " DEPRECATED
IMPORTING
it_mapping_fields TYPE zif_abapgit_ajson_mapping=>ty_mapping_fields
RETURNING
VALUE(ri_mapping) TYPE REF TO zif_abapgit_ajson_mapping.
CLASS-METHODS create_rename
IMPORTING
it_rename_map TYPE zif_abapgit_ajson_mapping=>tty_rename_map
iv_rename_by TYPE i DEFAULT rename_by-attr_name
RETURNING
VALUE(ri_mapping) TYPE REF TO zif_abapgit_ajson_mapping.
CLASS-METHODS create_compound_mapper
IMPORTING
ii_mapper1 TYPE REF TO zif_abapgit_ajson_mapping OPTIONAL
ii_mapper2 TYPE REF TO zif_abapgit_ajson_mapping OPTIONAL
ii_mapper3 TYPE REF TO zif_abapgit_ajson_mapping OPTIONAL
it_more TYPE zif_abapgit_ajson_mapping=>ty_table_of OPTIONAL
RETURNING
VALUE(ri_mapping) TYPE REF TO zif_abapgit_ajson_mapping.
CLASS-METHODS create_to_snake_case
RETURNING
VALUE(ri_mapping) TYPE REF TO zif_abapgit_ajson_mapping.
CLASS-METHODS create_to_camel_case
IMPORTING
iv_first_json_upper TYPE abap_bool DEFAULT abap_false
RETURNING
VALUE(ri_mapping) TYPE REF TO zif_abapgit_ajson_mapping.
PROTECTED SECTION.
PRIVATE SECTION.
@ -67,6 +102,21 @@ CLASS zcl_abapgit_ajson_mapping IMPLEMENTATION.
ENDMETHOD.
METHOD create_compound_mapper.
DATA lt_queue TYPE zif_abapgit_ajson_mapping=>ty_table_of.
APPEND ii_mapper1 TO lt_queue.
APPEND ii_mapper2 TO lt_queue.
APPEND ii_mapper3 TO lt_queue.
APPEND LINES OF it_more TO lt_queue.
DELETE lt_queue WHERE table_line IS INITIAL.
CREATE OBJECT ri_mapping TYPE lcl_compound_mapper
EXPORTING
it_queue = lt_queue.
ENDMETHOD.
METHOD create_upper_case.
@ -75,4 +125,28 @@ CLASS zcl_abapgit_ajson_mapping IMPLEMENTATION.
it_mapping_fields = it_mapping_fields.
ENDMETHOD.
METHOD create_rename.
CREATE OBJECT ri_mapping TYPE lcl_rename
EXPORTING
it_rename_map = it_rename_map
iv_rename_by = iv_rename_by.
ENDMETHOD.
METHOD create_to_snake_case.
CREATE OBJECT ri_mapping TYPE lcl_to_snake.
ENDMETHOD.
METHOD create_to_camel_case.
CREATE OBJECT ri_mapping TYPE lcl_to_camel
EXPORTING
iv_first_json_upper = iv_first_json_upper.
ENDMETHOD.
ENDCLASS.

View File

@ -3,9 +3,6 @@ CLASS lcl_mapping_fields DEFINITION.
PUBLIC SECTION.
INTERFACES zif_abapgit_ajson_mapping.
ALIASES to_abap FOR zif_abapgit_ajson_mapping~to_abap.
ALIASES to_json FOR zif_abapgit_ajson_mapping~to_json.
METHODS constructor
IMPORTING
it_mapping_fields TYPE zif_abapgit_ajson_mapping~ty_mapping_fields OPTIONAL.
@ -17,6 +14,23 @@ CLASS lcl_mapping_fields DEFINITION.
ENDCLASS.
CLASS lcl_rename DEFINITION.
PUBLIC SECTION.
INTERFACES zif_abapgit_ajson_mapping.
METHODS constructor
IMPORTING
it_rename_map TYPE zif_abapgit_ajson_mapping~tty_rename_map
iv_rename_by TYPE i.
PROTECTED SECTION.
PRIVATE SECTION.
DATA mt_rename_map TYPE zif_abapgit_ajson_mapping~tty_rename_map.
DATA mv_rename_by TYPE i.
ENDCLASS.
CLASS lcl_mapping_to_upper DEFINITION.
@ -69,3 +83,34 @@ CLASS lcl_mapping_camel DEFINITION.
DATA mi_mapping_fields TYPE REF TO zif_abapgit_ajson_mapping.
ENDCLASS.
CLASS lcl_compound_mapper DEFINITION.
PUBLIC SECTION.
INTERFACES zif_abapgit_ajson_mapping.
METHODS constructor
IMPORTING
it_queue TYPE zif_abapgit_ajson_mapping=>ty_table_of.
PROTECTED SECTION.
PRIVATE SECTION.
DATA mt_queue TYPE zif_abapgit_ajson_mapping=>ty_table_of.
ENDCLASS.
CLASS lcl_to_snake DEFINITION.
PUBLIC SECTION.
INTERFACES zif_abapgit_ajson_mapping.
ENDCLASS.
CLASS lcl_to_camel DEFINITION.
PUBLIC SECTION.
INTERFACES zif_abapgit_ajson_mapping.
METHODS constructor
IMPORTING
iv_first_json_upper TYPE abap_bool.
PRIVATE SECTION.
DATA mv_first_json_upper TYPE abap_bool.
ENDCLASS.

View File

@ -1,4 +1,4 @@
CLASS lcl_mapping_fields IMPLEMENTATION.
CLASS lcl_mapping_fields IMPLEMENTATION. "DEPRECATED
METHOD constructor.
@ -41,9 +41,58 @@ CLASS lcl_mapping_fields IMPLEMENTATION.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~rename_node.
ENDMETHOD.
ENDCLASS.
CLASS lcl_rename IMPLEMENTATION.
METHOD constructor.
mt_rename_map = it_rename_map.
mv_rename_by = iv_rename_by.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~to_abap.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~to_json.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~rename_node.
DATA lv_full_path TYPE string.
DATA lv_pair_found TYPE abap_bool.
FIELD-SYMBOLS <r> LIKE LINE OF mt_rename_map.
CASE mv_rename_by.
WHEN zcl_abapgit_ajson_mapping=>rename_by-attr_name.
READ TABLE mt_rename_map ASSIGNING <r> WITH TABLE KEY by_name COMPONENTS from = cv_name.
lv_pair_found = boolc( sy-subrc = 0 ).
WHEN zcl_abapgit_ajson_mapping=>rename_by-full_path.
lv_full_path = is_node-path && cv_name.
READ TABLE mt_rename_map ASSIGNING <r> WITH TABLE KEY by_name COMPONENTS from = lv_full_path.
lv_pair_found = boolc( sy-subrc = 0 ).
WHEN zcl_abapgit_ajson_mapping=>rename_by-pattern.
lv_full_path = is_node-path && cv_name.
LOOP AT mt_rename_map ASSIGNING <r>.
IF lv_full_path CP <r>-from.
lv_pair_found = abap_true.
EXIT.
ENDIF.
ENDLOOP.
WHEN OTHERS.
lv_pair_found = abap_false. " No rename
ENDCASE.
IF lv_pair_found = abap_true.
cv_name = <r>-to.
ENDIF.
ENDMETHOD.
ENDCLASS.
CLASS lcl_mapping_to_upper IMPLEMENTATION.
@ -76,6 +125,11 @@ CLASS lcl_mapping_to_upper IMPLEMENTATION.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~rename_node.
cv_name = to_upper( cv_name ).
ENDMETHOD.
ENDCLASS.
@ -111,11 +165,16 @@ CLASS lcl_mapping_to_lower IMPLEMENTATION.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~rename_node.
cv_name = to_lower( cv_name ).
ENDMETHOD.
ENDCLASS.
CLASS lcl_mapping_camel IMPLEMENTATION.
CLASS lcl_mapping_camel IMPLEMENTATION. "DEPRECATED
METHOD constructor.
@ -179,5 +238,104 @@ CLASS lcl_mapping_camel IMPLEMENTATION.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~rename_node.
ENDMETHOD.
ENDCLASS.
CLASS lcl_compound_mapper IMPLEMENTATION.
METHOD constructor.
mt_queue = it_queue.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~rename_node.
DATA ls_node LIKE is_node.
DATA li_mapper LIKE LINE OF mt_queue.
ls_node = is_node.
LOOP AT mt_queue INTO li_mapper.
li_mapper->rename_node(
EXPORTING
is_node = ls_node
CHANGING
cv_name = cv_name ).
ls_node-name = cv_name.
ENDLOOP.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~to_abap.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~to_json.
ENDMETHOD.
ENDCLASS.
CLASS lcl_to_snake IMPLEMENTATION.
METHOD zif_abapgit_ajson_mapping~rename_node.
REPLACE ALL OCCURRENCES OF REGEX `([a-z])([A-Z])` IN cv_name WITH `$1_$2`.
cv_name = to_lower( cv_name ).
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~to_abap.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~to_json.
ENDMETHOD.
ENDCLASS.
CLASS lcl_to_camel IMPLEMENTATION.
METHOD constructor.
mv_first_json_upper = iv_first_json_upper.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~rename_node.
TYPES lty_token TYPE c LENGTH 255.
CONSTANTS lc_forced_underscore_marker TYPE c LENGTH 1 VALUE cl_abap_char_utilities=>horizontal_tab.
DATA lt_tokens TYPE STANDARD TABLE OF lty_token.
DATA lv_from TYPE i.
FIELD-SYMBOLS <token> LIKE LINE OF lt_tokens.
IF mv_first_json_upper = abap_true.
lv_from = 1.
ELSE.
lv_from = 2.
ENDIF.
REPLACE ALL OCCURRENCES OF `__` IN cv_name WITH lc_forced_underscore_marker. " Force underscore
SPLIT cv_name AT `_` INTO TABLE lt_tokens.
DELETE lt_tokens WHERE table_line IS INITIAL.
LOOP AT lt_tokens ASSIGNING <token> FROM lv_from.
TRANSLATE <token>+0(1) TO UPPER CASE.
ENDLOOP.
CONCATENATE LINES OF lt_tokens INTO cv_name.
REPLACE ALL OCCURRENCES OF lc_forced_underscore_marker IN cv_name WITH `_`.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~to_abap.
ENDMETHOD.
METHOD zif_abapgit_ajson_mapping~to_json.
ENDMETHOD.
ENDCLASS.

View File

@ -1,4 +1,4 @@
CLASS ltcl_camel_case DEFINITION FINAL FOR TESTING
CLASS ltcl_test_mappers DEFINITION FINAL FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
@ -11,10 +11,21 @@ CLASS ltcl_camel_case DEFINITION FINAL FOR TESTING
to_json_nested_table FOR TESTING RAISING zcx_abapgit_ajson_error,
to_json_first_lower FOR TESTING RAISING zcx_abapgit_ajson_error.
METHODS:
to_snake FOR TESTING RAISING zcx_abapgit_ajson_error,
to_camel FOR TESTING RAISING zcx_abapgit_ajson_error,
to_camel_1st_upper FOR TESTING RAISING zcx_abapgit_ajson_error,
rename_by_attr FOR TESTING RAISING zcx_abapgit_ajson_error,
rename_by_path FOR TESTING RAISING zcx_abapgit_ajson_error,
rename_by_pattern FOR TESTING RAISING zcx_abapgit_ajson_error,
compound_mapper FOR TESTING RAISING zcx_abapgit_ajson_error,
test_to_upper FOR TESTING RAISING zcx_abapgit_ajson_error,
test_to_lower FOR TESTING RAISING zcx_abapgit_ajson_error.
ENDCLASS.
CLASS ltcl_camel_case IMPLEMENTATION.
CLASS ltcl_test_mappers IMPLEMENTATION.
METHOD from_json_to_json.
@ -175,6 +186,165 @@ CLASS ltcl_camel_case IMPLEMENTATION.
ENDMETHOD.
METHOD test_to_upper.
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>create_from(
ii_source_json = zcl_abapgit_ajson=>parse( '{"a":1,"b":{"c":2}}' )
ii_mapper = zcl_abapgit_ajson_mapping=>create_upper_case( ) )->stringify( )
exp = '{"A":1,"B":{"C":2}}' ).
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>parse( '{"a":1,"b":{"c":2}}'
)->map( zcl_abapgit_ajson_mapping=>create_upper_case( )
)->stringify( )
exp = '{"A":1,"B":{"C":2}}' ).
ENDMETHOD.
METHOD test_to_lower.
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>create_from(
ii_source_json = zcl_abapgit_ajson=>parse( '{"A":1,"B":{"C":2}}' )
ii_mapper = zcl_abapgit_ajson_mapping=>create_lower_case( ) )->stringify( )
exp = '{"a":1,"b":{"c":2}}' ).
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>parse( '{"A":1,"B":{"C":2}}'
)->map( zcl_abapgit_ajson_mapping=>create_lower_case( )
)->stringify( )
exp = '{"a":1,"b":{"c":2}}' ).
ENDMETHOD.
METHOD rename_by_attr.
DATA lt_map TYPE zif_abapgit_ajson_mapping=>tty_rename_map.
FIELD-SYMBOLS <i> LIKE LINE OF lt_map.
APPEND INITIAL LINE TO lt_map ASSIGNING <i>.
<i>-from = 'a'.
<i>-to = 'x'.
APPEND INITIAL LINE TO lt_map ASSIGNING <i>.
<i>-from = 'c'.
<i>-to = 'y'.
APPEND INITIAL LINE TO lt_map ASSIGNING <i>.
<i>-from = 'd'.
<i>-to = 'z'.
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>create_from(
ii_source_json = zcl_abapgit_ajson=>parse( '{"a":1,"b":{"c":2},"d":{"e":3}}' )
ii_mapper = zcl_abapgit_ajson_mapping=>create_rename( lt_map
) )->stringify( )
exp = '{"b":{"y":2},"x":1,"z":{"e":3}}' ).
ENDMETHOD.
METHOD rename_by_path.
DATA lt_map TYPE zif_abapgit_ajson_mapping=>tty_rename_map.
FIELD-SYMBOLS <i> LIKE LINE OF lt_map.
APPEND INITIAL LINE TO lt_map ASSIGNING <i>.
<i>-from = '/b/a'.
<i>-to = 'x'.
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>create_from(
ii_source_json = zcl_abapgit_ajson=>parse( '{"a":1,"b":{"a":2},"c":{"a":3}}' )
ii_mapper = zcl_abapgit_ajson_mapping=>create_rename(
it_rename_map = lt_map
iv_rename_by = zcl_abapgit_ajson_mapping=>rename_by-full_path
) )->stringify( )
exp = '{"a":1,"b":{"x":2},"c":{"a":3}}' ).
ENDMETHOD.
METHOD rename_by_pattern.
DATA lt_map TYPE zif_abapgit_ajson_mapping=>tty_rename_map.
FIELD-SYMBOLS <i> LIKE LINE OF lt_map.
APPEND INITIAL LINE TO lt_map ASSIGNING <i>.
<i>-from = '/*/this*'.
<i>-to = 'x'.
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>create_from(
ii_source_json = zcl_abapgit_ajson=>parse( '{"andthisnot":1,"b":{"thisone":2},"c":{"a":3}}' )
ii_mapper = zcl_abapgit_ajson_mapping=>create_rename(
it_rename_map = lt_map
iv_rename_by = zcl_abapgit_ajson_mapping=>rename_by-pattern
) )->stringify( )
exp = '{"andthisnot":1,"b":{"x":2},"c":{"a":3}}' ).
ENDMETHOD.
METHOD compound_mapper.
DATA lt_map TYPE zif_abapgit_ajson_mapping=>tty_rename_map.
FIELD-SYMBOLS <i> LIKE LINE OF lt_map.
APPEND INITIAL LINE TO lt_map ASSIGNING <i>.
<i>-from = '/b/a'.
<i>-to = 'x'.
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>create_from(
ii_source_json = zcl_abapgit_ajson=>parse( '{"a":1,"b":{"a":2},"c":{"a":3}}' )
ii_mapper = zcl_abapgit_ajson_mapping=>create_compound_mapper(
ii_mapper1 = zcl_abapgit_ajson_mapping=>create_rename(
it_rename_map = lt_map
iv_rename_by = zcl_abapgit_ajson_mapping=>rename_by-full_path )
ii_mapper2 = zcl_abapgit_ajson_mapping=>create_upper_case( ) )
)->stringify( )
exp = '{"A":1,"B":{"X":2},"C":{"A":3}}' ).
ENDMETHOD.
METHOD to_snake.
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>create_from(
ii_source_json = zcl_abapgit_ajson=>parse( '{"aB":1,"BbC":2,"cD":{"xY":3},"ZZ":4}' )
ii_mapper = zcl_abapgit_ajson_mapping=>create_to_snake_case( )
)->stringify( )
exp = '{"a_b":1,"bb_c":2,"c_d":{"x_y":3},"zz":4}' ).
ENDMETHOD.
METHOD to_camel.
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>create_from(
ii_source_json = zcl_abapgit_ajson=>parse( '{"a_b":1,"bb_c":2,"c_d":{"x_y":3},"zz":4}' )
ii_mapper = zcl_abapgit_ajson_mapping=>create_to_camel_case( )
)->stringify( )
exp = '{"aB":1,"bbC":2,"cD":{"xY":3},"zz":4}' ).
" Forced underscore
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>create_from(
ii_source_json = zcl_abapgit_ajson=>parse( '{"a__b":1}' )
ii_mapper = zcl_abapgit_ajson_mapping=>create_to_camel_case( )
)->stringify( )
exp = '{"a_b":1}' ).
ENDMETHOD.
METHOD to_camel_1st_upper.
cl_abap_unit_assert=>assert_equals(
act = zcl_abapgit_ajson=>create_from(
ii_source_json = zcl_abapgit_ajson=>parse( '{"aj_bc":1,"bb_c":2,"c_d":{"xq_yq":3},"zz":4}' )
ii_mapper = zcl_abapgit_ajson_mapping=>create_to_camel_case( iv_first_json_upper = abap_true )
)->stringify( )
exp = '{"AjBc":1,"BbC":2,"CD":{"XqYq":3},"Zz":4}' ).
ENDMETHOD.
ENDCLASS.

View File

@ -43,11 +43,14 @@ public section.
importing
!IV_MSG type STRING
!IV_LOCATION type STRING optional
!IS_NODE type ANY optional
raising
zcx_abapgit_ajson_error .
methods set_location
methods SET_LOCATION
importing
iv_location type string.
!IV_LOCATION type STRING optional
!IS_NODE type ANY optional
preferred parameter IV_LOCATION .
protected section.
private section.
types:
@ -64,7 +67,7 @@ ENDCLASS.
CLASS zcx_abapgit_ajson_error IMPLEMENTATION.
method CONSTRUCTOR.
method CONSTRUCTOR.
CALL METHOD SUPER->CONSTRUCTOR
EXPORTING
PREVIOUS = PREVIOUS
@ -82,51 +85,53 @@ if textid is initial.
else.
IF_T100_MESSAGE~T100KEY = TEXTID.
endif.
endmethod.
endmethod.
method raise.
data ls_msg type ty_message_parts.
data lv_tmp type string.
data lx type ref to zcx_abapgit_ajson_error.
if iv_location is initial.
lv_tmp = iv_msg.
else.
lv_tmp = iv_msg && | @{ iv_location }|.
endif.
ls_msg = lv_tmp.
raise exception type zcx_abapgit_ajson_error
exporting
textid = zcx_ajson_error
message = iv_msg
location = iv_location
a1 = ls_msg-a1
a2 = ls_msg-a2
a3 = ls_msg-a3
a4 = ls_msg-a4.
create object lx exporting message = iv_msg.
lx->set_location(
iv_location = iv_location
is_node = is_node ).
raise exception lx.
endmethod.
method set_location.
data ls_msg type ty_message_parts.
data lv_location type string.
data lv_tmp type string.
field-symbols <path> type string.
field-symbols <name> type string.
if iv_location is initial.
lv_tmp = message.
else.
lv_tmp = message && | @{ iv_location }|.
if iv_location is not initial.
lv_location = iv_location.
elseif is_node is not initial.
assign component 'PATH' of structure is_node to <path>.
assign component 'NAME' of structure is_node to <name>.
if <path> is assigned and <name> is assigned.
lv_location = <path> && <name>.
endif.
endif.
if lv_location is not initial.
lv_tmp = message && | @{ lv_location }|.
else.
lv_tmp = message.
endif.
ls_msg = lv_tmp.
location = iv_location.
location = lv_location.
a1 = ls_msg-a1.
a2 = ls_msg-a2.
a3 = ls_msg-a3.
a4 = ls_msg-a4.
endmethod.
ENDCLASS.

View File

@ -8,6 +8,7 @@ class ltcl_error definition
methods raise for testing.
methods raise_w_location for testing.
methods raise_w_node for testing.
methods set_location for testing.
endclass.
@ -50,6 +51,26 @@ class ltcl_error implementation.
endmethod.
method raise_w_node.
data lx type ref to zcx_abapgit_ajson_error.
data ls_node type zif_abapgit_ajson=>ty_node.
ls_node-path = '/x/'.
ls_node-name = 'y'.
try.
zcx_abapgit_ajson_error=>raise( iv_msg = 'a'
is_node = ls_node ).
cl_abap_unit_assert=>fail( ).
catch zcx_abapgit_ajson_error into lx.
cl_abap_unit_assert=>assert_equals(
exp = 'a @/x/y'
act = lx->get_text( ) ).
endtry.
endmethod.
method set_location.
data lx type ref to zcx_abapgit_ajson_error.

View File

@ -48,6 +48,27 @@ INTERFACE zif_abapgit_ajson
DATA mt_json_tree TYPE ty_nodes_ts READ-ONLY.
" CLONING
METHODS clone
RETURNING
VALUE(ri_json) TYPE REF TO zif_abapgit_ajson
RAISING
zcx_abapgit_ajson_error.
METHODS filter
IMPORTING
ii_filter TYPE REF TO zif_abapgit_ajson_filter
RETURNING
VALUE(ri_json) TYPE REF TO zif_abapgit_ajson
RAISING
zcx_abapgit_ajson_error.
METHODS map
IMPORTING
ii_mapper TYPE REF TO zif_abapgit_ajson_mapping
RETURNING
VALUE(ri_json) TYPE REF TO zif_abapgit_ajson
RAISING
zcx_abapgit_ajson_error.
" METHODS
METHODS freeze.
@ -166,6 +187,14 @@ INTERFACE zif_abapgit_ajson
RAISING
zcx_abapgit_ajson_error.
METHODS setx
IMPORTING
iv_param TYPE string
RETURNING
VALUE(ri_json) TYPE REF TO zif_abapgit_ajson
RAISING
zcx_abapgit_ajson_error.
METHODS set_boolean
IMPORTING
iv_path TYPE string

View File

@ -2,7 +2,7 @@ INTERFACE zif_abapgit_ajson_mapping
PUBLIC.
TYPES:
BEGIN OF ty_mapping_field,
BEGIN OF ty_mapping_field, " deprecated, will be removed
abap TYPE string,
json TYPE string,
END OF ty_mapping_field,
@ -10,18 +10,35 @@ INTERFACE zif_abapgit_ajson_mapping
WITH UNIQUE SORTED KEY abap COMPONENTS abap
WITH UNIQUE SORTED KEY json COMPONENTS json.
METHODS to_abap
TYPES:
BEGIN OF ty_rename,
from TYPE string,
to TYPE string,
END OF ty_rename,
tty_rename_map TYPE STANDARD TABLE OF ty_rename
WITH UNIQUE SORTED KEY by_name COMPONENTS from.
TYPES:
ty_table_of TYPE STANDARD TABLE OF REF TO zif_abapgit_ajson_mapping.
METHODS to_abap " deprecated, will be removed
IMPORTING
!iv_path TYPE string
!iv_name TYPE string
RETURNING
VALUE(rv_result) TYPE string.
METHODS to_json
METHODS to_json " deprecated, will be removed
IMPORTING
!iv_path TYPE string
!iv_name TYPE string
RETURNING
VALUE(rv_result) TYPE string.
METHODS rename_node
IMPORTING
!is_node TYPE zif_abapgit_ajson=>ty_node
CHANGING
!cv_name TYPE zif_abapgit_ajson=>ty_node-name.
ENDINTERFACE.

View File

@ -88,7 +88,7 @@ ENDCLASS.
CLASS ZCL_ABAPGIT_JSON_HANDLER IMPLEMENTATION.
CLASS zcl_abapgit_json_handler IMPLEMENTATION.
METHOD deserialize.
@ -248,7 +248,7 @@ CLASS ZCL_ABAPGIT_JSON_HANDLER IMPLEMENTATION.
lo_mapping = zcl_abapgit_ajson_mapping=>create_camel_case( iv_first_json_upper = abap_false ).
lo_ajson = zcl_abapgit_ajson=>create_empty( lo_mapping ).
lo_ajson = zcl_abapgit_ajson=>create_empty( ii_custom_mapping = lo_mapping ).
lo_ajson->keep_item_order( ).
lo_ajson->set(

View File

@ -108,6 +108,7 @@
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_json_to_abap", "method": "to_abap_array_of_arrays", "note": "Expected table to contain 2 rows, got 4"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_writer_test", "method": "set_tab_hashed", "note": "Expected table to contain 4 rows, got 3"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_integrated", "method": "reader", "note": "Path not found @/false, keywords?"},
{"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_writer_test", "method": "setx_float", "note": "DecFloat34"},
{"object": "ZCL_ABAPGIT_REQUIREMENT_HELPER", "class": "ltcl_lower_release", "method": "empty_patch", "note": "Void type: CVERS_SDU"},
{"object": "ZCL_ABAPGIT_REQUIREMENT_HELPER", "class": "ltcl_lower_release", "method": "lower_patch", "note": "Void type: CVERS_SDU"},