1
mirror of https://github.com/CarmJos/EasyConfiguration.git synced 2026-06-04 10:38:19 +08:00

Compare commits

..

15 Commits

Author SHA1 Message Date
carm 0bfd15aaad feat(record): Support record type values adapter. 2025-07-02 11:04:27 +08:00
carm 15f395a8e0 test(record): Add testcase for nullable values. 2025-06-26 03:04:21 +08:00
carm a61040a0e2 ci(jdk): Using JDK 21. 2025-06-26 02:28:32 +08:00
carm 8766b4d77b feat(adapter): Support complex ParameterizedType's serialize & deserialize. 2025-06-26 02:24:42 +08:00
carm 8c1214612a feat(adapter): Support complex ParameterizedType's serialize & deserialize. 2025-06-25 09:31:07 +08:00
carm 608d92f834 feat(record): Support record type values adapter. 2025-06-25 07:10:26 +08:00
carm ad6ab9eb36 feat(temp): Add a "temporary source" for Testing/FastDev cases. (Use default config in codes first.) 2025-06-25 07:10:04 +08:00
dependabot[bot] 0eda8d8a0f build(deps-dev): bump log4j.version from 2.24.3 to 2.25.0
Bumps `log4j.version` from 2.24.3 to 2.25.0.

Updates `org.apache.logging.log4j:log4j-api` from 2.24.3 to 2.25.0

Updates `org.apache.logging.log4j:log4j-core` from 2.24.3 to 2.25.0

Updates `org.apache.logging.log4j:log4j-slf4j-impl` from 2.24.3 to 2.25.0

---
updated-dependencies:
- dependency-name: org.apache.logging.log4j:log4j-api
  dependency-version: 2.25.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
- dependency-name: org.apache.logging.log4j:log4j-core
  dependency-version: 2.25.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
- dependency-name: org.apache.logging.log4j:log4j-slf4j-impl
  dependency-version: 2.25.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-25 06:29:38 +08:00
