mirror of
https://github.com/CarmJos/EasyConfiguration.git
synced 2026-06-04 18:48:20 +08:00
Compare commits
130 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0bfd15aaad | |||
| 15f395a8e0 | |||
| a61040a0e2 | |||
| 8766b4d77b | |||
| 8c1214612a | |||
| 608d92f834 | |||
| ad6ab9eb36 | |||
| 0eda8d8a0f | |||
| b19691b5a4 | |||
| c7331aa556 | |||
| a440c050e5 | |||
| b9d45a9bb9 | |||
| 67482de7a9 | |||
| 04bedbef07 | |||
| a4abfb733a | |||
| 76d276436b | |||
| e7198f22d5 | |||
| 5bd20e173f | |||
| 15c4bb13e8 | |||
| b74eb5c035 | |||
| ed3a68af1e | |||
| 447b82c880 | |||
| 5700f8c1c6 | |||
| 1cf230d6b6 | |||
| 1ffd4b2f0b | |||
| 92ce780d6f | |||
| a2de3303e8 | |||
| 47a1981002 | |||
| b97bc5d1a9 | |||
| cc927fdc0e | |||
| 5dc2693106 | |||
| 472ce66ca7 | |||
| 796771554f | |||
| 28cb5d4c83 | |||
| a670aec986 | |||
| 51c54b9b53 | |||
| fa99385ff0 | |||
| 70a3b893a6 | |||
| c32a941906 | |||
| 8b597d10f9 | |||
| cedfcfd262 | |||
| 12add75232 | |||
| 4d29a24768 | |||
| 8626b86961 | |||
| 754dc1de1f | |||
| 3d1d4ca609 | |||
| 990b10b6f0 | |||
| 7462cd720e | |||
| 6bc83eb3b3 | |||
| dbec551c84 | |||
| 82cca5eca2 | |||
| 65f3cc1b3d | |||
| fae048dd69 | |||
| 854e3df49f | |||
| f6167c3b5e | |||
| ffe3e88b3b | |||
| caa3077f48 | |||
| 05dbf0b504 | |||
| 810e95198e | |||
| 10004f16b4 | |||
| 8e19748c7c | |||
| 17762a2e70 | |||
| 7dbd607a3f | |||
| 035e8a227e | |||
| 04eaf6606d | |||
| e558e93410 | |||
| e55fe3a8d5 | |||
| 8f075b99b5 | |||
| 09a0b3c373 | |||
| 4df4977733 | |||
| 6434feb980 | |||
| bc3e4b3e6f | |||
| c2a9e2254c | |||
| 251dd208af | |||
| afd1bbfc0f | |||
| a699f6c164 | |||
| 844cbfab53 | |||
| f74d5d29f9 | |||
| 6f28abebb9 | |||
| 842cd78ce3 | |||
| 11f1f36a15 | |||
| ee9f29ba30 | |||
| f5bccdaad5 | |||
| f5f70ff69b | |||
| 3e221740bc | |||
| 96d09be977 | |||
| 5d7c946db5 | |||
| 9e008ff4cd | |||
| df19da170b | |||
| 3473ef2247 | |||
| d543530305 | |||
| d81855697c | |||
| 5c16e98f30 | |||
| 3f1ffadeff | |||
| d8191b7c6d | |||
| ba66220f92 | |||
| 730d6d7e9c | |||
| 4523190cb0 | |||
| 2a49e2ee6b | |||
| 77b223b2cb | |||
| 8e7ac263e7 | |||
| 80f03ec501 | |||
| 1c002ae535 | |||
| a4659c5c9f | |||
| 1c27c2f881 | |||
| 476cb79e2f | |||
| bf716b06ae | |||
| 00170e6d77 | |||
| 1bac201427 | |||
| cd77639df5 | |||
| 5ae756929a | |||
| a9e80aecce | |||
| 477f0d11bc | |||
| 53ff38a76f | |||
| c32bea3864 | |||
| 15823bb076 | |||
| f303f56199 | |||
| 22f2674e7c | |||
| 9eb9c9e13d | |||
| 616314c7f0 | |||
| 05f504a347 | |||
| bf6ea97b99 | |||
| 9847399e56 | |||
| 18515d4a78 | |||
| 9f1fc5bf90 | |||
| e7847b2166 | |||
| 69cec281be | |||
| 28dc9b9e55 | |||
| c60ba074d9 | |||
| e88bf301cc |
@@ -1,9 +1,6 @@
|
|||||||
# EasyConfiguration Javadoc
|
# configured Javadoc
|
||||||
|
|
||||||
基于 [Github Pages](https://pages.github.com/) 搭建,请访问 [JavaDoc](https://carmjos.github.io/EasyConfiguration) 。
|
Based
|
||||||
|
on [Github Pages](https://pages.github.com/),
|
||||||
## 如何实现?
|
please
|
||||||
|
see [JavaDoc](https://carmjos.github.io/configured) 。
|
||||||
若您也想通过 [Github Actions](https://docs.github.com/en/actions/learn-github-actions)
|
|
||||||
自动部署项目的Javadoc到 [Github Pages](https://pages.github.com/) ,
|
|
||||||
可以参考我的文章 [《自动部署Javadoc到Github Pages》](https://pages.carm.cc/doc/javadoc-in-github.html) 。
|
|
||||||
|
|||||||
+1
-16
@@ -1,16 +1 @@
|
|||||||
# 欢迎使用 EasyConfiguration !
|
# Documentation
|
||||||
|
|
||||||
这个项目刚刚创建,详细的Javadoc与开发指南还在补充,请给我一点时间~
|
|
||||||
|
|
||||||
|
|
||||||
## 基本定义
|
|
||||||
|
|
||||||
Value: 实际配置的单例值。
|
|
||||||
|
|
||||||
Manifest: 用于描述值基本配置的对象。
|
|
||||||
|
|
||||||
Provider: 用于提供配置文件的接口。
|
|
||||||
|
|
||||||
Wrapper: 用于包装配置文件的接口。
|
|
||||||
|
|
||||||
Initializer: 用于初始化的接口
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 112 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 23 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 21 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 99 KiB |
+346
@@ -0,0 +1,346 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
indent_style = space
|
||||||
|
tab_width = 4
|
||||||
|
|
||||||
|
[*.java]
|
||||||
|
indent_size = 4
|
||||||
|
max_line_length = 120
|
||||||
|
ij_java_align_consecutive_assignments = false
|
||||||
|
ij_java_align_consecutive_variable_declarations = false
|
||||||
|
ij_java_align_group_field_declarations = false
|
||||||
|
ij_java_align_multiline_annotation_parameters = false
|
||||||
|
ij_java_align_multiline_array_initializer_expression = false
|
||||||
|
ij_java_align_multiline_assignment = false
|
||||||
|
ij_java_align_multiline_binary_operation = false
|
||||||
|
ij_java_align_multiline_chained_methods = false
|
||||||
|
ij_java_align_multiline_deconstruction_list_components = true
|
||||||
|
ij_java_align_multiline_extends_list = false
|
||||||
|
ij_java_align_multiline_for = true
|
||||||
|
ij_java_align_multiline_method_parentheses = false
|
||||||
|
ij_java_align_multiline_parameters = true
|
||||||
|
ij_java_align_multiline_parameters_in_calls = false
|
||||||
|
ij_java_align_multiline_parenthesized_expression = false
|
||||||
|
ij_java_align_multiline_records = true
|
||||||
|
ij_java_align_multiline_resources = true
|
||||||
|
ij_java_align_multiline_ternary_operation = false
|
||||||
|
ij_java_align_multiline_text_blocks = false
|
||||||
|
ij_java_align_multiline_throws_list = false
|
||||||
|
ij_java_align_subsequent_simple_methods = false
|
||||||
|
ij_java_align_throws_keyword = false
|
||||||
|
ij_java_align_types_in_multi_catch = true
|
||||||
|
ij_java_annotation_new_line_in_record_component = false
|
||||||
|
ij_java_annotation_parameter_wrap = off
|
||||||
|
ij_java_array_initializer_new_line_after_left_brace = false
|
||||||
|
ij_java_array_initializer_right_brace_on_new_line = false
|
||||||
|
ij_java_array_initializer_wrap = off
|
||||||
|
ij_java_assert_statement_colon_on_next_line = false
|
||||||
|
ij_java_assert_statement_wrap = off
|
||||||
|
ij_java_assignment_wrap = off
|
||||||
|
ij_java_binary_operation_sign_on_next_line = false
|
||||||
|
ij_java_binary_operation_wrap = off
|
||||||
|
ij_java_blank_lines_after_anonymous_class_header = 0
|
||||||
|
ij_java_blank_lines_after_class_header = 0
|
||||||
|
ij_java_blank_lines_after_imports = 1
|
||||||
|
ij_java_blank_lines_after_package = 1
|
||||||
|
ij_java_blank_lines_around_class = 1
|
||||||
|
ij_java_blank_lines_around_field = 0
|
||||||
|
ij_java_blank_lines_around_field_in_interface = 0
|
||||||
|
ij_java_blank_lines_around_field_with_annotations = 0
|
||||||
|
ij_java_blank_lines_around_initializer = 1
|
||||||
|
ij_java_blank_lines_around_method = 1
|
||||||
|
ij_java_blank_lines_around_method_in_interface = 1
|
||||||
|
ij_java_blank_lines_before_class_end = 0
|
||||||
|
ij_java_blank_lines_before_imports = 1
|
||||||
|
ij_java_blank_lines_before_method_body = 0
|
||||||
|
ij_java_blank_lines_before_package = 0
|
||||||
|
ij_java_blank_lines_between_record_components = 0
|
||||||
|
ij_java_block_brace_style = end_of_line
|
||||||
|
ij_java_block_comment_add_space = false
|
||||||
|
ij_java_block_comment_at_first_column = true
|
||||||
|
ij_java_builder_methods =
|
||||||
|
ij_java_call_parameters_new_line_after_left_paren = false
|
||||||
|
ij_java_call_parameters_right_paren_on_new_line = false
|
||||||
|
ij_java_call_parameters_wrap = off
|
||||||
|
ij_java_case_statement_on_separate_line = true
|
||||||
|
ij_java_catch_on_new_line = false
|
||||||
|
ij_java_class_annotation_wrap = split_into_lines
|
||||||
|
ij_java_class_brace_style = end_of_line
|
||||||
|
ij_java_class_count_to_use_import_on_demand = 5
|
||||||
|
ij_java_class_names_in_javadoc = 1
|
||||||
|
ij_java_deconstruction_list_wrap = normal
|
||||||
|
ij_java_do_not_indent_top_level_class_members = false
|
||||||
|
ij_java_do_not_wrap_after_single_annotation = false
|
||||||
|
ij_java_do_not_wrap_after_single_annotation_in_parameter = false
|
||||||
|
ij_java_do_while_brace_force = never
|
||||||
|
ij_java_doc_add_blank_line_after_description = true
|
||||||
|
ij_java_doc_add_blank_line_after_param_comments = false
|
||||||
|
ij_java_doc_add_blank_line_after_return = false
|
||||||
|
ij_java_doc_add_p_tag_on_empty_lines = true
|
||||||
|
ij_java_doc_align_exception_comments = true
|
||||||
|
ij_java_doc_align_param_comments = true
|
||||||
|
ij_java_doc_do_not_wrap_if_one_line = false
|
||||||
|
ij_java_doc_enable_formatting = true
|
||||||
|
ij_java_doc_enable_leading_asterisks = true
|
||||||
|
ij_java_doc_indent_on_continuation = false
|
||||||
|
ij_java_doc_keep_empty_lines = true
|
||||||
|
ij_java_doc_keep_empty_parameter_tag = true
|
||||||
|
ij_java_doc_keep_empty_return_tag = true
|
||||||
|
ij_java_doc_keep_empty_throws_tag = true
|
||||||
|
ij_java_doc_keep_invalid_tags = true
|
||||||
|
ij_java_doc_param_description_on_new_line = false
|
||||||
|
ij_java_doc_preserve_line_breaks = false
|
||||||
|
ij_java_doc_use_throws_not_exception_tag = true
|
||||||
|
ij_java_else_on_new_line = false
|
||||||
|
ij_java_entity_dd_prefix =
|
||||||
|
ij_java_entity_dd_suffix = EJB
|
||||||
|
ij_java_entity_eb_prefix =
|
||||||
|
ij_java_entity_eb_suffix = Bean
|
||||||
|
ij_java_entity_hi_prefix =
|
||||||
|
ij_java_entity_hi_suffix = Home
|
||||||
|
ij_java_entity_lhi_prefix = Local
|
||||||
|
ij_java_entity_lhi_suffix = Home
|
||||||
|
ij_java_entity_li_prefix = Local
|
||||||
|
ij_java_entity_li_suffix =
|
||||||
|
ij_java_entity_pk_class = java.lang.String
|
||||||
|
ij_java_entity_ri_prefix =
|
||||||
|
ij_java_entity_ri_suffix =
|
||||||
|
ij_java_entity_vo_prefix =
|
||||||
|
ij_java_entity_vo_suffix = VO
|
||||||
|
ij_java_enum_constants_wrap = off
|
||||||
|
ij_java_enum_field_annotation_wrap = off
|
||||||
|
ij_java_extends_keyword_wrap = off
|
||||||
|
ij_java_extends_list_wrap = off
|
||||||
|
ij_java_field_annotation_wrap = split_into_lines
|
||||||
|
ij_java_field_name_prefix =
|
||||||
|
ij_java_field_name_suffix =
|
||||||
|
ij_java_filter_class_prefix =
|
||||||
|
ij_java_filter_class_suffix =
|
||||||
|
ij_java_filter_dd_prefix =
|
||||||
|
ij_java_filter_dd_suffix =
|
||||||
|
ij_java_finally_on_new_line = false
|
||||||
|
ij_java_for_brace_force = never
|
||||||
|
ij_java_for_statement_new_line_after_left_paren = false
|
||||||
|
ij_java_for_statement_right_paren_on_new_line = false
|
||||||
|
ij_java_for_statement_wrap = off
|
||||||
|
ij_java_generate_final_locals = false
|
||||||
|
ij_java_generate_final_parameters = false
|
||||||
|
ij_java_generate_use_type_annotation_before_type = true
|
||||||
|
ij_java_if_brace_force = never
|
||||||
|
ij_java_imports_layout = @*, *, |, javax.**, java.**, |, $*
|
||||||
|
ij_java_indent_case_from_switch = true
|
||||||
|
ij_java_insert_inner_class_imports = false
|
||||||
|
ij_java_insert_override_annotation = true
|
||||||
|
ij_java_keep_blank_lines_before_right_brace = 2
|
||||||
|
ij_java_keep_blank_lines_between_package_declaration_and_header = 2
|
||||||
|
ij_java_keep_blank_lines_in_code = 2
|
||||||
|
ij_java_keep_blank_lines_in_declarations = 2
|
||||||
|
ij_java_keep_builder_methods_indents = false
|
||||||
|
ij_java_keep_control_statement_in_one_line = true
|
||||||
|
ij_java_keep_first_column_comment = true
|
||||||
|
ij_java_keep_indents_on_empty_lines = false
|
||||||
|
ij_java_keep_line_breaks = true
|
||||||
|
ij_java_keep_multiple_expressions_in_one_line = false
|
||||||
|
ij_java_keep_simple_blocks_in_one_line = false
|
||||||
|
ij_java_keep_simple_classes_in_one_line = false
|
||||||
|
ij_java_keep_simple_lambdas_in_one_line = false
|
||||||
|
ij_java_keep_simple_methods_in_one_line = false
|
||||||
|
ij_java_label_indent_absolute = false
|
||||||
|
ij_java_label_indent_size = 0
|
||||||
|
ij_java_lambda_brace_style = end_of_line
|
||||||
|
ij_java_layout_on_demand_import_from_same_package_first = true
|
||||||
|
ij_java_layout_static_imports_separately = true
|
||||||
|
ij_java_line_comment_add_space = false
|
||||||
|
ij_java_line_comment_add_space_on_reformat = false
|
||||||
|
ij_java_line_comment_at_first_column = true
|
||||||
|
ij_java_listener_class_prefix =
|
||||||
|
ij_java_listener_class_suffix =
|
||||||
|
ij_java_local_variable_name_prefix =
|
||||||
|
ij_java_local_variable_name_suffix =
|
||||||
|
ij_java_message_dd_prefix =
|
||||||
|
ij_java_message_dd_suffix = EJB
|
||||||
|
ij_java_message_eb_prefix =
|
||||||
|
ij_java_message_eb_suffix = Bean
|
||||||
|
ij_java_method_annotation_wrap = split_into_lines
|
||||||
|
ij_java_method_brace_style = end_of_line
|
||||||
|
ij_java_method_call_chain_wrap = off
|
||||||
|
ij_java_method_parameters_new_line_after_left_paren = false
|
||||||
|
ij_java_method_parameters_right_paren_on_new_line = false
|
||||||
|
ij_java_method_parameters_wrap = off
|
||||||
|
ij_java_modifier_list_wrap = false
|
||||||
|
ij_java_multi_catch_types_wrap = normal
|
||||||
|
ij_java_names_count_to_use_import_on_demand = 3
|
||||||
|
ij_java_new_line_after_lparen_in_annotation = false
|
||||||
|
ij_java_new_line_after_lparen_in_deconstruction_pattern = true
|
||||||
|
ij_java_new_line_after_lparen_in_record_header = false
|
||||||
|
ij_java_new_line_when_body_is_presented = false
|
||||||
|
ij_java_packages_to_use_import_on_demand = java.awt.*, javax.swing.*
|
||||||
|
ij_java_parameter_annotation_wrap = off
|
||||||
|
ij_java_parameter_name_prefix =
|
||||||
|
ij_java_parameter_name_suffix =
|
||||||
|
ij_java_parentheses_expression_new_line_after_left_paren = false
|
||||||
|
ij_java_parentheses_expression_right_paren_on_new_line = false
|
||||||
|
ij_java_place_assignment_sign_on_next_line = false
|
||||||
|
ij_java_prefer_longer_names = true
|
||||||
|
ij_java_prefer_parameters_wrap = false
|
||||||
|
ij_java_preserve_module_imports = true
|
||||||
|
ij_java_record_components_wrap = normal
|
||||||
|
ij_java_repeat_annotations =
|
||||||
|
ij_java_repeat_synchronized = true
|
||||||
|
ij_java_replace_instanceof_and_cast = false
|
||||||
|
ij_java_replace_null_check = true
|
||||||
|
ij_java_replace_sum_lambda_with_method_ref = true
|
||||||
|
ij_java_resource_list_new_line_after_left_paren = false
|
||||||
|
ij_java_resource_list_right_paren_on_new_line = false
|
||||||
|
ij_java_resource_list_wrap = off
|
||||||
|
ij_java_rparen_on_new_line_in_annotation = false
|
||||||
|
ij_java_rparen_on_new_line_in_deconstruction_pattern = true
|
||||||
|
ij_java_rparen_on_new_line_in_record_header = false
|
||||||
|
ij_java_servlet_class_prefix =
|
||||||
|
ij_java_servlet_class_suffix =
|
||||||
|
ij_java_servlet_dd_prefix =
|
||||||
|
ij_java_servlet_dd_suffix =
|
||||||
|
ij_java_session_dd_prefix =
|
||||||
|
ij_java_session_dd_suffix = EJB
|
||||||
|
ij_java_session_eb_prefix =
|
||||||
|
ij_java_session_eb_suffix = Bean
|
||||||
|
ij_java_session_hi_prefix =
|
||||||
|
ij_java_session_hi_suffix = Home
|
||||||
|
ij_java_session_lhi_prefix = Local
|
||||||
|
ij_java_session_lhi_suffix = Home
|
||||||
|
ij_java_session_li_prefix = Local
|
||||||
|
ij_java_session_li_suffix =
|
||||||
|
ij_java_session_ri_prefix =
|
||||||
|
ij_java_session_ri_suffix =
|
||||||
|
ij_java_session_si_prefix =
|
||||||
|
ij_java_session_si_suffix = Service
|
||||||
|
ij_java_space_after_closing_angle_bracket_in_type_argument = false
|
||||||
|
ij_java_space_after_colon = true
|
||||||
|
ij_java_space_after_comma = true
|
||||||
|
ij_java_space_after_comma_in_type_arguments = true
|
||||||
|
ij_java_space_after_for_semicolon = true
|
||||||
|
ij_java_space_after_quest = true
|
||||||
|
ij_java_space_after_type_cast = true
|
||||||
|
ij_java_space_before_annotation_array_initializer_left_brace = false
|
||||||
|
ij_java_space_before_annotation_parameter_list = false
|
||||||
|
ij_java_space_before_array_initializer_left_brace = false
|
||||||
|
ij_java_space_before_catch_keyword = true
|
||||||
|
ij_java_space_before_catch_left_brace = true
|
||||||
|
ij_java_space_before_catch_parentheses = true
|
||||||
|
ij_java_space_before_class_left_brace = true
|
||||||
|
ij_java_space_before_colon = true
|
||||||
|
ij_java_space_before_colon_in_foreach = true
|
||||||
|
ij_java_space_before_comma = false
|
||||||
|
ij_java_space_before_deconstruction_list = false
|
||||||
|
ij_java_space_before_do_left_brace = true
|
||||||
|
ij_java_space_before_else_keyword = true
|
||||||
|
ij_java_space_before_else_left_brace = true
|
||||||
|
ij_java_space_before_finally_keyword = true
|
||||||
|
ij_java_space_before_finally_left_brace = true
|
||||||
|
ij_java_space_before_for_left_brace = true
|
||||||
|
ij_java_space_before_for_parentheses = true
|
||||||
|
ij_java_space_before_for_semicolon = false
|
||||||
|
ij_java_space_before_if_left_brace = true
|
||||||
|
ij_java_space_before_if_parentheses = true
|
||||||
|
ij_java_space_before_method_call_parentheses = false
|
||||||
|
ij_java_space_before_method_left_brace = true
|
||||||
|
ij_java_space_before_method_parentheses = false
|
||||||
|
ij_java_space_before_opening_angle_bracket_in_type_parameter = false
|
||||||
|
ij_java_space_before_quest = true
|
||||||
|
ij_java_space_before_switch_left_brace = true
|
||||||
|
ij_java_space_before_switch_parentheses = true
|
||||||
|
ij_java_space_before_synchronized_left_brace = true
|
||||||
|
ij_java_space_before_synchronized_parentheses = true
|
||||||
|
ij_java_space_before_try_left_brace = true
|
||||||
|
ij_java_space_before_try_parentheses = true
|
||||||
|
ij_java_space_before_type_parameter_list = false
|
||||||
|
ij_java_space_before_while_keyword = true
|
||||||
|
ij_java_space_before_while_left_brace = true
|
||||||
|
ij_java_space_before_while_parentheses = true
|
||||||
|
ij_java_space_inside_one_line_enum_braces = false
|
||||||
|
ij_java_space_within_empty_array_initializer_braces = false
|
||||||
|
ij_java_space_within_empty_method_call_parentheses = false
|
||||||
|
ij_java_space_within_empty_method_parentheses = false
|
||||||
|
ij_java_spaces_around_additive_operators = true
|
||||||
|
ij_java_spaces_around_annotation_eq = true
|
||||||
|
ij_java_spaces_around_assignment_operators = true
|
||||||
|
ij_java_spaces_around_bitwise_operators = true
|
||||||
|
ij_java_spaces_around_equality_operators = true
|
||||||
|
ij_java_spaces_around_lambda_arrow = true
|
||||||
|
ij_java_spaces_around_logical_operators = true
|
||||||
|
ij_java_spaces_around_method_ref_dbl_colon = false
|
||||||
|
ij_java_spaces_around_multiplicative_operators = true
|
||||||
|
ij_java_spaces_around_relational_operators = true
|
||||||
|
ij_java_spaces_around_shift_operators = true
|
||||||
|
ij_java_spaces_around_type_bounds_in_type_parameters = true
|
||||||
|
ij_java_spaces_around_unary_operator = false
|
||||||
|
ij_java_spaces_inside_block_braces_when_body_is_present = false
|
||||||
|
ij_java_spaces_within_angle_brackets = false
|
||||||
|
ij_java_spaces_within_annotation_parentheses = false
|
||||||
|
ij_java_spaces_within_array_initializer_braces = false
|
||||||
|
ij_java_spaces_within_braces = false
|
||||||
|
ij_java_spaces_within_brackets = false
|
||||||
|
ij_java_spaces_within_cast_parentheses = false
|
||||||
|
ij_java_spaces_within_catch_parentheses = false
|
||||||
|
ij_java_spaces_within_deconstruction_list = false
|
||||||
|
ij_java_spaces_within_for_parentheses = false
|
||||||
|
ij_java_spaces_within_if_parentheses = false
|
||||||
|
ij_java_spaces_within_method_call_parentheses = false
|
||||||
|
ij_java_spaces_within_method_parentheses = false
|
||||||
|
ij_java_spaces_within_parentheses = false
|
||||||
|
ij_java_spaces_within_record_header = false
|
||||||
|
ij_java_spaces_within_switch_parentheses = false
|
||||||
|
ij_java_spaces_within_synchronized_parentheses = false
|
||||||
|
ij_java_spaces_within_try_parentheses = false
|
||||||
|
ij_java_spaces_within_while_parentheses = false
|
||||||
|
ij_java_special_else_if_treatment = true
|
||||||
|
ij_java_static_field_name_prefix =
|
||||||
|
ij_java_static_field_name_suffix =
|
||||||
|
ij_java_subclass_name_prefix =
|
||||||
|
ij_java_subclass_name_suffix = Impl
|
||||||
|
ij_java_switch_expressions_wrap = normal
|
||||||
|
ij_java_ternary_operation_signs_on_next_line = false
|
||||||
|
ij_java_ternary_operation_wrap = off
|
||||||
|
ij_java_test_name_prefix =
|
||||||
|
ij_java_test_name_suffix = Test
|
||||||
|
ij_java_throws_keyword_wrap = off
|
||||||
|
ij_java_throws_list_wrap = off
|
||||||
|
ij_java_use_external_annotations = false
|
||||||
|
ij_java_use_fq_class_names = false
|
||||||
|
ij_java_use_relative_indents = false
|
||||||
|
ij_java_use_single_class_imports = true
|
||||||
|
ij_java_variable_annotation_wrap = off
|
||||||
|
ij_java_visibility = public
|
||||||
|
ij_java_while_brace_force = never
|
||||||
|
ij_java_while_on_new_line = false
|
||||||
|
ij_java_wrap_comments = false
|
||||||
|
ij_java_wrap_first_method_in_call_chain = false
|
||||||
|
ij_java_wrap_long_lines = false
|
||||||
|
ij_java_wrap_semicolon_after_call_chain = false
|
||||||
|
|
||||||
|
[*.xml]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
tab_width = 4
|
||||||
|
max_line_length = 120
|
||||||
|
|
||||||
|
[*.json]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
tab_width = 2
|
||||||
|
max_line_length = 120
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
tab_width = 2
|
||||||
|
max_line_length = 120
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = 500
|
||||||
|
trim_trailing_whitespace = false
|
||||||
@@ -1,37 +1,70 @@
|
|||||||
---
|
---
|
||||||
name: 问题提交
|
name:
|
||||||
about: 描述问题并提交,帮助我们对其进行检查与修复。
|
问题提交
|
||||||
|
about:
|
||||||
|
描述问题并提交,帮助我们对其进行检查与修复。
|
||||||
title: ''
|
title: ''
|
||||||
labels: bug
|
labels:
|
||||||
|
bug
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### **问题简述**
|
###
|
||||||
|
*
|
||||||
|
*问题简述
|
||||||
|
**
|
||||||
|
|
||||||
用简短的话语描述一下大概问题。
|
用简短的话语描述一下大概问题。
|
||||||
|
|
||||||
### **问题来源**
|
###
|
||||||
|
*
|
||||||
|
*问题来源
|
||||||
|
**
|
||||||
|
|
||||||
描述一下通过哪些操作才发现的问题,如:
|
描述一下通过哪些操作才发现的问题,如:
|
||||||
|
|
||||||
1. 使用了 '...'
|
1.
|
||||||
2. 输入了 '....'
|
使用了 '...'
|
||||||
3. 出现了报错 '....'
|
2.
|
||||||
|
输入了 '....'
|
||||||
|
3.
|
||||||
|
出现了报错 '....'
|
||||||
|
|
||||||
### **预期结果** (可选)
|
###
|
||||||
|
*
|
||||||
|
*预期结果
|
||||||
|
** (可选)
|
||||||
|
|
||||||
如果问题不发生,应该是什么情况
|
如果问题不发生,应该是什么情况
|
||||||
|
|
||||||
### **问题截图/问题报错**
|
###
|
||||||
|
*
|
||||||
|
*问题截图/问题报错
|
||||||
|
**
|
||||||
|
|
||||||
如果有报错或输出,请提供截图。
|
如果有报错或输出,请提供截图。
|
||||||
|
|
||||||
### **操作环境**
|
###
|
||||||
|
*
|
||||||
|
*操作环境
|
||||||
|
**
|
||||||
|
|
||||||
- 系统环境: `Windows 10` / `Ubuntu` / `...`
|
-
|
||||||
- Java版本: `JDK11` / `OPENJDK8` / `JRE8` / `...`
|
系统环境:
|
||||||
|
`Windows 10` /
|
||||||
|
`Ubuntu` /
|
||||||
|
`...`
|
||||||
|
-
|
||||||
|
Java版本:
|
||||||
|
`JDK11` /
|
||||||
|
`OPENJDK8` /
|
||||||
|
`JRE8` /
|
||||||
|
`...`
|
||||||
|
|
||||||
### **其他补充**
|
###
|
||||||
|
*
|
||||||
|
*其他补充
|
||||||
|
**
|
||||||
|
|
||||||
如有其他补充,可以在这里描述。
|
如有其他补充,可以在这里描述。
|
||||||
|
|||||||
@@ -1,23 +1,38 @@
|
|||||||
---
|
---
|
||||||
name: 功能需求
|
name:
|
||||||
about: 希望我们提供更多的功能。
|
功能需求
|
||||||
|
about:
|
||||||
|
希望我们提供更多的功能。
|
||||||
title: ''
|
title: ''
|
||||||
labels: enhancement
|
labels:
|
||||||
|
enhancement
|
||||||
assignees: ''
|
assignees: ''
|
||||||
---
|
---
|
||||||
|
|
||||||
### **功能简述**
|
###
|
||||||
|
*
|
||||||
|
*功能简述
|
||||||
|
**
|
||||||
|
|
||||||
简单的描述一下你想要的功能
|
简单的描述一下你想要的功能
|
||||||
|
|
||||||
### **需求来源**
|
###
|
||||||
|
*
|
||||||
|
*需求来源
|
||||||
|
**
|
||||||
|
|
||||||
简单的描述一下为什么需要这个功能。
|
简单的描述一下为什么需要这个功能。
|
||||||
|
|
||||||
### **功能参考**(可选)
|
###
|
||||||
|
*
|
||||||
|
*功能参考
|
||||||
|
**(可选)
|
||||||
|
|
||||||
如果有相关功能的参考,如文本、截图,请提供给我们。
|
如果有相关功能的参考,如文本、截图,请提供给我们。
|
||||||
|
|
||||||
### **附加内容**
|
###
|
||||||
|
*
|
||||||
|
*附加内容
|
||||||
|
**
|
||||||
|
|
||||||
如果有什么小细节需要重点注意,请在这里告诉我们。
|
如果有什么小细节需要重点注意,请在这里告诉我们。
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
# This workflow uses actions that are not certified by GitHub.
|
|
||||||
# They are provided by a third-party and are governed by
|
|
||||||
# separate terms of service, privacy policy, and support
|
|
||||||
# documentation.
|
|
||||||
|
|
||||||
# This workflow checks out code, performs a Codacy security scan
|
|
||||||
# and integrates the results with the
|
|
||||||
# GitHub Advanced Security code scanning feature. For more information on
|
|
||||||
# the Codacy security scan action usage and parameters, see
|
|
||||||
# https://github.com/codacy/codacy-analysis-cli-action.
|
|
||||||
# For more information on Codacy Analysis CLI in general, see
|
|
||||||
# https://github.com/codacy/codacy-analysis-cli.
|
|
||||||
|
|
||||||
name: "Codacy Security Scan"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
# The branches below must be a subset of the branches above
|
|
||||||
branches: [ master ]
|
|
||||||
schedule:
|
|
||||||
- cron: '27 16 * * 5'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
codacy-security-scan:
|
|
||||||
name: Codacy Security Scan
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
# Checkout the repository to the GitHub Actions runner
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
|
|
||||||
- name: Run Codacy Analysis CLI
|
|
||||||
uses: codacy/codacy-analysis-cli-action@09916000460adeeedc96b9704f86deba53e2ad5d
|
|
||||||
with:
|
|
||||||
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
|
|
||||||
# You can also omit the token and run the tools that support default configurations
|
|
||||||
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
|
|
||||||
verbose: true
|
|
||||||
output: results.sarif
|
|
||||||
format: sarif
|
|
||||||
# Adjust severity of non-security issues
|
|
||||||
gh-code-scanning-compat: true
|
|
||||||
# Force 0 exit code to allow SARIF file generation
|
|
||||||
# This will handover control about PR rejection to the GitHub side
|
|
||||||
max-allowed-issues: 2147483647
|
|
||||||
|
|
||||||
# Upload the SARIF file generated in the previous step
|
|
||||||
- name: Upload SARIF results file
|
|
||||||
uses: github/codeql-action/upload-sarif@v3
|
|
||||||
with:
|
|
||||||
sarif_file: results.sarif
|
|
||||||
@@ -20,7 +20,7 @@ jobs:
|
|||||||
- name: "Set up JDK"
|
- name: "Set up JDK"
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: '11'
|
java-version: '21'
|
||||||
distribution: 'adopt'
|
distribution: 'adopt'
|
||||||
cache: maven
|
cache: maven
|
||||||
server-id: github
|
server-id: github
|
||||||
@@ -40,14 +40,14 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
rm -rf docs
|
rm -rf docs
|
||||||
mkdir -vp docs
|
mkdir -vp docs
|
||||||
cp -vrf core/target/apidocs/* docs/
|
cp -vrf core/target/reports/apidocs/* docs/
|
||||||
cp -vrf .doc/JAVADOC-README.md docs/README.md
|
cp -vrf .doc/JAVADOC-README.md docs/README.md
|
||||||
|
|
||||||
- name: "Generate the Javadoc sitemap"
|
- name: "Generate the Javadoc sitemap"
|
||||||
id: sitemap
|
id: sitemap
|
||||||
uses: cicirello/generate-sitemap@v1
|
uses: cicirello/generate-sitemap@v1
|
||||||
with:
|
with:
|
||||||
base-url-path: https://CarmJos.github.io/EasyConfiguration
|
base-url-path: https://CarmJos.github.io/configured
|
||||||
path-to-root: docs
|
path-to-root: docs
|
||||||
|
|
||||||
- name: "Output stats"
|
- name: "Output stats"
|
||||||
@@ -72,7 +72,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd docs
|
cd docs
|
||||||
git init
|
git init
|
||||||
git remote add origin git@github.com:CarmJos/EasyConfiguration.git
|
git remote add origin git@github.com:CarmJos/configured.git
|
||||||
git checkout -b gh-pages
|
git checkout -b gh-pages
|
||||||
git add -A
|
git add -A
|
||||||
git commit -m "API Document generated."
|
git commit -m "API Document generated."
|
||||||
@@ -91,7 +91,7 @@ jobs:
|
|||||||
- name: "Set up JDK"
|
- name: "Set up JDK"
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: '11'
|
java-version: '21'
|
||||||
distribution: 'adopt'
|
distribution: 'adopt'
|
||||||
cache: maven
|
cache: maven
|
||||||
server-id: central
|
server-id: central
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ jobs:
|
|||||||
- name: "Set up JDK"
|
- name: "Set up JDK"
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: '11'
|
java-version: '21'
|
||||||
distribution: 'adopt'
|
distribution: 'adopt'
|
||||||
- name: "Package"
|
- name: "Package"
|
||||||
run: mvn -B package --file pom.xml -Dgpg.skip
|
run: mvn -B package --file pom.xml -Dgpg.skip
|
||||||
|
|||||||
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
/.idea/
|
.idea/*
|
||||||
|
!.idea/icon.svg
|
||||||
**/target/
|
**/target/
|
||||||
**.iml
|
**.iml
|
||||||
Generated
+36
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 23 KiB |
@@ -1,6 +1,7 @@
|
|||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
of this license document, but changing it is not allowed.
|
of this license document, but changing it is not allowed.
|
||||||
|
|||||||
@@ -1,31 +1,30 @@
|
|||||||
```text
|
<div align=center>
|
||||||
____ _____ ____ __ _
|
<img src=".doc/images/banner.png" alt="Banner"/>
|
||||||
/ __/__ ____ __ __ / ___/__ ___ / _(_)__ ___ _________ _/ /_(_)__ ___
|
|
||||||
/ _// _ `(_-</ // / / /__/ _ \/ _ \/ _/ / _ `/ // / __/ _ `/ __/ / _ \/ _ \
|
[](https://github.com/CarmJos/configured/releases)
|
||||||
/___/\_,_/___/\_, / \___/\___/_//_/_//_/\_, /\_,_/_/ \_,_/\__/_/\___/_//_/
|
[](https://www.gnu.org/licenses/lgpl-3.0.html)
|
||||||
/___/ /___/
|
[](https://github.com/CarmJos/configured/actions/workflows/maven.yml)
|
||||||
```
|
[](https://www.codefactor.io/repository/github/carmjos/configured)
|
||||||
|

|
||||||
|
|
||||||
README LANGUAGES [ [**English**](README.md) | [中文](README_CN.md) ]
|
README LANGUAGES [ [**English**](README.md) | [中文](README_CN.md) ]
|
||||||
|
</div>
|
||||||
|
|
||||||
# EasyConfiguration
|
# configured _(config framework)_
|
||||||
|
|
||||||
[](https://github.com/CarmJos/EasyConfiguration/releases)
|
<img src=".doc/images/logo-bg.svg" width="150px" alt="logo" align="right" style="float: right"/>
|
||||||
[](https://www.gnu.org/licenses/lgpl-3.0.html)
|
|
||||||
[](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml)
|
|
||||||
[](https://www.codefactor.io/repository/github/carmjos/easyconfiguration)
|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
**Easy _(to make)_ Configurations!**
|
_**"Once set, Simple get."**_
|
||||||
|
|
||||||
A simple, easy-to-use and universal solution for managing configuration files.
|
A simple, easy-to-use and universal solution for managing, loading, reading,
|
||||||
Enjoy the ease of use with customizable formats for loading, reading, and updating your configuration files.
|
and updating configuration files.
|
||||||
|
|
||||||
|
Supported **JSON**, **YAML**, **Hocon**, **TOML**, **SQL**, **MongoDB**... and much more!
|
||||||
|
|
||||||
## Features & Advantages
|
## Features & Advantages
|
||||||
|
|
||||||
Supported [YAML](impl/yaml), [JSON](impl/json), [HOCON](impl/hocon) and [SQL](impl/sql) based configuration files
|
Supported [YAML](providers/yaml), [JSON](providers/json), [HOCON](providers/hocon) and [SQL](providers/sql)
|
||||||
format.
|
based configuration files format.
|
||||||
|
|
||||||
- Class-based mechanism for initializing, loading, retrieving, and updating configuration files, ensuring convenience
|
- Class-based mechanism for initializing, loading, retrieving, and updating configuration files, ensuring convenience
|
||||||
and efficiency.
|
and efficiency.
|
||||||
@@ -35,55 +34,74 @@ format.
|
|||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
For the latest JavaDoc release, [CLICK HERE](https://CarmJos.github.io/EasyConfiguration).
|
For the latest JavaDoc release, [CLICK HERE](https://CarmJos.github.io/configured).
|
||||||
|
|
||||||
For a detailed development guide, [CLICK HERE](.doc/README.md).
|
For a detailed development guide, [CLICK HERE](.doc/README.md).
|
||||||
|
|
||||||
### Code Samples
|
### Preview
|
||||||
|
|
||||||
To quickly demonstrate the applicability of the project, here are a few practical demonstrations:
|
To quickly demonstrate the applicability of the project, here are a few practical demonstrations:
|
||||||
|
|
||||||
- [Database configuration.](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java)
|
- [Database configuration.](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java)
|
||||||
- [Demonstration of all types of configuration instance classes.](demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java)
|
- [Demonstration of configurations instance classes.](demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java)
|
||||||
|
|
||||||
Check out all code demonstrations [HERE](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java).
|
Check out all code demonstrations [HERE](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java).
|
||||||
For more examples, see the [Development Guide](.doc/README.md).
|
For more examples, see the [Development Guide](.doc/README.md).
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@HeaderComment("Configurations for sample")
|
|
||||||
interface SampleConfig extends Configuration {
|
@ConfigPath(root = true)
|
||||||
|
@HeaderComments("Configurations for sample")
|
||||||
|
public interface SampleConfig extends Configuration {
|
||||||
|
|
||||||
@InlineComment("Enabled?") // Inline comment
|
@InlineComment("Enabled?") // Inline comment
|
||||||
ConfiguredValue<Boolean> ENABLED = ConfiguredValue.of(true);
|
ConfiguredValue<Boolean> ENABLED = ConfiguredValue.of(true);
|
||||||
|
|
||||||
|
@HeaderComments("Server configurations") // Header comment
|
||||||
|
ConfiguredValue<Integer> PORT = ConfiguredValue.of(Integer.class);
|
||||||
|
|
||||||
|
@HeaderComments({"[ UUID >-----------------------------------", "A lot of UUIDs"})
|
||||||
|
@FooterComments("[ UUID >-----------------------------------")
|
||||||
ConfiguredList<UUID> UUIDS = ConfiguredList.builderOf(UUID.class).fromString()
|
ConfiguredList<UUID> UUIDS = ConfiguredList.builderOf(UUID.class).fromString()
|
||||||
.parseValue(UUID::fromString).serializeValue(UUID::toString)
|
.parse(UUID::fromString).serialize(UUID::toString)
|
||||||
.defaults(
|
.defaults(
|
||||||
UUID.fromString("00000000-0000-0000-0000-000000000000"),
|
UUID.fromString("00000000-0000-0000-0000-000000000000"),
|
||||||
UUID.fromString("00000000-0000-0000-0000-000000000001")
|
UUID.fromString("00000000-0000-0000-0000-000000000001")
|
||||||
).build();
|
).build();
|
||||||
|
|
||||||
|
@ConfigPath("info") // Custom path
|
||||||
interface INFO extends Configuration {
|
interface INFO extends Configuration {
|
||||||
|
|
||||||
@HeaderComment("Configure your name!") // Header comment
|
@HeaderComments("Configure your name!") // Header comment
|
||||||
ConfiguredValue<String> NAME = ConfiguredValue.of("Joker");
|
ConfiguredValue<String> NAME = ConfiguredValue.of("Joker");
|
||||||
|
|
||||||
@ConfigPath("year") // Custom path
|
@ConfigPath("how-old-are-you") // Custom path
|
||||||
ConfiguredValue<Integer> AGE = ConfiguredValue.of(24);
|
ConfiguredValue<Integer> AGE = ConfiguredValue.of(24);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class Sample {
|
public class Sample {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
// 1. Make a configuration provider from a file.
|
// 1. Make a configuration provider from a file.
|
||||||
ConfigurationProvider<?> provider = EasyConfiguration.from("config.yml");
|
ConfigurationHolder<?> holder = YAMLConfigFactory.from("target/config.yml")
|
||||||
|
.resourcePath("configs/sample.yml")
|
||||||
|
.indent(4) // Optional: Set the indentation of the configuration file.
|
||||||
|
.build();
|
||||||
|
|
||||||
// 2. Initialize the configuration classes or instances.
|
// 2. Initialize the configuration classes or instances.
|
||||||
provider.initialize(SampleConfig.class);
|
holder.initialize(SampleConfig.class);
|
||||||
// 3. Enjoy using the configuration!
|
// 3. Enjoy using the configuration!
|
||||||
|
System.out.println("Enabled? -> " + SampleConfig.ENABLED.resolve()); // true
|
||||||
SampleConfig.ENABLED.set(false);
|
SampleConfig.ENABLED.set(false);
|
||||||
System.out.println("Your name is " + SampleConfig.INFO.NAME.getNotNull() + " !");
|
System.out.println("And now? -> " + SampleConfig.ENABLED.resolve()); // false
|
||||||
|
// p.s. Changes not save so enable value will still be true in the next run.
|
||||||
|
|
||||||
|
System.out.println("Your name is " + SampleConfig.INFO.NAME.resolve() + " (age=" + SampleConfig.INFO.AGE.resolve() + ")!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,16 +110,22 @@ public class Sample {
|
|||||||
```yaml
|
```yaml
|
||||||
# Configurations for sample
|
# Configurations for sample
|
||||||
|
|
||||||
enabled: true # Enabled?
|
enabled: true #Enabled?
|
||||||
|
|
||||||
|
# Server configurations
|
||||||
|
port:
|
||||||
|
|
||||||
|
# [ UUID >-----------------------------------
|
||||||
|
# A lot of UUIDs
|
||||||
uuids:
|
uuids:
|
||||||
- 00000000-0000-0000-0000-000000000000
|
- 00000000-0000-0000-0000-000000000000
|
||||||
- 00000000-0000-0000-0000-000000000001
|
- 00000000-0000-0000-0000-000000000001
|
||||||
|
# [ UUID >-----------------------------------
|
||||||
|
|
||||||
info:
|
info:
|
||||||
# Configure your name!
|
# Configure your name!
|
||||||
name: Joker
|
name: Joker
|
||||||
year: 24
|
how-old-are-you: 24
|
||||||
```
|
```
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
@@ -125,9 +149,9 @@ info:
|
|||||||
|
|
||||||
<repository>
|
<repository>
|
||||||
<!-- Using GitHub dependencies for real-time updates, configuration required (recommended). -->
|
<!-- Using GitHub dependencies for real-time updates, configuration required (recommended). -->
|
||||||
<id>EasyConfiguration</id>
|
<id>configured</id>
|
||||||
<name>GitHub Packages</name>
|
<name>GitHub Packages</name>
|
||||||
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url>
|
<url>https://maven.pkg.github.com/CarmJos/configured</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
|
||||||
</repositories>
|
</repositories>
|
||||||
@@ -146,7 +170,7 @@ info:
|
|||||||
<!-- Basic implementation part, requiring custom implementation of “Provider” and “Wrapper”. -->
|
<!-- Basic implementation part, requiring custom implementation of “Provider” and “Wrapper”. -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<artifactId>easyconfiguration-core</artifactId>
|
<artifactId>configured-core</artifactId>
|
||||||
<version>[LATEST RELEASE]</version>
|
<version>[LATEST RELEASE]</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
@@ -154,15 +178,15 @@ info:
|
|||||||
<!-- YAML file-based implementation, compatible with all Java environments. -->
|
<!-- YAML file-based implementation, compatible with all Java environments. -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<artifactId>easyconfiguration-yaml</artifactId>
|
<artifactId>configured-yaml</artifactId>
|
||||||
<version>[LATEST RELEASE]</version>
|
<version>[LATEST RELEASE]</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- JSON file-based implementation, compatible with all Java environments. Note: JSON does not support file comments. -->
|
<!-- JSON file-based implementation, compatible with all Java environments. -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<artifactId>easyconfiguration-json</artifactId>
|
<artifactId>configured-gson</artifactId>
|
||||||
<version>[LATEST RELEASE]</version>
|
<version>[LATEST RELEASE]</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
@@ -185,7 +209,7 @@ repositories {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|
||||||
// Using GitHub dependencies for real-time updates, configuration required (recommended).
|
// Using GitHub dependencies for real-time updates, configuration required (recommended).
|
||||||
maven { url 'https://maven.pkg.github.com/CarmJos/EasyConfiguration' }
|
maven { url 'https://maven.pkg.github.com/CarmJos/configured' }
|
||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -200,13 +224,13 @@ repositories {
|
|||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
// Basic implementation part, requiring custom implementation of “Provider” and “Wrapper”.
|
// Basic implementation part, requiring custom implementation of “Provider” and “Wrapper”.
|
||||||
api "cc.carm.lib:easyconfiguration-core:[LATEST RELEASE]"
|
api "cc.carm.lib:configured-core:[LATEST RELEASE]"
|
||||||
|
|
||||||
// YAML file-based implementation, compatible with all Java environments.
|
// YAML file-based implementation, compatible with all Java environments.
|
||||||
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]"
|
api "cc.carm.lib:configured-yaml:[LATEST RELEASE]"
|
||||||
|
|
||||||
// JSON file-based implementation, compatible with all Java environments. Note: JSON does not support file comments.
|
// JSON file-based implementation, compatible with all Java environments.
|
||||||
api "cc.carm.lib:easyconfiguration-json:[LATEST RELEASE]"
|
api "cc.carm.lib:configured-gson:[LATEST RELEASE]"
|
||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -217,10 +241,11 @@ dependencies {
|
|||||||
|
|
||||||
### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos)
|
### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos)
|
||||||
|
|
||||||
EasyConfiguration for MineCraft!
|
configured for MineCraft!
|
||||||
Easily manage configurations on MineCraft-related server platforms.
|
Easily manage configurations on MineCraft-related server platforms.
|
||||||
|
|
||||||
Currently supports BungeeCord, Bukkit (Spigot) servers, with more platforms to be supported soon.
|
Currently, it supports BungeeCord, Velocity, Bukkit (Spigot) servers,
|
||||||
|
with more platforms to be supported soon.
|
||||||
|
|
||||||
## Support and Donation
|
## Support and Donation
|
||||||
|
|
||||||
@@ -230,7 +255,12 @@ Thank you for supporting open-source projects!
|
|||||||
|
|
||||||
Many thanks to Jetbrains for kindly providing a license for us to work on this and other open-source projects.
|
Many thanks to Jetbrains for kindly providing a license for us to work on this and other open-source projects.
|
||||||
|
|
||||||
[](https://www.jetbrains.com/?from=https://github.com/CarmJos/EasyConfiguration)
|
[](https://www.jetbrains.com/?from=https://github.com/CarmJos/configured)
|
||||||
|
|
||||||
|
Many thanks to [ArtformGames](https://github.com/ArtformGames) for their
|
||||||
|
strong support and active contribution to this project!
|
||||||
|
|
||||||
|
<img src="https://raw.githubusercontent.com/ArtformGames/.github/master/logo/logo_full.svg" width="317px" height="117px" alt="ArtformGames">
|
||||||
|
|
||||||
## Open Source License
|
## Open Source License
|
||||||
|
|
||||||
|
|||||||
+72
-47
@@ -1,29 +1,27 @@
|
|||||||
```text
|
<div align=center>
|
||||||
____ _____ ____ __ _
|
<img src=".doc/images/banner.png" alt="Banner"/>
|
||||||
/ __/__ ____ __ __ / ___/__ ___ / _(_)__ ___ _________ _/ /_(_)__ ___
|
|
||||||
/ _// _ `(_-</ // / / /__/ _ \/ _ \/ _/ / _ `/ // / __/ _ `/ __/ / _ \/ _ \
|
[](https://github.com/CarmJos/configured/releases)
|
||||||
/___/\_,_/___/\_, / \___/\___/_//_/_//_/\_, /\_,_/_/ \_,_/\__/_/\___/_//_/
|
[](https://www.gnu.org/licenses/lgpl-3.0.html)
|
||||||
/___/ /___/
|
[](https://github.com/CarmJos/configured/actions/workflows/maven.yml)
|
||||||
```
|
[](https://www.codefactor.io/repository/github/carmjos/configured)
|
||||||
|

|
||||||
|
|
||||||
README LANGUAGES [ [English](README.md) | [**中文**](README_CN.md) ]
|
README LANGUAGES [ [English](README.md) | [**中文**](README_CN.md) ]
|
||||||
|
|
||||||
# EasyConfiguration
|
</div>
|
||||||
|
|
||||||
[](https://github.com/CarmJos/EasyConfiguration/releases)
|
# configured _(配置文件框架)_
|
||||||
[](https://www.gnu.org/licenses/lgpl-3.0.html)
|
|
||||||
[](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml)
|
|
||||||
[](https://www.codefactor.io/repository/github/carmjos/easyconfiguration)
|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
**轻松(做)配置!**
|
<img src=".doc/images/logo-bg.svg" width="150px" alt="logo" align="right" style="float: right"/>
|
||||||
|
|
||||||
|
**一次配置,轻松读取!**
|
||||||
|
|
||||||
一款简单便捷的通用配置文件加载、读取与更新工具,可自定义配置的格式。
|
一款简单便捷的通用配置文件加载、读取与更新工具,可自定义配置的格式。
|
||||||
|
|
||||||
## 特性 & 优势
|
## 特性 & 优势
|
||||||
|
|
||||||
支持 [YAML](impl/yaml), [JSON](impl/json), [HOCON](impl/hocon) 和 [SQL](impl/sql) 等多种配置文件格式。
|
支持 [YAML](providers/yaml), [JSON](providers/gson), [HOCON](providers/hocon) 和 [SQL](providers/sql) 等多种配置文件格式。
|
||||||
|
|
||||||
- 基于类的配置文件初始化、加载、获取与更新机制,方便快捷。
|
- 基于类的配置文件初始化、加载、获取与更新机制,方便快捷。
|
||||||
- 支持复杂配置的手动序列化、反序列化。
|
- 支持复杂配置的手动序列化、反序列化。
|
||||||
@@ -32,26 +30,35 @@ README LANGUAGES [ [English](README.md) | [**中文**](README_CN.md) ]
|
|||||||
|
|
||||||
## 开发
|
## 开发
|
||||||
|
|
||||||
详细开发介绍请 [点击这里](.doc/README.md) , JavaDoc(最新Release) 请 [点击这里](https://CarmJos.github.io/EasyConfiguration) 。
|
详细开发介绍请 [点击这里](.doc/README.md) , JavaDoc(最新Release)
|
||||||
|
请 [点击这里](https://CarmJos.github.io/configured) 。
|
||||||
|
|
||||||
### 示例代码
|
### 示例代码
|
||||||
|
|
||||||
为快速的展示该项目的适用性,这里有几个实际演示:
|
为快速的展示该项目的适用性,这里有几个实际演示:
|
||||||
|
|
||||||
- [数据库配置文件实例](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java)
|
- [数据库配置文件实例](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java)
|
||||||
- [全种类配置实例类演示](demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java)
|
- [全种类配置实例类演示](demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java)
|
||||||
|
|
||||||
您可以 [点击这里](demo/src/main/java/cc/carm/lib/configuration/demo) 直接查看现有的代码演示,更多复杂情况演示详见 [开发介绍](.doc/README.md) 。
|
您可以 [点击这里](demo/src/main/java/cc/carm/lib/configuration/demo)
|
||||||
|
直接查看现有的代码演示,更多复杂情况演示详见 [开发介绍](.doc/README.md) 。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@HeaderComment("Configurations for sample")
|
|
||||||
interface SampleConfig extends Configuration {
|
|
||||||
|
|
||||||
@InlineComment("Enabled?") // 行内注释
|
@ConfigPath(root = true)
|
||||||
|
@HeaderComments("Configurations for sample")
|
||||||
|
public interface SampleConfig extends Configuration {
|
||||||
|
|
||||||
|
@InlineComment("Enabled?") // 行后注释
|
||||||
ConfiguredValue<Boolean> ENABLED = ConfiguredValue.of(true);
|
ConfiguredValue<Boolean> ENABLED = ConfiguredValue.of(true);
|
||||||
|
|
||||||
|
@HeaderComments("Server configurations") // 头部注释
|
||||||
|
ConfiguredValue<Integer> PORT = ConfiguredValue.of(Integer.class);
|
||||||
|
|
||||||
|
@HeaderComments({"[ UUID >-----------------------------------", "A lot of UUIDs"})
|
||||||
|
@FooterComments("[ UUID >-----------------------------------")
|
||||||
ConfiguredList<UUID> UUIDS = ConfiguredList.builderOf(UUID.class).fromString()
|
ConfiguredList<UUID> UUIDS = ConfiguredList.builderOf(UUID.class).fromString()
|
||||||
.parseValue(UUID::fromString).serializeValue(UUID::toString)
|
.parse(UUID::fromString).serialize(UUID::toString)
|
||||||
.defaults(
|
.defaults(
|
||||||
UUID.fromString("00000000-0000-0000-0000-000000000000"),
|
UUID.fromString("00000000-0000-0000-0000-000000000000"),
|
||||||
UUID.fromString("00000000-0000-0000-0000-000000000001")
|
UUID.fromString("00000000-0000-0000-0000-000000000001")
|
||||||
@@ -59,26 +66,34 @@ interface SampleConfig extends Configuration {
|
|||||||
|
|
||||||
interface INFO extends Configuration {
|
interface INFO extends Configuration {
|
||||||
|
|
||||||
@HeaderComment("Configure your name!") // 头部注释
|
@HeaderComments("Configure your name!") // Header comment
|
||||||
ConfiguredValue<String> NAME = ConfiguredValue.of("Joker");
|
ConfiguredValue<String> NAME = ConfiguredValue.of("Joker");
|
||||||
|
|
||||||
@ConfigPath("year") // 自定义配置路径,若不定义,则按照默认规则生成
|
@ConfigPath("how-old-are-you") // 自定义路径
|
||||||
ConfiguredValue<Integer> AGE = ConfiguredValue.of(24);
|
ConfiguredValue<Integer> AGE = ConfiguredValue.of(24);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class Sample {
|
public class Sample {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
// 1. 生成一个 “Provider” 用于给配置类提供源配置的文件。
|
// 1. 生成一个 “holder” 用于给配置类提供源配置的文件。
|
||||||
ConfigurationProvider<?> provider = EasyConfiguration.from("config.yml");
|
ConfigurationHolder<?> holder = YAMLConfigFactory.from("target/config.yml")
|
||||||
// 2. 通过 “Provider” 初始化配置类或配置实例。
|
.resourcePath("configs/sample.yml")
|
||||||
provider.initialize(SampleConfig.class);
|
.indent(4) // Optional: Set the indentation of the configuration file.
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 2. 通过 “holder” 初始化配置类或配置实例。
|
||||||
|
holder.initialize(SampleConfig.class);
|
||||||
// 3. 现在可以享受快捷方便的配置文件使用方式了~
|
// 3. 现在可以享受快捷方便的配置文件使用方式了~
|
||||||
|
System.out.println("Enabled? -> " + SampleConfig.ENABLED.resolve());
|
||||||
SampleConfig.ENABLED.set(false);
|
SampleConfig.ENABLED.set(false);
|
||||||
System.out.println("Your name is " + SampleConfig.INFO.NAME.getNotNull() + " !");
|
System.out.println("And now? -> " + SampleConfig.ENABLED.resolve());
|
||||||
|
// p.s. 在本示例里的更改未保存,因此启用值在下次运行中仍将为 true。
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -86,16 +101,22 @@ public class Sample {
|
|||||||
```yaml
|
```yaml
|
||||||
# Configurations for sample
|
# Configurations for sample
|
||||||
|
|
||||||
enabled: true # Enabled?
|
enabled: true #Enabled?
|
||||||
|
|
||||||
|
# Server configurations
|
||||||
|
port:
|
||||||
|
|
||||||
|
# [ UUID >-----------------------------------
|
||||||
|
# A lot of UUIDs
|
||||||
uuids:
|
uuids:
|
||||||
- 00000000-0000-0000-0000-000000000000
|
- 00000000-0000-0000-0000-000000000000
|
||||||
- 00000000-0000-0000-0000-000000000001
|
- 00000000-0000-0000-0000-000000000001
|
||||||
|
# [ UUID >-----------------------------------
|
||||||
|
|
||||||
info:
|
info:
|
||||||
# Configure your name!
|
# Configure your name!
|
||||||
name: Joker
|
name: Joker
|
||||||
year: 24
|
how-old-are-you: 24
|
||||||
```
|
```
|
||||||
|
|
||||||
### 依赖方式
|
### 依赖方式
|
||||||
@@ -119,9 +140,9 @@ info:
|
|||||||
|
|
||||||
<repository>
|
<repository>
|
||||||
<!--采用github依赖库,实时更新,但需要配置 (推荐) -->
|
<!--采用github依赖库,实时更新,但需要配置 (推荐) -->
|
||||||
<id>EasyConfiguration</id>
|
<id>configured</id>
|
||||||
<name>GitHub Packages</name>
|
<name>GitHub Packages</name>
|
||||||
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url>
|
<url>https://maven.pkg.github.com/CarmJos/configured</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
|
||||||
<repository>
|
<repository>
|
||||||
@@ -147,7 +168,7 @@ info:
|
|||||||
<!--基础实现部分,需要自行实现“Provider”与“Wrapper”。-->
|
<!--基础实现部分,需要自行实现“Provider”与“Wrapper”。-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<artifactId>easyconfiguration-core</artifactId>
|
<artifactId>configured-core</artifactId>
|
||||||
<version>[LATEST RELEASE]</version>
|
<version>[LATEST RELEASE]</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
@@ -155,7 +176,7 @@ info:
|
|||||||
<!--基于YAML文件的实现版本,可用于全部Java环境。-->
|
<!--基于YAML文件的实现版本,可用于全部Java环境。-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<artifactId>easyconfiguration-yaml</artifactId>
|
<artifactId>configured-yaml</artifactId>
|
||||||
<version>[LATEST RELEASE]</version>
|
<version>[LATEST RELEASE]</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
@@ -164,21 +185,21 @@ info:
|
|||||||
<!--需要注意的是,JSON不支持文件注释。-->
|
<!--需要注意的是,JSON不支持文件注释。-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<artifactId>easyconfiguration-json</artifactId>
|
<artifactId>configured-gson</artifactId>
|
||||||
<version>[LATEST RELEASE]</version>
|
<version>[LATEST RELEASE]</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<artifactId>easyconfiguration-hocon</artifactId>
|
<artifactId>configured-hocon</artifactId>
|
||||||
<version>[LATEST RELEASE]</version>
|
<version>[LATEST RELEASE]</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<artifactId>easyconfiguration-sql</artifactId>
|
<artifactId>configured-sql</artifactId>
|
||||||
<version>[LATEST RELEASE]</version>
|
<version>[LATEST RELEASE]</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
@@ -201,7 +222,7 @@ repositories {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|
||||||
// 采用github依赖库,实时更新,但需要配置 (推荐)
|
// 采用github依赖库,实时更新,但需要配置 (推荐)
|
||||||
maven { url 'https://maven.pkg.github.com/CarmJos/EasyConfiguration' }
|
maven { url 'https://maven.pkg.github.com/CarmJos/configured' }
|
||||||
|
|
||||||
// 采用我的私人依赖库,简单方便,但可能因为变故而无法使用
|
// 采用我的私人依赖库,简单方便,但可能因为变故而无法使用
|
||||||
maven { url 'https://repo.carm.cc/repository/maven-public/' }
|
maven { url 'https://repo.carm.cc/repository/maven-public/' }
|
||||||
@@ -218,18 +239,18 @@ repositories {
|
|||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
//基础实现部分,需要自行实现“Provider”与“Wrapper”。
|
//基础实现部分,需要自行实现“Provider”与“Wrapper”。
|
||||||
api "cc.carm.lib:easyconfiguration-core:[LATEST RELEASE]"
|
api "cc.carm.lib:configured-core:[LATEST RELEASE]"
|
||||||
|
|
||||||
//基于YAML文件的实现版本,可用于全部Java环境。
|
//基于YAML文件的实现版本,可用于全部Java环境。
|
||||||
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]"
|
api "cc.carm.lib:configured-yaml:[LATEST RELEASE]"
|
||||||
|
|
||||||
//基于JSON文件的实现版本,可用于全部Java环境。
|
//基于JSON文件的实现版本,可用于全部Java环境。
|
||||||
//需要注意的是,JSON不支持文件注释。
|
//需要注意的是,JSON不支持文件注释。
|
||||||
api "cc.carm.lib:easyconfiguration-json:[LATEST RELEASE]"
|
api "cc.carm.lib:configured-gson:[LATEST RELEASE]"
|
||||||
|
|
||||||
api "cc.carm.lib:easyconfiguration-hocon:[LATEST RELEASE]"
|
api "cc.carm.lib:configured-hocon:[LATEST RELEASE]"
|
||||||
|
|
||||||
api "cc.carm.lib:easyconfiguration-sql:[LATEST RELEASE]"
|
api "cc.carm.lib:configured-sql:[LATEST RELEASE]"
|
||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -240,7 +261,7 @@ dependencies {
|
|||||||
|
|
||||||
### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos )
|
### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos )
|
||||||
|
|
||||||
EasyConfiguration for MineCraft!
|
configured for MineCraft!
|
||||||
开始在 MineCraft 相关服务器平台上轻松(做)配置吧!
|
开始在 MineCraft 相关服务器平台上轻松(做)配置吧!
|
||||||
|
|
||||||
目前支持 BungeeCord, Bukkit(Spigot) 服务端,后续将支持更多平台。
|
目前支持 BungeeCord, Bukkit(Spigot) 服务端,后续将支持更多平台。
|
||||||
@@ -253,7 +274,11 @@ EasyConfiguration for MineCraft!
|
|||||||
|
|
||||||
万分感谢 Jetbrains 为我们提供了从事此项目和其他开源项目的许可!
|
万分感谢 Jetbrains 为我们提供了从事此项目和其他开源项目的许可!
|
||||||
|
|
||||||
[](https://www.jetbrains.com/?from=https://github.com/CarmJos/EasyConfiguration)
|
[](https://www.jetbrains.com/?from=https://github.com/CarmJos/configured)
|
||||||
|
|
||||||
|
万分感谢来自 [ArtformGames](https://github.com/ArtformGames) 对本项目的大力支持与积极贡献!
|
||||||
|
|
||||||
|
<img src="https://raw.githubusercontent.com/ArtformGames/.github/master/logo/logo_full.svg" width="317px" height="117px" alt="ArtformGames">
|
||||||
|
|
||||||
## 开源协议
|
## 开源协议
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -3,9 +3,9 @@
|
|||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>easyconfiguration-parent</artifactId>
|
<artifactId>configured-parent</artifactId>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<version>4.0.0</version>
|
<version>4.1.7</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<properties>
|
<properties>
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<artifactId>easyconfiguration-core</artifactId>
|
<artifactId>configured-core</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ package cc.carm.lib.configuration;
|
|||||||
* The root interface of the configuration file interfaces,
|
* The root interface of the configuration file interfaces,
|
||||||
* which is used to label a class as a configuration.
|
* which is used to label a class as a configuration.
|
||||||
*/
|
*/
|
||||||
public interface Configuration { }
|
public interface Configuration {
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public class ValueAdapter<TYPE>
|
|||||||
implements ValueSerializer<TYPE>, ValueParser<TYPE> {
|
implements ValueSerializer<TYPE>, ValueParser<TYPE> {
|
||||||
|
|
||||||
protected final @NotNull ValueType<TYPE> type;
|
protected final @NotNull ValueType<TYPE> type;
|
||||||
|
|
||||||
protected @Nullable ValueSerializer<TYPE> serializer;
|
protected @Nullable ValueSerializer<TYPE> serializer;
|
||||||
protected @Nullable ValueParser<TYPE> deserializer;
|
protected @Nullable ValueParser<TYPE> deserializer;
|
||||||
|
|
||||||
@@ -53,13 +54,21 @@ public class ValueAdapter<TYPE>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object serialize(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<? super TYPE> type, @NotNull TYPE value) throws Exception {
|
public @Nullable Object serialize(
|
||||||
|
@NotNull ConfigurationHolder<?> holder,
|
||||||
|
@NotNull ValueType<? super TYPE> type,
|
||||||
|
@NotNull TYPE value
|
||||||
|
) throws Exception {
|
||||||
if (serializer == null) throw new UnsupportedOperationException("Serializer is not supported");
|
if (serializer == null) throw new UnsupportedOperationException("Serializer is not supported");
|
||||||
return serializer.serialize(holder, type, value);
|
return serializer.serialize(holder, type, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TYPE parse(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<? super TYPE> type, @NotNull Object value) throws Exception {
|
public @Nullable TYPE parse(
|
||||||
|
@NotNull ConfigurationHolder<?> holder,
|
||||||
|
@NotNull ValueType<? super TYPE> type,
|
||||||
|
@NotNull Object value
|
||||||
|
) throws Exception {
|
||||||
if (deserializer == null) throw new UnsupportedOperationException("Deserializer is not supported");
|
if (deserializer == null) throw new UnsupportedOperationException("Deserializer is not supported");
|
||||||
return deserializer.parse(holder, type, value);
|
return deserializer.parse(holder, type, value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ package cc.carm.lib.configuration.adapter;
|
|||||||
|
|
||||||
import cc.carm.lib.configuration.function.DataFunction;
|
import cc.carm.lib.configuration.function.DataFunction;
|
||||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
import org.jetbrains.annotations.Contract;
|
import cc.carm.lib.configuration.source.section.ConfigureSection;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.util.HashSet;
|
import java.lang.reflect.Type;
|
||||||
import java.util.Set;
|
import java.util.*;
|
||||||
|
|
||||||
public class ValueAdapterRegistry {
|
public class ValueAdapterRegistry {
|
||||||
|
|
||||||
@@ -61,7 +61,9 @@ public class ValueAdapterRegistry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> void register(@NotNull ValueType<T> type, @Nullable ValueSerializer<T> serializer, @Nullable ValueParser<T> deserializer) {
|
public <T> void register(@NotNull ValueType<T> type,
|
||||||
|
@Nullable ValueSerializer<T> serializer,
|
||||||
|
@Nullable ValueParser<T> deserializer) {
|
||||||
if (serializer == null && deserializer == null) return;
|
if (serializer == null && deserializer == null) return;
|
||||||
ValueAdapter<T> existing = adapterOf(type);
|
ValueAdapter<T> existing = adapterOf(type);
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
@@ -82,7 +84,9 @@ public class ValueAdapterRegistry {
|
|||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> @Nullable ValueAdapter<T> adapterOf(@NotNull ValueType<T> type) {
|
public <T> @Nullable ValueAdapter<T> adapterOf(@NotNull ValueType<T> type) {
|
||||||
ValueAdapter<?> matched = adapters.stream().filter(adapter -> adapter.type().equals(type)).findFirst().orElse(null);
|
ValueAdapter<?> matched = adapters.stream()
|
||||||
|
.filter(adapter -> adapter.type().equals(type))
|
||||||
|
.findFirst().orElse(null);
|
||||||
if (matched != null) return (ValueAdapter<T>) matched;
|
if (matched != null) return (ValueAdapter<T>) matched;
|
||||||
|
|
||||||
// If no adapter found, try to find the adapter for the super type
|
// If no adapter found, try to find the adapter for the super type
|
||||||
@@ -99,28 +103,112 @@ public class ValueAdapterRegistry {
|
|||||||
return adapterOf(ValueType.of(type));
|
return adapterOf(ValueType.of(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract("_,_,null -> null")
|
|
||||||
public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull Class<T> type, @Nullable Object source) throws Exception {
|
public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull Class<T> type, @Nullable Object source) throws Exception {
|
||||||
return deserialize(holder, ValueType.of(type), source);
|
return deserialize(holder, ValueType.of(type), source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract("_,_,null -> null")
|
|
||||||
public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> type, @Nullable Object source) throws Exception {
|
public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> type, @Nullable Object source) throws Exception {
|
||||||
if (source == null) return null; // Null check
|
if (source == null) return null; // Null check
|
||||||
if (type.isInstance(source)) return type.cast(source); // Not required to deserialize
|
if (!(type.getType() instanceof ParameterizedType) && type.isInstance(source)) {
|
||||||
ValueAdapter<T> adapter = adapterOf(type);
|
return type.cast(source); // Not required to deserialize
|
||||||
if (adapter == null) throw new RuntimeException("No adapter for type " + type);
|
|
||||||
return adapter.parse(holder, type, source);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract("_,null -> null")
|
ValueAdapter<T> adapter = adapterOf(type); // Try to find an existed adapter for the type
|
||||||
|
if (adapter != null) {
|
||||||
|
return adapter.parse(holder, type, source);
|
||||||
|
} // If no adapter found, we will try to handle the type manually
|
||||||
|
|
||||||
|
if (type.getRawType().isArray()) { // For arrays.
|
||||||
|
List<?> list = deserializeList(holder, type, source);
|
||||||
|
Object[] array = (Object[]) java.lang.reflect.Array.newInstance(type.getRawType().getComponentType(), list.size());
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
array[i] = deserialize(holder, type.getRawType().getComponentType(), list.get(i));
|
||||||
|
}
|
||||||
|
return type.cast(array);
|
||||||
|
} else if (type.getType() instanceof ParameterizedType) {
|
||||||
|
ParameterizedType pt = (ParameterizedType) type.getType();
|
||||||
|
Type rawType = pt.getRawType();
|
||||||
|
Type[] typeArgs = pt.getActualTypeArguments();
|
||||||
|
if (rawType == List.class || rawType == Collection.class || rawType == ArrayList.class) {
|
||||||
|
return type.cast(new ArrayList<>(deserializeList(holder, ValueType.of(typeArgs[0]), source)));
|
||||||
|
} else if (rawType == Set.class || rawType == HashSet.class) {
|
||||||
|
return type.cast(new HashSet<>(deserializeList(holder, ValueType.of(typeArgs[0]), source)));
|
||||||
|
} else if (rawType == Map.class || rawType == LinkedHashMap.class) {
|
||||||
|
Map<?, ?> map;
|
||||||
|
if (source instanceof Map<?, ?>) {
|
||||||
|
map = (Map<?, ?>) source;
|
||||||
|
} else if (source instanceof ConfigureSection) {
|
||||||
|
map = ((ConfigureSection) source).asMap();
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Cannot deserialize to Map from " + source.getClass());
|
||||||
|
}
|
||||||
|
Map<Object, Object> resultMap = new LinkedHashMap<>(map.size());
|
||||||
|
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
||||||
|
Object key = deserialize(holder, ValueType.of(typeArgs[0]), entry.getKey());
|
||||||
|
Object value = deserialize(holder, ValueType.of(typeArgs[1]), entry.getValue());
|
||||||
|
resultMap.put(key, value);
|
||||||
|
}
|
||||||
|
return type.cast(resultMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RuntimeException("No adapter for type " + type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public <T> Object serialize(@NotNull ConfigurationHolder<?> holder, @Nullable T value) throws Exception {
|
public <T> Object serialize(@NotNull ConfigurationHolder<?> holder, @Nullable T value) throws Exception {
|
||||||
if (value == null) return null; // Null check
|
if (value == null) return null; // Null check
|
||||||
|
|
||||||
ValueType<T> type = ValueType.of(value);
|
ValueType<T> type = ValueType.of(value);
|
||||||
ValueAdapter<T> adapter = adapterOf(type);
|
ValueAdapter<T> adapter = adapterOf(type);
|
||||||
if (adapter == null) return value; // No adapters, try to return the original value
|
if (adapter != null) return adapter.serialize(holder, type, value);
|
||||||
return adapter.serialize(holder, type, value);
|
|
||||||
|
if (value.getClass().isArray()) {
|
||||||
|
Object[] array = (Object[]) value;
|
||||||
|
List<Object> serializedList = new ArrayList<>(array.length);
|
||||||
|
for (Object item : array) {
|
||||||
|
serializedList.add(serialize(holder, item));
|
||||||
|
}
|
||||||
|
return serializedList;
|
||||||
|
} else if (value instanceof Collection<?>) {
|
||||||
|
Collection<?> collection = (Collection<?>) value;
|
||||||
|
List<Object> serializedList = new ArrayList<>(collection.size());
|
||||||
|
for (Object item : collection) {
|
||||||
|
serializedList.add(serialize(holder, item));
|
||||||
|
}
|
||||||
|
return serializedList;
|
||||||
|
} else if (value instanceof Map<?, ?>) {
|
||||||
|
Map<?, ?> map = (Map<?, ?>) value;
|
||||||
|
Map<Object, Object> serializedMap = new LinkedHashMap<>(map.size());
|
||||||
|
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
||||||
|
Object key = serialize(holder, entry.getKey());
|
||||||
|
Object val = serialize(holder, entry.getValue());
|
||||||
|
serializedMap.put(key, val);
|
||||||
|
}
|
||||||
|
return serializedMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return value; // No adapters, and cannot handle, try to return the original value
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <T> List<T> deserializeList(@NotNull ConfigurationHolder<?> holder,
|
||||||
|
@NotNull ValueType<T> type, @Nullable Object source) throws Exception {
|
||||||
|
if (source == null) return Collections.emptyList(); // Null check
|
||||||
|
if (source instanceof List<?>) {
|
||||||
|
List<?> list = (List<?>) source;
|
||||||
|
List<T> result = new ArrayList<>(list.size());
|
||||||
|
for (Object item : list) {
|
||||||
|
T deserializedItem = deserialize(holder, type, item);
|
||||||
|
if (deserializedItem != null) {
|
||||||
|
result.add(deserializedItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} else { // Maybe singleton? Let's try to deserialize it as a single element list
|
||||||
|
T deserializedItem = deserialize(holder, type, source);
|
||||||
|
if (deserializedItem != null) {
|
||||||
|
return Collections.singletonList(deserializedItem);
|
||||||
|
} else return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package cc.carm.lib.configuration.adapter;
|
|||||||
|
|
||||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Value deserializer, convert base data to target value.
|
* Value deserializer, convert base data to target value.
|
||||||
@@ -11,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface ValueParser<TYPE> {
|
public interface ValueParser<TYPE> {
|
||||||
|
|
||||||
TYPE parse(
|
@Nullable TYPE parse(
|
||||||
@NotNull ConfigurationHolder<?> holder,
|
@NotNull ConfigurationHolder<?> holder,
|
||||||
@NotNull ValueType<? super TYPE> type, @NotNull Object data
|
@NotNull ValueType<? super TYPE> type, @NotNull Object data
|
||||||
) throws Exception;
|
) throws Exception;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package cc.carm.lib.configuration.adapter;
|
|||||||
|
|
||||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Value serializer, convert target value to base data.
|
* Value serializer, convert target value to base data.
|
||||||
@@ -11,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface ValueSerializer<TYPE> {
|
public interface ValueSerializer<TYPE> {
|
||||||
|
|
||||||
Object serialize(
|
@Nullable Object serialize(
|
||||||
@NotNull ConfigurationHolder<?> holder,
|
@NotNull ConfigurationHolder<?> holder,
|
||||||
@NotNull ValueType<? super TYPE> type, @NotNull TYPE value
|
@NotNull ValueType<? super TYPE> type, @NotNull TYPE value
|
||||||
) throws Exception;
|
) throws Exception;
|
||||||
|
|||||||
@@ -1,14 +1,22 @@
|
|||||||
package cc.carm.lib.configuration.adapter;
|
package cc.carm.lib.configuration.adapter;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to get the generic type.
|
* {@link ValueType} used to get the generic type of the value,
|
||||||
|
* It can be used to check if an object is an instance of a specific type,
|
||||||
|
* and to cast objects to the correct type.
|
||||||
|
* <p>
|
||||||
|
* Java's type system is not capable of retaining generic type information at runtime.
|
||||||
|
* This class is used to represent a type with its generic parameters.
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
public abstract class ValueType<T> {
|
public abstract class ValueType<T> {
|
||||||
|
|
||||||
@@ -43,7 +51,7 @@ public abstract class ValueType<T> {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T> ValueType<T> of(final Type type) {
|
public static <T> ValueType<T> of(final Type type) {
|
||||||
if (type == null) throw new NullPointerException("Type cannot be null");
|
if (type == null) throw new NullPointerException("Type cannot be null");
|
||||||
if (type instanceof Class<?>) { // Try handle primitive types
|
if (type instanceof Class<?>) { // Try to fast handle primitive types
|
||||||
Class<?> clazz = (Class<?>) type;
|
Class<?> clazz = (Class<?>) type;
|
||||||
for (ValueType<?> valueType : PRIMITIVE_TYPES) {
|
for (ValueType<?> valueType : PRIMITIVE_TYPES) {
|
||||||
if (valueType.getRawType() == clazz) {
|
if (valueType.getRawType() == clazz) {
|
||||||
@@ -55,10 +63,26 @@ public abstract class ValueType<T> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> ValueType<T> of(final Class<T> clazz) {
|
public static <T> ValueType<T> of(final @NotNull Class<T> clazz) {
|
||||||
return of((Type) clazz);
|
return of((Type) clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> ValueType<List<T>> ofList(final @NotNull Class<T> paramType) {
|
||||||
|
return of(List.class, paramType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ValueType<List<T>> ofList(final @NotNull ValueType<T> paramType) {
|
||||||
|
return of(List.class, paramType.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <K, V> ValueType<Map<K, V>> ofMap(final @NotNull Class<K> keyType, final @NotNull Class<V> valueType) {
|
||||||
|
return of(Map.class, keyType, valueType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <K, V> ValueType<Map<K, V>> ofMap(final @NotNull ValueType<K> keyType, final @NotNull ValueType<V> valueType) {
|
||||||
|
return of(Map.class, keyType.getType(), valueType.getType());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the generic type of the complex type.
|
* Get the generic type of the complex type.
|
||||||
*
|
*
|
||||||
@@ -87,6 +111,7 @@ public abstract class ValueType<T> {
|
|||||||
return of(parameterizedType);
|
return of(parameterizedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiStatus.Internal
|
||||||
private static <T> ValueType<T> ofPrimitiveType(Class<T> clazz) {
|
private static <T> ValueType<T> ofPrimitiveType(Class<T> clazz) {
|
||||||
return new ValueType<T>(clazz) {
|
return new ValueType<T>(clazz) {
|
||||||
};
|
};
|
||||||
@@ -106,40 +131,65 @@ public abstract class ValueType<T> {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this ValueType is a subtype of the given Class.
|
||||||
|
*
|
||||||
|
* @param target The target Class to check against
|
||||||
|
* @return true if this ValueType is a subtype of the target Class, false otherwise
|
||||||
|
*/
|
||||||
public boolean isSubtypeOf(Class<?> target) {
|
public boolean isSubtypeOf(Class<?> target) {
|
||||||
Class<?> rawType = getRawType();
|
Class<?> rawType = getRawType();
|
||||||
return target.isAssignableFrom(rawType);
|
return target.isAssignableFrom(rawType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this ValueType is a subtype of the given ValueType.
|
||||||
|
*
|
||||||
|
* @param target The target ValueType to check against
|
||||||
|
* @return true if this ValueType is a subtype of the target, false otherwise
|
||||||
|
*/
|
||||||
public boolean isSubtypeOf(ValueType<?> target) {
|
public boolean isSubtypeOf(ValueType<?> target) {
|
||||||
return target.isSubtypeOf(getRawType());
|
return target.isSubtypeOf(getRawType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given object is an instance of the type represented by this ValueType.
|
||||||
|
*
|
||||||
|
* @param obj The object to check
|
||||||
|
* @return true if the object is an instance of the type, false otherwise
|
||||||
|
*/
|
||||||
public boolean isInstance(Object obj) {
|
public boolean isInstance(Object obj) {
|
||||||
return obj != null && getRawType().isInstance(obj);
|
return obj != null && getRawType().isInstance(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提取当前 ValueType 的原始类型(Class 对象)。
|
* Extracts the raw type from the generic type.
|
||||||
*
|
*
|
||||||
* @return 对应的 Class 对象
|
* @return The raw type of the generic type
|
||||||
* @throws IllegalStateException 如果无法提取出原始类型
|
* @throws IllegalStateException if the type is not a Class or ParameterizedType
|
||||||
*/
|
*/
|
||||||
public Class<?> getRawType() {
|
@SuppressWarnings("unchecked")
|
||||||
|
public Class<T> getRawType() {
|
||||||
if (type instanceof Class<?>) {
|
if (type instanceof Class<?>) {
|
||||||
return (Class<?>) type;
|
return (Class<T>) type;
|
||||||
}
|
}
|
||||||
if (type instanceof ParameterizedType) {
|
if (type instanceof ParameterizedType) {
|
||||||
ParameterizedType pt = (ParameterizedType) type;
|
ParameterizedType pt = (ParameterizedType) type;
|
||||||
Type raw = pt.getRawType();
|
Type raw = pt.getRawType();
|
||||||
if (raw instanceof Class<?>) {
|
if (raw instanceof Class<?>) {
|
||||||
return (Class<?>) raw;
|
return (Class<T>) raw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new IllegalStateException("Unsupported type: " + type);
|
throw new IllegalStateException("Unsupported type: " + type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Casts the object to the type represented by this ValueType.
|
||||||
|
*
|
||||||
|
* @param obj The object to cast
|
||||||
|
* @return The object cast to the type represented by this ValueType
|
||||||
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public T cast(Object obj) {
|
public T cast(Object obj) {
|
||||||
if (!isInstance(obj)) {
|
if (!isInstance(obj)) {
|
||||||
@@ -148,6 +198,12 @@ public abstract class ValueType<T> {
|
|||||||
return (T) obj;
|
return (T) obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the type.
|
||||||
|
* Like "{@code java.util.List<java.lang.String>}" or "java.lang.Integer".
|
||||||
|
*
|
||||||
|
* @return String representation of the type
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if (type instanceof Class<?>) {
|
if (type instanceof Class<?>) {
|
||||||
@@ -157,7 +213,7 @@ public abstract class ValueType<T> {
|
|||||||
ParameterizedType pt = (ParameterizedType) type;
|
ParameterizedType pt = (ParameterizedType) type;
|
||||||
Type raw = pt.getRawType();
|
Type raw = pt.getRawType();
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(raw.getTypeName());
|
sb.append(raw.getClass().getName());
|
||||||
sb.append('<');
|
sb.append('<');
|
||||||
Type[] args = pt.getActualTypeArguments();
|
Type[] args = pt.getActualTypeArguments();
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
@@ -166,6 +222,7 @@ public abstract class ValueType<T> {
|
|||||||
}
|
}
|
||||||
sb.append(args[i].getTypeName());
|
sb.append(args[i].getTypeName());
|
||||||
}
|
}
|
||||||
|
sb.append('>');
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
return type.getTypeName();
|
return type.getTypeName();
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import cc.carm.lib.configuration.adapter.ValueType;
|
|||||||
import cc.carm.lib.configuration.source.section.ConfigureSection;
|
import cc.carm.lib.configuration.source.section.ConfigureSection;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import static cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapter.*;
|
import static cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapter.*;
|
||||||
|
|
||||||
public interface StandardAdapters {
|
public interface StandardAdapters {
|
||||||
@@ -17,6 +19,12 @@ public interface StandardAdapters {
|
|||||||
|
|
||||||
@NotNull ValueAdapter<Enum<?>> ENUMS = PrimitiveAdapter.ofEnum();
|
@NotNull ValueAdapter<Enum<?>> ENUMS = PrimitiveAdapter.ofEnum();
|
||||||
|
|
||||||
|
@NotNull ValueAdapter<UUID> UUID = new ValueAdapter<>(
|
||||||
|
ValueType.of(UUID.class),
|
||||||
|
(provider, type, value) -> value.toString(),
|
||||||
|
(provider, type, value) -> java.util.UUID.fromString(value.toString())
|
||||||
|
);
|
||||||
|
|
||||||
@NotNull ValueAdapter<ConfigureSection> SECTIONS = new ValueAdapter<>(
|
@NotNull ValueAdapter<ConfigureSection> SECTIONS = new ValueAdapter<>(
|
||||||
ValueType.of(ConfigureSection.class),
|
ValueType.of(ConfigureSection.class),
|
||||||
(provider, type, value) -> value,
|
(provider, type, value) -> value,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package cc.carm.lib.configuration.builder;
|
package cc.carm.lib.configuration.builder;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.adapter.ValueType;
|
import cc.carm.lib.configuration.adapter.ValueType;
|
||||||
|
import cc.carm.lib.configuration.function.DataValidator;
|
||||||
|
import cc.carm.lib.configuration.function.ValueValidator;
|
||||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
|
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
|
||||||
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
|
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
|
||||||
@@ -11,11 +13,12 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public abstract class AbstractConfigBuilder<
|
public abstract class AbstractConfigBuilder<
|
||||||
TYPE, RESULT extends ConfigValue<TYPE>, HOLDER extends ConfigurationHolder<?>,
|
TYPE, UNIT, RESULT extends ConfigValue<TYPE, UNIT>, HOLDER extends ConfigurationHolder<?>,
|
||||||
SELF extends AbstractConfigBuilder<TYPE, RESULT, HOLDER, SELF>
|
SELF extends AbstractConfigBuilder<TYPE, UNIT, RESULT, HOLDER, SELF>
|
||||||
> {
|
> {
|
||||||
|
|
||||||
protected final Class<? super HOLDER> providerClass;
|
protected final Class<? super HOLDER> providerClass;
|
||||||
@@ -24,6 +27,7 @@ public abstract class AbstractConfigBuilder<
|
|||||||
protected @Nullable HOLDER holder;
|
protected @Nullable HOLDER holder;
|
||||||
protected @Nullable String path;
|
protected @Nullable String path;
|
||||||
|
|
||||||
|
protected @NotNull ValueValidator<UNIT> valueValidator = ValueValidator.none();
|
||||||
protected @NotNull Supplier<@Nullable TYPE> defaultValueSupplier = () -> null;
|
protected @NotNull Supplier<@Nullable TYPE> defaultValueSupplier = () -> null;
|
||||||
protected @NotNull BiConsumer<ConfigurationHolder<?>, String> initializer = (h, p) -> {
|
protected @NotNull BiConsumer<ConfigurationHolder<?>, String> initializer = (h, p) -> {
|
||||||
};
|
};
|
||||||
@@ -37,54 +41,121 @@ public abstract class AbstractConfigBuilder<
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract @NotNull SELF self();
|
protected abstract SELF self();
|
||||||
|
|
||||||
public abstract @NotNull RESULT build();
|
public abstract @NotNull RESULT build();
|
||||||
|
|
||||||
public @NotNull SELF holder(@Nullable HOLDER holder) {
|
public SELF holder(@Nullable HOLDER holder) {
|
||||||
this.holder = holder;
|
this.holder = holder;
|
||||||
return self();
|
return self();
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull SELF path(@Nullable String path) {
|
public SELF path(@Nullable String path) {
|
||||||
this.path = path;
|
this.path = path;
|
||||||
return self();
|
return self();
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull SELF initializer(@NotNull BiConsumer<ConfigurationHolder<?>, String> initializer) {
|
/**
|
||||||
|
* Set the {@link ValueValidator} for the value.
|
||||||
|
*
|
||||||
|
* @param validator The validator to set.
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public SELF validator(@NotNull ValueValidator<UNIT> validator) {
|
||||||
|
this.valueValidator = validator;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link DataValidator} for the value.
|
||||||
|
*
|
||||||
|
* @param validator The validator to set.
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public SELF validator(@NotNull DataValidator<? super UNIT> validator) {
|
||||||
|
return validator((h, value) -> validator.validate(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the value with the specified condition.
|
||||||
|
*
|
||||||
|
* @param validator The validator to append.
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public SELF validate(@NotNull ValueValidator<? super UNIT> validator) {
|
||||||
|
return validator(this.valueValidator.and(validator));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the value with the specified condition.
|
||||||
|
*
|
||||||
|
* @param validator The validator to append.
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public SELF validate(@NotNull DataValidator<? super UNIT> validator) {
|
||||||
|
return validate((h, value) -> validator.validate(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the value with the specified condition.
|
||||||
|
*
|
||||||
|
* @param condition The condition to check, if the condition is false, an exception will be thrown.
|
||||||
|
* @param exception The exception to throw if the condition is false.
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public SELF validate(@NotNull Predicate<? super UNIT> condition, @NotNull Exception exception) {
|
||||||
|
return validate((h, value) -> {
|
||||||
|
if (!condition.test(value)) throw exception;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the value with the specified condition.
|
||||||
|
*
|
||||||
|
* @param condition The condition to check, if the condition is false, an exception will be thrown.
|
||||||
|
* @param msg The message to throw if the condition is false.
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public SELF validate(@NotNull Predicate<? super UNIT> condition, @NotNull String msg) {
|
||||||
|
return validate((h, value) -> {
|
||||||
|
if (!condition.test(value)) throw new IllegalArgumentException(msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public SELF initializer(@NotNull BiConsumer<ConfigurationHolder<?>, String> initializer) {
|
||||||
this.initializer = initializer;
|
this.initializer = initializer;
|
||||||
return self();
|
return self();
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull SELF append(@NotNull BiConsumer<ConfigurationHolder<?>, String> initializer) {
|
public SELF append(@NotNull BiConsumer<ConfigurationHolder<?>, String> initializer) {
|
||||||
return initializer(initializer.andThen(initializer));
|
return initializer(initializer.andThen(initializer));
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull SELF append(@NotNull Consumer<ConfigurationHolder<?>> initializer) {
|
public SELF append(@NotNull Consumer<ConfigurationHolder<?>> initializer) {
|
||||||
return append((provider, valuePath) -> initializer.accept(provider));
|
return append((provider, valuePath) -> initializer.accept(provider));
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull SELF defaults(@Nullable TYPE defaultValue) {
|
public SELF defaults(@Nullable TYPE defaultValue) {
|
||||||
return defaults(() -> defaultValue);
|
return defaults(() -> defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull SELF defaults(@NotNull Supplier<@Nullable TYPE> supplier) {
|
public SELF defaults(@NotNull Supplier<@Nullable TYPE> supplier) {
|
||||||
this.defaultValueSupplier = supplier;
|
this.defaultValueSupplier = supplier;
|
||||||
return self();
|
return self();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <M> @NotNull SELF meta(@NotNull Consumer<@NotNull ConfigurationMetaHolder> metaConsumer) {
|
public SELF meta(@NotNull Consumer<@NotNull ConfigurationMetaHolder> metaConsumer) {
|
||||||
return append((h, p) -> metaConsumer.accept(h.metadata(p)));
|
return append((h, p) -> metaConsumer.accept(h.metadata(p)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public <M> @NotNull SELF meta(@NotNull ConfigurationMetadata<M> type, @Nullable M value) {
|
public <M> SELF meta(@NotNull ConfigurationMetadata<M> type, @Nullable M value) {
|
||||||
return meta(h -> h.set(type, value));
|
return meta(h -> h.set(type, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected @NotNull ValueManifest<TYPE> buildManifest() {
|
protected @NotNull ValueManifest<TYPE, UNIT> buildManifest() {
|
||||||
return new ValueManifest<>(
|
return new ValueManifest<>(
|
||||||
type(), this.defaultValueSupplier, this.initializer,
|
type(), this.defaultValueSupplier, this.valueValidator,
|
||||||
this.holder, this.path
|
this.initializer, this.holder, this.path
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,11 @@ import cc.carm.lib.configuration.adapter.ValueType;
|
|||||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
import cc.carm.lib.configuration.value.ConfigValue;
|
import cc.carm.lib.configuration.value.ConfigValue;
|
||||||
|
|
||||||
public abstract class CommonConfigBuilder<TYPE, RESULT extends ConfigValue<TYPE>, SELF extends CommonConfigBuilder<TYPE, RESULT, SELF>>
|
public abstract class CommonConfigBuilder<
|
||||||
extends AbstractConfigBuilder<TYPE, RESULT, ConfigurationHolder<?>, SELF> {
|
TYPE, UNIT,
|
||||||
|
RESULT extends ConfigValue<TYPE, UNIT>,
|
||||||
|
SELF extends CommonConfigBuilder<TYPE, UNIT, RESULT, SELF>
|
||||||
|
> extends AbstractConfigBuilder<TYPE, UNIT, RESULT, ConfigurationHolder<?>, SELF> {
|
||||||
|
|
||||||
protected CommonConfigBuilder(ValueType<TYPE> type) {
|
protected CommonConfigBuilder(ValueType<TYPE> type) {
|
||||||
super(ConfigurationHolder.class, type);
|
super(ConfigurationHolder.class, type);
|
||||||
|
|||||||
+22
-22
@@ -3,8 +3,8 @@ package cc.carm.lib.configuration.builder.impl;
|
|||||||
import cc.carm.lib.configuration.adapter.ValueAdapter;
|
import cc.carm.lib.configuration.adapter.ValueAdapter;
|
||||||
import cc.carm.lib.configuration.adapter.ValueType;
|
import cc.carm.lib.configuration.adapter.ValueType;
|
||||||
import cc.carm.lib.configuration.builder.CommonConfigBuilder;
|
import cc.carm.lib.configuration.builder.CommonConfigBuilder;
|
||||||
import cc.carm.lib.configuration.function.DataConsumer;
|
|
||||||
import cc.carm.lib.configuration.function.DataFunction;
|
import cc.carm.lib.configuration.function.DataFunction;
|
||||||
|
import cc.carm.lib.configuration.function.ValueComposer;
|
||||||
import cc.carm.lib.configuration.function.ValueHandler;
|
import cc.carm.lib.configuration.function.ValueHandler;
|
||||||
import cc.carm.lib.configuration.source.section.ConfigureSection;
|
import cc.carm.lib.configuration.source.section.ConfigureSection;
|
||||||
import cc.carm.lib.configuration.value.ConfigValue;
|
import cc.carm.lib.configuration.value.ConfigValue;
|
||||||
@@ -14,53 +14,53 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public abstract class AbstractSectionBuilder<
|
public abstract class AbstractSectionBuilder<
|
||||||
TYPE, PARAM,
|
TYPE, UNIT,
|
||||||
RESULT extends ConfigValue<TYPE>,
|
RESULT extends ConfigValue<TYPE, UNIT>,
|
||||||
SELF extends AbstractSectionBuilder<TYPE, PARAM, RESULT, SELF>
|
SELF extends AbstractSectionBuilder<TYPE, UNIT, RESULT, SELF>
|
||||||
> extends CommonConfigBuilder<TYPE, RESULT, SELF> {
|
> extends CommonConfigBuilder<TYPE, UNIT, RESULT, SELF> {
|
||||||
|
|
||||||
|
|
||||||
protected final @NotNull ValueType<PARAM> paramType;
|
protected final @NotNull ValueType<UNIT> paramType;
|
||||||
|
|
||||||
protected @NotNull ValueHandler<ConfigureSection, PARAM> parser;
|
protected @NotNull ValueHandler<ConfigureSection, UNIT> parser;
|
||||||
protected @NotNull ValueHandler<PARAM, ? extends Map<String, Object>> serializer;
|
protected @NotNull ValueHandler<UNIT, ? extends Map<String, Object>> serializer;
|
||||||
|
|
||||||
protected AbstractSectionBuilder(@NotNull ValueType<TYPE> type, @NotNull ValueType<PARAM> paramType,
|
protected AbstractSectionBuilder(@NotNull ValueType<TYPE> type, @NotNull ValueType<UNIT> paramType,
|
||||||
@NotNull ValueHandler<ConfigureSection, PARAM> parser,
|
@NotNull ValueHandler<ConfigureSection, UNIT> parser,
|
||||||
@NotNull ValueHandler<PARAM, ? extends Map<String, Object>> serializer) {
|
@NotNull ValueHandler<UNIT, ? extends Map<String, Object>> serializer) {
|
||||||
super(type);
|
super(type);
|
||||||
this.paramType = paramType;
|
this.paramType = paramType;
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
this.serializer = serializer;
|
this.serializer = serializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull SELF parse(DataFunction<ConfigureSection, PARAM> valueParser) {
|
public @NotNull SELF parse(@NotNull DataFunction<ConfigureSection, UNIT> valueParser) {
|
||||||
return parse((p, section) -> valueParser.handle(section));
|
return parse((p, section) -> valueParser.handle(section));
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull SELF parse(ValueHandler<ConfigureSection, PARAM> valueParser) {
|
public @NotNull SELF parse(@NotNull ValueHandler<ConfigureSection, UNIT> valueParser) {
|
||||||
this.parser = valueParser;
|
this.parser = valueParser;
|
||||||
return self();
|
return self();
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull SELF serialize(DataFunction<PARAM, ? extends Map<String, Object>> serializer) {
|
public @NotNull SELF serialize(@NotNull ValueHandler<UNIT, ? extends Map<String, Object>> serializer) {
|
||||||
return serialize((p, value) -> serializer.handle(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NotNull SELF serialize(ValueHandler<PARAM, ? extends Map<String, Object>> serializer) {
|
|
||||||
this.serializer = serializer;
|
this.serializer = serializer;
|
||||||
return self();
|
return self();
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull SELF serialize(DataConsumer<Map<String, Object>> serializer) {
|
public @NotNull SELF serialize(@NotNull DataFunction<UNIT, ? extends Map<String, Object>> serializer) {
|
||||||
return serialize((p, value) -> {
|
return serialize((p, value) -> serializer.handle(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull SELF serialize(@NotNull ValueComposer<Map<String, Object>, UNIT> serializer) {
|
||||||
|
return serialize((h, value) -> {
|
||||||
Map<String, Object> map = new LinkedHashMap<>();
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
serializer.accept(map);
|
serializer.accept(h, map, value);
|
||||||
return map;
|
return map;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ValueAdapter<PARAM> buildAdapter() {
|
protected ValueAdapter<UNIT> buildAdapter() {
|
||||||
return new ValueAdapter<>(this.paramType)
|
return new ValueAdapter<>(this.paramType)
|
||||||
.parser((p, type, data) -> {
|
.parser((p, type, data) -> {
|
||||||
ConfigureSection section = p.deserialize(ConfigureSection.class, data);
|
ConfigureSection section = p.deserialize(ConfigureSection.class, data);
|
||||||
|
|||||||
+14
-14
@@ -9,19 +9,19 @@ import cc.carm.lib.configuration.value.ConfigValue;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public abstract class AbstractSourceBuilder<
|
public abstract class AbstractSourceBuilder<
|
||||||
V, SOURCE, PARAM, RESULT extends ConfigValue<V>,
|
V, SOURCE, UNIT, RESULT extends ConfigValue<V, UNIT>,
|
||||||
SELF extends AbstractSourceBuilder<V, SOURCE, PARAM, RESULT, SELF>
|
SELF extends AbstractSourceBuilder<V, SOURCE, UNIT, RESULT, SELF>
|
||||||
> extends CommonConfigBuilder<V, RESULT, SELF> {
|
> extends CommonConfigBuilder<V, UNIT, RESULT, SELF> {
|
||||||
|
|
||||||
protected final @NotNull ValueType<SOURCE> sourceType;
|
protected final @NotNull ValueType<SOURCE> sourceType;
|
||||||
protected final @NotNull ValueType<PARAM> paramType;
|
protected final @NotNull ValueType<UNIT> paramType;
|
||||||
protected @NotNull ValueHandler<SOURCE, PARAM> valueParser;
|
protected @NotNull ValueHandler<SOURCE, UNIT> valueParser;
|
||||||
protected @NotNull ValueHandler<PARAM, SOURCE> valueSerializer;
|
protected @NotNull ValueHandler<UNIT, SOURCE> valueSerializer;
|
||||||
|
|
||||||
protected AbstractSourceBuilder(@NotNull ValueType<V> type,
|
protected AbstractSourceBuilder(@NotNull ValueType<V> type,
|
||||||
@NotNull ValueType<SOURCE> sourceType, @NotNull ValueType<PARAM> paramType,
|
@NotNull ValueType<SOURCE> sourceType, @NotNull ValueType<UNIT> paramType,
|
||||||
@NotNull ValueHandler<SOURCE, PARAM> parser,
|
@NotNull ValueHandler<SOURCE, UNIT> parser,
|
||||||
@NotNull ValueHandler<PARAM, SOURCE> serializer) {
|
@NotNull ValueHandler<UNIT, SOURCE> serializer) {
|
||||||
super(type);
|
super(type);
|
||||||
this.sourceType = sourceType;
|
this.sourceType = sourceType;
|
||||||
this.paramType = paramType;
|
this.paramType = paramType;
|
||||||
@@ -29,25 +29,25 @@ public abstract class AbstractSourceBuilder<
|
|||||||
this.valueSerializer = serializer;
|
this.valueSerializer = serializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull SELF parse(DataFunction<SOURCE, PARAM> parser) {
|
public @NotNull SELF parse(@NotNull DataFunction<SOURCE, UNIT> parser) {
|
||||||
return parse((p, source) -> parser.handle(source));
|
return parse((p, source) -> parser.handle(source));
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull SELF parse(@NotNull ValueHandler<SOURCE, PARAM> parser) {
|
public @NotNull SELF parse(@NotNull ValueHandler<SOURCE, UNIT> parser) {
|
||||||
this.valueParser = parser;
|
this.valueParser = parser;
|
||||||
return self();
|
return self();
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull SELF serialize(@NotNull ValueHandler<PARAM, SOURCE> serializer) {
|
public @NotNull SELF serialize(@NotNull ValueHandler<UNIT, SOURCE> serializer) {
|
||||||
this.valueSerializer = serializer;
|
this.valueSerializer = serializer;
|
||||||
return self();
|
return self();
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull SELF serialize(@NotNull DataFunction<PARAM, SOURCE> serializer) {
|
public @NotNull SELF serialize(@NotNull DataFunction<UNIT, SOURCE> serializer) {
|
||||||
return serialize((p, value) -> serializer.handle(value));
|
return serialize((p, value) -> serializer.handle(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ValueAdapter<PARAM> buildAdapter() {
|
protected ValueAdapter<UNIT> buildAdapter() {
|
||||||
return new ValueAdapter<>(this.paramType)
|
return new ValueAdapter<>(this.paramType)
|
||||||
.parser((holder, type, data) -> {
|
.parser((holder, type, data) -> {
|
||||||
SOURCE source = holder.deserialize(this.sourceType, data);
|
SOURCE source = holder.deserialize(this.sourceType, data);
|
||||||
|
|||||||
@@ -8,9 +8,11 @@ import cc.carm.lib.configuration.value.standard.ConfiguredList;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class SectionListBuilder<V> extends AbstractSectionBuilder<List<V>, V, ConfiguredList<V>, SectionListBuilder<V>> {
|
public class SectionListBuilder<V>
|
||||||
|
extends AbstractSectionBuilder<List<V>, V, ConfiguredList<V>, SectionListBuilder<V>> {
|
||||||
|
|
||||||
protected @NotNull Supplier<? extends List<V>> constructor;
|
protected @NotNull Supplier<? extends List<V>> constructor;
|
||||||
|
|
||||||
@@ -32,6 +34,14 @@ public class SectionListBuilder<V> extends AbstractSectionBuilder<List<V>, V, Co
|
|||||||
return defaults(new ArrayList<>(values));
|
return defaults(new ArrayList<>(values));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final @NotNull SectionListBuilder<V> defaults(@NotNull Consumer<List<V>> constructor) {
|
||||||
|
return defaults(() -> {
|
||||||
|
List<V> list = new ArrayList<>();
|
||||||
|
constructor.accept(list);
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public SectionListBuilder<V> constructor(@NotNull Supplier<? extends List<V>> constructor) {
|
public SectionListBuilder<V> constructor(@NotNull Supplier<? extends List<V>> constructor) {
|
||||||
this.constructor = constructor;
|
this.constructor = constructor;
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class SourceListBuilder<SOURCE, V>
|
public class SourceListBuilder<SOURCE, V>
|
||||||
@@ -34,6 +35,23 @@ public class SourceListBuilder<SOURCE, V>
|
|||||||
return defaults(new ArrayList<>(values));
|
return defaults(new ArrayList<>(values));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final @NotNull SourceListBuilder<SOURCE, V> defaults(@NotNull Consumer<List<V>> constructor) {
|
||||||
|
return defaults(() -> {
|
||||||
|
List<V> list = new ArrayList<>();
|
||||||
|
constructor.accept(list);
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public SourceListBuilder<SOURCE, V> constructor(@NotNull Supplier<? extends List<V>> constructor) {
|
||||||
|
this.constructor = constructor;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <LIST extends List<V>> SourceListBuilder<SOURCE, V> construct(@NotNull LIST list) {
|
||||||
|
return constructor(() -> list);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected @NotNull SourceListBuilder<SOURCE, V> self() {
|
protected @NotNull SourceListBuilder<SOURCE, V> self() {
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -3,10 +3,7 @@ package cc.carm.lib.configuration.builder.map;
|
|||||||
import cc.carm.lib.configuration.adapter.ValueType;
|
import cc.carm.lib.configuration.adapter.ValueType;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class ConfigMapCreator<K, V> {
|
public class ConfigMapCreator<K, V> {
|
||||||
@@ -45,4 +42,8 @@ public class ConfigMapCreator<K, V> {
|
|||||||
return constructor(TreeMap::new);
|
return constructor(TreeMap::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @NotNull ConfigMapBuilder<TreeMap<K, V>, K, V> asTreeMap(@NotNull Comparator<? super K> comparator) {
|
||||||
|
return constructor(() -> new TreeMap<>(comparator));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -14,10 +14,7 @@ import java.util.function.Consumer;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class SectionMapBuilder<MAP extends Map<K, V>, K, V>
|
public class SectionMapBuilder<MAP extends Map<K, V>, K, V>
|
||||||
extends AbstractSectionBuilder<
|
extends AbstractSectionBuilder<Map<K, V>, V, ConfiguredMap<K, V>, SectionMapBuilder<MAP, K, V>> {
|
||||||
Map<K, V>, V, ConfiguredMap<K, V>,
|
|
||||||
SectionMapBuilder<MAP, K, V>
|
|
||||||
> {
|
|
||||||
|
|
||||||
protected final @NotNull ValueType<K> keyType;
|
protected final @NotNull ValueType<K> keyType;
|
||||||
|
|
||||||
@@ -75,6 +72,10 @@ public class SectionMapBuilder<MAP extends Map<K, V>, K, V>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @NotNull SectionMapBuilder<MAP, K, V> defaults(@NotNull K key, @NotNull V value) {
|
||||||
|
return defaults(map -> map.put(key, value));
|
||||||
|
}
|
||||||
|
|
||||||
public @NotNull ValueAdapter<K> buildKeyAdapter() {
|
public @NotNull ValueAdapter<K> buildKeyAdapter() {
|
||||||
return new ValueAdapter<>(this.keyType)
|
return new ValueAdapter<>(this.keyType)
|
||||||
.parser((holder, type, data) -> {
|
.parser((holder, type, data) -> {
|
||||||
|
|||||||
@@ -13,10 +13,7 @@ import java.util.function.Consumer;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class SourceMapBuilder<MAP extends Map<K, V>, SOURCE, K, V>
|
public class SourceMapBuilder<MAP extends Map<K, V>, SOURCE, K, V>
|
||||||
extends AbstractSourceBuilder<
|
extends AbstractSourceBuilder<Map<K, V>, SOURCE, V, ConfiguredMap<K, V>, SourceMapBuilder<MAP, SOURCE, K, V>> {
|
||||||
Map<K, V>, SOURCE, V, ConfiguredMap<K, V>,
|
|
||||||
SourceMapBuilder<MAP, SOURCE, K, V>
|
|
||||||
> {
|
|
||||||
|
|
||||||
protected final @NotNull ValueType<K> keyType;
|
protected final @NotNull ValueType<K> keyType;
|
||||||
|
|
||||||
@@ -53,6 +50,10 @@ public class SourceMapBuilder<MAP extends Map<K, V>, SOURCE, K, V>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @NotNull SourceMapBuilder<MAP, SOURCE, K, V> defaults(@NotNull K key, @NotNull V value) {
|
||||||
|
return defaults(map -> map.put(key, value));
|
||||||
|
}
|
||||||
|
|
||||||
public @NotNull SourceMapBuilder<MAP, SOURCE, K, V> parseKey(@NotNull DataFunction<String, K> keyParser) {
|
public @NotNull SourceMapBuilder<MAP, SOURCE, K, V> parseKey(@NotNull DataFunction<String, K> keyParser) {
|
||||||
return parseKey((holder, data) -> keyParser.handle(data));
|
return parseKey((holder, data) -> keyParser.handle(data));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package cc.carm.lib.configuration.builder.value;
|
package cc.carm.lib.configuration.builder.value;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.adapter.ValueType;
|
import cc.carm.lib.configuration.adapter.ValueType;
|
||||||
import cc.carm.lib.configuration.builder.impl.AbstractSectionBuilder;
|
|
||||||
import cc.carm.lib.configuration.function.ValueHandler;
|
import cc.carm.lib.configuration.function.ValueHandler;
|
||||||
import cc.carm.lib.configuration.source.section.ConfigureSection;
|
import cc.carm.lib.configuration.source.section.ConfigureSection;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import cc.carm.lib.configuration.function.ValueHandler;
|
|||||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class SourceValueBuilder<S, V> extends AbstractSourceBuilder<V, S, V, ConfiguredValue<V>, SourceValueBuilder<S, V>> {
|
public class SourceValueBuilder<S, V>
|
||||||
|
extends AbstractSourceBuilder<V, S, V, ConfiguredValue<V>, SourceValueBuilder<S, V>> {
|
||||||
|
|
||||||
|
|
||||||
public SourceValueBuilder(@NotNull ValueType<S> sourceType, @NotNull ValueType<V> valueType,
|
public SourceValueBuilder(@NotNull ValueType<S> sourceType, @NotNull ValueType<V> valueType,
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package cc.carm.lib.configuration.function;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ConfigExceptionHandler {
|
||||||
|
|
||||||
|
void handle(@NotNull String path, @NotNull Throwable throwable);
|
||||||
|
|
||||||
|
static @NotNull ConfigExceptionHandler silence() {
|
||||||
|
return (path, throwable) -> {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static @NotNull ConfigExceptionHandler print() {
|
||||||
|
return (path, throwable) -> {
|
||||||
|
System.err.println("Error occurred at path: " + path);
|
||||||
|
throwable.printStackTrace();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package cc.carm.lib.configuration.function;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface DataValidator<T> {
|
||||||
|
|
||||||
|
void validate(@Nullable T value) throws Exception;
|
||||||
|
|
||||||
|
default DataValidator<T> compose(DataValidator<? super T> other) {
|
||||||
|
return value -> {
|
||||||
|
validate(value);
|
||||||
|
other.validate(value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package cc.carm.lib.configuration.function;
|
||||||
|
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ValueComposer<T, U> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accept the value and the data, and then compose the value.
|
||||||
|
*
|
||||||
|
* @param holder The configuration holder
|
||||||
|
* @param type The value type, e.g. {@link java.util.List}, {@link java.util.Map}, etc.
|
||||||
|
* @param data The unit data
|
||||||
|
* @throws Exception If an error occurs
|
||||||
|
*/
|
||||||
|
void accept(@NotNull ConfigurationHolder<?> holder, @NotNull T type, @NotNull U data) throws Exception;
|
||||||
|
|
||||||
|
default ValueComposer<T, U> andThen(ValueComposer<? super T, ? super U> after) {
|
||||||
|
return (holder, unit, data) -> {
|
||||||
|
accept(holder, unit, data);
|
||||||
|
after.accept(holder, unit, data);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package cc.carm.lib.configuration.function;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ValueValidator<T> {
|
||||||
|
|
||||||
|
void validate(@NotNull ConfigurationHolder<?> holder, @Nullable T value) throws Exception;
|
||||||
|
|
||||||
|
default ValueValidator<T> and(ValueValidator<? super T> other) {
|
||||||
|
return (holder, value) -> {
|
||||||
|
validate(holder, value);
|
||||||
|
other.validate(holder, value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static <V> ValueValidator<V> none() {
|
||||||
|
return (holder, data) -> {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static <V> ValueValidator<V> nonnull() {
|
||||||
|
return nonnull("Value cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
static <V> ValueValidator<V> nonnull(String message) {
|
||||||
|
return (holder, data) -> {
|
||||||
|
if (data == null) throw new IllegalArgumentException(message);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static <V extends Number> ValueValidator<V> range(V min, V max) {
|
||||||
|
return range(min, max, "Value must be in range [" + min + ", " + max + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
static <V extends Number> ValueValidator<V> range(V min, V max, String message) {
|
||||||
|
return (holder, data) -> {
|
||||||
|
if (data.doubleValue() < min.doubleValue() || data.doubleValue() > max.doubleValue()) {
|
||||||
|
throw new IllegalArgumentException(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,7 +2,9 @@ package cc.carm.lib.configuration.source;
|
|||||||
|
|
||||||
import cc.carm.lib.configuration.adapter.*;
|
import cc.carm.lib.configuration.adapter.*;
|
||||||
import cc.carm.lib.configuration.adapter.strandard.StandardAdapters;
|
import cc.carm.lib.configuration.adapter.strandard.StandardAdapters;
|
||||||
|
import cc.carm.lib.configuration.function.ConfigExceptionHandler;
|
||||||
import cc.carm.lib.configuration.function.DataFunction;
|
import cc.carm.lib.configuration.function.DataFunction;
|
||||||
|
import cc.carm.lib.configuration.function.ValueValidator;
|
||||||
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
|
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
|
||||||
import cc.carm.lib.configuration.source.loader.PathGenerator;
|
import cc.carm.lib.configuration.source.loader.PathGenerator;
|
||||||
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
|
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
|
||||||
@@ -20,21 +22,30 @@ import java.util.function.Consumer;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConfigurationFactory, used to create configuration holder.
|
||||||
|
*
|
||||||
|
* @param <SOURCE> The {@link ConfigureSource} type
|
||||||
|
* @param <HOLDER> The {@link ConfigurationHolder} type.
|
||||||
|
* @param <SELF> Self builder, for further implement support.
|
||||||
|
*/
|
||||||
public abstract class ConfigurationFactory<
|
public abstract class ConfigurationFactory<
|
||||||
SOURCE extends ConfigureSource<?, ?, SOURCE>,
|
SOURCE extends ConfigureSource<?, ?, SOURCE>,
|
||||||
HOLDER extends ConfigurationHolder<SOURCE>,
|
HOLDER extends ConfigurationHolder<SOURCE>,
|
||||||
SELF
|
SELF
|
||||||
> {
|
> {
|
||||||
|
|
||||||
protected ValueAdapterRegistry adapters = new ValueAdapterRegistry();
|
protected @NotNull ValueAdapterRegistry adapters = new ValueAdapterRegistry();
|
||||||
protected ConfigurationOptionHolder options = new ConfigurationOptionHolder();
|
protected @NotNull ConfigurationOptionHolder options = new ConfigurationOptionHolder();
|
||||||
protected @NotNull Map<String, ConfigurationMetaHolder> metadata = new HashMap<>();
|
protected @NotNull Map<String, ConfigurationMetaHolder> metadata = new HashMap<>();
|
||||||
protected ConfigurationInitializer initializer = new ConfigurationInitializer();
|
protected @NotNull ConfigurationInitializer initializer = new ConfigurationInitializer();
|
||||||
|
protected @NotNull ConfigExceptionHandler exceptionHandler = ConfigExceptionHandler.print();
|
||||||
|
|
||||||
public ConfigurationFactory() {
|
protected ConfigurationFactory() {
|
||||||
this.adapters.register(StandardAdapters.PRIMITIVES);
|
this.adapters.register(StandardAdapters.PRIMITIVES);
|
||||||
this.adapters.register(StandardAdapters.SECTIONS);
|
this.adapters.register(StandardAdapters.SECTIONS);
|
||||||
this.adapters.register(StandardAdapters.ENUMS);
|
this.adapters.register(StandardAdapters.ENUMS);
|
||||||
|
this.adapters.register(StandardAdapters.UUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract SELF self();
|
protected abstract SELF self();
|
||||||
@@ -139,18 +150,55 @@ public abstract class ConfigurationFactory<
|
|||||||
return self();
|
return self();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SELF pathGenerator(PathGenerator generator) {
|
public SELF exceptionally(@NotNull ConfigExceptionHandler handler) {
|
||||||
return initializer(loader -> {
|
this.exceptionHandler = handler;
|
||||||
loader.pathGenerator(generator);
|
return self();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supply the base path generator for this configuration holder
|
||||||
|
*
|
||||||
|
* @param generator {@link PathGenerator}
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SELF pathGenerator(PathGenerator generator) {
|
||||||
|
return initializer(loader -> loader.pathGenerator(generator));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new annotation for metadata to the configuration loader
|
||||||
|
*
|
||||||
|
* @param annotation The {@link Annotation}
|
||||||
|
* @param metadata The {@link ConfigurationMetadata} type
|
||||||
|
* @param extractor The {@link Function} to extract the metadata from the annotation
|
||||||
|
* @param <M> The metadata type
|
||||||
|
* @param <A> The annotation type
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
public <M, A extends Annotation> SELF metaAnnotation(@NotNull Class<A> annotation,
|
public <M, A extends Annotation> SELF metaAnnotation(@NotNull Class<A> annotation,
|
||||||
@NotNull ConfigurationMetadata<M> metadata,
|
@NotNull ConfigurationMetadata<M> metadata,
|
||||||
@NotNull Function<A, M> extractor) {
|
@NotNull Function<A, M> extractor) {
|
||||||
return initializer(loader -> loader.registerAnnotation(annotation, metadata, extractor));
|
return initializer(loader -> loader.registerAnnotation(annotation, metadata, extractor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new annotation for {@link ValueValidator} to the configuration loader
|
||||||
|
*
|
||||||
|
* @param annotation The {@link Annotation}
|
||||||
|
* @param builder The {@link Function} to build the {@link ValueValidator} from the annotation
|
||||||
|
* @param <A> The annotation type
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public <A extends Annotation> SELF validAnnotation(@NotNull Class<A> annotation,
|
||||||
|
@NotNull Function<A, ValueValidator<Object>> builder) {
|
||||||
|
return initializer(loader -> loader.registerValidAnnotation(annotation, builder));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the configuration holder.
|
||||||
|
*
|
||||||
|
* @return The configuration holder
|
||||||
|
*/
|
||||||
public abstract @NotNull HOLDER build();
|
public abstract @NotNull HOLDER build();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,16 @@ package cc.carm.lib.configuration.source;
|
|||||||
import cc.carm.lib.configuration.Configuration;
|
import cc.carm.lib.configuration.Configuration;
|
||||||
import cc.carm.lib.configuration.adapter.ValueAdapterRegistry;
|
import cc.carm.lib.configuration.adapter.ValueAdapterRegistry;
|
||||||
import cc.carm.lib.configuration.adapter.ValueType;
|
import cc.carm.lib.configuration.adapter.ValueType;
|
||||||
|
import cc.carm.lib.configuration.function.ConfigExceptionHandler;
|
||||||
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
|
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
|
||||||
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
|
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
|
||||||
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
|
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
|
||||||
|
import cc.carm.lib.configuration.source.meta.StandardMeta;
|
||||||
|
import cc.carm.lib.configuration.source.option.ConfigurationOption;
|
||||||
import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder;
|
import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder;
|
||||||
import cc.carm.lib.configuration.source.section.ConfigureSource;
|
import cc.carm.lib.configuration.source.section.ConfigureSource;
|
||||||
|
import cc.carm.lib.configuration.value.ConfigValue;
|
||||||
import cc.carm.lib.configuration.value.ValueManifest;
|
import cc.carm.lib.configuration.value.ValueManifest;
|
||||||
import org.jetbrains.annotations.Contract;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.annotations.UnmodifiableView;
|
import org.jetbrains.annotations.UnmodifiableView;
|
||||||
@@ -17,6 +20,8 @@ import org.jetbrains.annotations.UnmodifiableView;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, SOURCE>> {
|
public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, SOURCE>> {
|
||||||
|
|
||||||
@@ -26,14 +31,25 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
|
|||||||
|
|
||||||
protected final @NotNull ConfigurationInitializer initializer;
|
protected final @NotNull ConfigurationInitializer initializer;
|
||||||
|
|
||||||
|
protected @NotNull ConfigExceptionHandler exceptionHandler;
|
||||||
|
|
||||||
public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters,
|
public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters,
|
||||||
@NotNull ConfigurationOptionHolder options,
|
@NotNull ConfigurationOptionHolder options,
|
||||||
@NotNull Map<String, ConfigurationMetaHolder> metadata,
|
@NotNull Map<String, ConfigurationMetaHolder> metadata,
|
||||||
@NotNull ConfigurationInitializer initializer) {
|
@NotNull ConfigurationInitializer initializer) {
|
||||||
|
this(adapters, options, metadata, initializer, ConfigExceptionHandler.print());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters,
|
||||||
|
@NotNull ConfigurationOptionHolder options,
|
||||||
|
@NotNull Map<String, ConfigurationMetaHolder> metadata,
|
||||||
|
@NotNull ConfigurationInitializer initializer,
|
||||||
|
@NotNull ConfigExceptionHandler exceptionHandler) {
|
||||||
this.initializer = initializer;
|
this.initializer = initializer;
|
||||||
this.adapters = adapters;
|
this.adapters = adapters;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.metadata = metadata;
|
this.metadata = metadata;
|
||||||
|
this.exceptionHandler = exceptionHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract @NotNull SOURCE config();
|
public abstract @NotNull SOURCE config();
|
||||||
@@ -50,6 +66,10 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
|
|||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <O> @NotNull O option(@NotNull ConfigurationOption<O> option) {
|
||||||
|
return options().get(option);
|
||||||
|
}
|
||||||
|
|
||||||
public @NotNull Map<String, ConfigurationMetaHolder> metadata() {
|
public @NotNull Map<String, ConfigurationMetaHolder> metadata() {
|
||||||
return this.metadata;
|
return this.metadata;
|
||||||
}
|
}
|
||||||
@@ -61,14 +81,26 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
|
|||||||
@NotNull
|
@NotNull
|
||||||
@UnmodifiableView
|
@UnmodifiableView
|
||||||
public <M> Map<String, M> extractMetadata(@NotNull ConfigurationMetadata<M> type) {
|
public <M> Map<String, M> extractMetadata(@NotNull ConfigurationMetadata<M> type) {
|
||||||
|
return extractMetadata(type, Objects::nonNull);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@UnmodifiableView
|
||||||
|
public <M> Map<String, M> extractMetadata(@NotNull ConfigurationMetadata<M> type, @NotNull Predicate<@Nullable M> filter) {
|
||||||
Map<String, M> metas = new LinkedHashMap<>();
|
Map<String, M> metas = new LinkedHashMap<>();
|
||||||
for (Map.Entry<String, ConfigurationMetaHolder> entry : this.metadata.entrySet()) {
|
for (Map.Entry<String, ConfigurationMetaHolder> entry : this.metadata.entrySet()) {
|
||||||
M data = entry.getValue().get(type);
|
M data = entry.getValue().get(type);
|
||||||
if (data != null) metas.put(entry.getKey(), data);
|
if (filter.test(data)) metas.put(entry.getKey(), data);
|
||||||
}
|
}
|
||||||
return Collections.unmodifiableMap(metas);
|
return Collections.unmodifiableMap(metas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@UnmodifiableView
|
||||||
|
public Map<String, ConfigValue<?, ?>> registeredValues() {
|
||||||
|
return extractMetadata(StandardMeta.VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
public ValueAdapterRegistry adapters() {
|
public ValueAdapterRegistry adapters() {
|
||||||
return this.adapters;
|
return this.adapters;
|
||||||
}
|
}
|
||||||
@@ -77,17 +109,17 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
|
|||||||
return initializer;
|
return initializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract("_,null -> null")
|
@Nullable
|
||||||
public <T> T deserialize(@NotNull Class<T> type, @Nullable Object source) throws Exception {
|
public <T> T deserialize(@NotNull Class<T> type, @Nullable Object source) throws Exception {
|
||||||
return adapters().deserialize(this, type, source);
|
return adapters().deserialize(this, type, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract("_,null -> null")
|
@Nullable
|
||||||
public <T> T deserialize(@NotNull ValueType<T> type, @Nullable Object source) throws Exception {
|
public <T> T deserialize(@NotNull ValueType<T> type, @Nullable Object source) throws Exception {
|
||||||
return adapters().deserialize(this, type, source);
|
return adapters().deserialize(this, type, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract("null -> null")
|
@Nullable
|
||||||
public <T> Object serialize(@Nullable T value) throws Exception {
|
public <T> Object serialize(@Nullable T value) throws Exception {
|
||||||
return adapters().serialize(this, value);
|
return adapters().serialize(this, value);
|
||||||
}
|
}
|
||||||
@@ -96,7 +128,7 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
|
|||||||
try {
|
try {
|
||||||
initializer.initialize(this, configClass);
|
initializer.initialize(this, configClass);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
throwing(configClass.getName(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,12 +136,20 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
|
|||||||
try {
|
try {
|
||||||
initializer.initialize(this, config);
|
initializer.initialize(this, config);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
throwing(config.getClass().getName(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initialize(@NotNull ValueManifest<?> value) {
|
public void initialize(@NotNull ValueManifest<?, ?> value) {
|
||||||
value.holder(this);
|
value.holder(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void throwing(@NotNull String path, @NotNull Throwable e) {
|
||||||
|
this.exceptionHandler.handle(path, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void exceptionally(@NotNull ConfigExceptionHandler handler) {
|
||||||
|
this.exceptionHandler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-12
@@ -5,26 +5,27 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface ConfigInitializeHandler<T> {
|
public interface ConfigInitializeHandler<T, V> {
|
||||||
|
|
||||||
static <T> ConfigInitializeHandler<T> start() {
|
static <T, V> ConfigInitializeHandler<T, V> start() {
|
||||||
return (provider, path, value) -> {
|
return (provider, path, value, instance) -> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void whenInitialize(@NotNull ConfigurationHolder<?> holder, @Nullable String path, @NotNull T value) throws Exception;
|
void whenInitialize(@NotNull ConfigurationHolder<?> holder, @Nullable String path,
|
||||||
|
@NotNull T value, @Nullable V instance) throws Exception;
|
||||||
|
|
||||||
default ConfigInitializeHandler<T> andThen(ConfigInitializeHandler<T> after) {
|
default ConfigInitializeHandler<T, V> andThen(ConfigInitializeHandler<T, V> after) {
|
||||||
return (provider, path, value) -> {
|
return (provider, path, value, instance) -> {
|
||||||
whenInitialize(provider, path, value);
|
whenInitialize(provider, path, value, instance);
|
||||||
after.whenInitialize(provider, path, value);
|
after.whenInitialize(provider, path, value, instance);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
default ConfigInitializeHandler<T> compose(ConfigInitializeHandler<T> before) {
|
default ConfigInitializeHandler<T, V> compose(ConfigInitializeHandler<T, V> before) {
|
||||||
return (provider, path, value) -> {
|
return (provider, path, value, instance) -> {
|
||||||
before.whenInitialize(provider, path, value);
|
before.whenInitialize(provider, path, value, instance);
|
||||||
whenInitialize(provider, path, value);
|
whenInitialize(provider, path, value, instance);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+45
-31
@@ -1,8 +1,10 @@
|
|||||||
package cc.carm.lib.configuration.source.loader;
|
package cc.carm.lib.configuration.source.loader;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.Configuration;
|
import cc.carm.lib.configuration.Configuration;
|
||||||
|
import cc.carm.lib.configuration.function.ValueValidator;
|
||||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
|
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
|
||||||
|
import cc.carm.lib.configuration.source.meta.StandardMeta;
|
||||||
import cc.carm.lib.configuration.source.option.StandardOptions;
|
import cc.carm.lib.configuration.source.option.StandardOptions;
|
||||||
import cc.carm.lib.configuration.value.ConfigValue;
|
import cc.carm.lib.configuration.value.ConfigValue;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -20,18 +22,18 @@ import java.util.function.Function;
|
|||||||
public class ConfigurationInitializer {
|
public class ConfigurationInitializer {
|
||||||
|
|
||||||
protected @NotNull PathGenerator pathGenerator;
|
protected @NotNull PathGenerator pathGenerator;
|
||||||
protected @NotNull ConfigInitializeHandler<Field> fieldInitializer;
|
protected @NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> valueInitializer;
|
||||||
protected @NotNull ConfigInitializeHandler<Class<? extends Configuration>> classInitializer;
|
protected @NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer;
|
||||||
|
|
||||||
public ConfigurationInitializer() {
|
public ConfigurationInitializer() {
|
||||||
this(PathGenerator.of(), ConfigInitializeHandler.start(), ConfigInitializeHandler.start());
|
this(PathGenerator.of(), ConfigInitializeHandler.start(), ConfigInitializeHandler.start());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigurationInitializer(@NotNull PathGenerator pathGenerator,
|
public ConfigurationInitializer(@NotNull PathGenerator pathGenerator,
|
||||||
@NotNull ConfigInitializeHandler<Field> fieldInitializer,
|
@NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> valueInitializer,
|
||||||
@NotNull ConfigInitializeHandler<Class<? extends Configuration>> classInitializer) {
|
@NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer) {
|
||||||
this.pathGenerator = pathGenerator;
|
this.pathGenerator = pathGenerator;
|
||||||
this.fieldInitializer = fieldInitializer;
|
this.valueInitializer = valueInitializer;
|
||||||
this.classInitializer = classInitializer;
|
this.classInitializer = classInitializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,34 +45,34 @@ public class ConfigurationInitializer {
|
|||||||
return pathGenerator;
|
return pathGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigInitializeHandler<Field> fieldInitializer() {
|
public ConfigInitializeHandler<Field, ConfigValue<?, ?>> fieldInitializer() {
|
||||||
return fieldInitializer;
|
return valueInitializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fieldInitializer(@NotNull ConfigInitializeHandler<Field> fieldInitializer) {
|
public void fieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> fieldInitializer) {
|
||||||
this.fieldInitializer = fieldInitializer;
|
this.valueInitializer = fieldInitializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigInitializeHandler<Class<? extends Configuration>> classInitializer() {
|
public ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer() {
|
||||||
return classInitializer;
|
return classInitializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void classInitializer(@NotNull ConfigInitializeHandler<Class<? extends Configuration>> classInitializer) {
|
public void classInitializer(@NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer) {
|
||||||
this.classInitializer = classInitializer;
|
this.classInitializer = classInitializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void appendFieldInitializer(@NotNull ConfigInitializeHandler<Field> fieldInitializer) {
|
public void appendFieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> fieldInitializer) {
|
||||||
this.fieldInitializer = this.fieldInitializer.andThen(fieldInitializer);
|
this.valueInitializer = this.valueInitializer.andThen(fieldInitializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void appendClassInitializer(@NotNull ConfigInitializeHandler<Class<? extends Configuration>> classInitializer) {
|
public void appendClassInitializer(@NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer) {
|
||||||
this.classInitializer = this.classInitializer.andThen(classInitializer);
|
this.classInitializer = this.classInitializer.andThen(classInitializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T, A extends Annotation> void registerClassAnnotation(@NotNull Class<A> annotation,
|
public <T, A extends Annotation> void registerClassAnnotation(@NotNull Class<A> annotation,
|
||||||
@NotNull ConfigurationMetadata<T> metadata,
|
@NotNull ConfigurationMetadata<T> metadata,
|
||||||
@NotNull Function<A, T> extractor) {
|
@NotNull Function<A, T> extractor) {
|
||||||
appendClassInitializer((holder, path, clazz) -> {
|
appendClassInitializer((holder, path, clazz, instance) -> {
|
||||||
A data = clazz.getAnnotation(annotation);
|
A data = clazz.getAnnotation(annotation);
|
||||||
if (data == null) return;
|
if (data == null) return;
|
||||||
holder.metadata(path).setIfAbsent(metadata, extractor.apply(data));
|
holder.metadata(path).setIfAbsent(metadata, extractor.apply(data));
|
||||||
@@ -80,7 +82,7 @@ public class ConfigurationInitializer {
|
|||||||
public <T, A extends Annotation> void registerFieldAnnotation(@NotNull Class<A> annotation,
|
public <T, A extends Annotation> void registerFieldAnnotation(@NotNull Class<A> annotation,
|
||||||
@NotNull ConfigurationMetadata<T> metadata,
|
@NotNull ConfigurationMetadata<T> metadata,
|
||||||
@NotNull Function<A, T> extractor) {
|
@NotNull Function<A, T> extractor) {
|
||||||
appendFieldInitializer((holder, path, field) -> {
|
appendFieldInitializer((holder, path, field, instance) -> {
|
||||||
A data = field.getAnnotation(annotation);
|
A data = field.getAnnotation(annotation);
|
||||||
if (data == null) return;
|
if (data == null) return;
|
||||||
holder.metadata(path).setIfAbsent(metadata, extractor.apply(data));
|
holder.metadata(path).setIfAbsent(metadata, extractor.apply(data));
|
||||||
@@ -94,6 +96,14 @@ public class ConfigurationInitializer {
|
|||||||
registerFieldAnnotation(annotation, metadata, extractor);
|
registerFieldAnnotation(annotation, metadata, extractor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <A extends Annotation> void registerValidAnnotation(@NotNull Class<A> annotation,
|
||||||
|
@NotNull Function<A, ValueValidator<Object>> builder) {
|
||||||
|
appendFieldInitializer((holder, path, field, instance) -> {
|
||||||
|
A data = field.getAnnotation(annotation);
|
||||||
|
if (data == null) return;
|
||||||
|
instance.validate((h, t) -> builder.apply(data).validate(h, t));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public @Nullable String getFieldPath(@NotNull ConfigurationHolder<?> holder, @Nullable String parentPath, @NotNull Field field) {
|
public @Nullable String getFieldPath(@NotNull ConfigurationHolder<?> holder, @Nullable String parentPath, @NotNull Field field) {
|
||||||
return pathGenerator.getFieldPath(holder, parentPath, field);
|
return pathGenerator.getFieldPath(holder, parentPath, field);
|
||||||
@@ -107,13 +117,13 @@ public class ConfigurationInitializer {
|
|||||||
public void initialize(@NotNull ConfigurationHolder<?> holder,
|
public void initialize(@NotNull ConfigurationHolder<?> holder,
|
||||||
@NotNull Configuration config) throws Exception {
|
@NotNull Configuration config) throws Exception {
|
||||||
initializeInstance(holder, config, null, null);
|
initializeInstance(holder, config, null, null);
|
||||||
if (holder.options().get(StandardOptions.SET_DEFAULTS)) holder.save();
|
if (holder.option(StandardOptions.SET_DEFAULTS)) holder.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initialize(@NotNull ConfigurationHolder<?> holder,
|
public void initialize(@NotNull ConfigurationHolder<?> holder,
|
||||||
@NotNull Class<? extends Configuration> clazz) throws Exception {
|
@NotNull Class<? extends Configuration> clazz) throws Exception {
|
||||||
initializeStaticClass(holder, clazz, null, null);
|
initializeStaticClass(holder, clazz, null, null);
|
||||||
if (holder.options().get(StandardOptions.SET_DEFAULTS)) holder.save();
|
if (holder.option(StandardOptions.SET_DEFAULTS)) holder.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -122,9 +132,9 @@ public class ConfigurationInitializer {
|
|||||||
@Nullable String parentPath, @Nullable Field configField) {
|
@Nullable String parentPath, @Nullable Field configField) {
|
||||||
String path = getClassPath(holder, parentPath, root.getClass(), configField);
|
String path = getClassPath(holder, parentPath, root.getClass(), configField);
|
||||||
try {
|
try {
|
||||||
this.classInitializer.whenInitialize(holder, path, root.getClass());
|
this.classInitializer.whenInitialize(holder, path, root.getClass(), root);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
holder.throwing(path, e);
|
||||||
}
|
}
|
||||||
Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(holder, root, field, path));
|
Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(holder, root, field, path));
|
||||||
}
|
}
|
||||||
@@ -139,16 +149,16 @@ public class ConfigurationInitializer {
|
|||||||
String path = getClassPath(holder, parentPath, clazz, configField);
|
String path = getClassPath(holder, parentPath, clazz, configField);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.classInitializer.whenInitialize(holder, path, (Class<? extends Configuration>) clazz);
|
this.classInitializer.whenInitialize(holder, path, (Class<? extends Configuration>) clazz, configField);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
holder.throwing(path, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Field field : clazz.getDeclaredFields()) {
|
for (Field field : clazz.getDeclaredFields()) {
|
||||||
initializeField(holder, clazz, field, path);
|
initializeField(holder, clazz, field, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (holder.options().get(StandardOptions.LOAD_SUB_CLASSES)) {
|
if (holder.option(StandardOptions.LOAD_SUB_CLASSES)) {
|
||||||
Class<?>[] classes = clazz.getDeclaredClasses();
|
Class<?>[] classes = clazz.getDeclaredClasses();
|
||||||
for (int i = classes.length - 1; i >= 0; i--) { // 逆向加载,保持顺序。
|
for (int i = classes.length - 1; i >= 0; i--) { // 逆向加载,保持顺序。
|
||||||
initializeStaticClass(holder, classes[i], path, null);
|
initializeStaticClass(holder, classes[i], path, null);
|
||||||
@@ -162,19 +172,23 @@ public class ConfigurationInitializer {
|
|||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
Object object = field.get(source);
|
Object object = field.get(source);
|
||||||
//
|
//
|
||||||
if (object instanceof ConfigValue<?>) {
|
if (object instanceof ConfigValue<?, ?>) {
|
||||||
// 目标是 ConfigValue 实例,进行具体的初始化注入
|
// 目标是 ConfigValue 实例,进行具体的初始化注入
|
||||||
ConfigValue<?> value = (ConfigValue<?>) object;
|
ConfigValue<?, ?> value = (ConfigValue<?, ?>) object;
|
||||||
String path = getFieldPath(holder, parent, field);
|
String path = getFieldPath(holder, parent, field);
|
||||||
if (path == null) return;
|
if (path == null) return;
|
||||||
value.initialize(holder, path);
|
value.initialize(holder, path);
|
||||||
try {
|
holder.metadata(path).set(StandardMeta.VALUE, value); // Mark the minimal config value unit.
|
||||||
this.fieldInitializer.whenInitialize(holder, path, field);
|
if (holder.option(StandardOptions.SET_DEFAULTS)) {
|
||||||
} catch (Exception e) {
|
value.setDefault(); // Set default value.
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
if (holder.options().get(StandardOptions.SET_DEFAULTS)) {
|
try {
|
||||||
value.setDefault();
|
this.valueInitializer.whenInitialize(holder, path, field, value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
holder.throwing(path, e);
|
||||||
|
}
|
||||||
|
if (holder.option(StandardOptions.PRELOAD)) {
|
||||||
|
value.get(); // Preload the value by calling #get method.
|
||||||
}
|
}
|
||||||
} else if (source instanceof Configuration && object instanceof Configuration) {
|
} else if (source instanceof Configuration && object instanceof Configuration) {
|
||||||
// 当且仅当 源字段与字段 均为Configuration实例时,才对目标字段进行下一步初始化加载。
|
// 当且仅当 源字段与字段 均为Configuration实例时,才对目标字段进行下一步初始化加载。
|
||||||
|
|||||||
@@ -9,6 +9,12 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.function.UnaryOperator;
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path generator for configuration.
|
||||||
|
* <p>
|
||||||
|
* Path generator is a utility class that helps to generate the path of the configuration.
|
||||||
|
* It can be used to generate the path of the field or class.
|
||||||
|
*/
|
||||||
public class PathGenerator {
|
public class PathGenerator {
|
||||||
|
|
||||||
public static PathGenerator of() {
|
public static PathGenerator of() {
|
||||||
@@ -80,7 +86,7 @@ public class PathGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static char pathSeparator(ConfigurationHolder<?> holder) {
|
public static char pathSeparator(ConfigurationHolder<?> holder) {
|
||||||
return holder.options().get(StandardOptions.PATH_SEPARATOR);
|
return holder.option(StandardOptions.PATH_SEPARATOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package cc.carm.lib.configuration.source.meta;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.value.ConfigValue;
|
||||||
|
|
||||||
|
public interface StandardMeta {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To mark the {@link ConfigValue} instance of specific path.
|
||||||
|
*/
|
||||||
|
ConfigurationMetadata<ConfigValue<?, ?>> VALUE = ConfigurationMetadata.of();
|
||||||
|
|
||||||
|
}
|
||||||
+2
-14
@@ -6,32 +6,20 @@ import java.util.function.Supplier;
|
|||||||
|
|
||||||
public class ConfigurationOption<V> {
|
public class ConfigurationOption<V> {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <T> ConfigurationOption<T> of(@NotNull T defaultValue) {
|
public static <T> ConfigurationOption<T> of(@NotNull T defaultValue) {
|
||||||
return of((Class<T>) defaultValue.getClass(), defaultValue);
|
return new ConfigurationOption<>(defaultValue);
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> ConfigurationOption<T> of(@NotNull Class<T> valueClazz, @NotNull T defaultValue) {
|
|
||||||
return new ConfigurationOption<>(valueClazz, defaultValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> ConfigurationOption<T> of(@NotNull Supplier<T> defaultValue) {
|
public static <T> ConfigurationOption<T> of(@NotNull Supplier<T> defaultValue) {
|
||||||
return of(defaultValue.get());
|
return of(defaultValue.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
private final @NotNull Class<V> valueClazz;
|
|
||||||
private @NotNull V defaultValue;
|
private @NotNull V defaultValue;
|
||||||
|
|
||||||
public ConfigurationOption(@NotNull Class<V> valueClazz, @NotNull V defaultValue) {
|
public ConfigurationOption(@NotNull V defaultValue) {
|
||||||
this.valueClazz = valueClazz;
|
|
||||||
this.defaultValue = defaultValue;
|
this.defaultValue = defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public Class<V> valueClass() {
|
|
||||||
return this.valueClazz;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NotNull V defaults() {
|
public @NotNull V defaults() {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,12 +23,13 @@ public interface StandardOptions {
|
|||||||
ConfigurationOption<Boolean> LOAD_SUB_CLASSES = of(true);
|
ConfigurationOption<Boolean> LOAD_SUB_CLASSES = of(true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to pre parse the config values.
|
* Whether to pre parse the config values,
|
||||||
* <br> if false, the values will be parsed when calling
|
* may good to set true if you want to keep the config format.
|
||||||
* {@link cc.carm.lib.configuration.value.ConfigValue#get()}
|
|
||||||
* <br> if true, the values will be parsed when
|
* <br> if true, the values will be parsed when
|
||||||
* {@link ConfigurationHolder#initialize(Configuration)}.
|
* {@link ConfigurationHolder#initialize(Configuration)}.
|
||||||
|
* <br> if false, the values will be parsed when calling
|
||||||
|
* {@link cc.carm.lib.configuration.value.ConfigValue#get()}
|
||||||
*/
|
*/
|
||||||
ConfigurationOption<Boolean> PRELOAD = of(false);
|
ConfigurationOption<Boolean> PRELOAD = of(true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+627
-39
@@ -1,73 +1,451 @@
|
|||||||
package cc.carm.lib.configuration.source.section;
|
package cc.carm.lib.configuration.source.section;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.function.DataFunction;
|
import cc.carm.lib.configuration.function.DataFunction;
|
||||||
import cc.carm.lib.configuration.source.option.StandardOptions;
|
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.annotations.UnmodifiableView;
|
import org.jetbrains.annotations.UnmodifiableView;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a section of a configuration.
|
||||||
|
*
|
||||||
|
* @author Carm
|
||||||
|
* @since 4.0.0
|
||||||
|
*/
|
||||||
public interface ConfigureSection {
|
public interface ConfigureSection {
|
||||||
|
|
||||||
@NotNull ConfigureSource<?, ?, ?> source();
|
/**
|
||||||
|
* Gets the parent section of this section.
|
||||||
|
* <p>
|
||||||
|
* For root sections, this will return null.
|
||||||
|
*
|
||||||
|
* @return Parent section, or null if this is a root section.
|
||||||
|
*/
|
||||||
|
@Contract(pure = true)
|
||||||
@Nullable ConfigureSection parent();
|
@Nullable ConfigureSection parent();
|
||||||
|
|
||||||
default char separator() {
|
/**
|
||||||
return source().holder().options().get(StandardOptions.PATH_SEPARATOR);
|
* Get the current section's path from {@link #parent()} of this section.
|
||||||
|
*
|
||||||
|
* @return The current path of this section, if {@link #isRoot()}, return empty string.
|
||||||
|
*/
|
||||||
|
@NotNull String path();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the full path of this section.
|
||||||
|
*
|
||||||
|
* @return The full path of this section, if {@link #isRoot()}, return empty string.
|
||||||
|
*/
|
||||||
|
default @NotNull String fullPath() {
|
||||||
|
if (parent() == null) return "";
|
||||||
|
return (parent().isRoot() ? "" : parent().fullPath() + pathSeparator()) + path();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path separator for the section.
|
||||||
|
*
|
||||||
|
* @return The path separator
|
||||||
|
*/
|
||||||
|
default char pathSeparator() {
|
||||||
|
return '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if this section is a root section.
|
||||||
|
*
|
||||||
|
* @return True if this section is a root section, false otherwise.
|
||||||
|
*/
|
||||||
|
@Contract(pure = true)
|
||||||
|
default boolean isRoot() {
|
||||||
|
return parent() == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if this section is empty.
|
||||||
|
*
|
||||||
|
* @return True if this section is empty, false otherwise.
|
||||||
|
*/
|
||||||
|
default boolean isEmpty() {
|
||||||
|
return getValues(false).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of keys in this section.
|
||||||
|
*
|
||||||
|
* @return Number of keys in this section.
|
||||||
|
*/
|
||||||
|
default int size(boolean deep) {
|
||||||
|
return getKeys(deep).size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a set containing all keys in this section.
|
||||||
|
* <p>
|
||||||
|
* If deep is set to true, then this will contain all the keys within any
|
||||||
|
* child {@link ConfigureSection}s (and their children paths).
|
||||||
|
* <p>
|
||||||
|
* If deep is set to false, then this will contain only the keys of any
|
||||||
|
* direct children, and not their own children.
|
||||||
|
*
|
||||||
|
* @param deep Whether to get a deep list.
|
||||||
|
* @return Set of keys contained within this Section.
|
||||||
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
@UnmodifiableView
|
@UnmodifiableView
|
||||||
default Set<String> getKeys(boolean deep) {
|
default Set<String> getKeys(boolean deep) {
|
||||||
return getValues(deep).keySet();
|
return getValues(deep).keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a set containing all primary keys in this section.
|
||||||
|
*
|
||||||
|
* @return Set of keys contained within this Section.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@UnmodifiableView
|
||||||
|
default Set<String> keys() {
|
||||||
|
return getKeys(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a set containing all values in this section.
|
||||||
|
* <p>
|
||||||
|
* If deep is set to true, then this will contain all the keys within any
|
||||||
|
* child {@link ConfigureSection}s (and their children paths).
|
||||||
|
* <p>
|
||||||
|
* If deep is set to false, then this will contain only the keys of any
|
||||||
|
* direct children, and not their own children.
|
||||||
|
*
|
||||||
|
* @param deep Whether to get a deep list.
|
||||||
|
* @return Map of data values contained within this Section.
|
||||||
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
@UnmodifiableView
|
@UnmodifiableView
|
||||||
Map<String, Object> getValues(boolean deep);
|
Map<String, Object> getValues(boolean deep);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a set containing all key-values in this section.
|
||||||
|
*
|
||||||
|
* @return Map of data values contained within this Section.
|
||||||
|
* @see #getValues(boolean)
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@UnmodifiableView
|
||||||
|
default Map<String, Object> values() {
|
||||||
|
return getValues(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get this section as a map.
|
||||||
|
* <p>
|
||||||
|
* In this map, child {@link ConfigureSection}s will also be represented as {@link Map}s.
|
||||||
|
*
|
||||||
|
* @return Map of data values contained within this Section.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@UnmodifiableView
|
||||||
|
Map<String, Object> asMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a stream of all values in this section.
|
||||||
|
*
|
||||||
|
* @return Stream of all values in this section.
|
||||||
|
*/
|
||||||
|
default Stream<Map.Entry<String, Object>> stream() {
|
||||||
|
return values().entrySet().stream();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates over all key-values in this section (include child sections)
|
||||||
|
*
|
||||||
|
* @param action The action to apply to each key.
|
||||||
|
*/
|
||||||
|
default void forEach(@NotNull BiConsumer<String, Object> action) {
|
||||||
|
values().forEach(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value at the given path.
|
||||||
|
* <p>
|
||||||
|
* Null values will be kept, if you want to remove a value use {@link #remove(String)}
|
||||||
|
* Path separator depends on holder's
|
||||||
|
* {@link cc.carm.lib.configuration.source.option.StandardOptions#PATH_SEPARATOR}
|
||||||
|
*
|
||||||
|
* @param path The path to set the value at.
|
||||||
|
* @param value The value to set.
|
||||||
|
*/
|
||||||
void set(@NotNull String path, @Nullable Object value);
|
void set(@NotNull String path, @Nullable Object value);
|
||||||
|
|
||||||
boolean contains(@NotNull String path);
|
/**
|
||||||
|
* Removes the value at the given path.
|
||||||
|
* <p>
|
||||||
|
* Path separator depends on holder's
|
||||||
|
* {@link cc.carm.lib.configuration.source.option.StandardOptions#PATH_SEPARATOR}
|
||||||
|
*
|
||||||
|
* @param path The path to remove the value at.
|
||||||
|
*/
|
||||||
|
void remove(@NotNull String path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given path is present.
|
||||||
|
* <p>
|
||||||
|
* Path separator depends on holder's
|
||||||
|
* {@link cc.carm.lib.configuration.source.option.StandardOptions#PATH_SEPARATOR}
|
||||||
|
*
|
||||||
|
* @param path The path to check.
|
||||||
|
* @return True if the value is present, false otherwise.
|
||||||
|
*/
|
||||||
|
default boolean contains(@NotNull String path) {
|
||||||
|
return getKeys(true).contains(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the value of given path is present.
|
||||||
|
* <p>
|
||||||
|
* Path separator depends on holder's
|
||||||
|
* {@link cc.carm.lib.configuration.source.option.StandardOptions#PATH_SEPARATOR}
|
||||||
|
*
|
||||||
|
* @param path The path to check.
|
||||||
|
* @return True if the value is present, false otherwise.
|
||||||
|
*/
|
||||||
|
default boolean containsValue(@NotNull String path) {
|
||||||
|
return get(path) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate the value of given path is specific type.
|
||||||
|
*
|
||||||
|
* @param path The path to check.
|
||||||
|
* @param typeClass The type's class
|
||||||
|
* @param <T> The type to check.
|
||||||
|
* @return True if the value is present and is the correct type, false otherwise.
|
||||||
|
*/
|
||||||
default <T> boolean isType(@NotNull String path, @NotNull Class<T> typeClass) {
|
default <T> boolean isType(@NotNull String path, @NotNull Class<T> typeClass) {
|
||||||
return typeClass.isInstance(get(path));
|
return typeClass.isInstance(get(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate the value of given path is a {@link List}.
|
||||||
|
*
|
||||||
|
* @param path The path to check.
|
||||||
|
* @return True if the value is present and is a list, false otherwise.
|
||||||
|
*/
|
||||||
default boolean isList(@NotNull String path) {
|
default boolean isList(@NotNull String path) {
|
||||||
return isType(path, List.class);
|
return isType(path, List.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable List<?> getList(@NotNull String path);
|
/**
|
||||||
|
* Get the value as a {@link List} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the {@link List}.
|
||||||
|
* @return The list if the path exists and is a list, otherwise null.
|
||||||
|
*/
|
||||||
|
default @Nullable List<?> getList(@NotNull String path) {
|
||||||
|
Object val = get(path);
|
||||||
|
return (val instanceof List<?>) ? (List<?>) val : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate the value of given path is a {@link ConfigureSection}.
|
||||||
|
*
|
||||||
|
* @param path The path to check.
|
||||||
|
* @return True if the value is present and is a section, false otherwise.
|
||||||
|
*/
|
||||||
default boolean isSection(@NotNull String path) {
|
default boolean isSection(@NotNull String path) {
|
||||||
return isType(path, ConfigureSection.class);
|
return isType(path, ConfigureSection.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link ConfigureSection} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the section.
|
||||||
|
* @return The section if the path exists and is a section, otherwise null.
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
ConfigureSection getSection(@NotNull String path);
|
default ConfigureSection getSection(@NotNull String path) {
|
||||||
|
Object val = get(path);
|
||||||
@Nullable Object get(@NotNull String path);
|
return (val instanceof ConfigureSection) ? (ConfigureSection) val : null;
|
||||||
|
|
||||||
default @Nullable <T> T get(@NotNull String path, @NotNull Class<T> clazz) {
|
|
||||||
return get(path, null, clazz);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default @Nullable <T> T get(@NotNull String path, @NotNull DataFunction<Object, T> parser) {
|
/**
|
||||||
|
* Creates a new {@link ConfigureSection} with specified values.
|
||||||
|
* <p> The {@link #parent()} of the new section will be this section.
|
||||||
|
* <p> This section will not be saved until {@link #set(String, Object)} is called.
|
||||||
|
* <p> If you want to create and use a section and set it to this section, use {@link #computeSection(String)}.
|
||||||
|
*
|
||||||
|
* @param data The data to be used to create section.
|
||||||
|
* @return Newly created section
|
||||||
|
*/
|
||||||
|
@NotNull ConfigureSection createSection(@NotNull String path, @NotNull Map<?, ?> data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ConfigureSection} with specified values.
|
||||||
|
* <p> The {@link #parent()} of the new section will be this section.
|
||||||
|
*
|
||||||
|
* @param data The data to be used to create section.
|
||||||
|
* @return Newly created section
|
||||||
|
*/
|
||||||
|
default @NotNull ConfigureSection createSection(@NotNull String path, @NotNull Consumer<Map<String, Object>> data) {
|
||||||
|
return createSection(path, () -> {
|
||||||
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
data.accept(map);
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ConfigureSection} with specified values.
|
||||||
|
* <p> The {@link #parent()} of the new section will be this section.
|
||||||
|
*
|
||||||
|
* @param data The data to be used to create section.
|
||||||
|
* @return Newly created section
|
||||||
|
*/
|
||||||
|
default @NotNull ConfigureSection createSection(@NotNull String path, @NotNull Supplier<Map<String, Object>> data) {
|
||||||
|
return createSection(path, data.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new empty {@link ConfigureSection}.
|
||||||
|
* <p> The {@link #parent()} of the new section will be this section.
|
||||||
|
*
|
||||||
|
* @return Newly created section
|
||||||
|
*/
|
||||||
|
default @NotNull ConfigureSection createSection(@NotNull String path) {
|
||||||
|
return createSection(path, new LinkedHashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or create a section at the given path.
|
||||||
|
* <p>
|
||||||
|
* Any value previously set at this path will be replaced if it is not a section
|
||||||
|
* or will be returned if it is an exists {@link ConfigureSection}.
|
||||||
|
*
|
||||||
|
* @param path The path to get the section from.
|
||||||
|
* @return The section at the path, or a new section if it does not exist.
|
||||||
|
* @see #createSection(String, Map)
|
||||||
|
*/
|
||||||
|
default @NotNull ConfigureSection computeSection(@NotNull String path) {
|
||||||
|
return computeSection(path, new LinkedHashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or create a section at the given path.
|
||||||
|
* <p>
|
||||||
|
* Any value previously set at this path will be replaced if it is not a section
|
||||||
|
* or will be returned if it is an exists {@link ConfigureSection}.
|
||||||
|
*
|
||||||
|
* @param path The path to get the section from.
|
||||||
|
* @return The section at the path, or a new section if it does not exist.
|
||||||
|
* @see #createSection(String, Map)
|
||||||
|
*/
|
||||||
|
default @NotNull ConfigureSection computeSection(@NotNull String path, @NotNull Map<?, ?> data) {
|
||||||
|
ConfigureSection current = getSection(path);
|
||||||
|
if (current == null) {
|
||||||
|
current = createSection(path, data);
|
||||||
|
set(path, current);
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or create a section at the given path.
|
||||||
|
* <p>
|
||||||
|
* Any value previously set at this path will be replaced if it is not a section
|
||||||
|
* or will be returned if it is an exists {@link ConfigureSection}.
|
||||||
|
*
|
||||||
|
* @param path The path to get the section from.
|
||||||
|
* @return The section at the path, or a new section if it does not exist.
|
||||||
|
* @see #createSection(String, Map)
|
||||||
|
*/
|
||||||
|
default @NotNull ConfigureSection computeSection(@NotNull String path, @NotNull Consumer<Map<String, Object>> data) {
|
||||||
|
return computeSection(path, () -> {
|
||||||
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
data.accept(map);
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or create a section at the given path.
|
||||||
|
* <p>
|
||||||
|
* Any value previously set at this path will be replaced if it is not a section
|
||||||
|
* or will be returned if it is an exists {@link ConfigureSection}.
|
||||||
|
*
|
||||||
|
* @param path The path to get the section from.
|
||||||
|
* @return The section at the path, or a new section if it does not exist.
|
||||||
|
* @see #createSection(String, Map)
|
||||||
|
*/
|
||||||
|
default @NotNull ConfigureSection computeSection(@NotNull String path, @NotNull Supplier<Map<String, Object>> data) {
|
||||||
|
return computeSection(path, data.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the origin value of the path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the value from.
|
||||||
|
* @return The value at the path, or null if not found.
|
||||||
|
*/
|
||||||
|
@Nullable Object get(@NotNull String path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of the path for specific type,
|
||||||
|
* if the path does not exist, return null.
|
||||||
|
*
|
||||||
|
* @param path The path to get the value from.
|
||||||
|
* @param type The type class of the value
|
||||||
|
* @param <T> The type of the value
|
||||||
|
* @return The value at the path, or the default value if not found.
|
||||||
|
*/
|
||||||
|
default @Nullable <T> T get(@NotNull String path, @NotNull Class<T> type) {
|
||||||
|
return get(path, null, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of the path using a parser function,
|
||||||
|
* if the path does not exist, return NULL.
|
||||||
|
*
|
||||||
|
* @param path The path to get the value from.
|
||||||
|
* @param parser The function to parse the value
|
||||||
|
* @param <T> The type of the value
|
||||||
|
* @return The value at the path, or null if not found.
|
||||||
|
*/
|
||||||
|
default @Nullable <T> T get(@NotNull String path, @NotNull DataFunction<@Nullable Object, T> parser) {
|
||||||
return get(path, null, parser);
|
return get(path, null, parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of the path for specific type,
|
||||||
|
* if the path does not exist, return the default value.
|
||||||
|
*
|
||||||
|
* @param path The path to get the value from.
|
||||||
|
* @param defaults The default value to return if the path does not exist.
|
||||||
|
* @param clazz The type class of the value
|
||||||
|
* @param <T> The type of the value
|
||||||
|
* @return The value at the path, or the default value if not found.
|
||||||
|
*/
|
||||||
@Contract("_,!null,_->!null")
|
@Contract("_,!null,_->!null")
|
||||||
default @Nullable <T> T get(@NotNull String path, @Nullable T defaultValue, @NotNull Class<T> clazz) {
|
default @Nullable <T> T get(@NotNull String path, @Nullable T defaults, @NotNull Class<T> clazz) {
|
||||||
return get(path, defaultValue, DataFunction.castObject(clazz));
|
return get(path, defaults, DataFunction.castObject(clazz));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of the path using a parser function,
|
||||||
|
* if the path does not exist, return the default value.
|
||||||
|
*
|
||||||
|
* @param path The path to get the value from.
|
||||||
|
* @param defaultValue The default value to return if the path does not exist.
|
||||||
|
* @param parser The function to parse the value
|
||||||
|
* @param <T> The type of the value
|
||||||
|
* @return The value at the path, or the default value if not found.
|
||||||
|
*/
|
||||||
@Contract("_,!null,_->!null")
|
@Contract("_,!null,_->!null")
|
||||||
default @Nullable <T> T get(@NotNull String path, @Nullable T defaultValue,
|
default @Nullable <T> T get(@NotNull String path, @Nullable T defaultValue,
|
||||||
@NotNull DataFunction<Object, T> parser) {
|
@NotNull DataFunction<Object, T> parser) {
|
||||||
@@ -82,132 +460,297 @@ public interface ConfigureSection {
|
|||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate the value of given path is a {@link Boolean}.
|
||||||
|
*
|
||||||
|
* @param path The path to check.
|
||||||
|
* @return True if the value is present and is a boolean, false otherwise.
|
||||||
|
*/
|
||||||
default boolean isBoolean(@NotNull String path) {
|
default boolean isBoolean(@NotNull String path) {
|
||||||
return isType(path, Boolean.class);
|
return isType(path, Boolean.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link Boolean} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the boolean.
|
||||||
|
* @return The boolean if the path exists and is a boolean, otherwise false.
|
||||||
|
*/
|
||||||
default boolean getBoolean(@NotNull String path) {
|
default boolean getBoolean(@NotNull String path) {
|
||||||
return getBoolean(path, false);
|
return getBoolean(path, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link Boolean} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the boolean.
|
||||||
|
* @param def The default value to return if the path does not exist.
|
||||||
|
* @return The boolean if the path exists and is a boolean, otherwise the default value.
|
||||||
|
*/
|
||||||
@Contract("_, !null -> !null")
|
@Contract("_, !null -> !null")
|
||||||
default @Nullable Boolean getBoolean(@NotNull String path, @Nullable Boolean def) {
|
default @Nullable Boolean getBoolean(@NotNull String path, @Nullable Boolean def) {
|
||||||
return get(path, def, DataFunction.booleanValue());
|
return get(path, def, DataFunction.booleanValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate the value of given path is a {@link Byte}.
|
||||||
|
*
|
||||||
|
* @param path The path to check.
|
||||||
|
* @return True if the value is present and is a byte, false otherwise.
|
||||||
|
*/
|
||||||
default @Nullable Boolean isByte(@NotNull String path) {
|
default @Nullable Boolean isByte(@NotNull String path) {
|
||||||
return isType(path, Byte.class);
|
return isType(path, Byte.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link Byte} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the byte.
|
||||||
|
* @return The byte if the path exists and is a byte, otherwise 0.
|
||||||
|
*/
|
||||||
default @Nullable Byte getByte(@NotNull String path) {
|
default @Nullable Byte getByte(@NotNull String path) {
|
||||||
return getByte(path, (byte) 0);
|
return getByte(path, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link Byte} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the byte.
|
||||||
|
* @param def The default value to return if the path does not exist.
|
||||||
|
* @return The byte if the path exists and is a byte, otherwise the default value.
|
||||||
|
*/
|
||||||
@Contract("_, !null -> !null")
|
@Contract("_, !null -> !null")
|
||||||
default @Nullable Byte getByte(@NotNull String path, @Nullable Byte def) {
|
default @Nullable Byte getByte(@NotNull String path, @Nullable Byte def) {
|
||||||
return get(path, def, DataFunction.byteValue());
|
return get(path, def, DataFunction.byteValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate the value of given path is a {@link Short}.
|
||||||
|
*
|
||||||
|
* @param path The path to check.
|
||||||
|
* @return True if the value is present and is a short, false otherwise.
|
||||||
|
*/
|
||||||
default boolean isShort(@NotNull String path) {
|
default boolean isShort(@NotNull String path) {
|
||||||
return isType(path, Short.class);
|
return isType(path, Short.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link Short} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the short.
|
||||||
|
* @return The short if the path exists and is a short, otherwise 0.
|
||||||
|
*/
|
||||||
default @Nullable Short getShort(@NotNull String path) {
|
default @Nullable Short getShort(@NotNull String path) {
|
||||||
return getShort(path, (short) 0);
|
return getShort(path, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link Short} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the short.
|
||||||
|
* @param def The default value to return if the path does not exist.
|
||||||
|
* @return The short if the path exists and is a short, otherwise the default value.
|
||||||
|
*/
|
||||||
@Contract("_, !null -> !null")
|
@Contract("_, !null -> !null")
|
||||||
default @Nullable Short getShort(@NotNull String path, @Nullable Short def) {
|
default @Nullable Short getShort(@NotNull String path, @Nullable Short def) {
|
||||||
return get(path, def, DataFunction.shortValue());
|
return get(path, def, DataFunction.shortValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate the value of given path is a {@link Integer}.
|
||||||
|
*
|
||||||
|
* @param path The path to check.
|
||||||
|
* @return True if the value is present and is an int, false otherwise.
|
||||||
|
*/
|
||||||
default boolean isInt(@NotNull String path) {
|
default boolean isInt(@NotNull String path) {
|
||||||
return isType(path, Integer.class);
|
return isType(path, Integer.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link Integer} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the int.
|
||||||
|
* @return The int if the path exists and is an int, otherwise 0.
|
||||||
|
*/
|
||||||
default @Nullable Integer getInt(@NotNull String path) {
|
default @Nullable Integer getInt(@NotNull String path) {
|
||||||
return getInt(path, 0);
|
return getInt(path, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link Integer} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the int.
|
||||||
|
* @param def The default value to return if the path does not exist.
|
||||||
|
* @return The int if the path exists and is an int, otherwise the default value.
|
||||||
|
*/
|
||||||
@Contract("_, !null -> !null")
|
@Contract("_, !null -> !null")
|
||||||
default @Nullable Integer getInt(@NotNull String path, @Nullable Integer def) {
|
default @Nullable Integer getInt(@NotNull String path, @Nullable Integer def) {
|
||||||
return get(path, def, DataFunction.intValue());
|
return get(path, def, DataFunction.intValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate the value of given path is a {@link Long}.F
|
||||||
|
*
|
||||||
|
* @param path The path to check.
|
||||||
|
* @return True if the value is present and is a long, false otherwise.
|
||||||
|
*/
|
||||||
default boolean isLong(@NotNull String path) {
|
default boolean isLong(@NotNull String path) {
|
||||||
return isType(path, Long.class);
|
return isType(path, Long.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link Long} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the long.
|
||||||
|
* @return The long if the path exists and is a long, otherwise 0.
|
||||||
|
*/
|
||||||
default @Nullable Long getLong(@NotNull String path) {
|
default @Nullable Long getLong(@NotNull String path) {
|
||||||
return getLong(path, 0L);
|
return getLong(path, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link Long} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the long.
|
||||||
|
* @param def The default value to return if the path does not exist.
|
||||||
|
* @return The long if the path exists and is a long, otherwise the default value.
|
||||||
|
*/
|
||||||
@Contract("_, !null -> !null")
|
@Contract("_, !null -> !null")
|
||||||
default @Nullable Long getLong(@NotNull String path, @Nullable Long def) {
|
default @Nullable Long getLong(@NotNull String path, @Nullable Long def) {
|
||||||
return get(path, def, DataFunction.longValue());
|
return get(path, def, DataFunction.longValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate the value of given path is a {@link Float}.
|
||||||
|
*
|
||||||
|
* @param path The path to check.
|
||||||
|
* @return True if the value is present and is a float, false otherwise.
|
||||||
|
*/
|
||||||
default boolean isFloat(@NotNull String path) {
|
default boolean isFloat(@NotNull String path) {
|
||||||
return isType(path, Float.class);
|
return isType(path, Float.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link Float} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the float.
|
||||||
|
* @return The float if the path exists and is a float, otherwise 0.
|
||||||
|
*/
|
||||||
default @Nullable Float getFloat(@NotNull String path) {
|
default @Nullable Float getFloat(@NotNull String path) {
|
||||||
return getFloat(path, 0.0F);
|
return getFloat(path, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link Float} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the float.
|
||||||
|
* @param def The default value to return if the path does not exist.
|
||||||
|
* @return The float if the path exists and is a float, otherwise the default value.
|
||||||
|
*/
|
||||||
@Contract("_, !null -> !null")
|
@Contract("_, !null -> !null")
|
||||||
default @Nullable Float getFloat(@NotNull String path, @Nullable Float def) {
|
default @Nullable Float getFloat(@NotNull String path, @Nullable Float def) {
|
||||||
return get(path, def, DataFunction.floatValue());
|
return get(path, def, DataFunction.floatValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate the value of given path is a {@link Double}.
|
||||||
|
*
|
||||||
|
* @param path The path to check.
|
||||||
|
* @return True if the value is present and is a double, false otherwise.
|
||||||
|
*/
|
||||||
default boolean isDouble(@NotNull String path) {
|
default boolean isDouble(@NotNull String path) {
|
||||||
return isType(path, Double.class);
|
return isType(path, Double.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link Double} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the double.
|
||||||
|
* @return The double if the path exists and is a double, otherwise 0.
|
||||||
|
*/
|
||||||
default @Nullable Double getDouble(@NotNull String path) {
|
default @Nullable Double getDouble(@NotNull String path) {
|
||||||
return getDouble(path, 0.0D);
|
return getDouble(path, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link Double} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the double.
|
||||||
|
* @param def The default value to return if the path does not exist.
|
||||||
|
* @return The double if the path exists and is a double, otherwise the default value.
|
||||||
|
*/
|
||||||
@Contract("_, !null -> !null")
|
@Contract("_, !null -> !null")
|
||||||
default @Nullable Double getDouble(@NotNull String path, @Nullable Double def) {
|
default @Nullable Double getDouble(@NotNull String path, @Nullable Double def) {
|
||||||
return get(path, def, DataFunction.doubleValue());
|
return get(path, def, DataFunction.doubleValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate the value of given path is a {@link Character}.
|
||||||
|
*
|
||||||
|
* @param path The path to check.
|
||||||
|
* @return True if the value is present and is a char, false otherwise.
|
||||||
|
*/
|
||||||
default boolean isChar(@NotNull String path) {
|
default boolean isChar(@NotNull String path) {
|
||||||
return isType(path, Boolean.class);
|
return isType(path, Character.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link Character} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the char.
|
||||||
|
* @return The char if the path exists and is a char, otherwise null.
|
||||||
|
*/
|
||||||
default @Nullable Character getChar(@NotNull String path) {
|
default @Nullable Character getChar(@NotNull String path) {
|
||||||
return getChar(path, null);
|
return getChar(path, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link Character} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the char.
|
||||||
|
* @param def The default value to return if the path does not exist.
|
||||||
|
* @return The char if the path exists and is a char, otherwise the default value.
|
||||||
|
*/
|
||||||
@Contract("_, !null -> !null")
|
@Contract("_, !null -> !null")
|
||||||
default @Nullable Character getChar(@NotNull String path, @Nullable Character def) {
|
default @Nullable Character getChar(@NotNull String path, @Nullable Character def) {
|
||||||
return get(path, def, Character.class);
|
return get(path, def, Character.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate the value of given path is a {@link String}.
|
||||||
|
*
|
||||||
|
* @param path The path to check.
|
||||||
|
* @return True if the value is present and is a string, false otherwise.
|
||||||
|
*/
|
||||||
default boolean isString(@NotNull String path) {
|
default boolean isString(@NotNull String path) {
|
||||||
return isType(path, String.class);
|
return isType(path, String.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link String} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the string.
|
||||||
|
* @return The string if the path exists and is a string, otherwise null.
|
||||||
|
*/
|
||||||
default @Nullable String getString(@NotNull String path) {
|
default @Nullable String getString(@NotNull String path) {
|
||||||
return getString(path, null);
|
return getString(path, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value as a {@link String} from the specified path.
|
||||||
|
*
|
||||||
|
* @param path The path to get the string.
|
||||||
|
* @param def The default value to return if the path does not exist.
|
||||||
|
* @return The string if the path exists and is a string, otherwise the default value.
|
||||||
|
*/
|
||||||
@Contract("_, !null -> !null")
|
@Contract("_, !null -> !null")
|
||||||
default @Nullable String getString(@NotNull String path, @Nullable String def) {
|
default @Nullable String getString(@NotNull String path, @Nullable String def) {
|
||||||
return get(path, def, String.class);
|
return get(path, def, String.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of values from the section
|
* Get a list of values from current section
|
||||||
* <p>
|
* <p>
|
||||||
* If the path does not exist, an empty list will be returned
|
* If the path does not exist, an empty list will be returned
|
||||||
* <br>Any changes please use {@link #set(String, Object)} after changes
|
* <br>Any changes please use {@link #set(String, Object)} after changes
|
||||||
@@ -222,7 +765,7 @@ public interface ConfigureSection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of strings from the section
|
* Get a list of strings from current section
|
||||||
* <p> Limitations see {@link #getList(String, DataFunction)}
|
* <p> Limitations see {@link #getList(String, DataFunction)}
|
||||||
*
|
*
|
||||||
* @param path The path to get the list from
|
* @param path The path to get the list from
|
||||||
@@ -233,7 +776,7 @@ public interface ConfigureSection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of integer from the section
|
* Get a list of integer from current section
|
||||||
* <p> Limitations see {@link #getList(String, DataFunction)}
|
* <p> Limitations see {@link #getList(String, DataFunction)}
|
||||||
*
|
*
|
||||||
* @param path The path to get the list from
|
* @param path The path to get the list from
|
||||||
@@ -244,7 +787,7 @@ public interface ConfigureSection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of long from the section
|
* Get a list of long from current section
|
||||||
* <p> Limitations see {@link #getList(String, DataFunction)}
|
* <p> Limitations see {@link #getList(String, DataFunction)}
|
||||||
*
|
*
|
||||||
* @param path The path to get the list from
|
* @param path The path to get the list from
|
||||||
@@ -255,7 +798,7 @@ public interface ConfigureSection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of double from the section
|
* Get a list of double from current section
|
||||||
* <p> Limitations see {@link #getList(String, DataFunction)}
|
* <p> Limitations see {@link #getList(String, DataFunction)}
|
||||||
*
|
*
|
||||||
* @param path The path to get the list from
|
* @param path The path to get the list from
|
||||||
@@ -266,7 +809,7 @@ public interface ConfigureSection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of floats from the section
|
* Get a list of floats from current section
|
||||||
* <p> Limitations see {@link #getList(String, DataFunction)}
|
* <p> Limitations see {@link #getList(String, DataFunction)}
|
||||||
*
|
*
|
||||||
* @param path The path to get the list from
|
* @param path The path to get the list from
|
||||||
@@ -277,7 +820,7 @@ public interface ConfigureSection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of bytes from the section
|
* Get a list of bytes from current section
|
||||||
* <p> Limitations see {@link #getList(String, DataFunction)}
|
* <p> Limitations see {@link #getList(String, DataFunction)}
|
||||||
*
|
*
|
||||||
* @param path The path to get the list from
|
* @param path The path to get the list from
|
||||||
@@ -288,7 +831,7 @@ public interface ConfigureSection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of char from the section
|
* Get a list of char from current section
|
||||||
* <p> Limitations see {@link #getList(String, DataFunction)}
|
* <p> Limitations see {@link #getList(String, DataFunction)}
|
||||||
*
|
*
|
||||||
* @param path The path to get the list from
|
* @param path The path to get the list from
|
||||||
@@ -298,23 +841,68 @@ public interface ConfigureSection {
|
|||||||
return getList(path, DataFunction.castObject(Character.class));
|
return getList(path, DataFunction.castObject(Character.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of {@link ConfigureSection} from current section
|
||||||
|
*
|
||||||
|
* @param path The path to get the list from
|
||||||
|
* @return The list of {@link ConfigureSection}
|
||||||
|
*/
|
||||||
|
default @NotNull List<ConfigureSection> getSectionList(@NotNull String path) {
|
||||||
|
return getList(path, obj -> {
|
||||||
|
if (obj instanceof ConfigureSection) {
|
||||||
|
return (ConfigureSection) obj;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the specific type of collection from current section.
|
||||||
|
*
|
||||||
|
* @param path The path to get the collection from
|
||||||
|
* @param constructor The constructor of the collection
|
||||||
|
* @param parser The function to parse the values
|
||||||
|
* @param <T> The type of the values
|
||||||
|
* @param <C> The type of the collection
|
||||||
|
* @return The collection of values
|
||||||
|
*/
|
||||||
default <T, C extends Collection<T>> @NotNull C getCollection(@NotNull String path,
|
default <T, C extends Collection<T>> @NotNull C getCollection(@NotNull String path,
|
||||||
@NotNull Supplier<C> constructor,
|
@NotNull Supplier<C> constructor,
|
||||||
@NotNull DataFunction<Object, T> parser) {
|
@NotNull DataFunction<Object, T> parser) {
|
||||||
return parseCollection(getList(path), constructor, parser);
|
return parseCollection(getList(path), constructor, parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the specific type of steam from current section.
|
||||||
|
*
|
||||||
|
* @param path The path to get the stream from
|
||||||
|
* @return The stream of values
|
||||||
|
*/
|
||||||
default @NotNull Stream<?> stream(@NotNull String path) {
|
default @NotNull Stream<?> stream(@NotNull String path) {
|
||||||
List<?> values = getList(path);
|
List<?> values = getList(path);
|
||||||
return values == null ? Stream.empty() : values.stream();
|
return values == null ? Stream.empty() : values.stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the specific type of steam from current section.
|
||||||
|
*
|
||||||
|
* @param path The path to get the stream from
|
||||||
|
* @param parser The function to parse the values
|
||||||
|
* @param <T> The type of the values
|
||||||
|
* @return The stream of values
|
||||||
|
*/
|
||||||
default <T> @NotNull Stream<T> stream(@NotNull String path, @NotNull Function<Object, T> parser) {
|
default <T> @NotNull Stream<T> stream(@NotNull String path, @NotNull Function<Object, T> parser) {
|
||||||
return stream(path).map(parser);
|
return stream(path).map(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default String childPath(String path) {
|
||||||
|
int index = path.indexOf(pathSeparator());
|
||||||
|
return (index == -1) ? path : path.substring(index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
static <T, C extends Collection<T>> @NotNull C parseCollection(
|
static <T, C extends Collection<T>> @NotNull C parseCollection(
|
||||||
@Nullable List<?> data, @NotNull Supplier<C> constructor,
|
@Nullable List<?> data,
|
||||||
|
@NotNull Supplier<C> constructor,
|
||||||
@NotNull DataFunction<Object, T> parser
|
@NotNull DataFunction<Object, T> parser
|
||||||
) {
|
) {
|
||||||
C values = constructor.get();
|
C values = constructor.get();
|
||||||
|
|||||||
@@ -1,12 +1,21 @@
|
|||||||
package cc.carm.lib.configuration.source.section;
|
package cc.carm.lib.configuration.source.section;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import cc.carm.lib.configuration.source.option.StandardOptions;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.*;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConfigureSource represents the source of configuration,
|
||||||
|
* which can be a file, a database, or any other source.
|
||||||
|
*
|
||||||
|
* @param <SECTION> The type of the root section.
|
||||||
|
* @param <ORIGINAL> The original configuration object.
|
||||||
|
* @param <SELF> The type of the source itself, for further implement support.
|
||||||
|
* @see ConfigureSection
|
||||||
|
*/
|
||||||
public abstract class ConfigureSource<
|
public abstract class ConfigureSource<
|
||||||
SECTION extends ConfigureSection, ORIGINAL,
|
SECTION extends ConfigureSection, ORIGINAL,
|
||||||
SELF extends ConfigureSource<SECTION, ORIGINAL, SELF>>
|
SELF extends ConfigureSource<SECTION, ORIGINAL, SELF>>
|
||||||
@@ -24,28 +33,46 @@ public abstract class ConfigureSource<
|
|||||||
return holder;
|
return holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void reload() throws Exception {
|
public void reload() throws Exception {
|
||||||
onReload(); // 调用重写的Reload方法
|
onReload(); // 调用重写的Reload方法
|
||||||
this.lastUpdateMillis = System.currentTimeMillis();
|
this.lastUpdateMillis = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract SELF self();
|
@Contract(pure = true)
|
||||||
|
@ApiStatus.Internal
|
||||||
|
protected abstract @NotNull SELF self();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Original configuration object
|
* @return The original configuration object.
|
||||||
*/
|
*/
|
||||||
|
@Contract(pure = true)
|
||||||
public abstract @NotNull ORIGINAL original();
|
public abstract @NotNull ORIGINAL original();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The root {@link ConfigureSection}
|
* @return The root {@link ConfigureSection}, which represents the entire configuration.
|
||||||
*/
|
*/
|
||||||
public abstract @NotNull SECTION section();
|
public abstract @NotNull SECTION section();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the whole configuration.
|
||||||
|
*
|
||||||
|
* @throws Exception If any error occurs while saving.
|
||||||
|
*/
|
||||||
public abstract void save() throws Exception;
|
public abstract void save() throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reload the configuration.
|
||||||
|
* <br>This used for implementation, for external usage, use {@link #reload()}
|
||||||
|
*
|
||||||
|
* @throws Exception If any error occurs while reloading.
|
||||||
|
*/
|
||||||
|
@ApiStatus.OverrideOnly
|
||||||
protected abstract void onReload() throws Exception;
|
protected abstract void onReload() throws Exception;
|
||||||
|
|
||||||
|
public char pathSeparator() {
|
||||||
|
return holder().options().get(StandardOptions.PATH_SEPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
public long getLastUpdateMillis() {
|
public long getLastUpdateMillis() {
|
||||||
return this.lastUpdateMillis;
|
return this.lastUpdateMillis;
|
||||||
}
|
}
|
||||||
@@ -54,14 +81,20 @@ public abstract class ConfigureSource<
|
|||||||
return getLastUpdateMillis() > parsedTime;
|
return getLastUpdateMillis() > parsedTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source also represents the root section, so it has no parent
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Contract(pure = true, value = "->null")
|
||||||
public @Nullable ConfigureSection parent() {
|
public @Nullable ConfigureSection parent() {
|
||||||
return null; // Source also represents the root section, so it has no parent
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull ConfigureSource<?, ?, ?> source() {
|
public @NotNull String path() {
|
||||||
return self();
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -69,34 +102,29 @@ public abstract class ConfigureSource<
|
|||||||
return section().getValues(deep);
|
return section().getValues(deep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Set<String> getKeys(boolean deep) {
|
||||||
|
return section().getKeys(deep);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Map<String, Object> asMap() {
|
||||||
|
return section().asMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ConfigureSection createSection(@NotNull String path, @NotNull Map<?, ?> data) {
|
||||||
|
return section().createSection(path, data);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void set(@NotNull String path, @Nullable Object value) {
|
public void set(@NotNull String path, @Nullable Object value) {
|
||||||
section().set(path, value);
|
section().set(path, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean contains(@NotNull String path) {
|
public void remove(@NotNull String path) {
|
||||||
return section().contains(path);
|
section().remove(path);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isList(@NotNull String path) {
|
|
||||||
return section().isList(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable List<?> getList(@NotNull String path) {
|
|
||||||
return section().getList(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSection(@NotNull String path) {
|
|
||||||
return section().isSection(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable ConfigureSection getSection(@NotNull String path) {
|
|
||||||
return section().getSection(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ import java.util.Optional;
|
|||||||
* @see ValueManifest Base class providing metadata and default value handling
|
* @see ValueManifest Base class providing metadata and default value handling
|
||||||
* @see ConfigurationHolder Responsible for configuration source persistence
|
* @see ConfigurationHolder Responsible for configuration source persistence
|
||||||
*/
|
*/
|
||||||
public abstract class ConfigValue<T> extends ValueManifest<T> {
|
public abstract class ConfigValue<T, U> extends ValueManifest<T, U> {
|
||||||
|
|
||||||
protected ConfigValue(@NotNull ValueManifest<T> manifest) {
|
protected ConfigValue(@NotNull ValueManifest<T, U> manifest) {
|
||||||
super(manifest);
|
super(manifest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ public abstract class ConfigValue<T> extends ValueManifest<T> {
|
|||||||
* @param override Whether to overwrite existing configured value
|
* @param override Whether to overwrite existing configured value
|
||||||
*/
|
*/
|
||||||
public void setDefault(boolean override) {
|
public void setDefault(boolean override) {
|
||||||
if (!override && config().contains(path())) return;
|
if (config().contains(path()) && !override) return; // Skip if the value is already set
|
||||||
set(defaults()); // Set the default value
|
set(defaults()); // Set the default value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,47 +1,59 @@
|
|||||||
package cc.carm.lib.configuration.value;
|
package cc.carm.lib.configuration.value;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.adapter.ValueType;
|
import cc.carm.lib.configuration.adapter.ValueType;
|
||||||
|
import cc.carm.lib.configuration.function.ValueValidator;
|
||||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
|
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
|
||||||
import cc.carm.lib.configuration.source.section.ConfigureSource;
|
import cc.carm.lib.configuration.source.section.ConfigureSource;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class ValueManifest<T> {
|
public class ValueManifest<TYPE, UNIT> {
|
||||||
|
|
||||||
protected final @NotNull ValueType<T> type;
|
protected final @NotNull ValueType<TYPE> type;
|
||||||
protected final @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer;
|
protected final @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer;
|
||||||
|
|
||||||
protected @Nullable ConfigurationHolder<?> holder;
|
protected @Nullable ConfigurationHolder<?> holder;
|
||||||
protected @Nullable String path; // Section path
|
protected @Nullable String path; // Section path
|
||||||
|
|
||||||
protected @NotNull Supplier<@Nullable T> defaultSupplier;
|
protected @NotNull ValueValidator<UNIT> validator;
|
||||||
|
protected @NotNull Supplier<@Nullable TYPE> defaultSupplier;
|
||||||
|
|
||||||
|
public ValueManifest(@NotNull ValueType<TYPE> type) {
|
||||||
public ValueManifest(@NotNull ValueType<T> type) {
|
this(type, () -> null, ValueValidator.none(), EMPTY_INITIALIZER, null, null);
|
||||||
this(type, () -> null, EMPTY_INITIALIZER, null, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueManifest(@NotNull T defaultValue) {
|
public ValueManifest(@NotNull TYPE defaultValue) {
|
||||||
this(ValueType.of(defaultValue), () -> defaultValue);
|
this(ValueType.of(defaultValue), () -> defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueManifest(@NotNull ValueType<T> type, @NotNull Supplier<@Nullable T> defaultSupplier) {
|
public ValueManifest(@NotNull ValueType<TYPE> type, @NotNull Supplier<@Nullable TYPE> defaultSupplier) {
|
||||||
this(type, defaultSupplier, EMPTY_INITIALIZER, null, null);
|
this(type, defaultSupplier, ValueValidator.none(), EMPTY_INITIALIZER, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueManifest(@NotNull ValueType<T> type, @NotNull Supplier<@Nullable T> defaultSupplier,
|
public ValueManifest(@NotNull ValueType<TYPE> type,
|
||||||
|
@NotNull Supplier<@Nullable TYPE> defaultSupplier,
|
||||||
|
@NotNull ValueValidator<UNIT> validator) {
|
||||||
|
this(type, defaultSupplier, validator, EMPTY_INITIALIZER, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueManifest(@NotNull ValueType<TYPE> type, @NotNull Supplier<@Nullable TYPE> defaultSupplier,
|
||||||
|
@NotNull ValueValidator<UNIT> validator,
|
||||||
@NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer) {
|
@NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer) {
|
||||||
this(type, defaultSupplier, initializer, null, null);
|
this(type, defaultSupplier, validator, initializer, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueManifest(@NotNull ValueType<T> type, @NotNull Supplier<@Nullable T> defaultSupplier,
|
public ValueManifest(@NotNull ValueType<TYPE> type,
|
||||||
|
@NotNull Supplier<@Nullable TYPE> defaultSupplier,
|
||||||
|
@NotNull ValueValidator<UNIT> validator,
|
||||||
@NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer,
|
@NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer,
|
||||||
@Nullable ConfigurationHolder<?> holder, @Nullable String path) {
|
@Nullable ConfigurationHolder<?> holder, @Nullable String path) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.validator = validator;
|
||||||
this.initializer = initializer;
|
this.initializer = initializer;
|
||||||
this.defaultSupplier = defaultSupplier;
|
this.defaultSupplier = defaultSupplier;
|
||||||
this.holder = holder;
|
this.holder = holder;
|
||||||
@@ -49,8 +61,8 @@ public class ValueManifest<T> {
|
|||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ValueManifest(@NotNull ValueManifest<T> manifest) {
|
protected ValueManifest(@NotNull ValueManifest<TYPE, UNIT> manifest) {
|
||||||
this(manifest.type, manifest.defaultSupplier, manifest.initializer, manifest.holder, manifest.path);
|
this(manifest.type, manifest.defaultSupplier, manifest.validator, manifest.initializer, manifest.holder, manifest.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initialize(@NotNull ConfigurationHolder<?> holder, @NotNull String path) {
|
public void initialize(@NotNull ConfigurationHolder<?> holder, @NotNull String path) {
|
||||||
@@ -63,7 +75,7 @@ public class ValueManifest<T> {
|
|||||||
if (holder != null && path != null) this.initializer.accept(holder, path);
|
if (holder != null && path != null) this.initializer.accept(holder, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull ValueType<T> type() {
|
public @NotNull ValueType<TYPE> type() {
|
||||||
return this.type;
|
return this.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,50 +87,77 @@ public class ValueManifest<T> {
|
|||||||
this.path = path;
|
this.path = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable T defaults() {
|
public @Nullable TYPE defaults() {
|
||||||
return this.defaultSupplier.get();
|
return this.defaultSupplier.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void defaults(@Nullable T defaultValue) {
|
public void defaults(@Nullable TYPE defaultValue) {
|
||||||
defaults(() -> defaultValue);
|
defaults(() -> defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void defaults(@NotNull Supplier<@Nullable T> defaultValue) {
|
public void defaults(@NotNull Supplier<@Nullable TYPE> defaultValue) {
|
||||||
this.defaultSupplier = defaultValue;
|
this.defaultSupplier = defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasDefaults() {
|
public boolean hasDefaults() {
|
||||||
return this.defaultSupplier.get() != null;
|
return defaults() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull ValueValidator<UNIT> validator() {
|
||||||
|
return this.validator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validator(@NotNull ValueValidator<UNIT> validator) {
|
||||||
|
this.validator = validator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validate(@NotNull ValueValidator<UNIT> validator) {
|
||||||
|
validator(this.validator.and(validator));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected UNIT withValidated(@Nullable UNIT value) throws Exception {
|
||||||
|
validator.validate(holder(), value);
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull String path() {
|
public @NotNull String path() {
|
||||||
if (path != null) return path;
|
if (path != null) return path;
|
||||||
else throw new IllegalStateException("No section path provided.");
|
else throw new IllegalStateException("No section path provided for Value(" + type() + ").");
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull ConfigurationHolder<?> holder() {
|
public @NotNull ConfigurationHolder<?> holder() {
|
||||||
if (this.holder != null) return this.holder;
|
if (this.holder != null) return this.holder;
|
||||||
throw new IllegalStateException("Value does not have a provider.");
|
throw new IllegalStateException("Value(" + type() + ") does not have a provider.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull ConfigureSource<?, ?, ?> config() {
|
public @NotNull ConfigureSource<?, ?, ?> config() {
|
||||||
return holder().config();
|
return holder().config();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigurationMetaHolder metadata() {
|
public @NotNull ConfigurationMetaHolder metadata() {
|
||||||
return holder().metadata(path());
|
return holder().metadata(path());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object getData() {
|
@ApiStatus.Internal
|
||||||
|
protected @Nullable Object getData() {
|
||||||
return config().get(path());
|
return config().get(path());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiStatus.Internal
|
||||||
protected void setData(@Nullable Object value) {
|
protected void setData(@Nullable Object value) {
|
||||||
config().set(path(), value);
|
config().set(path(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void throwing(@NotNull Throwable throwable) {
|
||||||
|
throwing(path, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
private static final @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> EMPTY_INITIALIZER = (provider, path) -> {
|
protected void throwing(@NotNull String path, @NotNull Throwable throwable) {
|
||||||
|
if (holder == null) throwable.printStackTrace();
|
||||||
|
else holder.throwing(path, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> EMPTY_INITIALIZER = (provider, valuePath) -> {
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import org.jetbrains.annotations.Contract;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public abstract class CachedConfigValue<T> extends ConfigValue<T> {
|
public abstract class CachedConfigValue<T, U> extends ConfigValue<T, U> {
|
||||||
|
|
||||||
protected @Nullable T cachedValue;
|
protected @Nullable T cachedValue;
|
||||||
protected long parsedTime = -1;
|
protected long parsedTime = -1;
|
||||||
|
|
||||||
protected CachedConfigValue(@NotNull ValueManifest<T> manifest) {
|
protected CachedConfigValue(@NotNull ValueManifest<T, U> manifest) {
|
||||||
super(manifest);
|
super(manifest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import cc.carm.lib.configuration.adapter.ValueParser;
|
|||||||
import cc.carm.lib.configuration.adapter.ValueSerializer;
|
import cc.carm.lib.configuration.adapter.ValueSerializer;
|
||||||
import cc.carm.lib.configuration.adapter.ValueType;
|
import cc.carm.lib.configuration.adapter.ValueType;
|
||||||
import cc.carm.lib.configuration.builder.list.ConfigListBuilder;
|
import cc.carm.lib.configuration.builder.list.ConfigListBuilder;
|
||||||
|
import cc.carm.lib.configuration.builder.list.SourceListBuilder;
|
||||||
import cc.carm.lib.configuration.value.ValueManifest;
|
import cc.carm.lib.configuration.value.ValueManifest;
|
||||||
import cc.carm.lib.configuration.value.impl.CachedConfigValue;
|
import cc.carm.lib.configuration.value.impl.CachedConfigValue;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -15,7 +16,7 @@ import java.util.function.Consumer;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements List<V> {
|
public class ConfiguredList<V> extends CachedConfigValue<List<V>, V> implements List<V> {
|
||||||
|
|
||||||
public static <T> @NotNull ConfigListBuilder<T> builderOf(@NotNull Class<T> type) {
|
public static <T> @NotNull ConfigListBuilder<T> builderOf(@NotNull Class<T> type) {
|
||||||
return builderOf(ValueType.of(type));
|
return builderOf(ValueType.of(type));
|
||||||
@@ -25,10 +26,26 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements Lis
|
|||||||
return new ConfigListBuilder<>(type);
|
return new ConfigListBuilder<>(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> @NotNull SourceListBuilder<T, T> with(@NotNull Class<T> registeredType) {
|
||||||
|
return with(ValueType.of(registeredType));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> @NotNull SourceListBuilder<T, T> with(@NotNull ValueType<T> registeredType) {
|
||||||
|
return new ConfigListBuilder<>(registeredType).from(registeredType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
public static <T> @NotNull ConfiguredList<T> of(@NotNull T value, @NotNull T... values) {
|
||||||
|
List<T> list = new ArrayList<>();
|
||||||
|
list.add(value);
|
||||||
|
Collections.addAll(list, values);
|
||||||
|
return with(ValueType.of(value)).defaults(list).build();
|
||||||
|
}
|
||||||
|
|
||||||
protected final @NotNull Supplier<? extends List<V>> constructor;
|
protected final @NotNull Supplier<? extends List<V>> constructor;
|
||||||
protected final @NotNull ValueAdapter<V> paramAdapter;
|
protected final @NotNull ValueAdapter<V> paramAdapter;
|
||||||
|
|
||||||
public ConfiguredList(@NotNull ValueManifest<List<V>> manifest,
|
public ConfiguredList(@NotNull ValueManifest<List<V>, V> manifest,
|
||||||
@NotNull Supplier<? extends List<V>> constructor,
|
@NotNull Supplier<? extends List<V>> constructor,
|
||||||
@NotNull ValueAdapter<V> paramAdapter) {
|
@NotNull ValueAdapter<V> paramAdapter) {
|
||||||
super(manifest);
|
super(manifest);
|
||||||
@@ -70,40 +87,46 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements Lis
|
|||||||
if (!cacheExpired()) return getCachedOrDefault(createList());
|
if (!cacheExpired()) return getCachedOrDefault(createList());
|
||||||
// Data that is outdated and needs to be parsed again.
|
// Data that is outdated and needs to be parsed again.
|
||||||
List<V> list = createList();
|
List<V> list = createList();
|
||||||
|
try {
|
||||||
List<?> data = config().contains(path()) ? config().getList(path()) : null;
|
List<?> data = config().contains(path()) ? config().getList(path()) : null;
|
||||||
if (data == null) return getDefaultFirst(list);
|
if (data == null) return getDefaultFirst(list);
|
||||||
|
|
||||||
ValueParser<V> parser = parser();
|
ValueParser<V> parser = parser();
|
||||||
if (parser == null) return getDefaultFirst(list);
|
if (parser == null) return getDefaultFirst(list);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
for (Object dataVal : data) {
|
for (Object dataVal : data) {
|
||||||
if (dataVal == null) continue;
|
if (dataVal == null) continue;
|
||||||
try {
|
try {
|
||||||
list.add(parser.parse(holder(), paramType(), dataVal));
|
list.add(withValidated(parser.parse(holder(), paramType(), dataVal)));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
throwing(path + "[" + i + "]", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throwing(ex);
|
||||||
|
}
|
||||||
return updateCache(list);
|
return updateCache(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void set(@Nullable List<V> value) {
|
public void set(@Nullable List<V> list) {
|
||||||
updateCache(value);
|
updateCache(list);
|
||||||
if (value == null) {
|
if (list == null) {
|
||||||
setData(null);
|
setData(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueSerializer<V> serializer = serializer();
|
ValueSerializer<V> serializer = serializer();
|
||||||
if (serializer == null) return;
|
if (serializer == null) return;
|
||||||
|
|
||||||
List<Object> data = new ArrayList<>();
|
List<Object> data = new ArrayList<>();
|
||||||
for (V val : value) {
|
for (V val : list) {
|
||||||
if (val == null) continue;
|
if (val == null) continue;
|
||||||
try {
|
try {
|
||||||
data.add(serializer.serialize(holder(), paramType(), val));
|
data.add(serializer.serialize(holder(), paramType(), withValidated(val)));
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
throwing(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setData(data);
|
setData(data);
|
||||||
|
|||||||
@@ -17,7 +17,11 @@ import java.util.function.Consumer;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements Map<K, V> {
|
public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>, V> implements Map<K, V> {
|
||||||
|
|
||||||
|
public static <V> ConfigMapCreator<String, V> builderOf(@NotNull Class<V> valueType) {
|
||||||
|
return builderOf(String.class, valueType);
|
||||||
|
}
|
||||||
|
|
||||||
public static <K, V> ConfigMapCreator<K, V> builderOf(@NotNull ValueType<K> keyType, @NotNull ValueType<V> valueType) {
|
public static <K, V> ConfigMapCreator<K, V> builderOf(@NotNull ValueType<K> keyType, @NotNull ValueType<V> valueType) {
|
||||||
return new ConfigMapCreator<>(keyType, valueType);
|
return new ConfigMapCreator<>(keyType, valueType);
|
||||||
@@ -38,7 +42,7 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
|
|||||||
protected final @NotNull ValueAdapter<K> keyAdapter;
|
protected final @NotNull ValueAdapter<K> keyAdapter;
|
||||||
protected final @NotNull ValueAdapter<V> valueAdapter;
|
protected final @NotNull ValueAdapter<V> valueAdapter;
|
||||||
|
|
||||||
public ConfiguredMap(@NotNull ValueManifest<Map<K, V>> manifest,
|
public ConfiguredMap(@NotNull ValueManifest<Map<K, V>, V> manifest,
|
||||||
@NotNull Supplier<? extends Map<K, V>> constructor,
|
@NotNull Supplier<? extends Map<K, V>> constructor,
|
||||||
@NotNull ValueAdapter<K> keyAdapter, @NotNull ValueAdapter<V> valueAdapter) {
|
@NotNull ValueAdapter<K> keyAdapter, @NotNull ValueAdapter<V> valueAdapter) {
|
||||||
super(manifest);
|
super(manifest);
|
||||||
@@ -73,6 +77,7 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
|
|||||||
// If the value is expired, we need to update it
|
// If the value is expired, we need to update it
|
||||||
Map<K, V> map = createMap();
|
Map<K, V> map = createMap();
|
||||||
|
|
||||||
|
try {
|
||||||
ConfigureSection section = config().getSection(path());
|
ConfigureSection section = config().getSection(path());
|
||||||
if (section == null) return getDefaultFirst(map);
|
if (section == null) return getDefaultFirst(map);
|
||||||
|
|
||||||
@@ -80,8 +85,9 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
|
|||||||
if (keys.isEmpty()) return getDefaultFirst(map);
|
if (keys.isEmpty()) return getDefaultFirst(map);
|
||||||
|
|
||||||
ValueParser<K> keyParser = parserFor(keyAdapter);
|
ValueParser<K> keyParser = parserFor(keyAdapter);
|
||||||
|
if (keyParser == null) return getDefaultFirst(map);
|
||||||
ValueParser<V> valueParser = parserFor(valueAdapter);
|
ValueParser<V> valueParser = parserFor(valueAdapter);
|
||||||
if (keyParser == null || valueParser == null) return getDefaultFirst(map);
|
if (valueParser == null) return getDefaultFirst(map);
|
||||||
|
|
||||||
for (String dataKey : keys) {
|
for (String dataKey : keys) {
|
||||||
Object dataVal = section.get(dataKey);
|
Object dataVal = section.get(dataKey);
|
||||||
@@ -89,11 +95,14 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
|
|||||||
try {
|
try {
|
||||||
K key = keyParser.parse(holder(), keyType(), dataKey);
|
K key = keyParser.parse(holder(), keyType(), dataKey);
|
||||||
V value = valueParser.parse(holder(), valueType(), dataVal);
|
V value = valueParser.parse(holder(), valueType(), dataVal);
|
||||||
map.put(key, value);
|
map.put(key, withValidated(value));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
throwing(path + "." + dataKey, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throwing(ex);
|
||||||
|
}
|
||||||
|
|
||||||
return updateCache(map);
|
return updateCache(map);
|
||||||
}
|
}
|
||||||
@@ -115,9 +124,11 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
ValueSerializer<K> keySerializer = serializerFor(keyAdapter);
|
ValueSerializer<K> keySerializer = serializerFor(keyAdapter);
|
||||||
|
if (keySerializer == null) return;
|
||||||
ValueSerializer<V> valueSerializer = serializerFor(valueAdapter);
|
ValueSerializer<V> valueSerializer = serializerFor(valueAdapter);
|
||||||
if (keySerializer == null || valueSerializer == null) return;
|
if (valueSerializer == null) return;
|
||||||
|
|
||||||
Map<Object, Object> data = new LinkedHashMap<>();
|
Map<Object, Object> data = new LinkedHashMap<>();
|
||||||
|
|
||||||
@@ -125,13 +136,16 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
|
|||||||
try {
|
try {
|
||||||
data.put(
|
data.put(
|
||||||
keySerializer.serialize(holder(), keyType(), entry.getKey()),
|
keySerializer.serialize(holder(), keyType(), entry.getKey()),
|
||||||
valueSerializer.serialize(holder(), valueType(), entry.getValue())
|
valueSerializer.serialize(holder(), valueType(), withValidated(entry.getValue()))
|
||||||
);
|
);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
throwing(path + "." + entry.getKey(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setData(data);
|
setData(data);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throwing(ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> @NotNull T handle(Function<Map<K, V>, T> function) {
|
public <T> @NotNull T handle(Function<Map<K, V>, T> function) {
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import cc.carm.lib.configuration.adapter.ValueParser;
|
|||||||
import cc.carm.lib.configuration.adapter.ValueSerializer;
|
import cc.carm.lib.configuration.adapter.ValueSerializer;
|
||||||
import cc.carm.lib.configuration.adapter.ValueType;
|
import cc.carm.lib.configuration.adapter.ValueType;
|
||||||
import cc.carm.lib.configuration.builder.value.ConfigValueBuilder;
|
import cc.carm.lib.configuration.builder.value.ConfigValueBuilder;
|
||||||
|
import cc.carm.lib.configuration.builder.value.SourceValueBuilder;
|
||||||
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
import cc.carm.lib.configuration.value.ValueManifest;
|
import cc.carm.lib.configuration.value.ValueManifest;
|
||||||
import cc.carm.lib.configuration.value.impl.CachedConfigValue;
|
import cc.carm.lib.configuration.value.impl.CachedConfigValue;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -12,16 +14,54 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
public class ConfiguredValue<V> extends CachedConfigValue<V, V> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new value builder.
|
||||||
|
*
|
||||||
|
* @param type The type of the value.
|
||||||
|
* @param <V> The type of the value.
|
||||||
|
* @return a {@link ConfigValueBuilder} with the specified type.
|
||||||
|
*/
|
||||||
public static <V> ConfigValueBuilder<V> builderOf(@NotNull Class<V> type) {
|
public static <V> ConfigValueBuilder<V> builderOf(@NotNull Class<V> type) {
|
||||||
return new ConfigValueBuilder<>(ValueType.of(type));
|
return new ConfigValueBuilder<>(ValueType.of(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new value builder.
|
||||||
|
*
|
||||||
|
* @param type The type of the value.
|
||||||
|
* @param <V> The type of the value.
|
||||||
|
* @return a {@link ConfigValueBuilder} with the specified type.
|
||||||
|
*/
|
||||||
public static <V> ConfigValueBuilder<V> builderOf(@NotNull ValueType<V> type) {
|
public static <V> ConfigValueBuilder<V> builderOf(@NotNull ValueType<V> type) {
|
||||||
return new ConfigValueBuilder<>(type);
|
return new ConfigValueBuilder<>(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new value builder with the specified {@link ConfigurationHolder#registeredValues()} type.
|
||||||
|
*
|
||||||
|
* @param registeredType The type of the value.
|
||||||
|
* @param <V> The type of the value.
|
||||||
|
* @return a {@link SourceValueBuilder} with the specified registered type.
|
||||||
|
* @see ValueAdapter
|
||||||
|
*/
|
||||||
|
public static <V> SourceValueBuilder<V, V> with(@NotNull Class<V> registeredType) {
|
||||||
|
return with(ValueType.of(registeredType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new value builder with the specified {@link ConfigurationHolder#registeredValues()} type.
|
||||||
|
*
|
||||||
|
* @param registeredType The type of the value.
|
||||||
|
* @param <V> The type of the value.
|
||||||
|
* @return a {@link SourceValueBuilder} with the specified registered type.
|
||||||
|
* @see ValueAdapter
|
||||||
|
*/
|
||||||
|
public static <V> SourceValueBuilder<V, V> with(@NotNull ValueType<V> registeredType) {
|
||||||
|
return new ConfigValueBuilder<>(registeredType).from(registeredType);
|
||||||
|
}
|
||||||
|
|
||||||
public static <V> ConfiguredValue<V> of(@NotNull V defaults) {
|
public static <V> ConfiguredValue<V> of(@NotNull V defaults) {
|
||||||
return of(ValueType.of(defaults), () -> defaults);
|
return of(ValueType.of(defaults), () -> defaults);
|
||||||
}
|
}
|
||||||
@@ -51,7 +91,7 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <V> ConfiguredValue<V> of(@NotNull ValueManifest<V> manifest,
|
public static <V> ConfiguredValue<V> of(@NotNull ValueManifest<V, V> manifest,
|
||||||
@Nullable ValueParser<V> parser,
|
@Nullable ValueParser<V> parser,
|
||||||
@Nullable ValueSerializer<V> serializer) {
|
@Nullable ValueSerializer<V> serializer) {
|
||||||
ValueAdapter<V> adapter = new ValueAdapter<>(manifest.type());
|
ValueAdapter<V> adapter = new ValueAdapter<>(manifest.type());
|
||||||
@@ -60,13 +100,13 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
|||||||
return of(manifest, adapter);
|
return of(manifest, adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <V> ConfiguredValue<V> of(@NotNull ValueManifest<V> manifest, @NotNull ValueAdapter<V> adapter) {
|
public static <V> ConfiguredValue<V> of(@NotNull ValueManifest<V, V> manifest, @NotNull ValueAdapter<V> adapter) {
|
||||||
return new ConfiguredValue<>(manifest, adapter);
|
return new ConfiguredValue<>(manifest, adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final @NotNull ValueAdapter<V> adapter;
|
protected final @NotNull ValueAdapter<V> adapter;
|
||||||
|
|
||||||
public ConfiguredValue(@NotNull ValueManifest<V> manifest, @NotNull ValueAdapter<V> adapter) {
|
public ConfiguredValue(@NotNull ValueManifest<V, V> manifest, @NotNull ValueAdapter<V> adapter) {
|
||||||
super(manifest);
|
super(manifest);
|
||||||
this.adapter = adapter;
|
this.adapter = adapter;
|
||||||
}
|
}
|
||||||
@@ -97,18 +137,19 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
|||||||
if (!cacheExpired()) return getCachedOrDefault();
|
if (!cacheExpired()) return getCachedOrDefault();
|
||||||
// Data that is outdated and needs to be parsed again.
|
// Data that is outdated and needs to be parsed again.
|
||||||
|
|
||||||
|
try {
|
||||||
Object data = getData();
|
Object data = getData();
|
||||||
if (data == null) return defaults();
|
if (data == null) return defaults();
|
||||||
|
|
||||||
ValueParser<V> parser = parser();
|
ValueParser<V> parser = parser();
|
||||||
if (parser == null) return defaults(); // No parser, return default value.
|
if (parser == null) return defaults(); // No parser, return default value.
|
||||||
|
|
||||||
try {
|
|
||||||
// If there are no errors, update the cache and return.
|
// If there are no errors, update the cache and return.
|
||||||
return updateCache(parser.parse(holder(), type(), data));
|
V parsed = parser.parse(holder(), type(), data);
|
||||||
|
return updateCache(withValidated(parsed));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// There was a parsing error, prompted and returned the default value.
|
// There was a validate or parsing error, prompted and returned the default value.
|
||||||
e.printStackTrace();
|
throwing(e);
|
||||||
return defaults();
|
return defaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,20 +162,20 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
|||||||
* @param value The value to be set
|
* @param value The value to be set
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void set(V value) {
|
public void set(@Nullable V value) {
|
||||||
updateCache(value); // Update cache
|
updateCache(value); // Update cache
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
setData(null);
|
setData(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
ValueSerializer<V> serializer = serializer();
|
ValueSerializer<V> serializer = serializer();
|
||||||
if (serializer == null) return; // No serializer, do nothing.
|
if (serializer == null) return; // No serializer, do nothing.
|
||||||
|
|
||||||
try {
|
setData(serializer.serialize(holder(), type(), withValidated(value)));
|
||||||
setData(serializer.serialize(holder(), type(), value));
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
throwing(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
//import java.util.LinkedList;
|
//import java.util.LinkedList;
|
||||||
//import java.util.List;
|
//import java.util.List;
|
||||||
//
|
//
|
||||||
///**
|
/// **
|
||||||
// * @author Chris2018998
|
// * @author Chris2018998
|
||||||
// */
|
// */
|
||||||
//public class OffsetUtil {
|
//public class OffsetUtil {
|
||||||
@@ -25,15 +25,15 @@
|
|||||||
// } catch (NoSuchFieldException | IllegalAccessException e) {
|
// } catch (NoSuchFieldException | IllegalAccessException e) {
|
||||||
// e.printStackTrace();
|
// e.printStackTrace();
|
||||||
// }
|
// }
|
||||||
//// try {
|
/// / try {
|
||||||
//// unsafe = AccessController.doPrivileged((PrivilegedExceptionAction<Unsafe>) () -> {
|
/// / unsafe = AccessController.doPrivileged((PrivilegedExceptionAction<Unsafe>) () -> {
|
||||||
//// Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
|
/// / Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
|
||||||
//// theUnsafe.setAccessible(true);
|
/// / theUnsafe.setAccessible(true);
|
||||||
//// return (Unsafe) theUnsafe.get(null);
|
/// / return (Unsafe) theUnsafe.get(null);
|
||||||
//// });
|
/// / });
|
||||||
//// } catch (Throwable e) {
|
/// / } catch (Throwable e) {
|
||||||
//// System.err.println("Unable to load unsafe");
|
/// / System.err.println("Unable to load unsafe");
|
||||||
//// }
|
/// / }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// public static List<FieldOffset> getClassMemberOffset(Class<?> beanClass) {
|
// public static List<FieldOffset> getClassMemberOffset(Class<?> beanClass) {
|
||||||
|
|||||||
+169
-11
@@ -3,9 +3,9 @@
|
|||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>easyconfiguration-parent</artifactId>
|
<artifactId>configured-parent</artifactId>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<version>4.0.0</version>
|
<version>4.1.7</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<properties>
|
<properties>
|
||||||
@@ -13,34 +13,127 @@
|
|||||||
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
|
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||||
|
<maven.javadoc.skip>true</maven.javadoc.skip>
|
||||||
|
<maven.deploy.skip>true</maven.deploy.skip>
|
||||||
|
|
||||||
|
<deps.mysql-driver.version>8.0.33</deps.mysql-driver.version>
|
||||||
|
<log4j.version>2.25.0</log4j.version>
|
||||||
</properties>
|
</properties>
|
||||||
<artifactId>easyconfiguration-demo</artifactId>
|
<artifactId>configured-demo</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.parent.groupId}</groupId>
|
<groupId>${project.parent.groupId}</groupId>
|
||||||
<artifactId>easyconfiguration-core</artifactId>
|
<artifactId>configured-core</artifactId>
|
||||||
<version>${project.parent.version}</version>
|
<version>${project.parent.version}</version>
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.parent.groupId}</groupId>
|
<groupId>${project.parent.groupId}</groupId>
|
||||||
<artifactId>easyconfiguration-feature-commentable</artifactId>
|
<artifactId>configured-feature-commentable</artifactId>
|
||||||
<version>${project.parent.version}</version>
|
<version>${project.parent.version}</version>
|
||||||
<scope>compile</scope>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.parent.groupId}</groupId>
|
||||||
|
<artifactId>configured-feature-versioned</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.parent.groupId}</groupId>
|
||||||
|
<artifactId>configured-feature-validators</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.parent.groupId}</groupId>
|
||||||
|
<artifactId>configured-feature-kotlin</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.parent.groupId}</groupId>
|
||||||
|
<artifactId>configured-yaml</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.parent.groupId}</groupId>
|
||||||
|
<artifactId>configured-gson</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.parent.groupId}</groupId>
|
||||||
|
<artifactId>configured-sql</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cc.carm.lib</groupId>
|
||||||
|
<artifactId>easysql-beecp</artifactId>
|
||||||
|
<version>0.4.7</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<version>${deps.mysql-driver.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.parent.groupId}</groupId>
|
||||||
|
<artifactId>configured-mongodb</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.parent.groupId}</groupId>
|
||||||
|
<artifactId>configured-hocon</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||||
|
<version>${kotlin.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-api</artifactId>
|
||||||
|
<version>${log4j.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-core</artifactId>
|
||||||
|
<version>${log4j.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-slf4j-impl</artifactId>
|
||||||
|
<version>${log4j.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
@@ -53,6 +146,71 @@
|
|||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-maven-plugin</artifactId>
|
||||||
|
<version>${kotlin.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>compile</id>
|
||||||
|
<phase>compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>compile</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<sourceDirs>
|
||||||
|
<source>src/main/java</source>
|
||||||
|
<source>target/generated-sources/annotations</source>
|
||||||
|
</sourceDirs>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>test-compile</id>
|
||||||
|
<phase>test-compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>test-compile</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<jvmTarget>1.8</jvmTarget>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>default-compile</id>
|
||||||
|
<phase>none</phase>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>default-testCompile</id>
|
||||||
|
<phase>none</phase>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>compile</id>
|
||||||
|
<phase>compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>compile</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>testCompile</id>
|
||||||
|
<phase>test-compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>testCompile</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,10 @@ package cc.carm.lib.configuration.demo;
|
|||||||
import cc.carm.lib.configuration.Configuration;
|
import cc.carm.lib.configuration.Configuration;
|
||||||
import cc.carm.lib.configuration.annotation.ConfigPath;
|
import cc.carm.lib.configuration.annotation.ConfigPath;
|
||||||
import cc.carm.lib.configuration.annotation.HeaderComments;
|
import cc.carm.lib.configuration.annotation.HeaderComments;
|
||||||
import cc.carm.lib.configuration.value.ConfigValue;
|
|
||||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||||
|
|
||||||
@HeaderComments({"", "数据库配置", " 用于提供数据库连接,进行数据库操作。"})
|
@HeaderComments({"", "数据库配置", " 用于提供数据库连接,进行数据库操作。"})
|
||||||
public class DatabaseConfiguration implements Configuration {
|
public interface DatabaseConfiguration extends Configuration {
|
||||||
|
|
||||||
@ConfigPath("driver")
|
@ConfigPath("driver")
|
||||||
@HeaderComments({
|
@HeaderComments({
|
||||||
@@ -16,18 +15,19 @@ public class DatabaseConfiguration implements Configuration {
|
|||||||
"- MySQL(新): com.mysql.cj.jdbc.Driver",
|
"- MySQL(新): com.mysql.cj.jdbc.Driver",
|
||||||
"- MariaDB(推荐): org.mariadb.jdbc.Driver",
|
"- MariaDB(推荐): org.mariadb.jdbc.Driver",
|
||||||
})
|
})
|
||||||
protected static final ConfigValue<String> DRIVER_NAME = ConfiguredValue.of(
|
ConfiguredValue<String> DRIVER_NAME = ConfiguredValue.of(
|
||||||
String.class, "com.mysql.cj.jdbc.Driver"
|
String.class, "com.mysql.cj.jdbc.Driver"
|
||||||
);
|
);
|
||||||
|
|
||||||
protected static final ConfigValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1");
|
ConfiguredValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1");
|
||||||
protected static final ConfigValue<Integer> PORT = ConfiguredValue.of(Integer.class, 3306);
|
ConfiguredValue<Integer> PORT = ConfiguredValue.of(Integer.class, 3306);
|
||||||
protected static final ConfigValue<String> DATABASE = ConfiguredValue.of(String.class, "minecraft");
|
ConfiguredValue<String> DATABASE = ConfiguredValue.of(String.class, "minecraft");
|
||||||
protected static final ConfigValue<String> USERNAME = ConfiguredValue.of(String.class, "root");
|
ConfiguredValue<String> USERNAME = ConfiguredValue.of(String.class, "root");
|
||||||
protected static final ConfigValue<String> PASSWORD = ConfiguredValue.of(String.class, "password");
|
ConfiguredValue<String> PASSWORD = ConfiguredValue.of(String.class, "password");
|
||||||
protected static final ConfigValue<String> EXTRA = ConfiguredValue.of(String.class, "?useSSL=false");
|
|
||||||
|
|
||||||
protected static String buildJDBC() {
|
ConfiguredValue<String> EXTRA = ConfiguredValue.of(String.class, "?useSSL=false");
|
||||||
|
|
||||||
|
static String buildJDBC() {
|
||||||
return String.format("jdbc:mysql://%s:%s/%s%s", HOST.get(), PORT.get(), DATABASE.get(), EXTRA.get());
|
return String.format("jdbc:mysql://%s:%s/%s%s", HOST.get(), PORT.get(), DATABASE.get(), EXTRA.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package cc.carm.lib.configuration.demo.tests;
|
package cc.carm.lib.configuration.demo.tests;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.demo.tests.conf.DemoConfiguration;
|
import cc.carm.lib.configuration.demo.tests.conf.DemoConfiguration;
|
||||||
|
import cc.carm.lib.configuration.demo.tests.conf.KotlinConfiguration;
|
||||||
import cc.carm.lib.configuration.demo.tests.conf.RegistryConfig;
|
import cc.carm.lib.configuration.demo.tests.conf.RegistryConfig;
|
||||||
import cc.carm.lib.configuration.demo.tests.model.UserRecord;
|
import cc.carm.lib.configuration.demo.tests.model.UserRecord;
|
||||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
import org.jetbrains.annotations.TestOnly;
|
import org.jetbrains.annotations.TestOnly;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -69,14 +71,30 @@ public class ConfigurationTest {
|
|||||||
provider.initialize(TEST);
|
provider.initialize(TEST);
|
||||||
|
|
||||||
System.out.println("> Test Inner value before:");
|
System.out.println("> Test Inner value before:");
|
||||||
System.out.println(TEST.INSTANCE.INNER_VALUE.resolve());
|
System.out.println(TEST.INSTANCE.STATUS.resolve());
|
||||||
|
|
||||||
double after = Math.random() * 200D;
|
double after = Math.random() * 200D;
|
||||||
System.out.println("> Test Inner value -> " + after);
|
System.out.println("> Test Inner value -> " + after);
|
||||||
TEST.INSTANCE.INNER_VALUE.set(after);
|
TEST.INSTANCE.STATUS.set(after);
|
||||||
|
|
||||||
System.out.println("> Test Inner value after:");
|
System.out.println("> Test Inner value after:");
|
||||||
System.out.println(TEST.INSTANCE.INNER_VALUE.resolve());
|
System.out.println(TEST.INSTANCE.STATUS.resolve());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void testKotlin(ConfigurationHolder<?> provider) {
|
||||||
|
provider.initialize(KotlinConfiguration.class);
|
||||||
|
|
||||||
|
System.out.println("> Test Kotlin value before:");
|
||||||
|
System.out.println(KotlinConfiguration.INSTANCE.getLINKED_MAP().get());
|
||||||
|
|
||||||
|
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
||||||
|
map.put("Language", "Kotlin");
|
||||||
|
System.out.println("> Test Kotlin value -> " + map);
|
||||||
|
KotlinConfiguration.INSTANCE.getLINKED_MAP().set(map);
|
||||||
|
|
||||||
|
System.out.println("> Test Kotlin value after:");
|
||||||
|
System.out.println(KotlinConfiguration.INSTANCE.getLINKED_MAP().get());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-16
@@ -1,14 +1,9 @@
|
|||||||
package cc.carm.lib.configuration.demo.tests.conf;
|
package cc.carm.lib.configuration.demo.tests.conf;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.Configuration;
|
import cc.carm.lib.configuration.Configuration;
|
||||||
import cc.carm.lib.configuration.annotation.ConfigPath;
|
import cc.carm.lib.configuration.annotation.*;
|
||||||
import cc.carm.lib.configuration.annotation.FooterComments;
|
|
||||||
import cc.carm.lib.configuration.annotation.HeaderComments;
|
|
||||||
import cc.carm.lib.configuration.annotation.InlineComment;
|
|
||||||
import cc.carm.lib.configuration.demo.DatabaseConfiguration;
|
|
||||||
import cc.carm.lib.configuration.demo.tests.model.ItemStack;
|
import cc.carm.lib.configuration.demo.tests.model.ItemStack;
|
||||||
import cc.carm.lib.configuration.demo.tests.model.UserRecord;
|
import cc.carm.lib.configuration.demo.tests.model.UserRecord;
|
||||||
import cc.carm.lib.configuration.value.ConfigValue;
|
|
||||||
import cc.carm.lib.configuration.value.standard.ConfiguredList;
|
import cc.carm.lib.configuration.value.standard.ConfiguredList;
|
||||||
import cc.carm.lib.configuration.value.standard.ConfiguredMap;
|
import cc.carm.lib.configuration.value.standard.ConfiguredMap;
|
||||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||||
@@ -24,30 +19,31 @@ import java.util.UUID;
|
|||||||
"------------------------------------------------",
|
"------------------------------------------------",
|
||||||
"此处内容将显示在配置文件的最下方",
|
"此处内容将显示在配置文件的最下方",
|
||||||
"可用于显示版权信息等",
|
"可用于显示版权信息等",
|
||||||
"感谢您使用 https://github.com/CarmJos/EasyConfiguration !"
|
"感谢您使用 https://github.com/CarmJos/configured !"
|
||||||
})
|
})
|
||||||
public interface DemoConfiguration extends Configuration {
|
public interface DemoConfiguration extends Configuration {
|
||||||
|
|
||||||
@ConfigPath(root = true)
|
@ConfigPath(root = true)
|
||||||
ConfigValue<Double> VERSION = ConfiguredValue.of(Double.class, 1.0D);
|
@ConfigVersion(2)
|
||||||
|
ConfiguredValue<Double> VERSION = ConfiguredValue.of(Double.class, 2.0D);
|
||||||
|
|
||||||
@ConfigPath(root = true)
|
@ConfigPath(root = true)
|
||||||
@FooterComments({"此处内容将显示在配置条目的下方", "可用于补充说明,但一般不建议使用"})
|
@FooterComments({"此处内容将显示在配置条目的下方", "可用于补充说明,但一般不建议使用"})
|
||||||
ConfigValue<Long> TEST_NUMBER = ConfiguredValue.of(1000000L);
|
ConfiguredValue<Long> TEST_NUMBER = ConfiguredValue.with(Long.class).defaults(123456789L).build();
|
||||||
|
|
||||||
@HeaderComments({"枚举类型测试"})
|
@HeaderComments({"枚举类型测试"})
|
||||||
@FooterComments({"上述的枚举内容本质上是通过STRING解析的"})
|
@FooterComments({"上述的枚举内容本质上是通过STRING解析的"})
|
||||||
ConfigValue<ChronoUnit> TEST_ENUM = ConfiguredValue.of(ChronoUnit.class, ChronoUnit.DAYS);
|
ConfiguredValue<ChronoUnit> TEST_ENUM = ConfiguredValue.of(ChronoUnit.class, ChronoUnit.DAYS);
|
||||||
|
|
||||||
// 支持通过 Class<?> 变量标注子配置,一并注册。
|
@HeaderComments({"空值测试"})
|
||||||
// 注意: 若对应类也有注解,则优先使用类的注解。
|
@InlineComment("空值Inline注释")
|
||||||
Class<?> DATABASE = DatabaseConfiguration.class;
|
ConfiguredMap<String, String> EMPTY = ConfiguredMap.builderOf(String.class, String.class)
|
||||||
|
.asLinkedMap().fromString()
|
||||||
|
.build();
|
||||||
|
|
||||||
@ConfigPath("registered_users") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
|
@ConfigPath("registered_users") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
|
||||||
@HeaderComments({"Section类型数据测试"}) // 通过注解给配置添加注释。
|
@HeaderComments({"Section类型数据测试"}) // 通过注解给配置添加注释。
|
||||||
@InlineComment("默认地注释会加到Section的首行末尾") // 通过注解给配置添加注释。
|
@InlineComment("默认地注释会加到Section的首行末尾") // 通过注解给配置添加注释。
|
||||||
@InlineComment(value = "用户名(匹配注释)", regex = "name") // 通过注解给配置添加注释。
|
|
||||||
@InlineComment(value = "信息", regex = "info.*") // 通过注解给配置添加注释。
|
|
||||||
ConfiguredList<UserRecord> ALLOWLISTS = ConfiguredList.builderOf(UserRecord.class).fromSection()
|
ConfiguredList<UserRecord> ALLOWLISTS = ConfiguredList.builderOf(UserRecord.class).fromSection()
|
||||||
.parse(UserRecord::deserialize).serialize(UserRecord::serialize)
|
.parse(UserRecord::deserialize).serialize(UserRecord::serialize)
|
||||||
.defaults(UserRecord.CARM).build();
|
.defaults(UserRecord.CARM).build();
|
||||||
@@ -75,12 +71,13 @@ public interface DemoConfiguration extends Configuration {
|
|||||||
class SUB implements Configuration {
|
class SUB implements Configuration {
|
||||||
|
|
||||||
@ConfigPath(value = "uuid-value", root = true)
|
@ConfigPath(value = "uuid-value", root = true)
|
||||||
public static final ConfigValue<UUID> UUID_CONFIG_VALUE = ConfiguredValue
|
public static final ConfiguredValue<UUID> UUID_CONFIG_VALUE = ConfiguredValue
|
||||||
.builderOf(UUID.class).fromString()
|
.builderOf(UUID.class).fromString()
|
||||||
.parse((holder, data) -> UUID.fromString(data))
|
.parse((holder, data) -> UUID.fromString(data))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@HeaderComments({"内部类的内部类测试", "通过这种方式,您可以轻易实现多层次的配置文件结构"})
|
@HeaderComments({"内部类的内部类测试", "通过这种方式,您可以轻易实现多层次的配置文件结构"})
|
||||||
|
@FooterComments({"-------------"})
|
||||||
public interface That extends Configuration {
|
public interface That extends Configuration {
|
||||||
|
|
||||||
ConfiguredList<UUID> OPERATORS = ConfiguredList
|
ConfiguredList<UUID> OPERATORS = ConfiguredList
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ package cc.carm.lib.configuration.demo.tests.conf;
|
|||||||
|
|
||||||
import cc.carm.lib.configuration.Configuration;
|
import cc.carm.lib.configuration.Configuration;
|
||||||
import cc.carm.lib.configuration.annotation.HeaderComments;
|
import cc.carm.lib.configuration.annotation.HeaderComments;
|
||||||
import cc.carm.lib.configuration.value.ConfigValue;
|
import cc.carm.lib.configuration.annotation.ValueRange;
|
||||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||||
|
|
||||||
@HeaderComments("Inner Test")
|
@HeaderComments("service")
|
||||||
public class InstanceConfig implements Configuration {
|
public class InstanceConfig implements Configuration {
|
||||||
|
|
||||||
public final ConfigValue<Double> INNER_VALUE = ConfiguredValue.of(1.0D);
|
@ValueRange(min = 0, max = 100, message = "The value must be between 0 and 100")
|
||||||
|
public final ConfiguredValue<Double> STATUS = ConfiguredValue.of(1.0D);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package cc.carm.lib.configuration.demo.tests.conf
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.Configuration
|
||||||
|
import cc.carm.lib.configuration.annotation.ConfigPath
|
||||||
|
import cc.carm.lib.configuration.annotation.ConfigVersion
|
||||||
|
import cc.carm.lib.configuration.kotlin.value.*
|
||||||
|
|
||||||
|
@ConfigPath(root = true)
|
||||||
|
object KotlinConfiguration : Configuration {
|
||||||
|
@ConfigVersion(1)
|
||||||
|
val VERSION = valueFrom(Double::class) {
|
||||||
|
defaults(1.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
val USER_LIST = listFrom(String::class) {
|
||||||
|
defaults("Carm Jos")
|
||||||
|
}
|
||||||
|
|
||||||
|
val NICKNAME = mapFrom(String::class, ::mutableMapOf) {
|
||||||
|
defaultMap(mapOf("Carm Jos" to "Carm"))
|
||||||
|
parse { v -> v }
|
||||||
|
serialize { v -> v }
|
||||||
|
}
|
||||||
|
|
||||||
|
val LINKED_MAP = linkedMapFrom(String::class) {
|
||||||
|
parse { value ->
|
||||||
|
value
|
||||||
|
}
|
||||||
|
serialize { v -> v }
|
||||||
|
defaults("key", "value")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,6 @@ import cc.carm.lib.configuration.annotation.FooterComments;
|
|||||||
import cc.carm.lib.configuration.annotation.HeaderComments;
|
import cc.carm.lib.configuration.annotation.HeaderComments;
|
||||||
import cc.carm.lib.configuration.annotation.InlineComment;
|
import cc.carm.lib.configuration.annotation.InlineComment;
|
||||||
import cc.carm.lib.configuration.demo.tests.model.UserRecord;
|
import cc.carm.lib.configuration.demo.tests.model.UserRecord;
|
||||||
import cc.carm.lib.configuration.value.ConfigValue;
|
|
||||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -18,7 +17,9 @@ public class RegistryConfig implements Configuration {
|
|||||||
|
|
||||||
@ConfigPath("test.user") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
|
@ConfigPath("test.user") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
|
||||||
@FooterComments({"12313213212"})
|
@FooterComments({"12313213212"})
|
||||||
public final ConfigValue<UserRecord> TEST_MODEL = ConfiguredValue.builderOf(UserRecord.class).fromSection()
|
@InlineComment(value = "用户名(匹配注释)", regex = "name") // 通过注解给配置添加注释。
|
||||||
|
@InlineComment(value = "信息", regex = {"info.*", "info.game.*"}) // 通过注解给配置添加注释。
|
||||||
|
public final ConfiguredValue<UserRecord> OWNER = ConfiguredValue.builderOf(UserRecord.class).fromSection()
|
||||||
.defaults(new UserRecord("Carm", UUID.randomUUID()))
|
.defaults(new UserRecord("Carm", UUID.randomUUID()))
|
||||||
.parse((holder, section) -> UserRecord.deserialize(section))
|
.parse((holder, section) -> UserRecord.deserialize(section))
|
||||||
.serialize((holder, data) -> data.serialize()).build();
|
.serialize((holder, data) -> data.serialize()).build();
|
||||||
|
|||||||
@@ -33,11 +33,11 @@ public class ItemStack {
|
|||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public @Nullable String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getLore() {
|
public @Nullable List<String> getLore() {
|
||||||
return lore;
|
return lore;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,11 +49,11 @@ public class ItemStack {
|
|||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(@Nullable String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLore(List<String> lore) {
|
public void setLore(@Nullable List<String> lore) {
|
||||||
this.lore = lore;
|
this.lore = lore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ public class UserRecord extends AbstractRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static UserRecord deserialize(ConfigureSection section) {
|
public static UserRecord deserialize(ConfigureSection section) {
|
||||||
|
System.out.println("> Deserializing -> " + section.fullPath());
|
||||||
String name = section.getString("name");
|
String name = section.getString("name");
|
||||||
if (name == null) throw new NullPointerException("name is null");
|
if (name == null) throw new NullPointerException("name is null");
|
||||||
String uuidString = section.getString("info.uuid");
|
String uuidString = section.getString("info.uuid");
|
||||||
|
|||||||
+3
-11
@@ -1,15 +1,13 @@
|
|||||||
package config;
|
package cc.carm.lib.configuration.tests.test;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
|
import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
|
||||||
import cc.carm.lib.configuration.source.json.JSONConfigFactory;
|
|
||||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
import cc.carm.lib.configuration.value.ConfigValue;
|
import cc.carm.lib.configuration.source.json.JSONConfigFactory;
|
||||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
public class JSONConfigTest {
|
public class JSONConfigTests {
|
||||||
|
|
||||||
protected final ConfigurationHolder<?> holder = JSONConfigFactory
|
protected final ConfigurationHolder<?> holder = JSONConfigFactory
|
||||||
.from(new File("target"), "config.json")
|
.from(new File("target"), "config.json")
|
||||||
@@ -18,12 +16,6 @@ public class JSONConfigTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onTest() {
|
public void onTest() {
|
||||||
|
|
||||||
ConfigValue<Boolean> EXAMPLE = ConfiguredValue.of(false);
|
|
||||||
EXAMPLE.initialize(this.holder, "example");
|
|
||||||
|
|
||||||
System.out.println("Example: " + EXAMPLE.get());
|
|
||||||
|
|
||||||
ConfigurationTest.testDemo(this.holder);
|
ConfigurationTest.testDemo(this.holder);
|
||||||
ConfigurationTest.testInner(this.holder);
|
ConfigurationTest.testInner(this.holder);
|
||||||
|
|
||||||
+15
-4
@@ -1,9 +1,11 @@
|
|||||||
package yaml.test;
|
package cc.carm.lib.configuration.tests.test;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.commentable.CommentableMeta;
|
import cc.carm.lib.configuration.commentable.CommentableMeta;
|
||||||
import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
|
import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
|
||||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
import cc.carm.lib.configuration.source.yaml.YAMLConfigFactory;
|
import cc.carm.lib.configuration.source.yaml.YAMLConfigFactory;
|
||||||
|
import cc.carm.lib.configuration.source.yaml.YAMLSource;
|
||||||
|
import cc.carm.lib.configuration.validators.Validators;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -12,15 +14,16 @@ import java.util.Map;
|
|||||||
public class YamlTests {
|
public class YamlTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() {
|
public void test() throws Exception {
|
||||||
|
|
||||||
ConfigurationHolder<?> holder = YAMLConfigFactory.from("target/tests.yml")
|
ConfigurationHolder<YAMLSource> holder = YAMLConfigFactory.from("target/tests.yml")
|
||||||
.resourcePath("configs/sample.yml").build();
|
.resourcePath("configs/sample.yml").build();
|
||||||
|
|
||||||
|
Validators.activate(holder);
|
||||||
|
|
||||||
ConfigurationTest.testDemo(holder);
|
ConfigurationTest.testDemo(holder);
|
||||||
ConfigurationTest.testInner(holder);
|
ConfigurationTest.testInner(holder);
|
||||||
|
|
||||||
|
|
||||||
Map<String, List<String>> headers = holder.extractMetadata(CommentableMeta.HEADER);
|
Map<String, List<String>> headers = holder.extractMetadata(CommentableMeta.HEADER);
|
||||||
System.out.println("Header comments: ");
|
System.out.println("Header comments: ");
|
||||||
headers.forEach((k, v) -> {
|
headers.forEach((k, v) -> {
|
||||||
@@ -41,5 +44,13 @@ public class YamlTests {
|
|||||||
ConfigurationTest.save(holder);
|
ConfigurationTest.save(holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKotlin() {
|
||||||
|
ConfigurationHolder<YAMLSource> holder = YAMLConfigFactory.from("target/kotlin.yml").build();
|
||||||
|
|
||||||
|
ConfigurationTest.testKotlin(holder);
|
||||||
|
|
||||||
|
ConfigurationTest.save(holder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package cc.carm.lib.configuration.tests.test.mongodb;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.Configuration;
|
||||||
|
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||||
|
|
||||||
|
interface MongoConfig extends Configuration {
|
||||||
|
ConfiguredValue<String> HOST = ConfiguredValue.of("127.0.0.1");
|
||||||
|
ConfiguredValue<Integer> PORT = ConfiguredValue.of(27017);
|
||||||
|
ConfiguredValue<String> USERNAME = ConfiguredValue.of("minecraft");
|
||||||
|
ConfiguredValue<String> PASSWORD = ConfiguredValue.of("minecraft");
|
||||||
|
ConfiguredValue<String> DATABASE = ConfiguredValue.of("minecraft");
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package cc.carm.lib.configuration.tests.test.mongodb;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
|
||||||
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
|
import cc.carm.lib.configuration.source.json.JSONConfigFactory;
|
||||||
|
import cc.carm.lib.configuration.source.mongodb.MongoConfigFactory;
|
||||||
|
import com.mongodb.ConnectionString;
|
||||||
|
import com.mongodb.MongoClientSettings;
|
||||||
|
import com.mongodb.MongoCredential;
|
||||||
|
import com.mongodb.client.MongoClient;
|
||||||
|
import com.mongodb.client.MongoClients;
|
||||||
|
import com.mongodb.client.MongoDatabase;
|
||||||
|
import org.bson.UuidRepresentation;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class MongoTest {
|
||||||
|
|
||||||
|
boolean local = false;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
|
||||||
|
if (!local) return;
|
||||||
|
|
||||||
|
ConfigurationHolder<?> gsonHolder = JSONConfigFactory.from(new File("target/mongo.json")).build();
|
||||||
|
gsonHolder.initialize(MongoConfig.class);
|
||||||
|
|
||||||
|
MongoClientSettings settings = MongoClientSettings.builder()
|
||||||
|
.applyConnectionString(new ConnectionString(
|
||||||
|
"mongodb://" + MongoConfig.HOST.resolve() + ":" + MongoConfig.PORT.resolve()
|
||||||
|
))
|
||||||
|
.credential(MongoCredential.createCredential(
|
||||||
|
MongoConfig.USERNAME.resolve(), MongoConfig.DATABASE.resolve(),
|
||||||
|
MongoConfig.PASSWORD.resolve().toCharArray()
|
||||||
|
))
|
||||||
|
.uuidRepresentation(UuidRepresentation.STANDARD)
|
||||||
|
.build();
|
||||||
|
MongoClient mongoClient = MongoClients.create(settings);
|
||||||
|
MongoDatabase mongoDatabase = mongoClient.getDatabase(MongoConfig.DATABASE.resolve());
|
||||||
|
|
||||||
|
ConfigurationHolder<?> mongoHolder = MongoConfigFactory
|
||||||
|
.from(mongoDatabase, "configs")
|
||||||
|
.namespace("my_plugin")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Test the configuration
|
||||||
|
ConfigurationTest.testDemo(mongoHolder);
|
||||||
|
ConfigurationTest.testInner(mongoHolder);
|
||||||
|
|
||||||
|
ConfigurationTest.save(mongoHolder);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package cc.carm.lib.configuration.tests.test.sql;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.demo.DatabaseConfiguration;
|
||||||
|
import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
|
||||||
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
|
import cc.carm.lib.configuration.source.json.JSONConfigFactory;
|
||||||
|
import cc.carm.lib.configuration.source.sql.SQLConfigFactory;
|
||||||
|
import cc.carm.lib.easysql.EasySQL;
|
||||||
|
import cc.carm.lib.easysql.api.SQLManager;
|
||||||
|
import cc.carm.lib.easysql.beecp.BeeDataSourceConfig;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class SQLConfigTest {
|
||||||
|
|
||||||
|
boolean local = false;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
if (!local) return;
|
||||||
|
|
||||||
|
ConfigurationHolder<?> gsonHolder = JSONConfigFactory.from(new File("target/sql.json")).build();
|
||||||
|
gsonHolder.initialize(DatabaseConfiguration.class);
|
||||||
|
|
||||||
|
BeeDataSourceConfig config = new BeeDataSourceConfig();
|
||||||
|
config.setDriverClassName(DatabaseConfiguration.DRIVER_NAME.resolve());
|
||||||
|
config.setJdbcUrl(DatabaseConfiguration.buildJDBC());
|
||||||
|
config.setUsername(DatabaseConfiguration.USERNAME.resolve());
|
||||||
|
config.setPassword(DatabaseConfiguration.PASSWORD.resolve());
|
||||||
|
|
||||||
|
SQLManager manager = EasySQL.createManager(config);
|
||||||
|
manager.setDebugMode(true);
|
||||||
|
|
||||||
|
ConfigurationHolder<?> holder = SQLConfigFactory.from(manager)
|
||||||
|
.tableName("test_configs")
|
||||||
|
.namespace("testing")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ConfigurationTest.testDemo(holder);
|
||||||
|
ConfigurationTest.testInner(holder);
|
||||||
|
|
||||||
|
ConfigurationTest.save(holder);
|
||||||
|
|
||||||
|
EasySQL.shutdownManager(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Configuration status="WARN" packages="config.SQLConfigTest">
|
<Configuration status="WARN" packages="cc.carm.lib.configuration.tests">
|
||||||
<Appenders>
|
<Appenders>
|
||||||
<console name="Console" target="SYSTEM_OUT">
|
<console name="Console" target="SYSTEM_OUT">
|
||||||
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg%n"/>
|
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg%n"/>
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<artifactId>easyconfiguration-parent</artifactId>
|
<artifactId>configured-parent</artifactId>
|
||||||
<version>4.0.0</version>
|
<version>4.1.7</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<properties>
|
<properties>
|
||||||
@@ -16,13 +16,13 @@
|
|||||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<artifactId>easyconfiguration-feature-commentable</artifactId>
|
<artifactId>configured-feature-commentable</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
<artifactId>easyconfiguration-core</artifactId>
|
<artifactId>configured-core</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
+4
-1
@@ -33,7 +33,7 @@ public @interface InlineComment {
|
|||||||
* If the regex is not empty, the comment will be added to
|
* If the regex is not empty, the comment will be added to
|
||||||
* all sub paths if the regex matches the value.
|
* all sub paths if the regex matches the value.
|
||||||
* If the regex is empty, the comment will be added to the current path.
|
* If the regex is empty, the comment will be added to the current path.
|
||||||
* <p> e.g. for section, set <b>{"^foo", "*", "bar"}</b> will be set like
|
* <p> e.g. for section, set <b>"foo.*.bar"</b> will be set like
|
||||||
* <blockquote><pre>
|
* <blockquote><pre>
|
||||||
* section:
|
* section:
|
||||||
* foo:
|
* foo:
|
||||||
@@ -44,6 +44,9 @@ public @interface InlineComment {
|
|||||||
* bar: "foobar" # Comment Contents
|
* bar: "foobar" # Comment Contents
|
||||||
* </pre></blockquote>
|
* </pre></blockquote>
|
||||||
*
|
*
|
||||||
|
* <p><i>Some implements may not support this feature
|
||||||
|
* in list values or other complex structures.</i>
|
||||||
|
*
|
||||||
* @return The path regexes of this comment
|
* @return The path regexes of this comment
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
+6
-1
@@ -9,7 +9,12 @@ import java.lang.annotation.Target;
|
|||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface InlineComments {
|
public @interface InlineComments {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiple inline comments support.
|
||||||
|
*
|
||||||
|
* @return inline comment contents.
|
||||||
|
* @see InlineComment
|
||||||
|
*/
|
||||||
InlineComment[] value();
|
InlineComment[] value();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
package cc.carm.lib.configuration.commentable;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
|
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
|
||||||
|
import cc.carm.lib.configuration.source.option.StandardOptions;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class Commentable {
|
||||||
|
|
||||||
|
private Commentable() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerMeta(@NotNull ConfigurationInitializer initializer) {
|
||||||
|
CommentableMeta.register(initializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable String getInlineComment(@NotNull ConfigurationHolder<?> holder, @NotNull String path) {
|
||||||
|
String comment = getInlineComment(holder, path, null);
|
||||||
|
if (comment != null) return comment;
|
||||||
|
|
||||||
|
String sep = String.valueOf(holder.option(StandardOptions.PATH_SEPARATOR));
|
||||||
|
|
||||||
|
// If the comment is not found, try to get the comment from the parent section
|
||||||
|
String[] keys = path.split(Pattern.quote(sep));
|
||||||
|
if (keys.length == 1) return null;
|
||||||
|
|
||||||
|
// Try every possible parent key&child key combination
|
||||||
|
for (int i = 1; i < keys.length; i++) {
|
||||||
|
String parentKey = String.join(sep, Arrays.copyOfRange(keys, 0, i));
|
||||||
|
String childKey = String.join(sep, Arrays.copyOfRange(keys, i, keys.length));
|
||||||
|
comment = getInlineComment(holder, parentKey, childKey);
|
||||||
|
if (comment != null) return comment;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable String getInlineComment(@NotNull ConfigurationHolder<?> holder, @NotNull String path, @Nullable String sectionKey) {
|
||||||
|
Map<String, String> pathComment = holder.metadata(path).get(CommentableMeta.INLINE);
|
||||||
|
if (pathComment == null || pathComment.isEmpty()) return null;
|
||||||
|
if (sectionKey == null) return pathComment.get(null);
|
||||||
|
for (Map.Entry<String/*regex*/, String/*content*/> entry : pathComment.entrySet()) {
|
||||||
|
if (entry.getKey() == null) continue;
|
||||||
|
if (Objects.equals(entry.getKey(), sectionKey)) return entry.getValue();
|
||||||
|
Pattern pattern = Pattern.compile(entry.getKey().replace(".", "\\.").replace("*", "(.*)"));
|
||||||
|
if (pattern.matcher(sectionKey).matches()) return entry.getValue();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable List<String> getHeaderComments(@NotNull ConfigurationHolder<?> holder, @Nullable String path) {
|
||||||
|
return holder.metadata(path).get(CommentableMeta.HEADER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable List<String> getFooterComments(@NotNull ConfigurationHolder<?> holder, @Nullable String path) {
|
||||||
|
return holder.metadata(path).get(CommentableMeta.FOOTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+11
@@ -49,6 +49,17 @@ public interface CommentableMeta {
|
|||||||
FooterComments.class, FOOTER,
|
FooterComments.class, FOOTER,
|
||||||
a -> Arrays.asList(a.value())
|
a -> Arrays.asList(a.value())
|
||||||
);
|
);
|
||||||
|
initializer.registerAnnotation(InlineComment.class, INLINE, a -> {
|
||||||
|
Map<String, String> map = new HashMap<>();
|
||||||
|
if (a.regex().length == 0) { // for current path
|
||||||
|
map.put(null, a.value());
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
for (String regex : a.regex()) { // for specified path
|
||||||
|
map.put(regex, a.value());
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
});
|
||||||
initializer.registerAnnotation(InlineComments.class, INLINE, a -> {
|
initializer.registerAnnotation(InlineComments.class, INLINE, a -> {
|
||||||
Map<String, String> map = new HashMap<>();
|
Map<String, String> map = new HashMap<>();
|
||||||
for (InlineComment comment : a.value()) {
|
for (InlineComment comment : a.value()) {
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package cc.carm.lib.configuration.option;
|
package cc.carm.lib.configuration.commentable;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.source.option.ConfigurationOption;
|
import cc.carm.lib.configuration.source.option.ConfigurationOption;
|
||||||
|
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<artifactId>easyconfiguration-parent</artifactId>
|
<artifactId>configured-parent</artifactId>
|
||||||
<version>4.0.0</version>
|
<version>4.1.7</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<properties>
|
<properties>
|
||||||
@@ -16,13 +16,13 @@
|
|||||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<artifactId>easyconfiguration-feature-file</artifactId>
|
<artifactId>configured-feature-file</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
<artifactId>easyconfiguration-core</artifactId>
|
<artifactId>configured-core</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
-2
@@ -1,7 +1,5 @@
|
|||||||
package cc.carm.lib.configuration.source.option;
|
package cc.carm.lib.configuration.source.option;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.source.option.ConfigurationOption;
|
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>cc.carm.lib</groupId>
|
||||||
|
<artifactId>configured-parent</artifactId>
|
||||||
|
<version>4.1.7</version>
|
||||||
|
<relativePath>../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
|
||||||
|
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||||
|
<kotlin.version>2.2.0</kotlin.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<artifactId>configured-feature-kotlin</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>configured-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||||
|
<version>${kotlin.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
|
||||||
|
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-maven-plugin</artifactId>
|
||||||
|
<version>${kotlin.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>compile</id>
|
||||||
|
<phase>compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>compile</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>test-compile</id>
|
||||||
|
<phase>test-compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>test-compile</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<jvmTarget>1.8</jvmTarget>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.jetbrains.dokka</groupId>
|
||||||
|
<artifactId>dokka-maven-plugin</artifactId>
|
||||||
|
<version>2.0.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>pre-site</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>dokka</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>default-compile</id>
|
||||||
|
<phase>none</phase>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>default-testCompile</id>
|
||||||
|
<phase>none</phase>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>compile</id>
|
||||||
|
<phase>compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>compile</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>testCompile</id>
|
||||||
|
<phase>test-compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>testCompile</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package cc.carm.lib.configuration.kotlin.value
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.adapter.ValueType
|
||||||
|
import cc.carm.lib.configuration.builder.list.SourceListBuilder
|
||||||
|
import cc.carm.lib.configuration.value.standard.ConfiguredList
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
inline fun <S : Any, reified V> listFrom(
|
||||||
|
clazz: KClass<S>, block: (SourceListBuilder<S, V>.() -> Unit)
|
||||||
|
): ConfiguredList<V> {
|
||||||
|
return listFrom(clazz.java, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <S : Any, reified V> listFrom(
|
||||||
|
clazz: Class<S>, block: (SourceListBuilder<S, V>.() -> Unit)
|
||||||
|
): ConfiguredList<V> {
|
||||||
|
return listFrom(ValueType.of(clazz), block)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <S : Any, reified V> listFrom(
|
||||||
|
valueType: ValueType<S>, block: (SourceListBuilder<S, V>.() -> Unit)
|
||||||
|
): ConfiguredList<V> {
|
||||||
|
val configBuilder = ConfiguredList.builderOf(V::class.java)
|
||||||
|
val sourceValueBuilder: SourceListBuilder<S, V> = if (valueType.rawType == String::class.java) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
configBuilder.fromString() as SourceListBuilder<S, V>
|
||||||
|
} else configBuilder.from(valueType)
|
||||||
|
return sourceValueBuilder.also(block).build()
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package cc.carm.lib.configuration.kotlin.value
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.adapter.ValueType
|
||||||
|
import cc.carm.lib.configuration.builder.map.SourceMapBuilder
|
||||||
|
import cc.carm.lib.configuration.value.standard.ConfiguredMap
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
inline fun <S : Any, reified K, reified V> hashmapFrom(
|
||||||
|
clazz: KClass<S>,
|
||||||
|
block: SourceMapBuilder<HashMap<K, V>, S, K, V>.() -> Unit
|
||||||
|
): ConfiguredMap<K, V> {
|
||||||
|
return hashmapFrom(clazz.java, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <S : Any, reified K, reified V> hashmapFrom(
|
||||||
|
clazz: Class<S>,
|
||||||
|
block: SourceMapBuilder<HashMap<K, V>, S, K, V>.() -> Unit
|
||||||
|
): ConfiguredMap<K, V> {
|
||||||
|
return hashmapFrom(ValueType.of(clazz), block)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <S : Any, reified K, reified V> hashmapFrom(
|
||||||
|
valueType: ValueType<S>,
|
||||||
|
block: SourceMapBuilder<HashMap<K, V>, S, K, V>.() -> Unit
|
||||||
|
): ConfiguredMap<K, V> {
|
||||||
|
val mapCreator = ConfiguredMap.builderOf(K::class.java, V::class.java)
|
||||||
|
val sourceValueBuilder: SourceMapBuilder<HashMap<K, V>, S, K, V> = mapCreator.asHashMap().from(valueType)
|
||||||
|
return sourceValueBuilder.also(block).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <S : Any, reified K, reified V> linkedMapFrom(
|
||||||
|
clazz: KClass<S>,
|
||||||
|
block: SourceMapBuilder<LinkedHashMap<K, V>, S, K, V>.() -> Unit
|
||||||
|
): ConfiguredMap<K, V> {
|
||||||
|
return linkedMapFrom(clazz.java, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <S : Any, reified K, reified V> linkedMapFrom(
|
||||||
|
clazz: Class<S>,
|
||||||
|
block: SourceMapBuilder<LinkedHashMap<K, V>, S, K, V>.() -> Unit
|
||||||
|
): ConfiguredMap<K, V> {
|
||||||
|
return linkedMapFrom(ValueType.of(clazz), block)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <S : Any, reified K, reified V> linkedMapFrom(
|
||||||
|
valueType: ValueType<S>,
|
||||||
|
block: SourceMapBuilder<LinkedHashMap<K, V>, S, K, V>.() -> Unit
|
||||||
|
): ConfiguredMap<K, V> {
|
||||||
|
val mapCreator = ConfiguredMap.builderOf(K::class.java, V::class.java)
|
||||||
|
val sourceValueBuilder: SourceMapBuilder<LinkedHashMap<K, V>, S, K, V> = mapCreator.asLinkedMap().from(valueType)
|
||||||
|
return sourceValueBuilder.also(block).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <S : Any, reified K, reified V> treeMapFrom(
|
||||||
|
clazz: KClass<S>,
|
||||||
|
block: SourceMapBuilder<TreeMap<K, V>, S, K, V>.() -> Unit
|
||||||
|
): ConfiguredMap<K, V> {
|
||||||
|
return treeMapFrom(clazz.java, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <S : Any, reified K, reified V> treeMapFrom(
|
||||||
|
clazz: Class<S>,
|
||||||
|
block: SourceMapBuilder<TreeMap<K, V>, S, K, V>.() -> Unit
|
||||||
|
): ConfiguredMap<K, V> {
|
||||||
|
return treeMapFrom(ValueType.of(clazz), block)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <S : Any, reified K, reified V> treeMapFrom(
|
||||||
|
valueType: ValueType<S>,
|
||||||
|
block: SourceMapBuilder<TreeMap<K, V>, S, K, V>.() -> Unit
|
||||||
|
): ConfiguredMap<K, V> {
|
||||||
|
val mapCreator = ConfiguredMap.builderOf(K::class.java, V::class.java)
|
||||||
|
val sourceValueBuilder: SourceMapBuilder<TreeMap<K, V>, S, K, V> = mapCreator.asTreeMap().from(valueType)
|
||||||
|
return sourceValueBuilder.also(block).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified MAP : Map<K, V>, S : Any, reified K, reified V> mapFrom(
|
||||||
|
clazz: KClass<S>,
|
||||||
|
noinline map: () -> MAP,
|
||||||
|
block: SourceMapBuilder<MAP, S, K, V>.() -> Unit
|
||||||
|
): ConfiguredMap<K, V> {
|
||||||
|
return mapFrom(clazz.java, map, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified MAP : Map<K, V>, S : Any, reified K, reified V> mapFrom(
|
||||||
|
clazz: Class<S>,
|
||||||
|
noinline map: () -> MAP,
|
||||||
|
block: SourceMapBuilder<MAP, S, K, V>.() -> Unit
|
||||||
|
): ConfiguredMap<K, V> {
|
||||||
|
return mapFrom(ValueType.of(clazz), map, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified MAP : Map<K, V>, S : Any, reified K, reified V> mapFrom(
|
||||||
|
valueType: ValueType<S>,
|
||||||
|
noinline map: () -> MAP,
|
||||||
|
block: SourceMapBuilder<MAP, S, K, V>.() -> Unit
|
||||||
|
): ConfiguredMap<K, V> {
|
||||||
|
val mapCreator = ConfiguredMap.builderOf(K::class.java, V::class.java)
|
||||||
|
val sourceValueBuilder: SourceMapBuilder<MAP, S, K, V> = mapCreator.constructor(map).from(valueType)
|
||||||
|
return sourceValueBuilder.also(block).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun <MAP : Map<K, V>, S, K, V> SourceMapBuilder<MAP, S, K, V>.defaultMap(map: MAP): SourceMapBuilder<MAP, S, K, V> {
|
||||||
|
return defaults(map)
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package cc.carm.lib.configuration.kotlin.value
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.adapter.ValueType
|
||||||
|
import cc.carm.lib.configuration.builder.value.SourceValueBuilder
|
||||||
|
import cc.carm.lib.configuration.value.standard.ConfiguredValue
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
inline fun <S : Any, reified T> valueFrom(
|
||||||
|
clazz: KClass<S>, block: (SourceValueBuilder<S, T>.() -> Unit)
|
||||||
|
): ConfiguredValue<T> {
|
||||||
|
return valueFrom(clazz.java, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <S : Any, reified V> valueFrom(
|
||||||
|
clazz: Class<S>, block: (SourceValueBuilder<S, V>.() -> Unit)
|
||||||
|
): ConfiguredValue<V> {
|
||||||
|
return valueFrom(ValueType.of(clazz), block)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <S : Any, reified V> valueFrom(
|
||||||
|
valueType: ValueType<S>, block: (SourceValueBuilder<S, V>.() -> Unit)
|
||||||
|
): ConfiguredValue<V> {
|
||||||
|
val configBuilder = ConfiguredValue.builderOf(V::class.java)
|
||||||
|
val sourceValueBuilder: SourceValueBuilder<S, V> = if (valueType.rawType == String::class.java) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
configBuilder.fromString() as SourceValueBuilder<S, V>
|
||||||
|
} else configBuilder.from(valueType)
|
||||||
|
sourceValueBuilder.parse { holder, data ->
|
||||||
|
holder.deserialize(V::class.java, data)
|
||||||
|
}
|
||||||
|
sourceValueBuilder.serialize { holder, data ->
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
holder.serialize(data) as? S
|
||||||
|
}
|
||||||
|
return sourceValueBuilder.also(block).build()
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>cc.carm.lib</groupId>
|
||||||
|
<artifactId>configured-parent</artifactId>
|
||||||
|
<version>4.1.7</version>
|
||||||
|
<relativePath>../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>configured-feature-record</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>16</maven.compiler.source>
|
||||||
|
<maven.compiler.target>16</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cc.carm.lib</groupId>
|
||||||
|
<artifactId>configured-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cc.carm.lib</groupId>
|
||||||
|
<artifactId>configured-temp</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>16</source>
|
||||||
|
<target>16</target>
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
|
<compilerArgument>-parameters</compilerArgument>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
+114
@@ -0,0 +1,114 @@
|
|||||||
|
package cc.carm.lib.configured.adapter.record;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.adapter.ValueAdapter;
|
||||||
|
import cc.carm.lib.configuration.adapter.ValueParser;
|
||||||
|
import cc.carm.lib.configuration.adapter.ValueSerializer;
|
||||||
|
import cc.carm.lib.configuration.adapter.ValueType;
|
||||||
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
|
import cc.carm.lib.configuration.source.section.ConfigureSection;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.RecordComponent;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class RecordAdapter<T extends Record> extends ValueAdapter<T> {
|
||||||
|
|
||||||
|
public static void register(ConfigurationHolder<?> holder) {
|
||||||
|
holder.adapters().register(of(Record.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <R extends Record> RecordAdapter<R> of(@NotNull Class<R> type) {
|
||||||
|
return of(ValueType.of(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <R extends Record> RecordAdapter<R> of(@NotNull ValueType<R> type) {
|
||||||
|
return new RecordAdapter<>(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordAdapter(@NotNull ValueType<T> type) {
|
||||||
|
super(type, serializer(type), parser(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <R extends Record> ValueSerializer<R> serializer(@NotNull ValueType<R> type) {
|
||||||
|
return (holder, type1, r) -> toMap(holder, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <R extends Record> ValueParser<R> parser(@NotNull ValueType<R> type) {
|
||||||
|
return (holder, valueType, value) -> {
|
||||||
|
if (value instanceof ConfigureSection section) {
|
||||||
|
return fromMap(holder, (Class<R>) valueType.getRawType(), section.asMap());
|
||||||
|
} else if (value instanceof Map<?, ?> map) {
|
||||||
|
return fromMap(holder, (Class<R>) valueType.getRawType(), (Map<String, Object>) map);
|
||||||
|
} else return null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <R extends Record> Map<String, Object> toMap(
|
||||||
|
@NotNull ConfigurationHolder<?> holder, @NotNull R record
|
||||||
|
) throws Exception {
|
||||||
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
Class<?> recordClass = record.getClass();
|
||||||
|
if (!recordClass.isRecord()) {
|
||||||
|
throw new IllegalArgumentException("Object is not a record");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
for (RecordComponent component : recordClass.getRecordComponents()) {
|
||||||
|
String name = component.getName();
|
||||||
|
Method accessor = component.getAccessor();
|
||||||
|
accessor.setAccessible(true);
|
||||||
|
Object value = accessor.invoke(record);
|
||||||
|
map.put(name, serializeValue(holder, value));
|
||||||
|
}
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new RuntimeException("Failed to convert record to map", e);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <R extends Record> R fromMap(
|
||||||
|
@NotNull ConfigurationHolder<?> holder,
|
||||||
|
@NotNull Class<R> type, @NotNull Map<String, Object> data
|
||||||
|
) throws Exception {
|
||||||
|
RecordComponent[] components = type.getRecordComponents();
|
||||||
|
Object[] args = new Object[components.length];
|
||||||
|
for (int i = 0; i < components.length; i++) {
|
||||||
|
RecordComponent component = components[i];
|
||||||
|
args[i] = parseValue(holder, component, data.get(component.getName()));
|
||||||
|
}
|
||||||
|
return createInstance(type, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static Object parseValue(ConfigurationHolder<?> holder, RecordComponent component, Object value) throws Exception {
|
||||||
|
if (value == null) return null;
|
||||||
|
if (component.getType().isRecord()) {
|
||||||
|
return fromMap(holder, component.getType().asSubclass(Record.class), (Map<String, Object>) value);
|
||||||
|
}
|
||||||
|
ValueType<?> valueType = ValueType.of(component.getGenericType());
|
||||||
|
return holder.deserialize(valueType, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object serializeValue(ConfigurationHolder<?> holder, Object value) throws Exception {
|
||||||
|
if (value == null) return null;
|
||||||
|
if (value.getClass().isRecord()) {
|
||||||
|
return toMap(holder, (Record) value);
|
||||||
|
}
|
||||||
|
return holder.serialize(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> T createInstance(Class<T> t, Object[] args) throws Exception {
|
||||||
|
Class<?>[] paramTypes = Arrays.stream(t.getRecordComponents())
|
||||||
|
.map(RecordComponent::getType).toArray(Class[]::new);
|
||||||
|
Constructor<T> constructor = t.getDeclaredConstructor(paramTypes);
|
||||||
|
constructor.setAccessible(true); // Make sure the constructor is accessible
|
||||||
|
return constructor.newInstance(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
import cc.carm.lib.configuration.Configuration;
|
||||||
|
import cc.carm.lib.configuration.annotation.ConfigPath;
|
||||||
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
|
import cc.carm.lib.configuration.source.temp.TempConfigFactory;
|
||||||
|
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||||
|
import cc.carm.lib.configured.adapter.record.RecordAdapter;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class RecordTest {
|
||||||
|
|
||||||
|
@ConfigPath(root = true)
|
||||||
|
interface ConfigA extends Configuration {
|
||||||
|
|
||||||
|
ConfiguredValue<Device> VAL = ConfiguredValue.of(new Device(
|
||||||
|
"device1",
|
||||||
|
"My Device",
|
||||||
|
UUID.fromString("123e4567-e89b-12d3-a456-426614174000"),
|
||||||
|
new Chip("chip1", null),
|
||||||
|
Arrays.asList(
|
||||||
|
new User("Alice", 30),
|
||||||
|
new User("Bob", 25)
|
||||||
|
),
|
||||||
|
Map.of(
|
||||||
|
"Cloud", new Connection("cloud.example.com", 443),
|
||||||
|
"Local", new Connection("127.0.0.1", 8080)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigPath(root = true)
|
||||||
|
interface ConfigB extends Configuration {
|
||||||
|
|
||||||
|
ConfiguredValue<Device> VAL = ConfiguredValue.of(Device.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
|
||||||
|
ConfigurationHolder<?> holder = TempConfigFactory.create().build();
|
||||||
|
RecordAdapter.register(holder);
|
||||||
|
holder.initialize(ConfigA.class);
|
||||||
|
|
||||||
|
System.out.println("Device ID: " + ConfigA.VAL.resolve().id());
|
||||||
|
System.out.println("Device Name: " + ConfigA.VAL.resolve().name());
|
||||||
|
System.out.println("Device Serial: " + ConfigA.VAL.resolve().serial());
|
||||||
|
System.out.println("Chip ID: " + ConfigA.VAL.resolve().chip().id());
|
||||||
|
System.out.println("Chip Serial: " + ConfigA.VAL.resolve().chip().serialNumber());
|
||||||
|
for (User user : ConfigA.VAL.resolve().users()) {
|
||||||
|
System.out.println("Another Users: " + user.name() + ", Age: " + user.age());
|
||||||
|
}
|
||||||
|
|
||||||
|
printMap(holder.config().asMap(), 0);
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// List<User> parsed = holder.deserialize(ValueType.ofList(User.class), holder.config().getList("val.users"));
|
||||||
|
// System.out.println("Parsed Users: " + parsed);
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
ConfigurationHolder<?> anotherHolder = TempConfigFactory.create().defaults(() -> holder.config().asMap()).build();
|
||||||
|
RecordAdapter.register(anotherHolder);
|
||||||
|
|
||||||
|
anotherHolder.initialize(ConfigB.class);
|
||||||
|
|
||||||
|
System.out.println("Another Device ID: " + ConfigB.VAL.resolve().id());
|
||||||
|
System.out.println("Another Device Name: " + ConfigB.VAL.resolve().name());
|
||||||
|
System.out.println("Another Device Serial: " + ConfigB.VAL.resolve().serial());
|
||||||
|
System.out.println("Another Chip ID: " + ConfigB.VAL.resolve().chip().id());
|
||||||
|
System.out.println("Another Chip Serial: " + ConfigB.VAL.resolve().chip().serialNumber());
|
||||||
|
System.out.println("users: " + ConfigB.VAL.resolve().users().size());
|
||||||
|
for (User user : ConfigB.VAL.resolve().users()) {
|
||||||
|
System.out.println("Another Users: " + user.name() + ", Age: " + user.age());
|
||||||
|
}
|
||||||
|
ConfigB.VAL.resolve().connections.forEach((k, v) -> {
|
||||||
|
System.out.println("Connection " + k + ": " + v.address() + ":" + v.port());
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
record User(String name, int age) {
|
||||||
|
}
|
||||||
|
|
||||||
|
record Connection(String address, int port) {
|
||||||
|
}
|
||||||
|
|
||||||
|
record Device(String id, String name, UUID serial, Chip chip,
|
||||||
|
List<User> users,
|
||||||
|
Map<String, Connection> connections) {
|
||||||
|
}
|
||||||
|
|
||||||
|
record Chip(String id, @Nullable String serialNumber) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void printMap(Map<String, Object> map, int indent) {
|
||||||
|
String indentStr = " ".repeat(indent);
|
||||||
|
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||||
|
if (entry.getValue() instanceof Map<?, ?> subMap) {
|
||||||
|
System.out.println(indentStr + entry.getKey() + ":");
|
||||||
|
printMap((Map<String, Object>) subMap, indent + 2);
|
||||||
|
} else if (entry.getValue() instanceof List<?> subList) {
|
||||||
|
System.out.println(indentStr + entry.getKey() + ":");
|
||||||
|
for (Object item : subList) {
|
||||||
|
if (item instanceof Map<?, ?> itemMap) {
|
||||||
|
System.out.println(indentStr + " - ");
|
||||||
|
printMap((Map<String, Object>) itemMap, indent + 2);
|
||||||
|
} else {
|
||||||
|
System.out.println(indentStr + " - " + item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println(indentStr + entry.getKey() + ": " + entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<artifactId>easyconfiguration-parent</artifactId>
|
<artifactId>configured-parent</artifactId>
|
||||||
<version>4.0.0</version>
|
<version>4.1.7</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<properties>
|
<properties>
|
||||||
@@ -16,13 +16,13 @@
|
|||||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<artifactId>easyconfiguration-feature-section</artifactId>
|
<artifactId>configured-feature-section</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
<artifactId>easyconfiguration-core</artifactId>
|
<artifactId>configured-core</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
+189
@@ -0,0 +1,189 @@
|
|||||||
|
package cc.carm.lib.configuration.source.section;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.annotations.UnmodifiableView;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public abstract class AbstractMapSection<R extends AbstractMapSection<R>> implements ConfigureSection {
|
||||||
|
|
||||||
|
protected final @NotNull Map<String, Object> data;
|
||||||
|
protected final @Nullable R parent;
|
||||||
|
protected final @NotNull String path;
|
||||||
|
|
||||||
|
protected AbstractMapSection(@Nullable R parent, @NotNull String path) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.path = path;
|
||||||
|
this.data = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void migrate(Map<?, ?> data) {
|
||||||
|
for (Map.Entry<?, ?> entry : data.entrySet()) {
|
||||||
|
String key = (entry.getKey() == null) ? "" : entry.getKey().toString();
|
||||||
|
if (entry.getValue() instanceof Map) {
|
||||||
|
this.data.put(key, createSection(key, (Map<?, ?>) entry.getValue()));
|
||||||
|
} else if (entry.getValue() instanceof List) {
|
||||||
|
List<Object> list = new ArrayList<>();
|
||||||
|
int index = 0;
|
||||||
|
for (Object obj : (List<?>) entry.getValue()) {
|
||||||
|
if (obj instanceof Map) {
|
||||||
|
list.add(createSection(key + "[" + index + "]", (Map<?, ?>) obj));
|
||||||
|
} else {
|
||||||
|
list.add(obj);
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
this.data.put(key, list);
|
||||||
|
} else {
|
||||||
|
this.data.put(key, entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract @NotNull R self();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract @NotNull R createSection(@NotNull String path, @NotNull Map<?, ?> data);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String path() {
|
||||||
|
return this.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(@NotNull String path) {
|
||||||
|
R section = getSectionFor(path);
|
||||||
|
if (section == this) {
|
||||||
|
return this.data().containsKey(path);
|
||||||
|
} else {
|
||||||
|
return section.contains(childPath(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull Map<String, Object> data() {
|
||||||
|
return this.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return this.data.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size(boolean deep) {
|
||||||
|
return deep ? getKeys(true).size() : this.data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@UnmodifiableView
|
||||||
|
public @NotNull Map<String, Object> asMap() {
|
||||||
|
Map<String, Object> output = new LinkedHashMap<>();
|
||||||
|
for (Map.Entry<String, Object> entry : this.data.entrySet()) {
|
||||||
|
if (entry.getValue() instanceof AbstractMapSection<?>) {
|
||||||
|
output.put(entry.getKey(), ((AbstractMapSection<?>) entry.getValue()).asMap());
|
||||||
|
} else if (entry.getValue() instanceof List<?>) {
|
||||||
|
List<Object> list = new ArrayList<>();
|
||||||
|
for (Object obj : (List<?>) entry.getValue()) {
|
||||||
|
if (obj instanceof AbstractMapSection<?>) {
|
||||||
|
list.add(((AbstractMapSection<?>) obj).asMap());
|
||||||
|
} else {
|
||||||
|
list.add(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output.put(entry.getKey(), list);
|
||||||
|
} else {
|
||||||
|
output.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable R parent() {
|
||||||
|
return this.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Map<String, Object> getValues(boolean deep) {
|
||||||
|
return Collections.unmodifiableMap(deep ? mappingValues(this, null, true, String.valueOf(pathSeparator())) : data());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Set<String> getKeys(boolean deep) {
|
||||||
|
return Collections.unmodifiableSet(deep ? mappingKeys(this, null, true, String.valueOf(pathSeparator())) : data().keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(@NotNull String path, @Nullable Object value) {
|
||||||
|
if (value instanceof Map) value = createSection(path, (Map<?, ?>) value);
|
||||||
|
|
||||||
|
R section = getSectionFor(path);
|
||||||
|
if (section == this) {
|
||||||
|
// Even this value is null, we still need to put it in the map
|
||||||
|
// to ensure that the path is marked as existing.
|
||||||
|
this.data.put(path, value);
|
||||||
|
} else {
|
||||||
|
section.set(childPath(path), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(@NotNull String path) {
|
||||||
|
R section = getSectionFor(path);
|
||||||
|
if (section != this) {
|
||||||
|
section.remove(childPath(path));
|
||||||
|
} else {
|
||||||
|
this.data.remove(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Object get(@NotNull String path) {
|
||||||
|
R section = getSectionFor(path);
|
||||||
|
return section == this ? data.get(path) : section.get(childPath(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private R getSectionFor(String path) {
|
||||||
|
int index = path.indexOf(pathSeparator());
|
||||||
|
if (index == -1) return self();
|
||||||
|
|
||||||
|
String root = path.substring(0, index);
|
||||||
|
return (R) computeSection(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map the values of the children of the section to the output map.
|
||||||
|
*
|
||||||
|
* @param section The section to map the values from
|
||||||
|
* @param parent The parent path
|
||||||
|
* @param deep If the mapping should be deep
|
||||||
|
*/
|
||||||
|
protected static Map<String, Object> mappingValues(@NotNull AbstractMapSection<?> section, @Nullable String parent, boolean deep, String pathSeparator) {
|
||||||
|
Map<String, Object> output = new LinkedHashMap<>();
|
||||||
|
for (Map.Entry<String, Object> entry : section.data().entrySet()) {
|
||||||
|
String path = (parent == null ? "" : parent + pathSeparator) + entry.getKey();
|
||||||
|
output.remove(path);
|
||||||
|
output.put(path, entry.getValue());
|
||||||
|
if (deep && entry.getValue() instanceof AbstractMapSection<?>) {
|
||||||
|
output.putAll(mappingValues((AbstractMapSection<?>) entry.getValue(), path, true, pathSeparator));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Set<String> mappingKeys(@NotNull AbstractMapSection<?> section, @Nullable String parent, boolean deep, String pathSeparator) {
|
||||||
|
Set<String> keys = new LinkedHashSet<>();
|
||||||
|
for (Map.Entry<String, Object> entry : section.data().entrySet()) {
|
||||||
|
String path = (parent == null ? "" : parent + pathSeparator) + entry.getKey();
|
||||||
|
keys.add(path);
|
||||||
|
if (deep && entry.getValue() instanceof AbstractMapSection<?>) {
|
||||||
|
keys.addAll(mappingKeys((AbstractMapSection<?>) entry.getValue(), path, true, pathSeparator));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+388
@@ -0,0 +1,388 @@
|
|||||||
|
package cc.carm.lib.configuration.source.section;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.function.DataFunction;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.annotations.UnmodifiableView;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class ImmutableSection implements ConfigureSection {
|
||||||
|
|
||||||
|
public static ImmutableSection of(@NotNull ConfigureSection section) {
|
||||||
|
if (section instanceof ImmutableSection) {
|
||||||
|
return (ImmutableSection) section;
|
||||||
|
} else return new ImmutableSection(null, section);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final @Nullable ImmutableSection parent;
|
||||||
|
protected final @NotNull ConfigureSection raw;
|
||||||
|
|
||||||
|
private ImmutableSection(@Nullable ImmutableSection parent, @NotNull ConfigureSection raw) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.raw = raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
private @NotNull ConfigureSection raw() {
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ImmutableSection parent() {
|
||||||
|
return this.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String path() {
|
||||||
|
return raw().path();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Map<String, Object> getValues(boolean deep) {
|
||||||
|
return raw().getValues(deep);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(@NotNull String path, @Nullable Object value) {
|
||||||
|
throw new IllegalStateException("This section is not modifiable!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(@NotNull String path) {
|
||||||
|
throw new IllegalStateException("This section is not modifiable!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ImmutableSection createSection(@NotNull String path, @NotNull Map<?, ?> data) {
|
||||||
|
return new ImmutableSection(this, raw().createSection(path, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Object get(@NotNull String path) {
|
||||||
|
Object value = raw().get(path);
|
||||||
|
if (value instanceof ConfigureSection && !(value instanceof ImmutableSection)) {
|
||||||
|
return new ImmutableSection(this, (ConfigureSection) value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ConfigureSection getSection(@NotNull String path) {
|
||||||
|
ConfigureSection get = raw().getSection(path);
|
||||||
|
if (!(get instanceof ImmutableSection)) {
|
||||||
|
return new ImmutableSection(this, get);
|
||||||
|
}
|
||||||
|
return get;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char pathSeparator() {
|
||||||
|
return raw().pathSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRoot() {
|
||||||
|
return raw().isRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return raw().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Set<String> getKeys(boolean deep) {
|
||||||
|
return raw().getKeys(deep);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Set<String> keys() {
|
||||||
|
return raw().keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Map<String, Object> values() {
|
||||||
|
return raw().values();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Map<String, Object> asMap() {
|
||||||
|
return raw().asMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<Map.Entry<String, Object>> stream() {
|
||||||
|
return raw().stream();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEach(@NotNull BiConsumer<String, Object> action) {
|
||||||
|
raw().forEach(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(@NotNull String path) {
|
||||||
|
return raw().contains(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsValue(@NotNull String path) {
|
||||||
|
return raw().containsValue(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> boolean isType(@NotNull String path, @NotNull Class<T> typeClass) {
|
||||||
|
return raw().isType(path, typeClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isList(@NotNull String path) {
|
||||||
|
return raw().isList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable List<?> getList(@NotNull String path) {
|
||||||
|
return raw().getList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSection(@NotNull String path) {
|
||||||
|
return raw().isSection(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> @Nullable T get(@NotNull String path, @NotNull Class<T> type) {
|
||||||
|
return raw().get(path, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> @Nullable T get(@NotNull String path, @NotNull DataFunction<@Nullable Object, T> parser) {
|
||||||
|
return raw().get(path, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> @Nullable T get(@NotNull String path, T defaults, @NotNull Class<T> clazz) {
|
||||||
|
return raw().get(path, defaults, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> @Nullable T get(@NotNull String path, T defaultValue, @NotNull DataFunction<Object, T> parser) {
|
||||||
|
return raw().get(path, defaultValue, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBoolean(@NotNull String path) {
|
||||||
|
return raw().isBoolean(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getBoolean(@NotNull String path) {
|
||||||
|
return raw().getBoolean(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Boolean getBoolean(@NotNull String path, @Nullable Boolean def) {
|
||||||
|
return raw().getBoolean(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Boolean isByte(@NotNull String path) {
|
||||||
|
return raw().isByte(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Byte getByte(@NotNull String path) {
|
||||||
|
return raw().getByte(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Byte getByte(@NotNull String path, @Nullable Byte def) {
|
||||||
|
return raw().getByte(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isShort(@NotNull String path) {
|
||||||
|
return raw().isShort(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Short getShort(@NotNull String path) {
|
||||||
|
return raw().getShort(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Short getShort(@NotNull String path, @Nullable Short def) {
|
||||||
|
return raw().getShort(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInt(@NotNull String path) {
|
||||||
|
return raw().isInt(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Integer getInt(@NotNull String path) {
|
||||||
|
return raw().getInt(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Integer getInt(@NotNull String path, @Nullable Integer def) {
|
||||||
|
return raw().getInt(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLong(@NotNull String path) {
|
||||||
|
return raw().isLong(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Long getLong(@NotNull String path) {
|
||||||
|
return raw().getLong(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Long getLong(@NotNull String path, @Nullable Long def) {
|
||||||
|
return raw().getLong(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFloat(@NotNull String path) {
|
||||||
|
return raw().isFloat(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Float getFloat(@NotNull String path) {
|
||||||
|
return raw().getFloat(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Float getFloat(@NotNull String path, @Nullable Float def) {
|
||||||
|
return raw().getFloat(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDouble(@NotNull String path) {
|
||||||
|
return raw().isDouble(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Double getDouble(@NotNull String path) {
|
||||||
|
return raw().getDouble(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Double getDouble(@NotNull String path, @Nullable Double def) {
|
||||||
|
return raw().getDouble(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isChar(@NotNull String path) {
|
||||||
|
return raw().isChar(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Character getChar(@NotNull String path) {
|
||||||
|
return raw().getChar(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Character getChar(@NotNull String path, @Nullable Character def) {
|
||||||
|
return raw().getChar(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isString(@NotNull String path) {
|
||||||
|
return raw().isString(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String getString(@NotNull String path) {
|
||||||
|
return raw().getString(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String getString(@NotNull String path, @Nullable String def) {
|
||||||
|
return raw().getString(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull <V> List<V> getList(@NotNull String path, @NotNull DataFunction<Object, V> parser) {
|
||||||
|
return raw().getList(path, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<String> getStringList(@NotNull String path) {
|
||||||
|
return raw().getStringList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<Integer> getIntegerList(@NotNull String path) {
|
||||||
|
return raw().getIntegerList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<Long> getLongList(@NotNull String path) {
|
||||||
|
return raw().getLongList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<Double> getDoubleList(@NotNull String path) {
|
||||||
|
return raw().getDoubleList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<Float> getFloatList(@NotNull String path) {
|
||||||
|
return raw().getFloatList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<Byte> getByteList(@NotNull String path) {
|
||||||
|
return raw().getByteList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<Character> getCharList(@NotNull String path) {
|
||||||
|
return raw().getCharList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<ConfigureSection> getSectionList(@NotNull String path) {
|
||||||
|
return raw().getSectionList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T, C extends Collection<T>> @NotNull C getCollection(@NotNull String path, @NotNull Supplier<C> constructor, @NotNull DataFunction<Object, T> parser) {
|
||||||
|
return raw().getCollection(path, constructor, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Stream<?> stream(@NotNull String path) {
|
||||||
|
return raw().stream(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull <T> Stream<T> stream(@NotNull String path, @NotNull Function<Object, T> parser) {
|
||||||
|
return raw().stream(path, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String childPath(String path) {
|
||||||
|
return raw().childPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return raw.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return Objects.equals(raw, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+32
-126
@@ -3,148 +3,54 @@ package cc.carm.lib.configuration.source.section;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class MemorySection implements ConfigureSection {
|
public class MemorySection extends AbstractMapSection<MemorySection> {
|
||||||
|
|
||||||
public static @NotNull MemorySection root(@NotNull ConfigureSource<? extends MemorySection, ?, ?> source) {
|
public static MemorySection of() {
|
||||||
return new MemorySection(source, new LinkedHashMap<>(), null);
|
return of(new LinkedHashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NotNull MemorySection root(@NotNull ConfigureSource<? extends MemorySection, ?, ?> source,
|
public static MemorySection of(@NotNull Consumer<Map<String, Object>> data) {
|
||||||
@Nullable Map<?, ?> data) {
|
return of(() -> {
|
||||||
return new MemorySection(source, data == null ? new LinkedHashMap<>() : data, null);
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
data.accept(map);
|
||||||
|
return map;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final @NotNull ConfigureSource<? extends MemorySection, ?, ?> source;
|
public static MemorySection of(@NotNull Supplier<Map<?, ?>> data) {
|
||||||
protected final @NotNull Map<String, Object> data;
|
return of(data.get());
|
||||||
protected final @Nullable MemorySection parent;
|
|
||||||
|
|
||||||
public MemorySection(@NotNull ConfigureSource<? extends MemorySection, ?, ?> source,
|
|
||||||
@NotNull Map<?, ?> data, @Nullable MemorySection parent) {
|
|
||||||
this.source = source;
|
|
||||||
this.parent = parent;
|
|
||||||
this.data = new LinkedHashMap<>();
|
|
||||||
for (Map.Entry<?, ?> entry : data.entrySet()) {
|
|
||||||
String key = (entry.getKey() == null) ? "null" : entry.getKey().toString();
|
|
||||||
if (entry.getValue() instanceof Map) {
|
|
||||||
this.data.put(key, createChild((Map<?, ?>) entry.getValue()));
|
|
||||||
} else if (entry.getValue() instanceof List) {
|
|
||||||
List<Object> list = new ArrayList<>();
|
|
||||||
for (Object obj : (List<?>) entry.getValue()) {
|
|
||||||
if (obj instanceof Map) {
|
|
||||||
list.add(createChild((Map<?, ?>) obj));
|
|
||||||
} else {
|
|
||||||
list.add(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.data.put(key, list);
|
|
||||||
} else {
|
|
||||||
this.data.put(key, entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected @NotNull MemorySection createChild(@NotNull Map<?, ?> data) {
|
public static MemorySection of(@NotNull Map<?, ?> data) {
|
||||||
return new MemorySection(source(), data, this);
|
return of(data, null, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected @NotNull MemorySection createChild() {
|
public static MemorySection of(@Nullable MemorySection parent, @NotNull String path) {
|
||||||
return createChild(new LinkedHashMap<>());
|
return of(new LinkedHashMap<>(), parent, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MemorySection of(@NotNull Map<?, ?> data, @Nullable MemorySection parent, @NotNull String path) {
|
||||||
|
return new MemorySection(data, parent, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MemorySection(@NotNull Map<?, ?> raw, @Nullable MemorySection parent, @NotNull String path) {
|
||||||
|
super(parent, path);
|
||||||
|
migrate(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull ConfigureSource<? extends MemorySection, ?, ?> source() {
|
public @NotNull MemorySection self() {
|
||||||
return this.source;
|
return this;
|
||||||
}
|
|
||||||
|
|
||||||
public @NotNull Map<String, Object> data() {
|
|
||||||
return this.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @Nullable MemorySection parent() {
|
|
||||||
return this.parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Map<String, Object> getValues(boolean deep) {
|
public @NotNull MemorySection createSection(@NotNull String path, @NotNull Map<?, ?> data) {
|
||||||
return Collections.unmodifiableMap(deep ? mapChildrenValues(this, null, true) : data());
|
return new MemorySection(data, this, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void set(@NotNull String path, @Nullable Object value) {
|
|
||||||
if (value instanceof Map) value = createChild((Map<?, ?>) value);
|
|
||||||
|
|
||||||
MemorySection section = getSectionFor(path);
|
|
||||||
if (section == this) {
|
|
||||||
// Even this value is null, we still need to put it in the map
|
|
||||||
// to ensure that the path is marked as existing.
|
|
||||||
this.data.put(path, value);
|
|
||||||
} else {
|
|
||||||
section.set(childPath(path), value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean contains(@NotNull String path) {
|
|
||||||
return get(path) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable Object get(@NotNull String path) {
|
|
||||||
MemorySection section = getSectionFor(path);
|
|
||||||
return section == this ? data.get(path) : section.get(childPath(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable List<?> getList(@NotNull String path) {
|
|
||||||
Object val = get(path);
|
|
||||||
return (val instanceof List<?>) ? (List<?>) val : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable ConfigureSection getSection(@NotNull String path) {
|
|
||||||
Object val = get(path);
|
|
||||||
return (val instanceof ConfigureSection) ? (ConfigureSection) val : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MemorySection getSectionFor(String path) {
|
|
||||||
int index = path.indexOf(separator());
|
|
||||||
if (index == -1) return this;
|
|
||||||
|
|
||||||
String root = path.substring(0, index);
|
|
||||||
Object section = this.data.get(root);
|
|
||||||
if (section == null) {
|
|
||||||
section = createChild();
|
|
||||||
this.data.put(root, section);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (MemorySection) section;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String childPath(String path) {
|
|
||||||
int index = path.indexOf(separator());
|
|
||||||
return (index == -1) ? path : path.substring(index + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map the values of the children of the section to the output map.
|
|
||||||
*
|
|
||||||
* @param section The section to map the values from
|
|
||||||
* @param parent The parent path
|
|
||||||
* @param deep If the mapping should be deep
|
|
||||||
*/
|
|
||||||
protected Map<String, Object> mapChildrenValues(@NotNull MemorySection section,
|
|
||||||
@Nullable String parent, boolean deep) {
|
|
||||||
Map<String, Object> output = new LinkedHashMap<>();
|
|
||||||
for (Map.Entry<String, Object> entry : section.data().entrySet()) {
|
|
||||||
String path = (parent == null ? "" : parent + separator()) + entry.getKey();
|
|
||||||
output.remove(path);
|
|
||||||
output.put(path, entry.getValue());
|
|
||||||
if (deep && entry.getValue() instanceof MemorySection) {
|
|
||||||
output.putAll(mapChildrenValues((MemorySection) entry.getValue(), path, true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+151
@@ -0,0 +1,151 @@
|
|||||||
|
package cc.carm.lib.configuration.source.section;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.annotations.UnmodifiableView;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class ShadedSection implements ConfigureSection {
|
||||||
|
|
||||||
|
public static ShadedSection create(@NotNull ConfigureSection template, @Nullable ConfigureSection source) {
|
||||||
|
return new ShadedSection(null, template, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final @Nullable ShadedSection parent;
|
||||||
|
protected @NotNull ConfigureSection template;
|
||||||
|
protected @Nullable ConfigureSection source;
|
||||||
|
|
||||||
|
public ShadedSection(@Nullable ShadedSection parent,
|
||||||
|
@NotNull ConfigureSection template, @Nullable ConfigureSection source) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.template = template;
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ConfigureSection parent() {
|
||||||
|
return this.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String path() {
|
||||||
|
return this.template.path();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Map<String, Object> getValues(boolean deep) {
|
||||||
|
if (source == null) return template.getValues(deep);
|
||||||
|
// 本函数为,当 getValues 时,递归合并 source 和 template
|
||||||
|
return merge(template, source).getValues(deep);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Map<String, Object> asMap() {
|
||||||
|
if (source == null) return template.asMap();
|
||||||
|
return merge(template, source).asMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Set<String> getKeys(boolean deep) {
|
||||||
|
Set<String> keys = new HashSet<>(template.getKeys(deep));
|
||||||
|
if (source != null) {
|
||||||
|
keys.addAll(source.getKeys(deep));
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableSet(keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConfigureSection merge(ConfigureSection templateSection, ConfigureSection valueSection) {
|
||||||
|
MemorySection merged = MemorySection.of();
|
||||||
|
Set<String> existingKey = new HashSet<>();
|
||||||
|
|
||||||
|
for (Map.Entry<String, Object> entry : valueSection.getValues(false).entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (value instanceof ConfigureSection) {
|
||||||
|
ConfigureSection subSectionFromValue = (ConfigureSection) value;
|
||||||
|
ConfigureSection subSectionFromTemplate = (ConfigureSection) templateSection.get(key);
|
||||||
|
if (subSectionFromTemplate == null) {
|
||||||
|
merged.set(key, value);
|
||||||
|
} else {
|
||||||
|
merged.set(key, merge(subSectionFromTemplate, subSectionFromValue));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
merged.set(key, value);
|
||||||
|
}
|
||||||
|
existingKey.add(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<String, Object> entry : templateSection.getValues(false).entrySet()) {
|
||||||
|
if (existingKey.contains(entry.getKey())) continue;
|
||||||
|
merged.set(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return merged;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(@NotNull String path, @Nullable Object value) {
|
||||||
|
if (value instanceof ConfigureSection) {
|
||||||
|
ConfigureSection targetSection = (ConfigureSection) value;
|
||||||
|
for (Map.Entry<String, Object> entry : targetSection.getValues(true).entrySet()) {
|
||||||
|
set(path + pathSeparator() + entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (Objects.equals(get(path), value)) {
|
||||||
|
remove(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional.ofNullable(source).ifPresent(s -> s.set(path, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(@NotNull String path) {
|
||||||
|
Optional.ofNullable(source).ifPresent(s -> s.remove(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ConfigureSection createSection(@NotNull String path, @NotNull Map<?, ?> data) {
|
||||||
|
if (source == null) {
|
||||||
|
return new ShadedSection(this, template, MemorySection.of(data));
|
||||||
|
} else {
|
||||||
|
ConfigureSection section = source.computeSection(path, data);
|
||||||
|
return new ShadedSection(this, template, section);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Object get(@NotNull String path) {
|
||||||
|
if (source == null) {
|
||||||
|
return getFromTemplate(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object value = source.get(path);
|
||||||
|
if (value == null) {
|
||||||
|
return getFromTemplate(path);
|
||||||
|
}
|
||||||
|
if (value instanceof ConfigureSection) {
|
||||||
|
ConfigureSection templateSection = (ConfigureSection) template.get(path);
|
||||||
|
if (templateSection == null) {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
return new ShadedSection(this, templateSection, (ConfigureSection) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Object getFromTemplate(@NotNull String path) {
|
||||||
|
Object value = template.get(path);
|
||||||
|
if (value instanceof ConfigureSection) {
|
||||||
|
return new ShadedSection(this, (ConfigureSection) value, null);
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable ConfigureSection getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
}
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
package cc.carm.lib.configuration.source.section;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class SourcedSection extends AbstractMapSection<SourcedSection> {
|
||||||
|
|
||||||
|
public static @NotNull SourcedSection root(@NotNull ConfigureSource<? extends SourcedSection, ?, ?> source) {
|
||||||
|
return new SourcedSection(source, new LinkedHashMap<>(), null, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NotNull SourcedSection root(@NotNull ConfigureSource<? extends SourcedSection, ?, ?> source,
|
||||||
|
@Nullable Map<?, ?> raw) {
|
||||||
|
return new SourcedSection(source, raw == null ? new LinkedHashMap<>() : raw, null, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final @NotNull ConfigureSource<? extends SourcedSection, ?, ?> source;
|
||||||
|
|
||||||
|
public SourcedSection(@NotNull ConfigureSource<? extends SourcedSection, ?, ?> source,
|
||||||
|
@NotNull Map<?, ?> raw, @Nullable SourcedSection parent, @NotNull String path) {
|
||||||
|
super(parent, path);
|
||||||
|
this.source = source;
|
||||||
|
migrate(raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull ConfigureSource<? extends SourcedSection, ?, ?> source() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char pathSeparator() {
|
||||||
|
return source().pathSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull SourcedSection self() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull SourcedSection createSection(@NotNull String path, @NotNull Map<?, ?> data) {
|
||||||
|
return new SourcedSection(source(), data, this, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package test.section;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.source.section.ConfigureSection;
|
||||||
|
import cc.carm.lib.configuration.source.section.MemorySection;
|
||||||
|
import cc.carm.lib.configuration.source.section.ShadedSection;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Lyzen
|
||||||
|
* @date 21/2/2025 下午2:18
|
||||||
|
*/
|
||||||
|
public class ShadeTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
ConfigureSection template = MemorySection.of(data -> {
|
||||||
|
data.put("name", "GentleMan");
|
||||||
|
data.put("age", 12);
|
||||||
|
data.put("gender", "male");
|
||||||
|
Map<String, Object> address = new LinkedHashMap<>();
|
||||||
|
address.put("Hotel", "Nanjing Road 101");
|
||||||
|
address.put("Store", "Beijing Road 404");
|
||||||
|
Map<String, Object> mapInside = new LinkedHashMap<>();
|
||||||
|
mapInside.put("InsideKeyExample", "InsideValueExample");
|
||||||
|
address.put("Inside", mapInside);
|
||||||
|
data.put("addresses", address);
|
||||||
|
data.put("cards", Arrays.asList("00000", "11111", "22222"));
|
||||||
|
});
|
||||||
|
ConfigureSection source = MemorySection.of(data -> {
|
||||||
|
data.put("age", 25);
|
||||||
|
Map<String, Object> address = new LinkedHashMap<>();
|
||||||
|
address.put("NewOne", "Guangdong Road 505");
|
||||||
|
data.put("addresses", address);
|
||||||
|
Map<String, Object> mapInside = new LinkedHashMap<>();
|
||||||
|
mapInside.put("AnotherInsideKey", "AnotherInsideValue");
|
||||||
|
address.put("Inside", mapInside);
|
||||||
|
data.put("cards", Arrays.asList("33333", "55555")); // 应当直接覆盖原先的List
|
||||||
|
});
|
||||||
|
|
||||||
|
ShadedSection root = new ShadedSection(null, template, source);
|
||||||
|
System.out.println("age: " + root.get("age"));
|
||||||
|
System.out.println("addresses: ");
|
||||||
|
for (Map.Entry<String, Object> entry : root.getSection("addresses").getValues(false).entrySet()) {
|
||||||
|
System.out.println(" " + entry.getKey() + ": " + entry.getValue());
|
||||||
|
if (entry.getValue() instanceof ConfigureSection) {
|
||||||
|
for (Map.Entry<String, Object> inner : ((ConfigureSection) entry.getValue()).getValues(false).entrySet()) {
|
||||||
|
System.out.println(" " + inner.getKey() + ": " + inner.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("cards: " + root.getList("cards"));
|
||||||
|
|
||||||
|
System.out.println("\n----------------------\n");
|
||||||
|
System.out.println("Deep Search Test");
|
||||||
|
System.out.println("addresses: ");
|
||||||
|
for (Map.Entry<String, Object> entry : root.getSection("addresses").getValues(true).entrySet()) {
|
||||||
|
System.out.println(" " + entry.getKey() + ": " + entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("\n----------------------\n");
|
||||||
|
|
||||||
|
root.set("addresses", MemorySection.of(map -> {
|
||||||
|
map.put("Hotel", "Nanjing Road 101");
|
||||||
|
map.put("Store", "Beijing Road banned");
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
for (Map.Entry<String, Object> entry : source.getValues(true).entrySet()) {
|
||||||
|
System.out.println(" " + entry.getKey() + ": " + entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>cc.carm.lib</groupId>
|
||||||
|
<artifactId>configured-parent</artifactId>
|
||||||
|
<version>4.1.7</version>
|
||||||
|
<relativePath>../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
|
||||||
|
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<artifactId>configured-feature-text</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>configured-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>configured-gson</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
package cc.carm.lib.configuration.value.text;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.adapter.ValueAdapter;
|
||||||
|
import cc.carm.lib.configuration.adapter.ValueType;
|
||||||
|
import cc.carm.lib.configuration.builder.AbstractConfigBuilder;
|
||||||
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
|
import cc.carm.lib.configuration.value.ValueManifest;
|
||||||
|
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||||
|
import cc.carm.lib.configuration.value.text.data.TextContents;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param <MSG> The type of the message
|
||||||
|
* @param <RECEIVER> The type of the receiver
|
||||||
|
*/
|
||||||
|
public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents> {
|
||||||
|
|
||||||
|
public static <M, R> Builder<M, R, ?> create() {
|
||||||
|
return new StardardBuilder<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final ValueType<TextContents> TEXT_TYPE = ValueType.of(TextContents.class);
|
||||||
|
public static final ValueAdapter<TextContents> TEXT_ADAPTER = new ValueAdapter<>(TEXT_TYPE,
|
||||||
|
(h, t, d) -> d.serialize(),
|
||||||
|
(h, t, d) -> TextContents.deserialize(d)
|
||||||
|
);
|
||||||
|
|
||||||
|
protected final @NotNull BiFunction<RECEIVER, String, String> parser;
|
||||||
|
protected final @NotNull BiFunction<RECEIVER, String, MSG> compiler;
|
||||||
|
protected final @NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher;
|
||||||
|
|
||||||
|
protected final @NotNull String[] params; // The parameters of the message.
|
||||||
|
|
||||||
|
public ConfiguredText(@NotNull ValueManifest<TextContents, TextContents> manifest,
|
||||||
|
@NotNull BiFunction<RECEIVER, String, String> parser,
|
||||||
|
@NotNull BiFunction<RECEIVER, String, MSG> compiler,
|
||||||
|
@NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher,
|
||||||
|
@NotNull String[] params) {
|
||||||
|
super(manifest, TEXT_ADAPTER);
|
||||||
|
this.parser = parser;
|
||||||
|
this.compiler = compiler;
|
||||||
|
this.dispatcher = dispatcher;
|
||||||
|
this.params = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PreparedText<MSG, RECEIVER> prepare(@NotNull Object... values) {
|
||||||
|
return new PreparedText<MSG, RECEIVER>(resolve(), this.params)
|
||||||
|
.parser(this.parser).compiler(this.compiler)
|
||||||
|
.dispatcher(this.dispatcher).placeholders(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the message for the receiver.
|
||||||
|
*
|
||||||
|
* @param receiver The receiver of the message.
|
||||||
|
* @param values The values to replace the {@link #params}.
|
||||||
|
* @return The parsed message.
|
||||||
|
*/
|
||||||
|
public List<String> parse(@Nullable RECEIVER receiver, @NotNull Object... values) {
|
||||||
|
return prepare(values).parse(receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the message for the receiver and send it.
|
||||||
|
*
|
||||||
|
* @param receiver The receiver of the message.
|
||||||
|
* @param values The values to replace the {@link #params}.
|
||||||
|
* @return The parsed message.
|
||||||
|
*/
|
||||||
|
public String parseLine(@Nullable RECEIVER receiver, @NotNull Object... values) {
|
||||||
|
return prepare(values).parseLine(receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile the message for the receiver.
|
||||||
|
*
|
||||||
|
* @param receiver The receiver of the message.
|
||||||
|
* @param values The values to replace the {@link #params}.
|
||||||
|
* @return The compiled message.
|
||||||
|
*/
|
||||||
|
public List<MSG> compile(@Nullable RECEIVER receiver, @NotNull Object... values) {
|
||||||
|
return prepare(values).compile(receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile the message for the receiver and send it.
|
||||||
|
*
|
||||||
|
* @param receiver The receiver of the message.
|
||||||
|
* @param values The values to replace the {@link #params}.
|
||||||
|
* @return The compiled message.
|
||||||
|
*/
|
||||||
|
public MSG compileLine(@Nullable RECEIVER receiver, @NotNull Object... values) {
|
||||||
|
return prepare(values).compileLine(receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the message to the receiver.
|
||||||
|
*
|
||||||
|
* @param receiver The receiver of the message.
|
||||||
|
* @param values The values to replace the {@link #params}.
|
||||||
|
*/
|
||||||
|
public void sendTo(@NotNull RECEIVER receiver, @NotNull Object... values) {
|
||||||
|
prepare(values).to(receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the message to the multiple receivers.
|
||||||
|
*
|
||||||
|
* @param receivers The receivers of the message.
|
||||||
|
* @param values The values to replace the {@link #params}.
|
||||||
|
*/
|
||||||
|
public void sendToAll(@NotNull Iterable<? extends RECEIVER> receivers, @NotNull Object... values) {
|
||||||
|
prepare(values).to(receivers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class Builder<MSG, RECEIVER, SELF extends Builder<MSG, RECEIVER, SELF>>
|
||||||
|
extends AbstractConfigBuilder<TextContents, TextContents, ConfiguredText<MSG, RECEIVER>, ConfigurationHolder<?>, SELF> {
|
||||||
|
protected @NotNull TextContents.Builder defaultBuilder = TextContents.builder();
|
||||||
|
protected @NotNull String[] params = new String[0];
|
||||||
|
|
||||||
|
protected @NotNull BiFunction<RECEIVER, String, String> parser = (r, s) -> s;
|
||||||
|
protected @NotNull BiFunction<RECEIVER, String, MSG> compiler = (r, s) -> {
|
||||||
|
throw new IllegalStateException("Compiler not supplied.");
|
||||||
|
};
|
||||||
|
protected @NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher = (r, l) -> {
|
||||||
|
throw new IllegalStateException("Dispatcher not supplied.");
|
||||||
|
};
|
||||||
|
|
||||||
|
protected Builder() {
|
||||||
|
super(ConfigurationHolder.class, TEXT_TYPE);
|
||||||
|
defaults(() -> defaultBuilder.build()); // Set the default value from the default builder.
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull SELF parser(@NotNull BiFunction<RECEIVER, String, String> parser) {
|
||||||
|
this.parser = parser;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull SELF compiler(@NotNull BiFunction<RECEIVER, String, MSG> compiler) {
|
||||||
|
this.compiler = compiler;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull SELF dispatcher(@NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher) {
|
||||||
|
this.dispatcher = dispatcher;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull SELF params(@NotNull String... params) {
|
||||||
|
this.params = params;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull SELF defaults(@NotNull Consumer<TextContents.Builder> consumer) {
|
||||||
|
consumer.accept(this.defaultBuilder);
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull SELF defaults(@NotNull String... contents) {
|
||||||
|
return defaults(builder -> builder.set(contents));
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull SELF defaults(@NotNull Iterable<String> contents) {
|
||||||
|
return defaults(builder -> builder.set(contents));
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull SELF optional(@NotNull String id, @NotNull String... lines) {
|
||||||
|
return defaults(builder -> builder.optional(id, lines));
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull SELF optional(@NotNull String id, @NotNull Iterable<String> lines) {
|
||||||
|
return defaults(builder -> builder.optional(id, lines));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ConfiguredText<MSG, RECEIVER> build() {
|
||||||
|
return new ConfiguredText<>(buildManifest(), this.parser, this.compiler, this.dispatcher, this.params);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class StardardBuilder<MSG, RECEIVER> extends Builder<MSG, RECEIVER, StardardBuilder<MSG, RECEIVER>> {
|
||||||
|
@Override
|
||||||
|
protected @NotNull StardardBuilder<MSG, RECEIVER> self() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package cc.carm.lib.configuration.value.text;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.value.text.data.TextContents;
|
||||||
|
import cc.carm.lib.configuration.value.text.function.TextDispatcher;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class PreparedText<MSG, RECEIVER> extends TextDispatcher<MSG, RECEIVER, PreparedText<MSG, RECEIVER>> {
|
||||||
|
|
||||||
|
protected final @NotNull TextContents texts;
|
||||||
|
|
||||||
|
public PreparedText(@NotNull TextContents texts, @NotNull String... params) {
|
||||||
|
this.params = params;
|
||||||
|
this.texts = texts;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TextContents texts() {
|
||||||
|
return this.texts;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PreparedText<MSG, RECEIVER> self() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PreparedText<MSG, RECEIVER> insert(@NotNull String key,
|
||||||
|
@NotNull ConfiguredText<?, RECEIVER> message,
|
||||||
|
@NotNull Object... values) {
|
||||||
|
return insert(key, receiver -> message.parse(receiver, values));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+160
@@ -0,0 +1,160 @@
|
|||||||
|
package cc.carm.lib.configuration.value.text.data;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.source.section.ConfigureSection;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class TextContents {
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextContents of(@NotNull List<String> lines, @NotNull Map<String, List<String>> optional) {
|
||||||
|
return new TextContents(lines, optional);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final @NotNull List<String> lines;
|
||||||
|
protected final @NotNull Map<String, List<String>> optional;
|
||||||
|
|
||||||
|
public TextContents(@NotNull List<String> lines, @NotNull Map<String, List<String>> optional) {
|
||||||
|
this.lines = lines;
|
||||||
|
this.optional = optional;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return lines.isEmpty() || lines.stream().allMatch(String::isEmpty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull List<String> lines() {
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull Map<String, List<String>> optionalLines() {
|
||||||
|
return optional;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Object serialize() {
|
||||||
|
if (optional.isEmpty()) {
|
||||||
|
if (lines.isEmpty()) return null;
|
||||||
|
else if (lines.size() == 1) return lines.get(0);
|
||||||
|
else return lines;
|
||||||
|
} else {
|
||||||
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
map.put("contents", lines);
|
||||||
|
map.put("optional", optional);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable TextContents deserialize(@NotNull Object data) {
|
||||||
|
Builder builder = builder();
|
||||||
|
if (data instanceof String) {
|
||||||
|
return builder.set((String) data).build();
|
||||||
|
} else if (data instanceof List<?>) {
|
||||||
|
((List<?>) data).stream().map(Object::toString).forEach(builder::add);
|
||||||
|
return builder.build();
|
||||||
|
} else if (data instanceof ConfigureSection) {
|
||||||
|
ConfigureSection section = (ConfigureSection) data;
|
||||||
|
builder.set(section.getStringList("contents"));
|
||||||
|
|
||||||
|
ConfigureSection optionalSection = section.getSection("optional");
|
||||||
|
if (optionalSection != null) {
|
||||||
|
for (String key : optionalSection.getKeys(false)) {
|
||||||
|
builder.optional(key, optionalSection.getStringList(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
|
||||||
|
protected List<String> lines = new ArrayList<>();
|
||||||
|
protected Map<String, List<String>> optional = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add lines to the contents
|
||||||
|
*
|
||||||
|
* @param lines lines to add
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder add(@NotNull String... lines) {
|
||||||
|
this.lines.addAll(Arrays.asList(lines));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add lines to the contents
|
||||||
|
*
|
||||||
|
* @param lines lines to add
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder add(@NotNull Iterable<String> lines) {
|
||||||
|
lines.forEach(this.lines::add);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the lines of the contents
|
||||||
|
*
|
||||||
|
* @param lines lines to set
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder set(@NotNull String... lines) {
|
||||||
|
this.lines = Arrays.asList(lines);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the lines of the contents
|
||||||
|
*
|
||||||
|
* @param lines lines to set
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder set(@NotNull Iterable<String> lines) {
|
||||||
|
this.lines = new ArrayList<>();
|
||||||
|
lines.forEach(this.lines::add);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add optional lines to the contents
|
||||||
|
*
|
||||||
|
* @param key key of the optional lines
|
||||||
|
* @param lines lines to add
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder optional(@NotNull String key, @NotNull String... lines) {
|
||||||
|
optional.put(key, Arrays.asList(lines));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add optional lines to the contents
|
||||||
|
*
|
||||||
|
* @param key key of the optional lines
|
||||||
|
* @param lines lines to add
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder optional(@NotNull String key, @NotNull Iterable<String> lines) {
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
lines.forEach(list::add);
|
||||||
|
optional.put(key, list);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The built TextContents
|
||||||
|
*/
|
||||||
|
public TextContents build() {
|
||||||
|
return of(lines, optional);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+274
@@ -0,0 +1,274 @@
|
|||||||
|
package cc.carm.lib.configuration.value.text.function;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.value.text.data.TextContents;
|
||||||
|
import cc.carm.lib.configuration.value.text.function.common.AppendLineInserter;
|
||||||
|
import cc.carm.lib.configuration.value.text.function.common.OptionalLineInserter;
|
||||||
|
import cc.carm.lib.configuration.value.text.function.common.ParamReplacer;
|
||||||
|
import cc.carm.lib.configuration.value.text.function.inserter.ContentInserter;
|
||||||
|
import cc.carm.lib.configuration.value.text.function.inserter.Insertable;
|
||||||
|
import cc.carm.lib.configuration.value.text.function.replacer.ContentReplacer;
|
||||||
|
import cc.carm.lib.configuration.value.text.function.replacer.Replaceable;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
|
public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEIVER, SELF>>
|
||||||
|
implements Replaceable<RECEIVER, SELF>, Insertable<RECEIVER, SELF> {
|
||||||
|
|
||||||
|
protected BiFunction<RECEIVER, String, String> parser = (receiver, value) -> value;
|
||||||
|
protected String lineSeparator = System.lineSeparator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to store the placeholders of the message
|
||||||
|
*/
|
||||||
|
protected @NotNull ParamReplacer<RECEIVER> paramReplacer = ParamReplacer.defaults();
|
||||||
|
protected @NotNull String[] params;
|
||||||
|
|
||||||
|
protected @NotNull List<ContentReplacer<RECEIVER>> replacers = new ArrayList<>();
|
||||||
|
protected @NotNull List<ContentInserter<RECEIVER>> inserters = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to store the insertion of the message
|
||||||
|
*/
|
||||||
|
protected final @NotNull Map<String, @Nullable Function<RECEIVER, List<String>>> insertion = new HashMap<>();
|
||||||
|
protected boolean disableInsertion = false;
|
||||||
|
|
||||||
|
public ContentHandler() {
|
||||||
|
inserters.add(new AppendLineInserter<>(0));
|
||||||
|
inserters.add(new OptionalLineInserter<>(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public abstract SELF self();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable the insertion of the text.
|
||||||
|
* <br> If the insertion is disabled, the text will be parsed directly.
|
||||||
|
*
|
||||||
|
* @return the current {@link ContentHandler} instance
|
||||||
|
*/
|
||||||
|
public SELF disableInsertion() {
|
||||||
|
this.disableInsertion = true;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable the insertion of the text.
|
||||||
|
*
|
||||||
|
* @return the current {@link ContentHandler} instance
|
||||||
|
*/
|
||||||
|
public SELF enableInsertion() {
|
||||||
|
this.disableInsertion = false;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean noneInsertion() {
|
||||||
|
return this.insertion.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the line separator for the text.
|
||||||
|
*
|
||||||
|
* @param lineSeparator the line separator, default is {@link System#lineSeparator()}
|
||||||
|
* @return the current {@link ContentHandler} instance
|
||||||
|
*/
|
||||||
|
public SELF lineSeparator(@NotNull String lineSeparator) {
|
||||||
|
this.lineSeparator = lineSeparator;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set all the placeholders for the text.
|
||||||
|
* <br> Will override the previous placeholders modifications.
|
||||||
|
*
|
||||||
|
* @param placeholders the placeholders
|
||||||
|
* @return the current {@link ContentHandler} instance
|
||||||
|
*/
|
||||||
|
public SELF placeholders(@NotNull Map<String, Object> placeholders) {
|
||||||
|
this.paramReplacer.set(placeholders);
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the placeholders for the text.
|
||||||
|
*
|
||||||
|
* @param consumer the placeholders
|
||||||
|
* @return the current {@link ContentHandler} instance
|
||||||
|
*/
|
||||||
|
public SELF placeholders(@NotNull Consumer<Map<String, Object>> consumer) {
|
||||||
|
consumer.accept(this.paramReplacer.placeholders());
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the placeholders for the text.
|
||||||
|
*
|
||||||
|
* @param values The values to replace the {@link #params(String...)}.
|
||||||
|
* @return the current {@link ContentHandler} instance
|
||||||
|
*/
|
||||||
|
public SELF placeholders(@Nullable Object... values) {
|
||||||
|
this.paramReplacer.putAll(this.params, values);
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the placeholder for the text.
|
||||||
|
*
|
||||||
|
* @param key the key of the placeholder
|
||||||
|
* @param value the value of the placeholder
|
||||||
|
* @return the current {@link ContentHandler} instance
|
||||||
|
*/
|
||||||
|
public SELF placeholder(@NotNull String key, @Nullable Object value) {
|
||||||
|
this.paramReplacer.put(key, value);
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the params for the text,
|
||||||
|
* used for {@link #placeholders(Object...)} to build the placeholders.
|
||||||
|
*
|
||||||
|
* @param params the params
|
||||||
|
* @return the current {@link ContentHandler} instance
|
||||||
|
*/
|
||||||
|
public SELF params(@NotNull String... params) {
|
||||||
|
this.params = params;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ContentReplacer<RECEIVER>> replacers() {
|
||||||
|
return this.replacers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SELF replacer(@NotNull ContentReplacer<RECEIVER> replacer) {
|
||||||
|
this.replacers.add(replacer);
|
||||||
|
this.replacers.sort(ContentReplacer::compareTo);
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SELF paramReplacer(@NotNull ParamReplacer<RECEIVER> paramReplacer) {
|
||||||
|
this.paramReplacer = paramReplacer;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ContentInserter<RECEIVER>> inserters() {
|
||||||
|
return this.inserters;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SELF inserter(@NotNull ContentInserter<RECEIVER> inserter) {
|
||||||
|
this.inserters.add(inserter);
|
||||||
|
this.inserters.sort(ContentInserter::compareTo);
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SELF insert(@NotNull String id, @Nullable Function<RECEIVER, List<String>> supplier) {
|
||||||
|
this.insertion.put(id, supplier);
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean inserting(@NotNull String id) {
|
||||||
|
return this.insertion.keySet().stream().anyMatch(key -> key.equalsIgnoreCase(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable List<String> getInsertion(@NotNull String id, @Nullable RECEIVER receiver) {
|
||||||
|
Function<RECEIVER, List<String>> function = this.insertion.get(id);
|
||||||
|
if (function == null) return null;
|
||||||
|
return function.apply(receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SELF removeInsert(@NotNull String id) {
|
||||||
|
this.insertion.remove(id);
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the parser for the text.
|
||||||
|
*
|
||||||
|
* @param parser The parser
|
||||||
|
* @return The current {@link ContentHandler} instance
|
||||||
|
*/
|
||||||
|
public SELF parser(@NotNull BiFunction<RECEIVER, String, String> parser) {
|
||||||
|
this.parser = parser;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the supplied single text for the receiver.
|
||||||
|
*
|
||||||
|
* @param receiver the receiver
|
||||||
|
* @param text the text to parse
|
||||||
|
* @return the parsed text
|
||||||
|
*/
|
||||||
|
protected @Nullable String parse(@Nullable RECEIVER receiver, @NotNull String text) {
|
||||||
|
text = applyReplacements(receiver, text); // First, apply the custom replacements
|
||||||
|
text = this.paramReplacer.replace(text, receiver); // Then, apply the static placeholders
|
||||||
|
return this.parser.apply(receiver, text); // Finally, parse the text
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handle(@NotNull TextContents contents, @Nullable RECEIVER receiver,
|
||||||
|
@NotNull Consumer<String> lineConsumer) {
|
||||||
|
if (contents.isEmpty()) return; // Nothing to parse
|
||||||
|
|
||||||
|
if (this.disableInsertion || noneInsertion()) {
|
||||||
|
contents.lines().forEach(line -> lineConsumer.accept(parse(receiver, line)));
|
||||||
|
return; // Simple parsed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the default insertion of the text
|
||||||
|
for (Map.Entry<String, @Nullable Function<RECEIVER, List<String>>> entry : this.insertion.entrySet()) {
|
||||||
|
if (entry.getValue() != null) continue;
|
||||||
|
List<String> lines = contents.optionalLines().get(entry.getKey());
|
||||||
|
if (lines == null) continue;
|
||||||
|
entry.setValue(r -> lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
lines:
|
||||||
|
for (String line : contents.lines()) {
|
||||||
|
for (ContentInserter<RECEIVER> inserter : inserters) {
|
||||||
|
List<String> inserted = inserter.handle(receiver, line, this);
|
||||||
|
if (inserted != null) { // Found the insertion
|
||||||
|
inserted.forEach(l -> lineConsumer.accept(parse(receiver, l)));
|
||||||
|
continue lines; // Go to the next line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lineConsumer.accept(parse(receiver, line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String setPlaceholders(@NotNull String messages,
|
||||||
|
@NotNull Map<String, Object> placeholders) {
|
||||||
|
if (messages.isEmpty()) return messages;
|
||||||
|
String parsed = messages;
|
||||||
|
for (Map.Entry<String, Object> entry : placeholders.entrySet()) {
|
||||||
|
parsed = parsed.replace(entry.getKey(), entry.getValue() == null ? "" : entry.getValue().toString());
|
||||||
|
}
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, Object> buildParams(@NotNull UnaryOperator<String> paramBuilder,
|
||||||
|
@Nullable String[] params, @Nullable Object[] values) {
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
if (params == null || params.length == 0) return map;
|
||||||
|
for (int i = 0; i < params.length; i++) {
|
||||||
|
map.put(paramBuilder.apply(params[i]), (values != null && values.length > i) ? values[i] : "?");
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user