1. 下载ABAPGIT安装在本地环境,官网有详细介绍。
使用教程:https://blog.youkuaiyun.com/Li958172829/article/details/132420657
2. 下载JSON2ABAPTYPE 开源代码
项目地址:GitHub - fidley/JSON2ABAPType: Creator of ABAP types on a base of JSON structure
3. 程序示例代码(亲测可用)
"! This is demo for converting JSON structure into
"! ABAP type
"! done by Lukasz Pegiel for http://abapblog.com
REPORT zjson2abaptype.
DATA: ok_code TYPE sy-ucomm.
SELECTION-SCREEN BEGIN OF SCREEN 1001 AS SUBSCREEN.
PARAMETERS: p_none RADIOBUTTON GROUP gr1,
p_low RADIOBUTTON GROUP gr1,
p_camel RADIOBUTTON GROUP gr1,
p_ext RADIOBUTTON GROUP gr1 DEFAULT 'X',
p_user RADIOBUTTON GROUP gr1,
p_userlo RADIOBUTTON GROUP gr1,
p_cases RADIOBUTTON GROUP gr1.
SELECTION-SCREEN END OF SCREEN 1001.
CLASS lcl_json_structure DEFINITION DEFERRED.
CLASS lcl_hlp DEFINITION.
PUBLIC SECTION.
TYPES: BEGIN OF t_source,
line TYPE char255,
END OF t_source.
TYPES: tt_source TYPE STANDARD TABLE OF t_source WITH DEFAULT KEY.
DATA: converter TYPE REF TO lcl_json_structure,
results TYPE string,
source_editor TYPE REF TO cl_gui_textedit,
abap_editor TYPE REF TO cl_gui_abapedit.
METHODS: constructor.
METHODS: create_source_editor.
METHODS: convert.
METHODS: pai IMPORTING VALUE(i_okcode) TYPE sy-ucomm.
PRIVATE SECTION.
METHODS call_editor
CHANGING
c_source TYPE tt_source OPTIONAL.
METHODS pretty_print_code
CHANGING
c_source TYPE tt_source.
METHODS get_pretty_name_mode RETURNING VALUE(pretty_name_mode) TYPE char1.
DATA: handler TYPE REF TO cl_wb_editor.
ENDCLASS.
CLASS lcl_json_structure DEFINITION.
PUBLIC SECTION.
TYPES: BEGIN OF t_hierarchy,
level TYPE i,
name TYPE string,
table TYPE abap_bool,
structure TYPE abap_bool,
type TYPE string,
length TYPE i,
decimals TYPE i,
absolute_type TYPE abap_abstypename,
parent TYPE string,
final_type TYPE string,
type_definition TYPE string,
id TYPE i,
END OF t_hierarchy,
tt_hierarchy TYPE STANDARD TABLE OF t_hierarchy WITH DEFAULT KEY.
CONSTANTS: c_components TYPE string VALUE '&&components&&'.
DATA: hierarchy TYPE tt_hierarchy.
METHODS: build_structure IMPORTING i_data TYPE REF TO data
EXPORTING e_data TYPE string.
PRIVATE SECTION.
DATA: current_id TYPE i.
METHODS check_component
IMPORTING
i_comp TYPE abap_compdescr
VALUE(i_data) TYPE REF TO data
VALUE(i_parent) TYPE abap_abstypename
i_level TYPE i
i_keep_level TYPE abap_bool DEFAULT abap_false
i_keep_id TYPE abap_bool DEFAULT abap_false.
METHODS check_object
IMPORTING
VALUE(i_data) TYPE REF TO data
VALUE(i_parent) TYPE abap_abstypename
i_abap_type TYPE REF TO cl_abap_structdescr
i_level TYPE i.
METHODS create_types RETURNING VALUE(r_definition) TYPE string.
METHODS: get_id RETURNING VALUE(r_id) TYPE i.
METHODS: display.
METHODS: get_types RETURNING VALUE(r_types) TYPE string,
init,
get_internal_types
CHANGING
VALUE(c_type) TYPE t_hierarchy.
ENDCLASS.
START-OF-SELECTION.
DATA(hlp) = NEW lcl_hlp( ).
CALL SCREEN 0100.
*&---------------------------------------------------------------------*
*& Module PBO OUTPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE pbo OUTPUT.
SET PF-STATUS 'STATUS_0100'.
SET TITLEBAR 'TITLE'.
hlp->create_source_editor( ).
ENDMODULE.
*&---------------------------------------------------------------------*
*& Module PAI INPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE pai INPUT.
hlp->pai( ok_code ).
ENDMODULE.
CLASS lcl_hlp IMPLEMENTATION.
METHOD constructor.
converter = NEW #( ).
ENDMETHOD.
METHOD create_source_editor.
IF source_editor IS INITIAL.
source_editor = NEW #( parent = NEW cl_gui_docking_container( side = cl_gui_docking_container=>dock_at_left
no_autodef_progid_dynnr = abap_true
extension = 500 ) ) .
ENDIF.
ENDMETHOD.
METHOD convert.
DATA: source TYPE soli_tab.
source_editor->get_text_as_stream(
IMPORTING
text = source
EXCEPTIONS
error_cntl_call_method = 1
OTHERS = 3
).
IF sy-subrc EQ 0.
IF source IS INITIAL.
MESSAGE s001(00) WITH 'Data input is required' DISPLAY LIKE 'E' ##MG_MISSING ##NO_TEXT.
RETURN.
ENDIF.
* DATA(json_data) = /ui2/cl_json=>generate(
DATA(json_data) = zui2_json=>generate(
json = cl_bcs_convert=>txt_to_string( it_soli = source )
pretty_name = get_pretty_name_mode( )
).
IF json_data IS INITIAL.
MESSAGE s001(00) WITH 'Problem converting JSON.' DISPLAY LIKE 'E' ##MG_MISSING ##NO_TEXT.
ELSE.
converter->build_structure(
EXPORTING
i_data = json_data
IMPORTING
e_data = results
).
DATA: target TYPE STANDARD TABLE OF t_source.
SPLIT results AT cl_abap_char_utilities=>newline INTO TABLE target.
pretty_print_code( CHANGING c_source = target ).
call_editor( CHANGING c_source = target ).
ENDIF.
ENDIF.
ENDMETHOD.
METHOD call_editor.
IF abap_editor IS INITIAL.
DATA(container) = NEW cl_gui_custom_container( container_name = 'CC_INPUT' ).
abap_editor = NEW #( parent = container ).
ENDIF.
abap_editor->draw( ).
abap_editor->set_text( c_source ).
abap_editor->undraw( ).
ENDMETHOD.
METHOD pretty_print_code.
CALL FUNCTION 'PRETTY_PRINTER'
EXPORTING
inctoo = abap_false " X = Process Include Programs as Well
TABLES
ntext = c_source " Table of Formatted Source Code
otext = c_source " Table of Source Code Pending Editing
EXCEPTIONS
enqueue_table_full = 0
include_enqueued = 0
include_readerror = 0
include_writeerror = 0
OTHERS = 0.
ENDMETHOD.
METHOD pai.
CLEAR sy-ucomm.
CASE i_okcode.
WHEN 'BACK' OR 'UP' OR 'EXIT'.
LEAVE PROGRAM.
WHEN 'CONVERT'.
convert( ).
ENDCASE.
ENDMETHOD.
METHOD get_pretty_name_mode.
pretty_name_mode = COND #( WHEN p_none EQ abap_true THEN zui2_json=>pretty_mode-none
WHEN p_camel EQ abap_true THEN zui2_json=>pretty_mode-camel_case
WHEN p_ext EQ abap_true THEN zui2_json=>pretty_mode-extended
WHEN p_low EQ abap_true THEN zui2_json=>pretty_mode-low_case
WHEN p_user EQ abap_true THEN zui2_json=>pretty_mode-user
WHEN p_userlo EQ abap_true THEN zui2_json=>pretty_mode-user_low_case
WHEN P_cases EQ abap_true THEN zui2_json=>pretty_mode-case_sensitive
ELSE zui2_json=>pretty_mode-extended
).
ENDMETHOD.
ENDCLASS.
CLASS lcl_json_structure IMPLEMENTATION.
METHOD get_id.
ADD 1 TO current_id.
r_id = current_id.
ENDMETHOD.
METHOD build_structure.
init( ).
DATA: level TYPE i VALUE 0,
abap_type TYPE REF TO cl_abap_structdescr,
abap_ref_type TYPE REF TO cl_abap_refdescr.
FIELD-SYMBOLS: <table> TYPE ANY TABLE.
TRY.
DATA(abap_type_table) = CAST cl_abap_tabledescr( cl_abap_tabledescr=>describe_by_data_ref( p_data_ref = i_data ) ).
ASSIGN i_data->* TO <table>.
LOOP AT <table> ASSIGNING FIELD-SYMBOL(<line>).
EXIT.
ENDLOOP.
APPEND VALUE #( level = level name = 'JSON' type = abap_type_table->type_kind absolute_type = abap_type_table->absolute_name table = abap_true id = get_id( ) ) TO hierarchy.
abap_type = CAST cl_abap_structdescr( cl_abap_structdescr=>describe_by_data_ref( p_data_ref = <line> ) ).
ADD 1 TO level.
APPEND VALUE #( level = level name = 'JSON' type = abap_type->type_kind absolute_type = abap_type->absolute_name structure = abap_true id = get_id( ) ) TO hierarchy.
check_object( i_abap_type = abap_type
i_level = level
i_data = <line>
i_parent = '' ).
CATCH cx_sy_move_cast_error.
abap_type = CAST cl_abap_structdescr( cl_abap_structdescr=>describe_by_data_ref( p_data_ref = i_data ) ).
APPEND VALUE #( level = level name = 'JSON' type = abap_type->type_kind absolute_type = abap_type->absolute_name structure = abap_true id = get_id( ) ) TO hierarchy.
check_object( i_abap_type = abap_type i_level = level i_data = i_data i_parent = '' ).
ENDTRY.
e_data = create_types( ).
ENDMETHOD.
METHOD init.
REFRESH: hierarchy.
CLEAR current_id.
ENDMETHOD.
METHOD display.
cl_demo_output=>display( create_types( ) ).
ENDMETHOD.
METHOD check_object.
LOOP AT i_abap_type->components ASSIGNING FIELD-SYMBOL(<comp>).
DATA(field) = |i_data->{ <comp>-name }|.
ASSIGN (field) TO FIELD-SYMBOL(<data>).
IF <data> IS ASSIGNED AND <data> IS NOT INITIAL.
check_component(
i_parent = i_abap_type->absolute_name
i_comp = <comp>
i_data = <data>
i_level = i_level ).
ENDIF.
UNASSIGN <data>.
ENDLOOP.
ENDMETHOD. "#EC CI_VALPAR
METHOD check_component.
DATA level TYPE i VALUE 0.
IF i_keep_level EQ abap_false.
level = i_level + 1.
ELSE.
level = i_level.
ENDIF.
TRY.
DATA(str_type) = CAST cl_abap_structdescr( cl_abap_structdescr=>describe_by_data_ref( p_data_ref = i_data ) ).
check_object( i_parent = i_parent
i_data = i_data
i_abap_type = str_type
i_level = level
).
APPEND VALUE #( level = level name = i_comp-name type = str_type->type_kind absolute_type = str_type->absolute_name parent = i_parent structure = abap_true id = get_id( ) ) TO hierarchy.
CATCH cx_root.
TRY.
DATA(table_type) = CAST cl_abap_tabledescr( cl_abap_tabledescr=>describe_by_data_ref( p_data_ref = i_data ) ).
IF i_keep_id EQ abap_false.
DATA(id) = get_id( ).
APPEND VALUE #( level = level name = i_comp-name type = table_type->type_kind absolute_type = table_type->absolute_name parent = i_parent table = abap_true id = id ) TO hierarchy.
ELSE.
id = current_id.
ENDIF.
FIELD-SYMBOLS: <tab> TYPE STANDARD TABLE,
<test> TYPE any.
ASSIGN i_data->* TO <tab>.
TRY.
ASSIGN <tab>[ 1 ] TO <test>.
IF sy-subrc NE 0.
APPEND INITIAL LINE TO <tab> ASSIGNING <test>.
ENDIF.
CATCH cx_root.
APPEND INITIAL LINE TO <tab> ASSIGNING <test>.
ENDTRY.
cl_abap_structdescr=>describe_by_data_ref( EXPORTING p_data_ref = <test>
RECEIVING p_descr_ref = DATA(table_line_ref)
EXCEPTIONS OTHERS = 1 ).
IF sy-subrc NE 0.
DATA: table_of_strings TYPE STANDARD TABLE OF string.
check_component(
EXPORTING
i_comp = i_comp
i_data = REF #( table_of_strings )
i_parent = i_parent
i_level = i_level
i_keep_level = abap_true
i_keep_id = abap_true
).
RETURN.
ENDIF.
DATA(table_line_type) = CAST cl_abap_structdescr( table_line_ref ).
APPEND VALUE #( level = level name = i_comp-name type = table_line_type->type_kind absolute_type = table_line_type->absolute_name parent = table_type->absolute_name structure = abap_true id = id ) TO hierarchy.
check_object( i_parent = table_type->absolute_name
i_data = <test>
i_abap_type = table_line_type
i_level = level
).
CATCH cx_root.
"May be a table of strings or integers.
IF table_type IS NOT INITIAL.
TRY.
IF table_type->type_kind EQ 'h'.
DATA(table_line_as_el_type) = CAST cl_abap_elemdescr( cl_abap_elemdescr=>describe_by_data_ref( p_data_ref = <test> ) ).
ADD 1 TO level.
APPEND VALUE #( level = level name = i_comp-name type = table_line_as_el_type->type_kind absolute_type = table_line_as_el_type->absolute_name parent = table_line_as_el_type->absolute_name structure = abap_true id = id ) TO hierarchy.
ENDIF.
CATCH cx_root.
TRY.
IF table_type->type_kind EQ 'h'.
table_line_as_el_type = CAST cl_abap_elemdescr( cl_abap_elemdescr=>describe_by_data( p_data = <test> ) ).
ADD 1 TO level.
APPEND VALUE #( level = level name = i_comp-name type = table_line_as_el_type->type_kind absolute_type = table_line_as_el_type->absolute_name parent = table_line_as_el_type->absolute_name structure = abap_true id = id ) TO hierarchy.
ENDIF.
CATCH cx_root.
DATA(other_type) = cl_abap_typedescr=>describe_by_data_ref( p_data_ref = i_data ) .
APPEND VALUE #( level = level name = i_comp-name type = other_type->type_kind length = other_type->length decimals = other_type->decimals absolute_type = other_type->absolute_name parent = i_parent ) TO hierarchy.
ENDTRY.
ENDTRY.
ELSE.
other_type = cl_abap_typedescr=>describe_by_data_ref( p_data_ref = i_data ) .
APPEND VALUE #( level = level name = i_comp-name type = other_type->type_kind length = other_type->length decimals = other_type->decimals absolute_type = other_type->absolute_name parent = i_parent ) TO hierarchy.
ENDIF.
ENDTRY.
ENDTRY.
ENDMETHOD. "#EC CI_VALPAR
METHOD create_types.
DATA: components TYPE string.
LOOP AT hierarchy ASSIGNING FIELD-SYMBOL(<h>).
IF <h>-structure EQ abap_true AND <h>-type NE 'g'.
<h>-final_type = |{ <h>-name } type t_{ <h>-name }{ <h>-id }| ##NO_TEXT.
<h>-type_definition = |types: begin of t_{ <h>-name }{ <h>-id },{ cl_abap_char_utilities=>newline }{ c_components }end of t_{ <h>-name }{ <h>-id }.| ##NO_TEXT.
ELSEIF <h>-structure EQ abap_true.
<h>-final_type = |{ <h>-name } type t_{ <h>-name }{ <h>-id }| ##NO_TEXT.
get_internal_types( CHANGING c_type = <h> ).
<h>-type_definition = |types: t_{ <h>-name }{ <h>-id } type { <h>-absolute_type }.| ##NO_TEXT.
ELSEIF <h>-table EQ abap_true.
<h>-final_type = |{ <h>-name } type tt_{ <h>-name }{ <h>-id }| ##NO_TEXT.
<h>-type_definition = |types: tt_{ <h>-name }{ <h>-id } type standard table of t_{ <h>-name }{ <h>-id } with default key.| ##NO_TEXT.
ELSE.
get_internal_types( CHANGING c_type = <h> ).
ENDIF.
ENDLOOP.
LOOP AT hierarchy ASSIGNING <h> GROUP BY ( parent = <h>-parent ).
CLEAR components.
LOOP AT GROUP <h> ASSIGNING FIELD-SYMBOL(<g>).
components = components && <g>-final_type && ',' && cl_abap_char_utilities=>newline.
ENDLOOP.
ASSIGN hierarchy[ absolute_type = <h>-parent ] TO FIELD-SYMBOL(<parent>).
IF sy-subrc EQ 0.
REPLACE ALL OCCURRENCES OF c_components IN <parent>-type_definition WITH components.
ENDIF.
ENDLOOP.
SORT hierarchy BY level DESCENDING structure DESCENDING.
LOOP AT hierarchy ASSIGNING <h> WHERE structure EQ abap_true
OR table EQ abap_true.
r_definition = r_definition && <h>-type_definition && cl_abap_char_utilities=>newline.
ENDLOOP.
ENDMETHOD.
METHOD get_types.
r_types = create_types( ).
ENDMETHOD.
METHOD get_internal_types.
REPLACE FIRST OCCURRENCE OF REGEX '\\TYPE-POOL=(.*)\\TYPE=' IN c_type-absolute_type WITH ''.
IF sy-subrc EQ 0.
c_type-final_type = |{ c_type-name } type { c_type-absolute_type }|.
RETURN.
ELSE.
REPLACE FIRST OCCURRENCE OF '\TYPE=' IN c_type-absolute_type WITH ' '.
ENDIF.
IF c_type-type EQ cl_abap_typedescr=>typekind_char.
c_type-final_type = |{ c_type-name } type { c_type-absolute_type } length { c_type-length }|.
ELSEIF c_type-type EQ cl_abap_typedescr=>typekind_packed.
c_type-final_type = |{ c_type-name } type { c_type-type } length { c_type-length } decimals { c_type-decimals }|.
ELSEIF c_type-type EQ cl_abap_typedescr=>typekind_num.
c_type-final_type = |{ c_type-name } type { c_type-absolute_type } length { c_type-length }|.
ELSE.
c_type-final_type = |{ c_type-name } type { c_type-absolute_type }|.
ENDIF.
ENDMETHOD. "#EC CI_VALPAR
ENDCLASS.