dependabot[bot] b19691b5a4 build(deps): bump org.sonatype.central:central-publishing-maven-plugin
Bumps [org.sonatype.central:central-publishing-maven-plugin](https://github.com/sonatype/central-publishing-maven-plugin) from 0.7.0 to 0.8.0.
- [Commits](https://github.com/sonatype/central-publishing-maven-plugin/commits)

---
updated-dependencies:
- dependency-name: org.sonatype.central:central-publishing-maven-plugin
  dependency-version: 0.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-25 06:29:28 +08:00
renovate[bot] c7331aa556 fix(deps): update kotlin monorepo to v2.2.0 2025-06-25 06:29:18 +08:00
carm a440c050e5 feat(type): Add ofMap(K,V) method for ValueType 2025-06-23 15:27:52 +08:00
renovate[bot] b9d45a9bb9 fix(deps): update dependency org.mongodb:mongodb-driver-sync to v5.5.1 2025-06-10 22:45:19 +08:00
carm 67482de7a9 docs: drop visitors counter 2025-05-14 04:25:23 +08:00
carm 04bedbef07 style: Reformatted code with .editorconfig 2025-05-14 04:24:56 +08:00
carm a4abfb733a style: Reformatted code with .editorconfig 2025-05-14 04:22:48 +08:00
94 changed files with 1525 additions and 455 deletions
+4 -1
View File
@@ -1,3 +1,6 @@
# configured Javadoc
Based on [Github Pages](https://pages.github.com/), please see [JavaDoc](https://carmjos.github.io/configured) 。
Based
on [Github Pages](https://pages.github.com/),
please
see [JavaDoc](https://carmjos.github.io/configured) 。
+346
View File
@@ -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
+47 -14
View File
@@ -1,37 +1,70 @@
---
name: 问题提交
about: 描述问题提交,帮助我们对其进行检查与修复。
name:
问题提交
about:
描述问题并提交,帮助我们对其进行检查与修复。
title: ''
labels: bug
labels:
bug
assignees: ''
---
### **问题简述**
###
*
*问题简述
**
用简短的话语描述一下大概问题。
### **问题来源**
###
*
*问题来源
**
描述一下通过哪些操作才发现的问题,如:
1. 使用了 '...'
2. 输入了 '....'
3. 出现了报错 '....'
1.
使用了 '...'
2.
输入了 '....'
3.
出现了报错 '....'
### **预期结果** (可选)
###
*
*预期结果
** (可选)
如果问题不发生,应该是什么情况
### **问题截图/问题报错**
###
*
*问题截图/问题报错
**
如果有报错或输出,请提供截图。
### **操作环境**
###
*
*操作环境
**
- 系统环境: `Windows 10` / `Ubuntu` / `...`
- Java版本: `JDK11` / `OPENJDK8` / `JRE8` / `...`
-
系统环境:
`Windows 10` /
`Ubuntu` /
`...`
-
Java版本:
`JDK11` /
`OPENJDK8` /
`JRE8` /
`...`
### **其他补充**
###
*
*其他补充
**
如有其他补充,可以在这里描述。
+22 -7
View File
@@ -1,23 +1,38 @@
---
name: 功能需求
about: 希望我们提供更多的功能。
name:
功能需求
about:
希望我们提供更多的功能。
title: ''
labels: enhancement
labels:
enhancement
assignees: ''
---
### **功能简述**
###
*
*功能简述
**
简单的描述一下你想要的功能
### **需求来源**
###
*
*需求来源
**
简单的描述一下为什么需要这个功能。
### **功能参考**(可选)
###
*
*功能参考
**(可选)
如果有相关功能的参考,如文本、截图,请提供给我们。
### **附加内容**
###
*
*附加内容
**
如果有什么小细节需要重点注意,请在这里告诉我们。
+3 -3
View File
@@ -20,7 +20,7 @@ jobs:
- name: "Set up JDK"
uses: actions/setup-java@v4
with:
java-version: '11'
java-version: '21'
distribution: 'adopt'
cache: maven
server-id: github
@@ -91,7 +91,7 @@ jobs:
- name: "Set up JDK"
uses: actions/setup-java@v4
with:
java-version: '11'
java-version: '21'
distribution: 'adopt'
cache: maven
server-id: central
@@ -105,4 +105,4 @@ jobs:
env:
MAVEN_USERNAME: ${{ secrets.OSSRH_USER }}
MAVEN_PASSWORD: ${{ secrets.OSSRH_PASS }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
- name: "Set up JDK"
uses: actions/setup-java@v4
with:
java-version: '11'
java-version: '21'
distribution: 'adopt'
- name: "Package"
run: mvn -B package --file pom.xml -Dgpg.skip
+3 -4
View File
@@ -6,7 +6,6 @@
[![workflow](https://github.com/CarmJos/configured/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/configured/actions/workflows/maven.yml)
[![CodeFactor](https://www.codefactor.io/repository/github/carmjos/configured/badge)](https://www.codefactor.io/repository/github/carmjos/configured)
![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/configured)
![](https://visitor-badge.glitch.me/badge?page_id=configured.readme)
README LANGUAGES [ [**English**](README.md) | [中文](README_CN.md) ]
</div>
@@ -24,8 +23,8 @@ Supported **JSON**, **YAML**, **Hocon**, **TOML**, **SQL**, **MongoDB**... and m
## Features & Advantages
Supported [YAML](impl/yaml), [JSON](impl/json), [HOCON](impl/hocon) and [SQL](impl/sql) based configuration files
format.
Supported [YAML](providers/yaml), [JSON](providers/json), [HOCON](providers/hocon) and [SQL](providers/sql)
based configuration files format.
- Class-based mechanism for initializing, loading, retrieving, and updating configuration files, ensuring convenience
and efficiency.
@@ -44,7 +43,7 @@ For a detailed development guide, [CLICK HERE](.doc/README.md).
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)
- [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).
For more examples, see the [Development Guide](.doc/README.md).
-1
View File
@@ -6,7 +6,6 @@
[![workflow](https://github.com/CarmJos/configured/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/configured/actions/workflows/maven.yml)
[![CodeFactor](https://www.codefactor.io/repository/github/carmjos/configured/badge)](https://www.codefactor.io/repository/github/carmjos/configured)
![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/configured)
![](https://visitor-badge.glitch.me/badge?page_id=configured.readme)
README LANGUAGES [ [English](README.md) | [**中文**](README_CN.md) ]
+2 -2
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>configured-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>4.1.5</version>
<version>4.1.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<properties>
@@ -39,4 +39,4 @@
</plugins>
</build>
</project>
</project>
@@ -4,4 +4,5 @@ package cc.carm.lib.configuration;
* The root interface of the configuration file interfaces,
* which is used to label a class as a configuration.
*/
public interface Configuration { }
public interface Configuration {
}
@@ -12,7 +12,7 @@ import java.util.Objects;
* @param <TYPE> The type of the target value
*/
public class ValueAdapter<TYPE>
implements ValueSerializer<TYPE>, ValueParser<TYPE> {
implements ValueSerializer<TYPE>, ValueParser<TYPE> {
protected final @NotNull ValueType<TYPE> type;
@@ -55,9 +55,9 @@ public class ValueAdapter<TYPE>
@Override
public @Nullable Object serialize(
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type,
@NotNull TYPE value
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type,
@NotNull TYPE value
) throws Exception {
if (serializer == null) throw new UnsupportedOperationException("Serializer is not supported");
return serializer.serialize(holder, type, value);
@@ -65,9 +65,9 @@ public class ValueAdapter<TYPE>
@Override
public @Nullable TYPE parse(
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type,
@NotNull Object value
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type,
@NotNull Object value
) throws Exception {
if (deserializer == null) throw new UnsupportedOperationException("Deserializer is not supported");
return deserializer.parse(holder, type, value);
@@ -2,12 +2,13 @@ package cc.carm.lib.configuration.adapter;
import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
public class ValueAdapterRegistry {
@@ -25,8 +26,8 @@ public class ValueAdapterRegistry {
ValueAdapter<FROM> fromAdapter = adapterOf(from);
if (fromAdapter == null) throw new IllegalArgumentException("No adapter for type " + from);
register(to,
serializer == null ? null : (provider, type, value) -> fromAdapter.serialize(provider, from, serializer.handle(value)),
parser == null ? null : (provider, type, data) -> parser.handle(fromAdapter.parse(provider, from, data))
serializer == null ? null : (provider, type, value) -> fromAdapter.serialize(provider, from, serializer.handle(value)),
parser == null ? null : (provider, type, data) -> parser.handle(fromAdapter.parse(provider, from, data))
);
}
@@ -84,14 +85,14 @@ public class ValueAdapterRegistry {
@SuppressWarnings("unchecked")
public <T> @Nullable ValueAdapter<T> adapterOf(@NotNull ValueType<T> type) {
ValueAdapter<?> matched = adapters.stream()
.filter(adapter -> adapter.type().equals(type))
.findFirst().orElse(null);
.filter(adapter -> adapter.type().equals(type))
.findFirst().orElse(null);
if (matched != null) return (ValueAdapter<T>) matched;
// If no adapter found, try to find the adapter for the super type
return (ValueAdapter<T>) adapters.stream()
.filter(adapter -> adapter.type().isSubtypeOf(type))
.findFirst().orElse(null);
.filter(adapter -> adapter.type().isSubtypeOf(type))
.findFirst().orElse(null);
}
public <T> ValueAdapter<T> adapterOf(@NotNull T value) {
@@ -108,20 +109,106 @@ public class ValueAdapterRegistry {
public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> type, @Nullable Object source) throws Exception {
if (source == null) return null; // Null check
if (type.isInstance(source)) return type.cast(source); // Not required to deserialize
ValueAdapter<T> adapter = adapterOf(type);
if (adapter == null) throw new RuntimeException("No adapter for type " + type);
return adapter.parse(holder, type, source);
if (!(type.getType() instanceof ParameterizedType) && type.isInstance(source)) {
return type.cast(source); // Not required to deserialize
}
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 {
if (value == null) return null; // Null check
ValueType<T> type = ValueType.of(value);
ValueAdapter<T> adapter = adapterOf(type);
if (adapter == null) return value; // No adapters, try to return the original value
return adapter.serialize(holder, type, value);
if (adapter != null) 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();
}
}
}
@@ -13,8 +13,8 @@ import org.jetbrains.annotations.Nullable;
public interface ValueParser<TYPE> {
@Nullable TYPE parse(
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type, @NotNull Object data
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type, @NotNull Object data
) throws Exception;
}
@@ -13,8 +13,8 @@ import org.jetbrains.annotations.Nullable;
public interface ValueSerializer<TYPE> {
@Nullable Object serialize(
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type, @NotNull TYPE value
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type, @NotNull TYPE value
) throws Exception;
}
@@ -1,14 +1,22 @@
package cc.carm.lib.configuration.adapter;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
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> {
@@ -31,8 +39,8 @@ public abstract class ValueType<T> {
public static final ValueType<Character> CHAR_TYPE = ofPrimitiveType(char.class);
public static final ValueType<?>[] PRIMITIVE_TYPES = {
STRING, INTEGER, LONG, DOUBLE, FLOAT, BOOLEAN, BYTE, SHORT, CHAR,
INTEGER_TYPE, LONG_TYPE, DOUBLE_TYPE, FLOAT_TYPE, BOOLEAN_TYPE, BYTE_TYPE, SHORT_TYPE, CHAR_TYPE
STRING, INTEGER, LONG, DOUBLE, FLOAT, BOOLEAN, BYTE, SHORT, CHAR,
INTEGER_TYPE, LONG_TYPE, DOUBLE_TYPE, FLOAT_TYPE, BOOLEAN_TYPE, BYTE_TYPE, SHORT_TYPE, CHAR_TYPE
};
@SuppressWarnings("unchecked")
@@ -43,7 +51,7 @@ public abstract class ValueType<T> {
@SuppressWarnings("unchecked")
public static <T> ValueType<T> of(final Type type) {
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;
for (ValueType<?> valueType : PRIMITIVE_TYPES) {
if (valueType.getRawType() == clazz) {
@@ -63,6 +71,18 @@ public abstract class ValueType<T> {
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.
*
@@ -91,6 +111,7 @@ public abstract class ValueType<T> {
return of(parameterizedType);
}
@ApiStatus.Internal
private static <T> ValueType<T> ofPrimitiveType(Class<T> clazz) {
return new ValueType<T>(clazz) {
};
@@ -110,40 +131,65 @@ public abstract class ValueType<T> {
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) {
Class<?> rawType = getRawType();
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) {
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) {
return obj != null && getRawType().isInstance(obj);
}
/**
* 提取当前 ValueType 的原始类型(Class 对象)。
* Extracts the raw type from the generic type.
*
* @return 对应的 Class 对象
* @throws IllegalStateException 如果无法提取出原始类型
* @return The raw type of the generic type
* @throws IllegalStateException if the type is not a Class or ParameterizedType
*/
public Class<?> getRawType() {
@SuppressWarnings("unchecked")
public Class<T> getRawType() {
if (type instanceof Class<?>) {
return (Class<?>) type;
return (Class<T>) type;
}
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
Type raw = pt.getRawType();
if (raw instanceof Class<?>) {
return (Class<?>) raw;
return (Class<T>) raw;
}
}
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")
public T cast(Object obj) {
if (!isInstance(obj)) {
@@ -152,6 +198,12 @@ public abstract class ValueType<T> {
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
public String toString() {
if (type instanceof Class<?>) {
@@ -11,11 +11,11 @@ import java.util.Arrays;
public class PrimitiveAdapter<T> extends ValueAdapter<T> {
public static final String[] TRUE_VALUES = new String[]{
"true", "yes", "on", "1", "enabled", "enable", "active"
"true", "yes", "on", "1", "enabled", "enable", "active"
};
public static final String[] FALSE_VALUES = new String[]{
"false", "no", "off", "0", "disabled", "disable", "inactive"
"false", "no", "off", "0", "disabled", "disable", "inactive"
};
@SuppressWarnings({"unchecked", "rawtypes"})
@@ -12,27 +12,27 @@ import static cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapter.*;
public interface StandardAdapters {
@NotNull PrimitiveAdapter<?>[] PRIMITIVES = new PrimitiveAdapter[]{
ofString(), ofBoolean(), ofBooleanType(), ofCharacter(), ofCharacterType(),
ofInteger(), ofIntegerType(), ofLong(), ofLongType(), ofDouble(), ofDoubleType(),
ofFloat(), ofFloatType(), ofShort(), ofShortType(), ofByte(), ofByteType()
ofString(), ofBoolean(), ofBooleanType(), ofCharacter(), ofCharacterType(),
ofInteger(), ofIntegerType(), ofLong(), ofLongType(), ofDouble(), ofDoubleType(),
ofFloat(), ofFloatType(), ofShort(), ofShortType(), ofByte(), ofByteType()
};
@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())
ValueType.of(UUID.class),
(provider, type, value) -> value.toString(),
(provider, type, value) -> java.util.UUID.fromString(value.toString())
);
@NotNull ValueAdapter<ConfigureSection> SECTIONS = new ValueAdapter<>(
ValueType.of(ConfigureSection.class),
(provider, type, value) -> value,
(provider, type, value) -> {
if (value instanceof ConfigureSection) {
return (ConfigureSection) value;
} else throw new IllegalArgumentException("Value is not a ConfigurationSection");
}
ValueType.of(ConfigureSection.class),
(provider, type, value) -> value,
(provider, type, value) -> {
if (value instanceof ConfigureSection) {
return (ConfigureSection) value;
} else throw new IllegalArgumentException("Value is not a ConfigurationSection");
}
);
}
@@ -9,7 +9,6 @@ import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
import cc.carm.lib.configuration.value.ConfigValue;
import cc.carm.lib.configuration.value.ValueManifest;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.NotNullByDefault;
import org.jetbrains.annotations.Nullable;
import java.util.function.BiConsumer;
@@ -17,11 +16,10 @@ import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
@NotNullByDefault
public abstract class AbstractConfigBuilder<
TYPE, UNIT, RESULT extends ConfigValue<TYPE, UNIT>, HOLDER extends ConfigurationHolder<?>,
SELF extends AbstractConfigBuilder<TYPE, UNIT, RESULT, HOLDER, SELF>
> {
TYPE, UNIT, RESULT extends ConfigValue<TYPE, UNIT>, HOLDER extends ConfigurationHolder<?>,
SELF extends AbstractConfigBuilder<TYPE, UNIT, RESULT, HOLDER, SELF>
> {
protected final Class<? super HOLDER> providerClass;
protected final ValueType<TYPE> type;
@@ -156,8 +154,8 @@ public abstract class AbstractConfigBuilder<
protected @NotNull ValueManifest<TYPE, UNIT> buildManifest() {
return new ValueManifest<>(
type(), this.defaultValueSupplier, this.valueValidator,
this.initializer, this.holder, this.path
type(), this.defaultValueSupplier, this.valueValidator,
this.initializer, this.holder, this.path
);
}
@@ -5,10 +5,10 @@ import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.value.ConfigValue;
public abstract class CommonConfigBuilder<
TYPE, UNIT,
RESULT extends ConfigValue<TYPE, UNIT>,
SELF extends CommonConfigBuilder<TYPE, UNIT, RESULT, SELF>
> extends AbstractConfigBuilder<TYPE, UNIT, 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) {
super(ConfigurationHolder.class, type);
@@ -14,10 +14,10 @@ import java.util.LinkedHashMap;
import java.util.Map;
public abstract class AbstractSectionBuilder<
TYPE, UNIT,
RESULT extends ConfigValue<TYPE, UNIT>,
SELF extends AbstractSectionBuilder<TYPE, UNIT, RESULT, SELF>
> extends CommonConfigBuilder<TYPE, UNIT, RESULT, SELF> {
TYPE, UNIT,
RESULT extends ConfigValue<TYPE, UNIT>,
SELF extends AbstractSectionBuilder<TYPE, UNIT, RESULT, SELF>
> extends CommonConfigBuilder<TYPE, UNIT, RESULT, SELF> {
protected final @NotNull ValueType<UNIT> paramType;
@@ -62,15 +62,15 @@ public abstract class AbstractSectionBuilder<
protected ValueAdapter<UNIT> buildAdapter() {
return new ValueAdapter<>(this.paramType)
.parser((p, type, data) -> {
ConfigureSection section = p.deserialize(ConfigureSection.class, data);
if (section == null) return null;
return this.parser.handle(p, section);
})
.serializer((p, type, data) -> {
Map<String, Object> map = this.serializer.handle(p, data);
return map == null || map.isEmpty() ? null : map;
});
.parser((p, type, data) -> {
ConfigureSection section = p.deserialize(ConfigureSection.class, data);
if (section == null) return null;
return this.parser.handle(p, section);
})
.serializer((p, type, data) -> {
Map<String, Object> map = this.serializer.handle(p, data);
return map == null || map.isEmpty() ? null : map;
});
}
}
@@ -9,9 +9,9 @@ import cc.carm.lib.configuration.value.ConfigValue;
import org.jetbrains.annotations.NotNull;
public abstract class AbstractSourceBuilder<
V, SOURCE, UNIT, RESULT extends ConfigValue<V, UNIT>,
SELF extends AbstractSourceBuilder<V, SOURCE, UNIT, RESULT, SELF>
> extends CommonConfigBuilder<V, UNIT, RESULT, SELF> {
V, SOURCE, UNIT, RESULT extends ConfigValue<V, UNIT>,
SELF extends AbstractSourceBuilder<V, SOURCE, UNIT, RESULT, SELF>
> extends CommonConfigBuilder<V, UNIT, RESULT, SELF> {
protected final @NotNull ValueType<SOURCE> sourceType;
protected final @NotNull ValueType<UNIT> paramType;
@@ -49,14 +49,14 @@ public abstract class AbstractSourceBuilder<
protected ValueAdapter<UNIT> buildAdapter() {
return new ValueAdapter<>(this.paramType)
.parser((holder, type, data) -> {
SOURCE source = holder.deserialize(this.sourceType, data);
return this.valueParser.handle(holder, source);
})
.serializer((holder, type, data) -> {
SOURCE source = this.valueSerializer.handle(holder, data);
return holder.serialize(source);
});
.parser((holder, type, data) -> {
SOURCE source = holder.deserialize(this.sourceType, data);
return this.valueParser.handle(holder, source);
})
.serializer((holder, type, data) -> {
SOURCE source = this.valueSerializer.handle(holder, data);
return holder.serialize(source);
});
}
@@ -20,23 +20,23 @@ public class ConfigListBuilder<V> {
public <S> @NotNull SourceListBuilder<S, V> from(@NotNull ValueType<S> sourceType) {
return new SourceListBuilder<>(
ArrayList::new, sourceType, type,
ValueHandler.required(type),
ValueHandler.required(sourceType)
ArrayList::new, sourceType, type,
ValueHandler.required(type),
ValueHandler.required(sourceType)
);
}
public @NotNull SourceListBuilder<String, V> fromString() {
return new SourceListBuilder<>(
ArrayList::new, ValueType.STRING, type,
ValueHandler.required(type), ValueHandler.stringValue()
ArrayList::new, ValueType.STRING, type,
ValueHandler.required(type), ValueHandler.stringValue()
);
}
public @NotNull SectionListBuilder<V> fromSection() {
return new SectionListBuilder<>(
ArrayList::new, type,
ValueHandler.required(type), ValueHandler.required()
ArrayList::new, type,
ValueHandler.required(type), ValueHandler.required()
);
}
@@ -12,7 +12,7 @@ import java.util.function.Consumer;
import java.util.function.Supplier;
public class SectionListBuilder<V>
extends AbstractSectionBuilder<List<V>, V, ConfiguredList<V>, SectionListBuilder<V>> {
extends AbstractSectionBuilder<List<V>, V, ConfiguredList<V>, SectionListBuilder<V>> {
protected @NotNull Supplier<? extends List<V>> constructor;
@@ -14,7 +14,7 @@ import java.util.function.Consumer;
import java.util.function.Supplier;
public class SourceListBuilder<SOURCE, V>
extends AbstractSourceBuilder<List<V>, SOURCE, V, ConfiguredList<V>, SourceListBuilder<SOURCE, V>> {
extends AbstractSourceBuilder<List<V>, SOURCE, V, ConfiguredList<V>, SourceListBuilder<SOURCE, V>> {
protected @NotNull Supplier<? extends List<V>> constructor;
@@ -32,9 +32,9 @@ public class ConfigMapBuilder<M extends Map<K, V>, K, V> {
public @NotNull <S> SourceMapBuilder<M, S, K, V> from(@NotNull ValueType<S> sourceType) {
return from(
sourceType,
ValueHandler.required(keyType), ValueHandler.stringValue(),
ValueHandler.required(valueType), ValueHandler.required()
sourceType,
ValueHandler.required(keyType), ValueHandler.stringValue(),
ValueHandler.required(valueType), ValueHandler.required()
);
}
@@ -44,35 +44,35 @@ public class ConfigMapBuilder<M extends Map<K, V>, K, V> {
@NotNull ValueHandler<S, V> valueParser,
@NotNull ValueHandler<V, S> valueSerializer) {
return new SourceMapBuilder<>(
this.constructor, sourceType, keyType, valueType,
keyParser, keySerializer, valueParser, valueSerializer
this.constructor, sourceType, keyType, valueType,
keyParser, keySerializer, valueParser, valueSerializer
);
}
public @NotNull SourceMapBuilder<M, String, K, V> fromString() {
return from(
ValueType.STRING,
ValueHandler.required(keyType), ValueHandler.stringValue(),
ValueHandler.required(valueType), ValueHandler.stringValue()
ValueType.STRING,
ValueHandler.required(keyType), ValueHandler.stringValue(),
ValueHandler.required(valueType), ValueHandler.stringValue()
);
}
public @NotNull SectionMapBuilder<M, K, V> fromSection() {
return fromSection(
ValueHandler.required(keyType), ValueHandler.stringValue(),
ValueHandler.required(valueType), ValueHandler.required()
ValueHandler.required(keyType), ValueHandler.stringValue(),
ValueHandler.required(valueType), ValueHandler.required()
);
}
public @NotNull SectionMapBuilder<M, K, V> fromSection(
@NotNull ValueHandler<String, K> keyParser,
@NotNull ValueHandler<K, String> keySerializer,
@NotNull ValueHandler<ConfigureSection, V> valueParser,
@NotNull ValueHandler<V, Map<String, Object>> valueSerializer
@NotNull ValueHandler<String, K> keyParser,
@NotNull ValueHandler<K, String> keySerializer,
@NotNull ValueHandler<ConfigureSection, V> valueParser,
@NotNull ValueHandler<V, Map<String, Object>> valueSerializer
) {
return new SectionMapBuilder<>(
this.constructor, keyType, valueType,
keyParser, keySerializer, valueParser, valueSerializer
this.constructor, keyType, valueType,
keyParser, keySerializer, valueParser, valueSerializer
);
}
@@ -14,7 +14,7 @@ import java.util.function.Consumer;
import java.util.function.Supplier;
public class SectionMapBuilder<MAP extends Map<K, V>, K, V>
extends AbstractSectionBuilder<Map<K, V>, V, ConfiguredMap<K, V>, SectionMapBuilder<MAP, K, V>> {
extends AbstractSectionBuilder<Map<K, V>, V, ConfiguredMap<K, V>, SectionMapBuilder<MAP, K, V>> {
protected final @NotNull ValueType<K> keyType;
@@ -78,14 +78,14 @@ public class SectionMapBuilder<MAP extends Map<K, V>, K, V>
public @NotNull ValueAdapter<K> buildKeyAdapter() {
return new ValueAdapter<>(this.keyType)
.parser((holder, type, data) -> {
String source = holder.deserialize(String.class, data);
return this.keyParser.handle(holder, source);
})
.serializer((holder, type, data) -> {
String source = this.keySerializer.handle(holder, data);
return holder.serialize(source);
});
.parser((holder, type, data) -> {
String source = holder.deserialize(String.class, data);
return this.keyParser.handle(holder, source);
})
.serializer((holder, type, data) -> {
String source = this.keySerializer.handle(holder, data);
return holder.serialize(source);
});
}
@Override
@@ -13,7 +13,7 @@ import java.util.function.Consumer;
import java.util.function.Supplier;
public class SourceMapBuilder<MAP extends Map<K, V>, SOURCE, K, V>
extends AbstractSourceBuilder<Map<K, V>, SOURCE, V, ConfiguredMap<K, V>, SourceMapBuilder<MAP, SOURCE, K, V>> {
extends AbstractSourceBuilder<Map<K, V>, SOURCE, V, ConfiguredMap<K, V>, SourceMapBuilder<MAP, SOURCE, K, V>> {
protected final @NotNull ValueType<K> keyType;
@@ -74,14 +74,14 @@ public class SourceMapBuilder<MAP extends Map<K, V>, SOURCE, K, V>
public @NotNull ValueAdapter<K> buildKeyAdapter() {
return new ValueAdapter<>(this.keyType)
.parser((holder, type, data) -> {
String source = holder.deserialize(String.class, data);
return this.keyParser.handle(holder, source);
})
.serializer((holder, type, data) -> {
String source = this.keySerializer.handle(holder, data);
return holder.serialize(source);
});
.parser((holder, type, data) -> {
String source = holder.deserialize(String.class, data);
return this.keyParser.handle(holder, source);
})
.serializer((holder, type, data) -> {
String source = this.keySerializer.handle(holder, data);
return holder.serialize(source);
});
}
@Override
@@ -38,8 +38,8 @@ public class ConfigValueBuilder<V> {
}
public @NotNull SectionValueBuilder<V> fromSection(
@NotNull ValueHandler<ConfigureSection, V> valueParser,
@NotNull ValueHandler<V, ? extends Map<String, Object>> valueSerializer
@NotNull ValueHandler<ConfigureSection, V> valueParser,
@NotNull ValueHandler<V, ? extends Map<String, Object>> valueSerializer
) {
return new SectionValueBuilder<>(this.type, valueParser, valueSerializer);
}
@@ -7,7 +7,7 @@ import cc.carm.lib.configuration.value.standard.ConfiguredValue;
import org.jetbrains.annotations.NotNull;
public class SourceValueBuilder<S, V>
extends AbstractSourceBuilder<V, S, V, ConfiguredValue<V>, SourceValueBuilder<S, V>> {
extends AbstractSourceBuilder<V, S, V, ConfiguredValue<V>, SourceValueBuilder<S, V>> {
public SourceValueBuilder(@NotNull ValueType<S> sourceType, @NotNull ValueType<V> valueType,
@@ -30,10 +30,10 @@ import java.util.function.Supplier;
* @param <SELF> Self builder, for further implement support.
*/
public abstract class ConfigurationFactory<
SOURCE extends ConfigureSource<?, ?, SOURCE>,
HOLDER extends ConfigurationHolder<SOURCE>,
SELF
> {
SOURCE extends ConfigureSource<?, ?, SOURCE>,
HOLDER extends ConfigurationHolder<SOURCE>,
SELF
> {
protected @NotNull ValueAdapterRegistry adapters = new ValueAdapterRegistry();
protected @NotNull ConfigurationOptionHolder options = new ConfigurationOptionHolder();
@@ -100,21 +100,21 @@ public class PathGenerator {
*/
public static String covertPathName(String name) {
return name
// Replace all uppercase letters with dashes
.replaceAll("[A-Z]", "=$0")
// If the first letter is also capitalized,
// it will also be converted and the first dash will need to be removed
.replaceAll("^=(.*)$", "$1")
// Because the name may contain _, it needs to be treated a little differently
.replaceAll("_=([A-Z])", "_$1")
// The content that is not named in all caps is then converted
.replaceAll("([a-z])=([A-Z])", "$1_$2")
// Remove any extra horizontal lines
.replace("=", "")
// Replace the underscore with a dash
.replace("_", "-")
// Finally, convert it to all lowercase
.toLowerCase();
// Replace all uppercase letters with dashes
.replaceAll("[A-Z]", "=$0")
// If the first letter is also capitalized,
// it will also be converted and the first dash will need to be removed
.replaceAll("^=(.*)$", "$1")
// Because the name may contain _, it needs to be treated a little differently
.replaceAll("_=([A-Z])", "_$1")
// The content that is not named in all caps is then converted
.replaceAll("([a-z])=([A-Z])", "$1_$2")
// Remove any extra horizontal lines
.replace("=", "")
// Replace the underscore with a dash
.replace("_", "-")
// Finally, convert it to all lowercase
.toLowerCase();
}
@@ -901,9 +901,9 @@ public interface ConfigureSection {
}
static <T, C extends Collection<T>> @NotNull C parseCollection(
@Nullable List<?> data,
@NotNull Supplier<C> constructor,
@NotNull DataFunction<Object, T> parser
@Nullable List<?> data,
@NotNull Supplier<C> constructor,
@NotNull DataFunction<Object, T> parser
) {
C values = constructor.get();
if (data == null) return values;
@@ -17,9 +17,9 @@ import java.util.Set;
* @see ConfigureSection
*/
public abstract class ConfigureSource<
SECTION extends ConfigureSection, ORIGINAL,
SELF extends ConfigureSource<SECTION, ORIGINAL, SELF>>
implements ConfigureSection {
SECTION extends ConfigureSection, ORIGINAL,
SELF extends ConfigureSource<SECTION, ORIGINAL, SELF>>
implements ConfigureSection {
protected final @NotNull ConfigurationHolder<? extends SELF> holder;
protected long lastUpdateMillis;
@@ -135,8 +135,8 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>, V> impleme
for (Map.Entry<K, V> entry : value.entrySet()) {
try {
data.put(
keySerializer.serialize(holder(), keyType(), entry.getKey()),
valueSerializer.serialize(holder(), valueType(), withValidated(entry.getValue()))
keySerializer.serialize(holder(), keyType(), entry.getKey()),
valueSerializer.serialize(holder(), valueType(), withValidated(entry.getValue()))
);
} catch (Exception e) {
throwing(path + "." + entry.getKey(), e);
@@ -85,9 +85,9 @@ public class ConfiguredValue<V> extends CachedConfigValue<V, V> {
public static <V> ConfiguredValue<V> of(@NotNull ValueType<V> type, @NotNull Supplier<@Nullable V> defaultSupplier) {
return of(
new ValueManifest<>(type, defaultSupplier),
(provider, t, data) -> provider.deserialize(type, data),
(provider, t, value) -> provider.serialize(value)
new ValueManifest<>(type, defaultSupplier),
(provider, t, data) -> provider.deserialize(type, data),
(provider, t, value) -> provider.serialize(value)
);
}
@@ -9,7 +9,7 @@
//import java.util.LinkedList;
//import java.util.List;
//
///**
/// **
// * @author Chris2018998
// */
//public class OffsetUtil {
@@ -25,15 +25,15 @@
// } catch (NoSuchFieldException | IllegalAccessException e) {
// e.printStackTrace();
// }
//// try {
//// unsafe = AccessController.doPrivileged((PrivilegedExceptionAction<Unsafe>) () -> {
//// Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
//// theUnsafe.setAccessible(true);
//// return (Unsafe) theUnsafe.get(null);
//// });
//// } catch (Throwable e) {
//// System.err.println("Unable to load unsafe");
//// }
/// / try {
/// / unsafe = AccessController.doPrivileged((PrivilegedExceptionAction<Unsafe>) () -> {
/// / Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
/// / theUnsafe.setAccessible(true);
/// / return (Unsafe) theUnsafe.get(null);
/// / });
/// / } catch (Throwable e) {
/// / System.err.println("Unable to load unsafe");
/// / }
// }
//
// public static List<FieldOffset> getClassMemberOffset(Class<?> beanClass) {
+3 -3
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>configured-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>4.1.5</version>
<version>4.1.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<properties>
@@ -17,7 +17,7 @@
<maven.deploy.skip>true</maven.deploy.skip>
<deps.mysql-driver.version>8.0.33</deps.mysql-driver.version>
<log4j.version>2.24.3</log4j.version>
<log4j.version>2.25.0</log4j.version>
</properties>
<artifactId>configured-demo</artifactId>
<packaging>jar</packaging>
@@ -214,4 +214,4 @@
</plugins>
</build>
</project>
</project>
@@ -10,13 +10,13 @@ public interface DatabaseConfiguration extends Configuration {
@ConfigPath("driver")
@HeaderComments({
"数据库驱动配置,请根据数据库类型设置。",
"- MySQL(旧): com.mysql.jdbc.Driver",
"- MySQL(新): com.mysql.cj.jdbc.Driver",
"- MariaDB(推荐): org.mariadb.jdbc.Driver",
"数据库驱动配置,请根据数据库类型设置。",
"- MySQL(旧): com.mysql.jdbc.Driver",
"- MySQL(新): com.mysql.cj.jdbc.Driver",
"- MariaDB(推荐): org.mariadb.jdbc.Driver",
})
ConfiguredValue<String> DRIVER_NAME = ConfiguredValue.of(
String.class, "com.mysql.cj.jdbc.Driver"
String.class, "com.mysql.cj.jdbc.Driver"
);
ConfiguredValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1");
@@ -16,10 +16,10 @@ import java.util.UUID;
@ConfigPath(root = true)
@HeaderComments({"此处内容将显示在配置文件的最上方"})
@FooterComments({
"------------------------------------------------",
"此处内容将显示在配置文件的最下方",
"可用于显示版权信息等",
"感谢您使用 https://github.com/CarmJos/configured !"
"------------------------------------------------",
"此处内容将显示在配置文件的最下方",
"可用于显示版权信息等",
"感谢您使用 https://github.com/CarmJos/configured !"
})
public interface DemoConfiguration extends Configuration {
@@ -38,30 +38,30 @@ public interface DemoConfiguration extends Configuration {
@HeaderComments({"空值测试"})
@InlineComment("空值Inline注释")
ConfiguredMap<String, String> EMPTY = ConfiguredMap.builderOf(String.class, String.class)
.asLinkedMap().fromString()
.build();
.asLinkedMap().fromString()
.build();
@ConfigPath("registered_users") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
@HeaderComments({"Section类型数据测试"}) // 通过注解给配置添加注释。
@InlineComment("默认地注释会加到Section的首行末尾") // 通过注解给配置添加注释。
ConfiguredList<UserRecord> ALLOWLISTS = ConfiguredList.builderOf(UserRecord.class).fromSection()
.parse(UserRecord::deserialize).serialize(UserRecord::serialize)
.defaults(UserRecord.CARM).build();
.parse(UserRecord::deserialize).serialize(UserRecord::serialize)
.defaults(UserRecord.CARM).build();
@HeaderComments({
"------------------------------------------------",
"[ID - ItemStack]对照表", "", "用于测试Map类型的解析与序列化保存"
"------------------------------------------------",
"[ID - ItemStack]对照表", "", "用于测试Map类型的解析与序列化保存"
})
@FooterComments("------------------------------------------------")
ConfiguredMap<Integer, ItemStack> ITEMS = ConfiguredMap.builderOf(Integer.class, ItemStack.class)
.asLinkedMap().fromSection()
.parseKey(data -> Integer.parseInt(data))
.parse(ItemStack::deserialize).serialize(ItemStack::serialize)
.defaults(m -> {
m.put(1, new ItemStack("stone", 64));
m.put(2, new ItemStack("iron", 64, "铁锭", Arrays.asList("一些铁锭", "可以制造东西")));
})
.build();
.asLinkedMap().fromSection()
.parseKey(data -> Integer.parseInt(data))
.parse(ItemStack::deserialize).serialize(ItemStack::serialize)
.defaults(m -> {
m.put(1, new ItemStack("stone", 64));
m.put(2, new ItemStack("iron", 64, "铁锭", Arrays.asList("一些铁锭", "可以制造东西")));
})
.build();
/**
@@ -72,18 +72,18 @@ public interface DemoConfiguration extends Configuration {
@ConfigPath(value = "uuid-value", root = true)
public static final ConfiguredValue<UUID> UUID_CONFIG_VALUE = ConfiguredValue
.builderOf(UUID.class).fromString()
.parse((holder, data) -> UUID.fromString(data))
.build();
.builderOf(UUID.class).fromString()
.parse((holder, data) -> UUID.fromString(data))
.build();
@HeaderComments({"内部类的内部类测试", "通过这种方式,您可以轻易实现多层次的配置文件结构"})
@FooterComments({"-------------"})
public interface That extends Configuration {
ConfiguredList<UUID> OPERATORS = ConfiguredList
.builderOf(UUID.class).fromString()
.parse(s -> Objects.requireNonNull(UUID.fromString(s)))
.build();
.builderOf(UUID.class).fromString()
.parse(s -> Objects.requireNonNull(UUID.fromString(s)))
.build();
}
}
@@ -4,7 +4,6 @@ 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.*
import java.util.*
@ConfigPath(root = true)
object KotlinConfiguration : Configuration {
@@ -30,4 +29,4 @@ object KotlinConfiguration : Configuration {
serialize { v -> v }
defaults("key", "value")
}
}
}
@@ -20,9 +20,9 @@ public class RegistryConfig implements Configuration {
@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()))
.parse((holder, section) -> UserRecord.deserialize(section))
.serialize((holder, data) -> data.serialize()).build();
.defaults(new UserRecord("Carm", UUID.randomUUID()))
.parse((holder, section) -> UserRecord.deserialize(section))
.serialize((holder, data) -> data.serialize()).build();
}
@@ -69,10 +69,10 @@ public class ItemStack {
public static ItemStack deserialize(ConfigureSection section) {
return new ItemStack(
section.getString("material"),
section.getInt("amount", 1),
section.getString("name"),
section.getStringList("lore")
section.getString("material"),
section.getInt("amount", 1),
section.getString("name"),
section.getStringList("lore")
);
}
}
@@ -52,8 +52,8 @@ public class UserRecord extends AbstractRecord {
@Override
public String toString() {
return "TestUser{" +
"name='" + name + '\'' +
", uuid=" + uuid +
'}';
"name='" + name + '\'' +
", uuid=" + uuid +
'}';
}
}
}
@@ -10,9 +10,9 @@ import java.io.File;
public class JSONConfigTests {
protected final ConfigurationHolder<?> holder = JSONConfigFactory
.from(new File("target"), "config.json")
.resourcePath("example.json")
.build();
.from(new File("target"), "config.json")
.resourcePath("example.json")
.build();
@Test
public void onTest() {
@@ -14,10 +14,10 @@ import java.util.Map;
public class YamlTests {
@Test
public void test() {
public void test() throws Exception {
ConfigurationHolder<YAMLSource> holder = YAMLConfigFactory.from("target/tests.yml")
.resourcePath("configs/sample.yml").build();
.resourcePath("configs/sample.yml").build();
Validators.activate(holder);
@@ -28,22 +28,22 @@ public class MongoTest {
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();
.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();
.from(mongoDatabase, "configs")
.namespace("my_plugin")
.build();
// Test the configuration
ConfigurationTest.testDemo(mongoHolder);
@@ -33,9 +33,9 @@ public class SQLConfigTest {
manager.setDebugMode(true);
ConfigurationHolder<?> holder = SQLConfigFactory.from(manager)
.tableName("test_configs")
.namespace("testing")
.build();
.tableName("test_configs")
.namespace("testing")
.build();
ConfigurationTest.testDemo(holder);
ConfigurationTest.testInner(holder);
+2 -2
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-parent</artifactId>
<version>4.1.5</version>
<version>4.1.7</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
@@ -48,4 +48,4 @@
</plugins>
</build>
</project>
</project>
@@ -42,12 +42,12 @@ public interface CommentableMeta {
static void register(@NotNull ConfigurationInitializer initializer) {
initializer.registerAnnotation(
HeaderComments.class, HEADER,
a -> Arrays.asList(a.value())
HeaderComments.class, HEADER,
a -> Arrays.asList(a.value())
);
initializer.registerAnnotation(
FooterComments.class, FOOTER,
a -> Arrays.asList(a.value())
FooterComments.class, FOOTER,
a -> Arrays.asList(a.value())
);
initializer.registerAnnotation(InlineComment.class, INLINE, a -> {
Map<String, String> map = new HashMap<>();
+2 -2
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-parent</artifactId>
<version>4.1.5</version>
<version>4.1.7</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
@@ -47,4 +47,4 @@
</plugin>
</plugins>
</build>
</project>
</project>
@@ -9,8 +9,8 @@ import java.io.File;
import java.nio.file.Path;
public abstract class FileConfigFactory<SOURCE extends FileConfigSource<?, ?, SOURCE>,
HOLDER extends ConfigurationHolder<SOURCE>, SELF extends FileConfigFactory<SOURCE, HOLDER, SELF>>
extends ConfigurationFactory<SOURCE, HOLDER, SELF> {
HOLDER extends ConfigurationHolder<SOURCE>, SELF extends FileConfigFactory<SOURCE, HOLDER, SELF>>
extends ConfigurationFactory<SOURCE, HOLDER, SELF> {
protected @NotNull File file;
@@ -17,7 +17,7 @@ import java.nio.file.Files;
import java.util.Objects;
public abstract class FileConfigSource<SECTION extends ConfigureSection, ORIGINAL, SELF extends FileConfigSource<SECTION, ORIGINAL, SELF>>
extends ConfigureSource<SECTION, ORIGINAL, SELF> {
extends ConfigureSource<SECTION, ORIGINAL, SELF> {
protected final @NotNull File file;
protected final @Nullable String resourcePath;
@@ -116,7 +116,7 @@ public abstract class FileConfigSource<SECTION extends ConfigureSection, ORIGINA
}
protected void saveResource(@NotNull String resourcePath, boolean replace)
throws IOException, IllegalArgumentException {
throws IOException, IllegalArgumentException {
Objects.requireNonNull(resourcePath, "ResourcePath cannot be null");
if (resourcePath.isEmpty()) throw new IllegalArgumentException("ResourcePath cannot be empty");
@@ -1,7 +1,5 @@
package cc.carm.lib.configuration.source.option;
import cc.carm.lib.configuration.source.option.ConfigurationOption;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
@@ -11,7 +9,7 @@ public interface FileConfigOptions {
* The charset of the file.
*/
ConfigurationOption<Charset> CHARSET = ConfigurationOption.of(StandardCharsets.UTF_8);
/**
* Whether to copy files from resource if exists.
*/
+3 -3
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-parent</artifactId>
<version>4.1.5</version>
<version>4.1.7</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
@@ -14,7 +14,7 @@
<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.1.21</kotlin.version>
<kotlin.version>2.2.0</kotlin.version>
</properties>
<artifactId>configured-feature-kotlin</artifactId>
@@ -117,4 +117,4 @@
</plugin>
</plugins>
</build>
</project>
</project>
+66
View File
@@ -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>
@@ -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());
}
}
}
}
+2 -2
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-parent</artifactId>
<version>4.1.5</version>
<version>4.1.7</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
@@ -48,4 +48,4 @@
</plugins>
</build>
</project>
</project>
+2 -2
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-parent</artifactId>
<version>4.1.5</version>
<version>4.1.7</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
@@ -57,4 +57,4 @@
</plugins>
</build>
</project>
</project>
@@ -27,8 +27,8 @@ public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents>
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)
(h, t, d) -> d.serialize(),
(h, t, d) -> TextContents.deserialize(d)
);
protected final @NotNull BiFunction<RECEIVER, String, String> parser;
@@ -51,8 +51,8 @@ public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents>
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);
.parser(this.parser).compiler(this.compiler)
.dispatcher(this.dispatcher).placeholders(values);
}
/**
@@ -120,7 +120,7 @@ public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents>
}
public abstract static class Builder<MSG, RECEIVER, SELF extends Builder<MSG, RECEIVER, SELF>>
extends AbstractConfigBuilder<TextContents, TextContents, ConfiguredText<MSG, RECEIVER>, ConfigurationHolder<?>, SELF> {
extends AbstractConfigBuilder<TextContents, TextContents, ConfiguredText<MSG, RECEIVER>, ConfigurationHolder<?>, SELF> {
protected @NotNull TextContents.Builder defaultBuilder = TextContents.builder();
protected @NotNull String[] params = new String[0];
@@ -21,7 +21,7 @@ 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> {
implements Replaceable<RECEIVER, SELF>, Insertable<RECEIVER, SELF> {
protected BiFunction<RECEIVER, String, String> parser = (receiver, value) -> value;
protected String lineSeparator = System.lineSeparator();
@@ -1,6 +1,5 @@
package cc.carm.lib.configuration.value.text.function;
import cc.carm.lib.configuration.value.text.data.TextContents;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
@@ -11,7 +11,7 @@ import java.util.function.BiFunction;
import java.util.function.Consumer;
public abstract class TextParser<RECEIVER, SELF extends TextParser<RECEIVER, SELF>>
extends ContentHandler<RECEIVER, SELF> {
extends ContentHandler<RECEIVER, SELF> {
public abstract TextContents texts();
@@ -29,7 +29,7 @@ public class AppendLineInserter<RECEIVER> extends ContentInserter<RECEIVER> {
* </ul>
*/
public static final @NotNull Pattern APPEND_PATTERN = Pattern.compile(
"^(?:\\{(?<prefix>.*)})?#(?<id>.*)#(?:\\{(?<above>-?\\d+)(?:,(?<down>-?\\d+))?})?$"
"^(?:\\{(?<prefix>.*)})?#(?<id>.*)#(?:\\{(?<above>-?\\d+)(?:,(?<down>-?\\d+))?})?$"
);
public AppendLineInserter(int priority) {
@@ -50,9 +50,9 @@ public class AppendLineInserter<RECEIVER> extends ContentInserter<RECEIVER> {
String prefix = Optional.ofNullable(matcher.group("prefix")).orElse("");
int offsetAbove = Optional.ofNullable(matcher.group("above"))
.map(Integer::parseInt).orElse(0);
.map(Integer::parseInt).orElse(0);
int offsetDown = Optional.ofNullable(matcher.group("down"))
.map(Integer::parseInt).orElse(offsetAbove); // If offsetDown is not set, use offsetAbove
.map(Integer::parseInt).orElse(offsetAbove); // If offsetDown is not set, use offsetAbove
List<String> contents = new ArrayList<>();
@@ -23,7 +23,7 @@ public class OptionalLineInserter<RECEIVER> extends ContentInserter<RECEIVER> {
* </ul>
*/
public static final @NotNull Pattern OPTIONAL_PATTERN = Pattern.compile(
"^\\?\\[(?<id>.+)](?<content>.*)$"
"^\\?\\[(?<id>.+)](?<content>.*)$"
);
public OptionalLineInserter(int priority) {
@@ -12,9 +12,9 @@ import java.util.List;
public class ConfigTest {
public static final String[] WEBSITES = new String[]{
"https://carm.cc",
"https://www.baidu.com",
"https://www.google.com"
"https://carm.cc",
"https://www.baidu.com",
"https://www.google.com"
};
@Test
@@ -27,10 +27,10 @@ public class ConfigTest {
System.out.println("--------------------------");
List<String> str = AppMessages.WELCOME.prepare()
.placeholders("Carm")
.insert("guidance")
.insert("websites", WEBSITES)
.compile(System.out);
.placeholders("Carm")
.insert("guidance")
.insert("websites", WEBSITES)
.compile(System.out);
System.out.println("--------------------------");
@@ -33,17 +33,17 @@ public class ParseTest {
TextContents textContents = new TextContents(lines, optional);
PreparedText<String, PrintStream> msg = new PreparedText<String, PrintStream>(textContents)
.dispatcher((p, s) -> s.forEach(p::println))
.parser((p, s) -> s)
.compiler((p, s) -> s)
.replace( // Custom replacer, replace $UUID$ with Random UUID
"$UUID$", () -> UUID.randomUUID().toString()
);
.dispatcher((p, s) -> s.forEach(p::println))
.parser((p, s) -> s)
.compiler((p, s) -> s)
.replace( // Custom replacer, replace $UUID$ with Random UUID
"$UUID$", () -> UUID.randomUUID().toString()
);
msg.placeholder("name", "Carm")
.insert("guidance")
.insert("click")
.insert("websites", "Baidu", "Bilibili", "Google");
.insert("guidance")
.insert("click")
.insert("websites", "Baidu", "Bilibili", "Google");
System.out.println("----------------------------");
@@ -7,22 +7,22 @@ import cc.carm.lib.configuration.annotation.ConfigPath;
public interface AppMessages extends Configuration {
ConfiguredMsg WELCOME = ConfiguredMsg.builder()
.defaults(
"Hello, %(name)",
"#more-creating#{1}",
"This is a test message",
"#guidance#",
"{- }#websites#{0,1}",
"Thanks for your reading!")
.optional("guidance", "To get more information for %(name), see:")
.params("name").build();
.defaults(
"Hello, %(name)",
"#more-creating#{1}",
"This is a test message",
"#guidance#",
"{- }#websites#{0,1}",
"Thanks for your reading!")
.optional("guidance", "To get more information for %(name), see:")
.params("name").build();
ConfiguredMsg NO_PERMISSION = ConfiguredMsg.builder()
.defaults("Sorry! But you don't have permissions to do this.")
.build();
.defaults("Sorry! But you don't have permissions to do this.")
.build();
ConfiguredMsg NOT_AVAILABLE = ConfiguredMsg.builder()
.defaults("Error! Service is not available now.", "Please contact your system manager.")
.build();
.defaults("Error! Service is not available now.", "Please contact your system manager.")
.build();
}
@@ -20,11 +20,11 @@ public class ConfiguredMsg extends ConfiguredText<String, PrintStream> {
public ConfiguredMsg(@NotNull ValueManifest<TextContents, TextContents> manifest,
@NotNull String[] params) {
super(
manifest,
(p, s) -> s,
(p, s) -> s,
(p, s) -> s.forEach(p::println),
params
manifest,
(p, s) -> s,
(p, s) -> s,
(p, s) -> s.forEach(p::println),
params
);
}
+2 -2
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-parent</artifactId>
<version>4.1.5</version>
<version>4.1.7</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
@@ -48,4 +48,4 @@
</plugins>
</build>
</project>
</project>
+2 -2
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-parent</artifactId>
<version>4.1.5</version>
<version>4.1.7</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
@@ -48,4 +48,4 @@
</plugins>
</build>
</project>
</project>
+7 -5
View File
@@ -5,18 +5,18 @@
<modelVersion>4.0.0</modelVersion>
<properties>
<project.jdk.version>1.8</project.jdk.version>
<project.jdk.version>8</project.jdk.version>
<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.1.21</kotlin.version>
<kotlin.version>2.2.0</kotlin.version>
</properties>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-parent</artifactId>
<packaging>pom</packaging>
<version>4.1.5</version>
<version>4.1.7</version>
<modules>
<module>core</module>
<module>features/section</module>
@@ -26,7 +26,9 @@
<module>features/validators</module>
<module>features/text</module>
<module>features/kotlin</module>
<module>features/record</module>
<module>providers/temp</module>
<module>providers/yaml</module>
<module>providers/gson</module>
<module>providers/hocon</module>
@@ -276,7 +278,7 @@
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.7.0</version>
<version>0.8.0</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
@@ -304,4 +306,4 @@
</profiles>
</project>
</project>
+18 -2
View File
@@ -1,8 +1,24 @@
# configured-JSON
JSON file-based implementation, compatible with all Java environments.
JSON
file-based
implementation,
compatible
with
all
Java
environments.
**Remember that JSON does not support file comments.**
*
*Remember
that
JSON
does
not
support
file
comments.
**
## Dependencies
+2 -2
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>configured-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>4.1.5</version>
<version>4.1.7</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -71,4 +71,4 @@
</plugins>
</build>
</project>
</project>
@@ -17,11 +17,11 @@ import java.util.Objects;
public class JSONSource extends FileConfigSource<SourcedSection, Map<String, Object>, JSONSource> {
public static final @NotNull Gson DEFAULT_GSON = new GsonBuilder()
.serializeNulls().disableHtmlEscaping().setPrettyPrinting()
.registerTypeAdapter(
SourcedSection.class,
(JsonSerializer<SourcedSection>) (src, t, c) -> c.serialize(src.data())
).create();
.serializeNulls().disableHtmlEscaping().setPrettyPrinting()
.registerTypeAdapter(
SourcedSection.class,
(JsonSerializer<SourcedSection>) (src, t, c) -> c.serialize(src.data())
).create();
protected final @NotNull Gson gson;
protected @Nullable SourcedSection rootSection;
+8 -1
View File
@@ -1,6 +1,13 @@
# configured-HOCON
HOCON file-based implementation, compatible with all Java environments.
HOCON
file-based
implementation,
compatible
with
all
Java
environments.
## Dependencies
+2 -2
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-parent</artifactId>
<version>4.1.5</version>
<version>4.1.7</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
@@ -74,4 +74,4 @@
</build>
</project>
</project>
@@ -9,15 +9,18 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.*;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
public class HOCONSource
extends FileConfigSource<SourcedSection, Map<String, Object>, HOCONSource> {
extends FileConfigSource<SourcedSection, Map<String, Object>, HOCONSource> {
protected @Nullable SourcedSection rootSection;
protected HOCONSource(
@NotNull ConfigurationHolder<? extends HOCONSource> holder,
@NotNull File file, @Nullable String resourcePath
@NotNull ConfigurationHolder<? extends HOCONSource> holder,
@NotNull File file, @Nullable String resourcePath
) {
super(holder, 0, file, resourcePath);
@@ -54,32 +57,32 @@ public class HOCONSource
// accumulator: 将 Section 中的信息为 typesafe config 添加并返回
// combiner: 合并两个配置文件
Config config = this.getValues(true).entrySet().stream().reduce(
ConfigFactory.empty(),
(cfg, entry) -> {
String key = entry.getKey(); // 源数据 key
Object value = entry.getValue(); // 源数据 value
ConfigFactory.empty(),
(cfg, entry) -> {
String key = entry.getKey(); // 源数据 key
Object value = entry.getValue(); // 源数据 value
ConfigValue result; // 最终转换为 typesafe 的 ConfigValue 类型
if (value == null || value instanceof Boolean || value instanceof String || value instanceof Number) {
result = ConfigValueFactory.fromAnyRef(value); // 原始数据类型
} else if (value instanceof Iterator) {
result = ConfigValueFactory.fromIterable((Iterable<?>) value);
} else if (value instanceof Map) {
//noinspection unchecked
result = ConfigValueFactory.fromMap((Map<String, ?>) value);
} else {
result = ConfigValueFactory.fromAnyRef(String.valueOf(value));
}
List<String> headerComments = HOCONSource.this.getHeaderComments(key); // 获取其注释
result = result.withOrigin(result.origin().withComments(headerComments)); // 赋予其注释
return cfg.withValue(key, result); // 将其添加到根 config 中
},
Config::withFallback
ConfigValue result; // 最终转换为 typesafe 的 ConfigValue 类型
if (value == null || value instanceof Boolean || value instanceof String || value instanceof Number) {
result = ConfigValueFactory.fromAnyRef(value); // 原始数据类型
} else if (value instanceof Iterator) {
result = ConfigValueFactory.fromIterable((Iterable<?>) value);
} else if (value instanceof Map) {
//noinspection unchecked
result = ConfigValueFactory.fromMap((Map<String, ?>) value);
} else {
result = ConfigValueFactory.fromAnyRef(String.valueOf(value));
}
List<String> headerComments = HOCONSource.this.getHeaderComments(key); // 获取其注释
result = result.withOrigin(result.origin().withComments(headerComments)); // 赋予其注释
return cfg.withValue(key, result); // 将其添加到根 config 中
},
Config::withFallback
);
return config.root().render(
ConfigRenderOptions.defaults()
.setJson(false)
.setOriginComments(false)
ConfigRenderOptions.defaults()
.setJson(false)
.setOriginComments(false)
);
}
@@ -18,11 +18,11 @@ public interface SampleConfig extends Configuration {
@HeaderComments({"[ UUID >-----------------------------------", "A lot of UUIDs"})
ConfiguredList<UUID> UUIDS = ConfiguredList.builderOf(UUID.class).fromString()
.parse(UUID::fromString).serialize(UUID::toString)
.defaults(
UUID.fromString("00000000-0000-0000-0000-000000000000"),
UUID.fromString("00000000-0000-0000-0000-000000000001")
).build();
.parse(UUID::fromString).serialize(UUID::toString)
.defaults(
UUID.fromString("00000000-0000-0000-0000-000000000000"),
UUID.fromString("00000000-0000-0000-0000-000000000001")
).build();
@ConfigPath("info") // Custom path
interface INFO extends Configuration {
@@ -4,14 +4,14 @@ import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.hocon.HOCONConfigFactory;
import org.junit.Test;
public class SampleTest {
public class SampleTest {
@Test
public void test() {
// 1. Make a configuration provider from a file.
ConfigurationHolder<?> holder = HOCONConfigFactory.from("target/config.conf")
.resourcePath("configs/sample.conf")
.build();
.resourcePath("configs/sample.conf")
.build();
// 2. Initialize the configuration classes or instances.
holder.initialize(SampleConfig.class);
+3 -3
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>configured-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>4.1.5</version>
<version>4.1.7</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -14,7 +14,7 @@
<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>
<deps.mongodb.version>5.5.0</deps.mongodb.version>
<deps.mongodb.version>5.5.1</deps.mongodb.version>
</properties>
<artifactId>configured-mongodb</artifactId>
@@ -63,4 +63,4 @@
</plugins>
</build>
</project>
</project>
+48 -15
View File
@@ -1,8 +1,16 @@
# configured-SQL
SQL database implementation, support for MySQL or MariaDB.
SQL
database
implementation,
support
for
MySQL
or
MariaDB.
## Table schema
```mysql
CREATE TABLE IF NOT EXISTS conf
(
@@ -16,9 +24,11 @@ CREATE TABLE IF NOT EXISTS conf
`version` MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, # 配置项的版本
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, # 创建时间
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`namespace`, `path`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
PRIMARY KEY (`namespace`,
`path`)
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
```
## Dependencies
@@ -32,16 +42,30 @@ CREATE TABLE IF NOT EXISTS conf
<repository>
<!-- Using Maven Central Repository for secure and stable updates, though synchronization might be needed. -->
<id>maven</id>
<name>Maven Central</name>
<url>https://repo1.maven.org/maven2</url>
<id>
maven
</id>
<name>
Maven
Central
</name>
<url>
https://repo1.maven.org/maven2
</url>
</repository>
<repository>
<!-- Using GitHub dependencies for real-time updates, configuration required (recommended). -->
<id>configured</id>
<name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/configured</url>
<id>
configured
</id>
<name>
GitHub
Packages
</name>
<url>
https://maven.pkg.github.com/CarmJos/configured
</url>
</repository>
</repositories>
@@ -53,10 +77,19 @@ CREATE TABLE IF NOT EXISTS conf
<project>
<dependencies>
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-sql</artifactId>
<version>[LATEST RELEASE]</version>
<scope>compile</scope>
<groupId>
cc.carm.lib
</groupId>
<artifactId>
configured-sql
</artifactId>
<version>
[LATEST
RELEASE]
</version>
<scope>
compile
</scope>
</dependency>
</dependencies>
</project>
@@ -80,4 +113,4 @@ repositories {
dependencies {
api "cc.carm.lib:configured-sql:[LATEST RELEASE]"
}
```
```
+2 -2
View File
@@ -6,7 +6,7 @@
<parent>
<artifactId>configured-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>4.1.5</version>
<version>4.1.7</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
@@ -81,4 +81,4 @@
</plugins>
</build>
</project>
</project>
@@ -32,7 +32,7 @@ public class SQLConfigFactory extends ConfigurationFactory<SQLSource, Configurat
}
protected static final @NotNull Gson DEFAULT_GSON = new GsonBuilder()
.serializeNulls().disableHtmlEscaping().create();
.serializeNulls().disableHtmlEscaping().create();
protected static final @NotNull BiConsumer<String, TableCreateBuilder> DEFAULT_TABLE_SCHEMA = (tableName, builder) -> {
builder.addColumn("namespace", "VARCHAR(32) NOT NULL");
@@ -48,17 +48,17 @@ public class SQLConfigFactory extends ConfigurationFactory<SQLSource, Configurat
builder.addColumn("version", "MEDIUMINT UNSIGNED NOT NULL DEFAULT 0");
builder.addColumn(
"create_time",
"TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP"
"create_time",
"TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP"
);
builder.addColumn(
"update_time",
"TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"
"update_time",
"TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"
);
builder.setIndex(
IndexType.PRIMARY_KEY, "pk_" + tableName.toLowerCase(),
"namespace", "path"
IndexType.PRIMARY_KEY, "pk_" + tableName.toLowerCase(),
"namespace", "path"
);
builder.setTableSettings("ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
};
@@ -163,8 +163,8 @@ public class SQLConfigFactory extends ConfigurationFactory<SQLSource, Configurat
return new ConfigurationHolder<SQLSource>(this.adapters, this.options, this.metadata, this.initializer) {
final SQLSource source = new SQLSource(
this, System.currentTimeMillis(),
gson, manager, resolvers, tableName, namespace
this, System.currentTimeMillis(),
gson, manager, resolvers, tableName, namespace
);
@Override
@@ -7,6 +7,6 @@ public interface SQLOptions {
/**
* Whether to purge the configuration's in-database data when saving.
*/
ConfigurationOption<Boolean> PURGE = ConfigurationOption.of( true);
ConfigurationOption<Boolean> PURGE = ConfigurationOption.of(true);
}
@@ -104,10 +104,10 @@ public class SQLSource extends ConfigureSource<SourcedSection, Map<String, Objec
int version = holder().metadata(path).get(VersionedMetaTypes.VERSION, 0);
dataValues.add(new Object[]{
namespace, path, time, version, typeID, data,
Commentable.getInlineComment(holder(), path),
gson.toJson(Commentable.getHeaderComments(holder(), path)),
gson.toJson(Commentable.getFooterComments(holder(), path))
namespace, path, time, version, typeID, data,
Commentable.getInlineComment(holder(), path),
gson.toJson(Commentable.getHeaderComments(holder(), path)),
gson.toJson(Commentable.getFooterComments(holder(), path))
});
} catch (Exception ex) {
ex.printStackTrace();
@@ -118,18 +118,18 @@ public class SQLSource extends ConfigureSource<SourcedSection, Map<String, Objec
purge();
}
this.table.createReplaceBatch()
.setColumnNames(
"namespace", "path", "update_time", "version", "type", "value",
"inline_comment", "header_comments", "footer_comments"
).setAllParams(dataValues).execute();
.setColumnNames(
"namespace", "path", "update_time", "version", "type", "value",
"inline_comment", "header_comments", "footer_comments"
).setAllParams(dataValues).execute();
}
@Override
protected void onReload() throws Exception {
Map<String, Object> loaded = new LinkedHashMap<>();
try (SQLQuery query = this.table.createQuery()
.addCondition("namespace", namespace)
.build().execute()) {
.addCondition("namespace", namespace)
.build().execute()) {
ResultSet rs = query.getResultSet();
while (rs.next()) {
String path = rs.getString("path");
@@ -161,9 +161,9 @@ public class SQLSource extends ConfigureSource<SourcedSection, Map<String, Objec
protected int typeIdOf(@NotNull Object value) {
return this.resolvers.entrySet().stream()
.filter(entry -> entry.getValue().isInstance(value))
.findFirst().map(Map.Entry::getKey)
.orElseThrow(() -> new IllegalStateException("No resolvers for value " + value.getClass().getName()));
.filter(entry -> entry.getValue().isInstance(value))
.findFirst().map(Map.Entry::getKey)
.orElseThrow(() -> new IllegalStateException("No resolvers for value " + value.getClass().getName()));
}
+62
View File
@@ -0,0 +1,62 @@
<?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>
<artifactId>configured-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<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-temp</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>configured-core</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>configured-feature-section</artifactId>
<version>${project.parent.version}</version>
<scope>compile</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,57 @@
package cc.carm.lib.configuration.source.temp;
import cc.carm.lib.configuration.source.ConfigurationFactory;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class TempConfigFactory
extends ConfigurationFactory<TempSource, ConfigurationHolder<TempSource>, TempConfigFactory> {
public static @NotNull TempConfigFactory create() {
return new TempConfigFactory();
}
protected Map<String, Object> defaults = new LinkedHashMap<>();
public TempConfigFactory defaults(@NotNull Map<String, Object> defaults) {
this.defaults = defaults;
return this;
}
public TempConfigFactory defaults(Supplier<Map<String, Object>> defaultsSupplier) {
return defaults(defaultsSupplier.get());
}
public TempConfigFactory defaults(@NotNull Consumer<Map<String, Object>> defaultsConsumer) {
return defaults(() -> {
Map<String, Object> defaults = new LinkedHashMap<>();
defaultsConsumer.accept(defaults);
return defaults;
});
}
@Override
protected TempConfigFactory self() {
return this;
}
@Override
public @NotNull ConfigurationHolder<TempSource> build() {
return new ConfigurationHolder<TempSource>(this.adapters, this.options, this.metadata, this.initializer) {
final @NotNull TempSource source = new TempSource(this, defaults);
@Override
public @NotNull TempSource config() {
return this.source;
}
};
}
}
@@ -0,0 +1,47 @@
package cc.carm.lib.configuration.source.temp;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.section.ConfigureSource;
import cc.carm.lib.configuration.source.section.SourcedSection;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.Objects;
public class TempSource extends ConfigureSource<SourcedSection, Map<String, Object>, TempSource> {
protected @NotNull SourcedSection rootSection;
protected TempSource(@NotNull ConfigurationHolder<? extends TempSource> holder,
@NotNull Map<String, Object> defaults) {
super(holder, 0);
this.rootSection = SourcedSection.root(this, defaults);
}
@Override
protected @NotNull TempSource self() {
return this;
}
@Override
public @NotNull Map<String, Object> original() {
return section().data();
}
@Override
public @NotNull SourcedSection section() {
return Objects.requireNonNull(this.rootSection, "Root section is not initialized.");
}
@Override
public void save() throws Exception {
// Nothing to do here.
}
@Override
protected void onReload() throws Exception {
// Also nothing to do, because this is a temporary source.
}
}
+9 -2
View File
@@ -1,6 +1,13 @@
# configured-YAML
YAML file-based implementation, compatible with all Java environments.
YAML
file-based
implementation,
compatible
with
all
Java
environments.
## Dependencies
@@ -61,4 +68,4 @@ repositories {
dependencies {
api "cc.carm.lib:configured-yaml:[LATEST RELEASE]"
}
```
```
+2 -2
View File
@@ -6,7 +6,7 @@
<parent>
<artifactId>configured-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>4.1.5</version>
<version>4.1.7</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
@@ -88,4 +88,4 @@
</build>
</project>
</project>
@@ -26,8 +26,8 @@ import java.nio.charset.StandardCharsets;
import java.util.*;
public class YAMLSource
extends FileConfigSource<SourcedSection, Map<String, Object>, YAMLSource>
implements CommentedSection {
extends FileConfigSource<SourcedSection, Map<String, Object>, YAMLSource>
implements CommentedSection {
protected final @NotNull YamlConstructor yamlConstructor;
protected final @NotNull YamlRepresenter yamlRepresenter;
@@ -109,9 +109,9 @@ public class YAMLSource
@Override
public void save() throws Exception {
CommentedYAMLWriter writer = new CommentedYAMLWriter(
String.valueOf(this.pathSeparator()),
dumperOptions().getIndent(),
holder.option(CommentableOptions.COMMENT_EMPTY_VALUE)
String.valueOf(this.pathSeparator()),
dumperOptions().getIndent(),
holder.option(CommentableOptions.COMMENT_EMPTY_VALUE)
);
try {
fileWriter(w -> w.write(writer.saveToString(this)));
@@ -23,11 +23,11 @@ public interface SampleConfig extends Configuration {
@HeaderComments({"[ UUID >-----------------------------------", "A lot of UUIDs"})
@FooterComments("[ UUID >-----------------------------------")
ConfiguredList<UUID> UUIDS = ConfiguredList.builderOf(UUID.class).fromString()
.parse(UUID::fromString).serialize(UUID::toString)
.defaults(
UUID.fromString("00000000-0000-0000-0000-000000000000"),
UUID.fromString("00000000-0000-0000-0000-000000000001")
).build();
.parse(UUID::fromString).serialize(UUID::toString)
.defaults(
UUID.fromString("00000000-0000-0000-0000-000000000000"),
UUID.fromString("00000000-0000-0000-0000-000000000001")
).build();
@ConfigPath("info") // Custom path
interface INFO extends Configuration {
@@ -10,9 +10,9 @@ public class SampleTest {
public void test() {
// 1. Make a configuration provider from a file.
ConfigurationHolder<?> holder = YAMLConfigFactory.from("target/config.yml")
.resourcePath("configs/sample.yml")
.indent(2) // Optional: Set the indentation of the configuration file.
.build();
.resourcePath("configs/sample.yml")
.indent(2) // Optional: Set the indentation of the configuration file.
.build();
// 2. Initialize the configuration classes or instances.
holder.initialize(SampleConfig.class);