1
mirror of https://github.com/CarmJos/EasyConfiguration.git synced 2026-06-05 02:58:20 +08:00

Compare commits

...

64 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
carm 76d276436b ci(deploy): Skip deployment for demo project. 2025-05-14 03:55:54 +08:00
carm e7198f22d5 ci(deploy): Skip deployment for demo project. 2025-05-14 03:48:54 +08:00
carm 5bd20e173f ci(deploy): Skip deployment for demo project. 2025-05-14 03:41:15 +08:00
carm 15c4bb13e8 build(repo): Use official repositories. 2025-05-14 03:33:45 +08:00
dependabot[bot] b74eb5c035 build(deps): bump com.google.code.gson:gson from 2.13.0 to 2.13.1
Bumps [com.google.code.gson:gson](https://github.com/google/gson) from 2.13.0 to 2.13.1.
- [Release notes](https://github.com/google/gson/releases)
- [Changelog](https://github.com/google/gson/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google/gson/compare/gson-parent-2.13.0...gson-parent-2.13.1)

---
updated-dependencies:
- dependency-name: com.google.code.gson:gson
  dependency-version: 2.13.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-14 03:27:17 +08:00
renovate[bot] ed3a68af1e fix(deps): update kotlin monorepo to v2.1.21 2025-05-14 03:25:58 +08:00
dependabot[bot] 447b82c880 build(deps): bump org.mongodb:mongodb-driver-sync from 5.4.0 to 5.5.0
Bumps [org.mongodb:mongodb-driver-sync](https://github.com/mongodb/mongo-java-driver) from 5.4.0 to 5.5.0.
- [Release notes](https://github.com/mongodb/mongo-java-driver/releases)
- [Commits](https://github.com/mongodb/mongo-java-driver/compare/r5.4.0...r5.5.0)

---
updated-dependencies:
- dependency-name: org.mongodb:mongodb-driver-sync
  dependency-version: 5.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-14 03:25:49 +08:00
carm 5700f8c1c6 Merge remote-tracking branch 'origin/master' 2025-04-18 00:53:01 +08:00
carm 1cf230d6b6 chore: Bump to 4.1.4 2025-04-18 00:52:51 +08:00
carm 1ffd4b2f0b build(checks): Bye codacy. 2025-04-18 00:31:42 +08:00
dependabot[bot] 92ce780d6f build(deps): bump kotlin.version from 1.9.22 to 2.1.20
Bumps `kotlin.version` from 1.9.22 to 2.1.20.

Updates `org.jetbrains.kotlin:kotlin-stdlib-jdk8` from 1.9.22 to 2.1.20
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.9.22...v2.1.20)

Updates `org.jetbrains.kotlin:kotlin-maven-plugin` from 1.9.22 to 2.1.20

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlin:kotlin-stdlib-jdk8
  dependency-version: 2.1.20
  dependency-type: direct:production
  update-type: version-update:semver-major
- dependency-name: org.jetbrains.kotlin:kotlin-maven-plugin
  dependency-version: 2.1.20
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-18 00:30:08 +08:00
carm a2de3303e8 feat(section): Add more section functions 2025-04-17 23:55:15 +08:00
renovate[bot] 47a1981002 fix(deps): update dependency com.google.code.gson:gson to v2.13.0 2025-04-17 22:06:46 +08:00
renovate[bot] b97bc5d1a9 chore(deps): update dependency org.apache.maven.plugins:maven-surefire-plugin to v3.5.3 2025-04-17 22:05:43 +08:00
carm cc927fdc0e Merge pull request #134 from huanmeng-qwq/language/kotlin
feat: Support kotlin dsl
2025-04-17 22:05:28 +08:00
carm 5dc2693106 build(doc): Removed javadoc generation for demo project. 2025-04-17 18:44:48 +08:00
carm 472ce66ca7 build(kotlin): Fixed version 2025-04-17 18:13:00 +08:00
carm 796771554f Merge branch 'master' into language/kotlin 2025-04-17 17:48:38 +08:00
carm 28cb5d4c83 refactor(demo): Move all tests to demo. 2025-04-17 17:43:29 +08:00
carm a670aec986 fix(deps): Fixed the missing kotlin version. 2025-03-30 22:48:19 +08:00
renovate[bot] 51c54b9b53 fix(deps): update dependency org.mongodb:mongodb-driver-sync to v5.4.0 2025-03-23 01:10:53 +08:00
huanmeng-qwq fa99385ff0 feat: Support kotlin dsl 2025-03-22 17:43:48 +08:00
carm 70a3b893a6 chore(text): Add missing text functions 2025-03-21 03:30:47 +08:00
carm c32a941906 docs: Edit logo size 2025-03-21 02:32:33 +08:00
carm 8b597d10f9 feat: Optimized ContentHandler with Replacer & Inserter. 2025-03-21 02:31:04 +08:00
carm cedfcfd262 docs: Update banners and icons 2025-03-21 02:30:35 +08:00
carm 12add75232 feat: Enhanced text content replacer 2025-03-20 20:28:33 +08:00
carm 4d29a24768 docs: Edited readme 2025-03-20 17:16:33 +08:00
carm 8626b86961 chore: Change logo 2025-03-20 16:08:17 +08:00
carm 754dc1de1f feat: Change logo 2025-03-20 16:04:50 +08:00
carm 3d1d4ca609 chore: Add logo & icon. 2025-03-20 15:32:27 +08:00
carm 990b10b6f0 chore: Add logo & icon. 2025-03-20 15:30:34 +08:00
carm 7462cd720e chore: Optimize code format & functions. 2025-03-19 18:36:08 +08:00
carm 6bc83eb3b3 chore: Optimize code format & functions. 2025-03-19 18:35:45 +08:00
carm dbec551c84 chore: Fixed the param errors. 2025-03-17 01:39:08 +08:00
carm 82cca5eca2 feat(exception): Supported ConfigExceptionHandler for holders. 2025-03-17 01:06:57 +08:00
carm 65f3cc1b3d feat(validator): Support validators for config values.
BREAKING CHANGE: `ValueManifest` and `ConfigValue` added a new type "UNIT" to mark the minimal unit value of this instance.

link #132
2025-03-17 00:26:47 +08:00
carm fae048dd69 feat(validator): Support validators for config values.
BREAKING CHANGE: `ValueManifest` and `ConfigValue` added a new type "UNIT" to mark the minimal unit value of this instance.

link #132
2025-03-16 23:56:36 +08:00
carm 854e3df49f feat: Upgrade configured to v4.1.0 2025-03-15 01:52:52 +08:00
carm f6167c3b5e docs: Update license [skip ci] 2025-03-15 01:51:07 +08:00
carm ffe3e88b3b docs: Translated to English 2025-03-14 19:34:06 +08:00
carm caa3077f48 chore: Add missing @Nullable 2025-03-14 19:33:30 +08:00
carm 05dbf0b504 docs: Redesign readme 2025-03-14 19:20:31 +08:00
carm 810e95198e docs: Redesign readme 2025-03-14 19:17:26 +08:00
carm 10004f16b4 docs(logo): Add project banner & logo 2025-03-14 19:09:43 +08:00
carm 8e19748c7c feat(map): Add more builder functions 2025-03-12 04:04:00 +08:00
carm 17762a2e70 refactor(proj): Change project name to "configured" 2025-03-12 03:27:35 +08:00
carm 7dbd607a3f refactor(proj): Change project name to "configured" 2025-03-12 03:22:40 +08:00
carm 035e8a227e test(parse): Add more tests 2025-03-06 20:12:33 +08:00
135 changed files with 3688 additions and 1227 deletions
+5 -8
View File
@@ -1,9 +1,6 @@
# EasyConfiguration Javadoc # configured Javadoc
基于 [Github Pages](https://pages.github.com/) 搭建,请访问 [JavaDoc](https://carmjos.github.io/EasyConfiguration) 。 Based
on [Github Pages](https://pages.github.com/),
## 如何实现? please
see [JavaDoc](https://carmjos.github.io/configured) 。
若您也想通过 [Github Actions](https://docs.github.com/en/actions/learn-github-actions)
自动部署项目的Javadoc到 [Github Pages](https://pages.github.com/)
可以参考我的文章 [《自动部署Javadoc到Github Pages》](https://pages.carm.cc/doc/javadoc-in-github.html) 。
+1 -16
View File
@@ -1,16 +1 @@
# 欢迎使用 EasyConfiguration # Documentation
这个项目刚刚创建,详细的Javadoc与开发指南还在补充,请给我一点时间~
## 基本定义
Value: 实际配置的单例值。
Manifest: 用于描述值基本配置的对象。
Provider: 用于提供配置文件的接口。
Wrapper: 用于包装配置文件的接口。
Initializer: 用于初始化的接口
Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

+346
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: 问题提交 name:
about: 描述问题提交,帮助我们对其进行检查与修复。 问题提交
about:
描述问题并提交,帮助我们对其进行检查与修复。
title: '' title: ''
labels: bug labels:
bug
assignees: '' assignees: ''
--- ---
### **问题简述** ###
*
*问题简述
**
用简短的话语描述一下大概问题。 用简短的话语描述一下大概问题。
### **问题来源** ###
*
*问题来源
**
描述一下通过哪些操作才发现的问题,如: 描述一下通过哪些操作才发现的问题,如:
1. 使用了 '...' 1.
2. 输入了 '....' 使用了 '...'
3. 出现了报错 '....' 2.
输入了 '....'
3.
出现了报错 '....'
### **预期结果** (可选) ###
*
*预期结果
** (可选)
如果问题不发生,应该是什么情况 如果问题不发生,应该是什么情况
### **问题截图/问题报错** ###
*
*问题截图/问题报错
**
如果有报错或输出,请提供截图。 如果有报错或输出,请提供截图。
### **操作环境** ###
*
*操作环境
**
- 系统环境: `Windows 10` / `Ubuntu` / `...` -
- Java版本: `JDK11` / `OPENJDK8` / `JRE8` / `...` 系统环境:
`Windows 10` /
`Ubuntu` /
`...`
-
Java版本:
`JDK11` /
`OPENJDK8` /
`JRE8` /
`...`
### **其他补充** ###
*
*其他补充
**
如有其他补充,可以在这里描述。 如有其他补充,可以在这里描述。
+22 -7
View File
@@ -1,23 +1,38 @@
--- ---
name: 功能需求 name:
about: 希望我们提供更多的功能。 功能需求
about:
希望我们提供更多的功能。
title: '' title: ''
labels: enhancement labels:
enhancement
assignees: '' assignees: ''
--- ---
### **功能简述** ###
*
*功能简述
**
简单的描述一下你想要的功能 简单的描述一下你想要的功能
### **需求来源** ###
*
*需求来源
**
简单的描述一下为什么需要这个功能。 简单的描述一下为什么需要这个功能。
### **功能参考**(可选) ###
*
*功能参考
**(可选)
如果有相关功能的参考,如文本、截图,请提供给我们。 如果有相关功能的参考,如文本、截图,请提供给我们。
### **附加内容** ###
*
*附加内容
**
如果有什么小细节需要重点注意,请在这里告诉我们。 如果有什么小细节需要重点注意,请在这里告诉我们。
-54
View File
@@ -1,54 +0,0 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow checks out code, performs a Codacy security scan
# and integrates the results with the
# GitHub Advanced Security code scanning feature. For more information on
# the Codacy security scan action usage and parameters, see
# https://github.com/codacy/codacy-analysis-cli-action.
# For more information on Codacy Analysis CLI in general, see
# https://github.com/codacy/codacy-analysis-cli.
name: "Codacy Security Scan"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '27 16 * * 5'
jobs:
codacy-security-scan:
name: Codacy Security Scan
runs-on: ubuntu-latest
steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout code
uses: actions/checkout@v4
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
- name: Run Codacy Analysis CLI
uses: codacy/codacy-analysis-cli-action@09916000460adeeedc96b9704f86deba53e2ad5d
with:
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
# You can also omit the token and run the tools that support default configurations
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
verbose: true
output: results.sarif
format: sarif
# Adjust severity of non-security issues
gh-code-scanning-compat: true
# Force 0 exit code to allow SARIF file generation
# This will handover control about PR rejection to the GitHub side
max-allowed-issues: 2147483647
# Upload the SARIF file generated in the previous step
- name: Upload SARIF results file
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
+4 -4
View File
@@ -20,7 +20,7 @@ jobs:
- name: "Set up JDK" - name: "Set up JDK"
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
java-version: '11' java-version: '21'
distribution: 'adopt' distribution: 'adopt'
cache: maven cache: maven
server-id: github server-id: github
@@ -47,7 +47,7 @@ jobs:
id: sitemap id: sitemap
uses: cicirello/generate-sitemap@v1 uses: cicirello/generate-sitemap@v1
with: with:
base-url-path: https://CarmJos.github.io/EasyConfiguration base-url-path: https://CarmJos.github.io/configured
path-to-root: docs path-to-root: docs
- name: "Output stats" - name: "Output stats"
@@ -72,7 +72,7 @@ jobs:
run: | run: |
cd docs cd docs
git init git init
git remote add origin git@github.com:CarmJos/EasyConfiguration.git git remote add origin git@github.com:CarmJos/configured.git
git checkout -b gh-pages git checkout -b gh-pages
git add -A git add -A
git commit -m "API Document generated." git commit -m "API Document generated."
@@ -91,7 +91,7 @@ jobs:
- name: "Set up JDK" - name: "Set up JDK"
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
java-version: '11' java-version: '21'
distribution: 'adopt' distribution: 'adopt'
cache: maven cache: maven
server-id: central server-id: central
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
- name: "Set up JDK" - name: "Set up JDK"
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
java-version: '11' java-version: '21'
distribution: 'adopt' distribution: 'adopt'
- name: "Package" - name: "Package"
run: mvn -B package --file pom.xml -Dgpg.skip run: mvn -B package --file pom.xml -Dgpg.skip
+2 -1
View File
@@ -1,3 +1,4 @@
.idea/ .idea/*
!.idea/icon.svg
**/target/ **/target/
**.iml **.iml
+36
View File
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

+1
View File
@@ -1,6 +1,7 @@
GNU LESSER GENERAL PUBLIC LICENSE GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007 Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.
+36 -35
View File
@@ -1,31 +1,30 @@
```text <div align=center>
____ _____ ____ __ _ <img src=".doc/images/banner.png" alt="Banner"/>
/ __/__ ____ __ __ / ___/__ ___ / _(_)__ ___ _________ _/ /_(_)__ ___
/ _// _ `(_-</ // / / /__/ _ \/ _ \/ _/ / _ `/ // / __/ _ `/ __/ / _ \/ _ \ [![version](https://img.shields.io/github/v/release/CarmJos/configured)](https://github.com/CarmJos/configured/releases)
/___/\_,_/___/\_, / \___/\___/_//_/_//_/\_, /\_,_/_/ \_,_/\__/_/\___/_//_/ [![License](https://img.shields.io/github/license/CarmJos/configured)](https://www.gnu.org/licenses/lgpl-3.0.html)
/___/ /___/ [![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)
README LANGUAGES [ [**English**](README.md) | [中文](README_CN.md) ] README LANGUAGES [ [**English**](README.md) | [中文](README_CN.md) ]
</div>
# EasyConfiguration # configured _(config framework)_
[![version](https://img.shields.io/github/v/release/CarmJos/EasyConfiguration)](https://github.com/CarmJos/EasyConfiguration/releases) <img src=".doc/images/logo-bg.svg" width="150px" alt="logo" align="right" style="float: right"/>
[![License](https://img.shields.io/github/license/CarmJos/EasyConfiguration)](https://www.gnu.org/licenses/lgpl-3.0.html)
[![workflow](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml)
[![CodeFactor](https://www.codefactor.io/repository/github/carmjos/easyconfiguration/badge)](https://www.codefactor.io/repository/github/carmjos/easyconfiguration)
![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/EasyConfiguration)
![](https://visitor-badge.glitch.me/badge?page_id=EasyConfiguration.readme)
**Easy _(to make)_ Configurations!** _**"Once set, Simple get."**_
A simple, easy-to-use and universal solution for managing configuration files. A simple, easy-to-use and universal solution for managing, loading, reading,
Enjoy the ease of use with customizable formats for loading, reading, and updating your configuration files. and updating configuration files.
Supported **JSON**, **YAML**, **Hocon**, **TOML**, **SQL**, **MongoDB**... and much more!
## Features & Advantages ## Features & Advantages
Supported [YAML](impl/yaml), [JSON](impl/json), [HOCON](impl/hocon) and [SQL](impl/sql) based configuration files Supported [YAML](providers/yaml), [JSON](providers/json), [HOCON](providers/hocon) and [SQL](providers/sql)
format. based configuration files format.
- Class-based mechanism for initializing, loading, retrieving, and updating configuration files, ensuring convenience - Class-based mechanism for initializing, loading, retrieving, and updating configuration files, ensuring convenience
and efficiency. and efficiency.
@@ -35,20 +34,22 @@ format.
## Development ## Development
For the latest JavaDoc release, [CLICK HERE](https://CarmJos.github.io/EasyConfiguration). For the latest JavaDoc release, [CLICK HERE](https://CarmJos.github.io/configured).
For a detailed development guide, [CLICK HERE](.doc/README.md). For a detailed development guide, [CLICK HERE](.doc/README.md).
### Code Samples ### Preview
To quickly demonstrate the applicability of the project, here are a few practical demonstrations: To quickly demonstrate the applicability of the project, here are a few practical demonstrations:
- [Database configuration.](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java) - [Database configuration.](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java)
- [Demonstration of all types of configuration instance classes.](demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java) - [Demonstration of configurations instance classes.](demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java)
Check out all code demonstrations [HERE](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java). Check out all code demonstrations [HERE](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java).
For more examples, see the [Development Guide](.doc/README.md). For more examples, see the [Development Guide](.doc/README.md).
```java ```java
@ConfigPath(root = true) @ConfigPath(root = true)
@HeaderComments("Configurations for sample") @HeaderComments("Configurations for sample")
public interface SampleConfig extends Configuration { public interface SampleConfig extends Configuration {
@@ -95,9 +96,9 @@ public class Sample {
// 2. Initialize the configuration classes or instances. // 2. Initialize the configuration classes or instances.
holder.initialize(SampleConfig.class); holder.initialize(SampleConfig.class);
// 3. Enjoy using the configuration! // 3. Enjoy using the configuration!
System.out.println("Enabled? -> " + SampleConfig.ENABLED.resolve()); System.out.println("Enabled? -> " + SampleConfig.ENABLED.resolve()); // true
SampleConfig.ENABLED.set(false); SampleConfig.ENABLED.set(false);
System.out.println("And now? -> " + SampleConfig.ENABLED.resolve()); System.out.println("And now? -> " + SampleConfig.ENABLED.resolve()); // false
// p.s. Changes not save so enable value will still be true in the next run. // p.s. Changes not save so enable value will still be true in the next run.
System.out.println("Your name is " + SampleConfig.INFO.NAME.resolve() + " (age=" + SampleConfig.INFO.AGE.resolve() + ")!"); System.out.println("Your name is " + SampleConfig.INFO.NAME.resolve() + " (age=" + SampleConfig.INFO.AGE.resolve() + ")!");
@@ -148,9 +149,9 @@ info:
<repository> <repository>
<!-- Using GitHub dependencies for real-time updates, configuration required (recommended). --> <!-- Using GitHub dependencies for real-time updates, configuration required (recommended). -->
<id>EasyConfiguration</id> <id>configured</id>
<name>GitHub Packages</name> <name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url> <url>https://maven.pkg.github.com/CarmJos/configured</url>
</repository> </repository>
</repositories> </repositories>
@@ -169,7 +170,7 @@ info:
<!-- Basic implementation part, requiring custom implementation of “Provider” and “Wrapper”. --> <!-- Basic implementation part, requiring custom implementation of “Provider” and “Wrapper”. -->
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -177,7 +178,7 @@ info:
<!-- YAML file-based implementation, compatible with all Java environments. --> <!-- YAML file-based implementation, compatible with all Java environments. -->
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-yaml</artifactId> <artifactId>configured-yaml</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -185,7 +186,7 @@ info:
<!-- JSON file-based implementation, compatible with all Java environments. --> <!-- JSON file-based implementation, compatible with all Java environments. -->
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-gson</artifactId> <artifactId>configured-gson</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -208,7 +209,7 @@ repositories {
mavenCentral() mavenCentral()
// Using GitHub dependencies for real-time updates, configuration required (recommended). // Using GitHub dependencies for real-time updates, configuration required (recommended).
maven { url 'https://maven.pkg.github.com/CarmJos/EasyConfiguration' } maven { url 'https://maven.pkg.github.com/CarmJos/configured' }
} }
``` ```
@@ -223,13 +224,13 @@ repositories {
dependencies { dependencies {
// Basic implementation part, requiring custom implementation of “Provider” and “Wrapper”. // Basic implementation part, requiring custom implementation of “Provider” and “Wrapper”.
api "cc.carm.lib:easyconfiguration-core:[LATEST RELEASE]" api "cc.carm.lib:configured-core:[LATEST RELEASE]"
// YAML file-based implementation, compatible with all Java environments. // YAML file-based implementation, compatible with all Java environments.
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]" api "cc.carm.lib:configured-yaml:[LATEST RELEASE]"
// JSON file-based implementation, compatible with all Java environments. // JSON file-based implementation, compatible with all Java environments.
api "cc.carm.lib:easyconfiguration-gson:[LATEST RELEASE]" api "cc.carm.lib:configured-gson:[LATEST RELEASE]"
} }
``` ```
@@ -240,7 +241,7 @@ dependencies {
### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos) ### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos)
EasyConfiguration for MineCraft! configured for MineCraft!
Easily manage configurations on MineCraft-related server platforms. Easily manage configurations on MineCraft-related server platforms.
Currently, it supports BungeeCord, Velocity, Bukkit (Spigot) servers, Currently, it supports BungeeCord, Velocity, Bukkit (Spigot) servers,
@@ -254,7 +255,7 @@ Thank you for supporting open-source projects!
Many thanks to Jetbrains for kindly providing a license for us to work on this and other open-source projects. Many thanks to Jetbrains for kindly providing a license for us to work on this and other open-source projects.
[![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/CarmJos/EasyConfiguration) [![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/CarmJos/configured)
Many thanks to [ArtformGames](https://github.com/ArtformGames) for their Many thanks to [ArtformGames](https://github.com/ArtformGames) for their
strong support and active contribution to this project! strong support and active contribution to this project!
+30 -32
View File
@@ -1,29 +1,27 @@
```text <div align=center>
____ _____ ____ __ _ <img src=".doc/images/banner.png" alt="Banner"/>
/ __/__ ____ __ __ / ___/__ ___ / _(_)__ ___ _________ _/ /_(_)__ ___
/ _// _ `(_-</ // / / /__/ _ \/ _ \/ _/ / _ `/ // / __/ _ `/ __/ / _ \/ _ \ [![version](https://img.shields.io/github/v/release/CarmJos/configured)](https://github.com/CarmJos/configured/releases)
/___/\_,_/___/\_, / \___/\___/_//_/_//_/\_, /\_,_/_/ \_,_/\__/_/\___/_//_/ [![License](https://img.shields.io/github/license/CarmJos/configured)](https://www.gnu.org/licenses/lgpl-3.0.html)
/___/ /___/ [![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)
README LANGUAGES [ [English](README.md) | [**中文**](README_CN.md) ] README LANGUAGES [ [English](README.md) | [**中文**](README_CN.md) ]
# EasyConfiguration </div>
[![version](https://img.shields.io/github/v/release/CarmJos/EasyConfiguration)](https://github.com/CarmJos/EasyConfiguration/releases) # configured _(配置文件框架)_
[![License](https://img.shields.io/github/license/CarmJos/EasyConfiguration)](https://www.gnu.org/licenses/lgpl-3.0.html)
[![workflow](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml)
[![CodeFactor](https://www.codefactor.io/repository/github/carmjos/easyconfiguration/badge)](https://www.codefactor.io/repository/github/carmjos/easyconfiguration)
![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/EasyConfiguration)
![](https://visitor-badge.glitch.me/badge?page_id=EasyConfiguration.readme)
**轻松(做)配置!** <img src=".doc/images/logo-bg.svg" width="150px" alt="logo" align="right" style="float: right"/>
**一次配置,轻松读取!**
一款简单便捷的通用配置文件加载、读取与更新工具,可自定义配置的格式。 一款简单便捷的通用配置文件加载、读取与更新工具,可自定义配置的格式。
## 特性 & 优势 ## 特性 & 优势
支持 [YAML](impl/yaml), [JSON](impl/json), [HOCON](impl/hocon) 和 [SQL](impl/sql) 等多种配置文件格式。 支持 [YAML](providers/yaml), [JSON](providers/gson), [HOCON](providers/hocon) 和 [SQL](providers/sql) 等多种配置文件格式。
- 基于类的配置文件初始化、加载、获取与更新机制,方便快捷。 - 基于类的配置文件初始化、加载、获取与更新机制,方便快捷。
- 支持复杂配置的手动序列化、反序列化。 - 支持复杂配置的手动序列化、反序列化。
@@ -33,7 +31,7 @@ README LANGUAGES [ [English](README.md) | [**中文**](README_CN.md) ]
## 开发 ## 开发
详细开发介绍请 [点击这里](.doc/README.md) , JavaDoc(最新Release) 详细开发介绍请 [点击这里](.doc/README.md) , JavaDoc(最新Release)
请 [点击这里](https://CarmJos.github.io/EasyConfiguration) 。 请 [点击这里](https://CarmJos.github.io/configured) 。
### 示例代码 ### 示例代码
@@ -142,9 +140,9 @@ info:
<repository> <repository>
<!--采用github依赖库,实时更新,但需要配置 (推荐) --> <!--采用github依赖库,实时更新,但需要配置 (推荐) -->
<id>EasyConfiguration</id> <id>configured</id>
<name>GitHub Packages</name> <name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url> <url>https://maven.pkg.github.com/CarmJos/configured</url>
</repository> </repository>
<repository> <repository>
@@ -170,7 +168,7 @@ info:
<!--基础实现部分,需要自行实现“Provider”与“Wrapper”。--> <!--基础实现部分,需要自行实现“Provider”与“Wrapper”。-->
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -178,7 +176,7 @@ info:
<!--基于YAML文件的实现版本,可用于全部Java环境。--> <!--基于YAML文件的实现版本,可用于全部Java环境。-->
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-yaml</artifactId> <artifactId>configured-yaml</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -187,21 +185,21 @@ info:
<!--需要注意的是,JSON不支持文件注释。--> <!--需要注意的是,JSON不支持文件注释。-->
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-gson</artifactId> <artifactId>configured-gson</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-hocon</artifactId> <artifactId>configured-hocon</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-sql</artifactId> <artifactId>configured-sql</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -224,7 +222,7 @@ repositories {
mavenCentral() mavenCentral()
// 采用github依赖库,实时更新,但需要配置 (推荐) // 采用github依赖库,实时更新,但需要配置 (推荐)
maven { url 'https://maven.pkg.github.com/CarmJos/EasyConfiguration' } maven { url 'https://maven.pkg.github.com/CarmJos/configured' }
// 采用我的私人依赖库,简单方便,但可能因为变故而无法使用 // 采用我的私人依赖库,简单方便,但可能因为变故而无法使用
maven { url 'https://repo.carm.cc/repository/maven-public/' } maven { url 'https://repo.carm.cc/repository/maven-public/' }
@@ -241,18 +239,18 @@ repositories {
dependencies { dependencies {
//基础实现部分,需要自行实现“Provider”与“Wrapper”。 //基础实现部分,需要自行实现“Provider”与“Wrapper”。
api "cc.carm.lib:easyconfiguration-core:[LATEST RELEASE]" api "cc.carm.lib:configured-core:[LATEST RELEASE]"
//基于YAML文件的实现版本,可用于全部Java环境。 //基于YAML文件的实现版本,可用于全部Java环境。
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]" api "cc.carm.lib:configured-yaml:[LATEST RELEASE]"
//基于JSON文件的实现版本,可用于全部Java环境。 //基于JSON文件的实现版本,可用于全部Java环境。
//需要注意的是,JSON不支持文件注释。 //需要注意的是,JSON不支持文件注释。
api "cc.carm.lib:easyconfiguration-gson:[LATEST RELEASE]" api "cc.carm.lib:configured-gson:[LATEST RELEASE]"
api "cc.carm.lib:easyconfiguration-hocon:[LATEST RELEASE]" api "cc.carm.lib:configured-hocon:[LATEST RELEASE]"
api "cc.carm.lib:easyconfiguration-sql:[LATEST RELEASE]" api "cc.carm.lib:configured-sql:[LATEST RELEASE]"
} }
``` ```
@@ -263,7 +261,7 @@ dependencies {
### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos ) ### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos )
EasyConfiguration for MineCraft! configured for MineCraft!
开始在 MineCraft 相关服务器平台上轻松(做)配置吧! 开始在 MineCraft 相关服务器平台上轻松(做)配置吧!
目前支持 BungeeCord, Bukkit(Spigot) 服务端,后续将支持更多平台。 目前支持 BungeeCord, Bukkit(Spigot) 服务端,后续将支持更多平台。
@@ -276,7 +274,7 @@ EasyConfiguration for MineCraft!
万分感谢 Jetbrains 为我们提供了从事此项目和其他开源项目的许可! 万分感谢 Jetbrains 为我们提供了从事此项目和其他开源项目的许可!
[![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/CarmJos/EasyConfiguration) [![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/CarmJos/configured)
万分感谢来自 [ArtformGames](https://github.com/ArtformGames) 对本项目的大力支持与积极贡献! 万分感谢来自 [ArtformGames](https://github.com/ArtformGames) 对本项目的大力支持与积极贡献!
+3 -3
View File
@@ -3,9 +3,9 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>4.0.11</version> <version>4.1.7</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<properties> <properties>
@@ -15,7 +15,7 @@
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties> </properties>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<build> <build>
@@ -4,4 +4,5 @@ package cc.carm.lib.configuration;
* The root interface of the configuration file interfaces, * The root interface of the configuration file interfaces,
* which is used to label a class as a configuration. * which is used to label a class as a configuration.
*/ */
public interface Configuration { } public interface Configuration {
}
@@ -15,6 +15,7 @@ public class ValueAdapter<TYPE>
implements ValueSerializer<TYPE>, ValueParser<TYPE> { implements ValueSerializer<TYPE>, ValueParser<TYPE> {
protected final @NotNull ValueType<TYPE> type; protected final @NotNull ValueType<TYPE> type;
protected @Nullable ValueSerializer<TYPE> serializer; protected @Nullable ValueSerializer<TYPE> serializer;
protected @Nullable ValueParser<TYPE> deserializer; protected @Nullable ValueParser<TYPE> deserializer;
@@ -53,13 +54,21 @@ public class ValueAdapter<TYPE>
} }
@Override @Override
public Object serialize(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<? super TYPE> type, @NotNull TYPE value) throws Exception { public @Nullable Object serialize(
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type,
@NotNull TYPE value
) throws Exception {
if (serializer == null) throw new UnsupportedOperationException("Serializer is not supported"); if (serializer == null) throw new UnsupportedOperationException("Serializer is not supported");
return serializer.serialize(holder, type, value); return serializer.serialize(holder, type, value);
} }
@Override @Override
public TYPE parse(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<? super TYPE> type, @NotNull Object value) throws Exception { public @Nullable TYPE parse(
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type,
@NotNull Object value
) throws Exception {
if (deserializer == null) throw new UnsupportedOperationException("Deserializer is not supported"); if (deserializer == null) throw new UnsupportedOperationException("Deserializer is not supported");
return deserializer.parse(holder, type, value); return deserializer.parse(holder, type, value);
} }
@@ -2,13 +2,13 @@ package cc.carm.lib.configuration.adapter;
import cc.carm.lib.configuration.function.DataFunction; import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.Contract; import cc.carm.lib.configuration.source.section.ConfigureSection;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Arrays; import java.lang.reflect.ParameterizedType;
import java.util.HashSet; import java.lang.reflect.Type;
import java.util.Set; import java.util.*;
public class ValueAdapterRegistry { public class ValueAdapterRegistry {
@@ -61,7 +61,9 @@ public class ValueAdapterRegistry {
} }
} }
public <T> void register(@NotNull ValueType<T> type, @Nullable ValueSerializer<T> serializer, @Nullable ValueParser<T> deserializer) { public <T> void register(@NotNull ValueType<T> type,
@Nullable ValueSerializer<T> serializer,
@Nullable ValueParser<T> deserializer) {
if (serializer == null && deserializer == null) return; if (serializer == null && deserializer == null) return;
ValueAdapter<T> existing = adapterOf(type); ValueAdapter<T> existing = adapterOf(type);
if (existing != null) { if (existing != null) {
@@ -82,7 +84,9 @@ public class ValueAdapterRegistry {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> @Nullable ValueAdapter<T> adapterOf(@NotNull ValueType<T> type) { public <T> @Nullable ValueAdapter<T> adapterOf(@NotNull ValueType<T> type) {
ValueAdapter<?> matched = adapters.stream().filter(adapter -> adapter.type().equals(type)).findFirst().orElse(null); ValueAdapter<?> matched = adapters.stream()
.filter(adapter -> adapter.type().equals(type))
.findFirst().orElse(null);
if (matched != null) return (ValueAdapter<T>) matched; if (matched != null) return (ValueAdapter<T>) matched;
// If no adapter found, try to find the adapter for the super type // If no adapter found, try to find the adapter for the super type
@@ -99,28 +103,112 @@ public class ValueAdapterRegistry {
return adapterOf(ValueType.of(type)); return adapterOf(ValueType.of(type));
} }
@Contract("_,_,null -> null")
public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull Class<T> type, @Nullable Object source) throws Exception { public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull Class<T> type, @Nullable Object source) throws Exception {
return deserialize(holder, ValueType.of(type), source); return deserialize(holder, ValueType.of(type), source);
} }
@Contract("_,_,null -> null")
public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> type, @Nullable Object source) throws Exception { public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> type, @Nullable Object source) throws Exception {
if (source == null) return null; // Null check if (source == null) return null; // Null check
if (type.isInstance(source)) return type.cast(source); // Not required to deserialize if (!(type.getType() instanceof ParameterizedType) && type.isInstance(source)) {
ValueAdapter<T> adapter = adapterOf(type); return type.cast(source); // Not required to deserialize
if (adapter == null) throw new RuntimeException("No adapter for type " + type);
return adapter.parse(holder, type, source);
} }
@Contract("_,null -> null") ValueAdapter<T> adapter = adapterOf(type); // Try to find an existed adapter for the type
if (adapter != null) {
return adapter.parse(holder, type, source);
} // If no adapter found, we will try to handle the type manually
if (type.getRawType().isArray()) { // For arrays.
List<?> list = deserializeList(holder, type, source);
Object[] array = (Object[]) java.lang.reflect.Array.newInstance(type.getRawType().getComponentType(), list.size());
for (int i = 0; i < list.size(); i++) {
array[i] = deserialize(holder, type.getRawType().getComponentType(), list.get(i));
}
return type.cast(array);
} else if (type.getType() instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type.getType();
Type rawType = pt.getRawType();
Type[] typeArgs = pt.getActualTypeArguments();
if (rawType == List.class || rawType == Collection.class || rawType == ArrayList.class) {
return type.cast(new ArrayList<>(deserializeList(holder, ValueType.of(typeArgs[0]), source)));
} else if (rawType == Set.class || rawType == HashSet.class) {
return type.cast(new HashSet<>(deserializeList(holder, ValueType.of(typeArgs[0]), source)));
} else if (rawType == Map.class || rawType == LinkedHashMap.class) {
Map<?, ?> map;
if (source instanceof Map<?, ?>) {
map = (Map<?, ?>) source;
} else if (source instanceof ConfigureSection) {
map = ((ConfigureSection) source).asMap();
} else {
throw new IllegalArgumentException("Cannot deserialize to Map from " + source.getClass());
}
Map<Object, Object> resultMap = new LinkedHashMap<>(map.size());
for (Map.Entry<?, ?> entry : map.entrySet()) {
Object key = deserialize(holder, ValueType.of(typeArgs[0]), entry.getKey());
Object value = deserialize(holder, ValueType.of(typeArgs[1]), entry.getValue());
resultMap.put(key, value);
}
return type.cast(resultMap);
}
}
throw new RuntimeException("No adapter for type " + type);
}
@Nullable
public <T> Object serialize(@NotNull ConfigurationHolder<?> holder, @Nullable T value) throws Exception { public <T> Object serialize(@NotNull ConfigurationHolder<?> holder, @Nullable T value) throws Exception {
if (value == null) return null; // Null check if (value == null) return null; // Null check
ValueType<T> type = ValueType.of(value); ValueType<T> type = ValueType.of(value);
ValueAdapter<T> adapter = adapterOf(type); ValueAdapter<T> adapter = adapterOf(type);
if (adapter == null) return value; // No adapters, try to return the original value if (adapter != null) return adapter.serialize(holder, type, value);
return adapter.serialize(holder, type, value);
if (value.getClass().isArray()) {
Object[] array = (Object[]) value;
List<Object> serializedList = new ArrayList<>(array.length);
for (Object item : array) {
serializedList.add(serialize(holder, item));
}
return serializedList;
} else if (value instanceof Collection<?>) {
Collection<?> collection = (Collection<?>) value;
List<Object> serializedList = new ArrayList<>(collection.size());
for (Object item : collection) {
serializedList.add(serialize(holder, item));
}
return serializedList;
} else if (value instanceof Map<?, ?>) {
Map<?, ?> map = (Map<?, ?>) value;
Map<Object, Object> serializedMap = new LinkedHashMap<>(map.size());
for (Map.Entry<?, ?> entry : map.entrySet()) {
Object key = serialize(holder, entry.getKey());
Object val = serialize(holder, entry.getValue());
serializedMap.put(key, val);
}
return serializedMap;
} }
return value; // No adapters, and cannot handle, try to return the original value
}
protected <T> List<T> deserializeList(@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<T> type, @Nullable Object source) throws Exception {
if (source == null) return Collections.emptyList(); // Null check
if (source instanceof List<?>) {
List<?> list = (List<?>) source;
List<T> result = new ArrayList<>(list.size());
for (Object item : list) {
T deserializedItem = deserialize(holder, type, item);
if (deserializedItem != null) {
result.add(deserializedItem);
}
}
return result;
} else { // Maybe singleton? Let's try to deserialize it as a single element list
T deserializedItem = deserialize(holder, type, source);
if (deserializedItem != null) {
return Collections.singletonList(deserializedItem);
} else return Collections.emptyList();
}
}
} }
@@ -2,6 +2,7 @@ package cc.carm.lib.configuration.adapter;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* Value deserializer, convert base data to target value. * Value deserializer, convert base data to target value.
@@ -11,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
@FunctionalInterface @FunctionalInterface
public interface ValueParser<TYPE> { public interface ValueParser<TYPE> {
TYPE parse( @Nullable TYPE parse(
@NotNull ConfigurationHolder<?> holder, @NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type, @NotNull Object data @NotNull ValueType<? super TYPE> type, @NotNull Object data
) throws Exception; ) throws Exception;
@@ -2,6 +2,7 @@ package cc.carm.lib.configuration.adapter;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* Value serializer, convert target value to base data. * Value serializer, convert target value to base data.
@@ -11,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
@FunctionalInterface @FunctionalInterface
public interface ValueSerializer<TYPE> { public interface ValueSerializer<TYPE> {
Object serialize( @Nullable Object serialize(
@NotNull ConfigurationHolder<?> holder, @NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type, @NotNull TYPE value @NotNull ValueType<? super TYPE> type, @NotNull TYPE value
) throws Exception; ) throws Exception;
@@ -1,5 +1,6 @@
package cc.carm.lib.configuration.adapter; package cc.carm.lib.configuration.adapter;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
@@ -9,7 +10,13 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
/** /**
* Used to get the generic type. * {@link ValueType} used to get the generic type of the value,
* It can be used to check if an object is an instance of a specific type,
* and to cast objects to the correct type.
* <p>
* Java's type system is not capable of retaining generic type information at runtime.
* This class is used to represent a type with its generic parameters.
* </p>
*/ */
public abstract class ValueType<T> { public abstract class ValueType<T> {
@@ -44,7 +51,7 @@ public abstract class ValueType<T> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> ValueType<T> of(final Type type) { public static <T> ValueType<T> of(final Type type) {
if (type == null) throw new NullPointerException("Type cannot be null"); if (type == null) throw new NullPointerException("Type cannot be null");
if (type instanceof Class<?>) { // Try handle primitive types if (type instanceof Class<?>) { // Try to fast handle primitive types
Class<?> clazz = (Class<?>) type; Class<?> clazz = (Class<?>) type;
for (ValueType<?> valueType : PRIMITIVE_TYPES) { for (ValueType<?> valueType : PRIMITIVE_TYPES) {
if (valueType.getRawType() == clazz) { if (valueType.getRawType() == clazz) {
@@ -56,10 +63,26 @@ public abstract class ValueType<T> {
}; };
} }
public static <T> ValueType<T> of(final Class<T> clazz) { public static <T> ValueType<T> of(final @NotNull Class<T> clazz) {
return of((Type) clazz); return of((Type) clazz);
} }
public static <T> ValueType<List<T>> ofList(final @NotNull Class<T> paramType) {
return of(List.class, paramType);
}
public static <T> ValueType<List<T>> ofList(final @NotNull ValueType<T> paramType) {
return of(List.class, paramType.getType());
}
public static <K, V> ValueType<Map<K, V>> ofMap(final @NotNull Class<K> keyType, final @NotNull Class<V> valueType) {
return of(Map.class, keyType, valueType);
}
public static <K, V> ValueType<Map<K, V>> ofMap(final @NotNull ValueType<K> keyType, final @NotNull ValueType<V> valueType) {
return of(Map.class, keyType.getType(), valueType.getType());
}
/** /**
* Get the generic type of the complex type. * Get the generic type of the complex type.
* *
@@ -88,6 +111,7 @@ public abstract class ValueType<T> {
return of(parameterizedType); return of(parameterizedType);
} }
@ApiStatus.Internal
private static <T> ValueType<T> ofPrimitiveType(Class<T> clazz) { private static <T> ValueType<T> ofPrimitiveType(Class<T> clazz) {
return new ValueType<T>(clazz) { return new ValueType<T>(clazz) {
}; };
@@ -107,40 +131,65 @@ public abstract class ValueType<T> {
return type; return type;
} }
/**
* Checks if this ValueType is a subtype of the given Class.
*
* @param target The target Class to check against
* @return true if this ValueType is a subtype of the target Class, false otherwise
*/
public boolean isSubtypeOf(Class<?> target) { public boolean isSubtypeOf(Class<?> target) {
Class<?> rawType = getRawType(); Class<?> rawType = getRawType();
return target.isAssignableFrom(rawType); return target.isAssignableFrom(rawType);
} }
/**
* Checks if this ValueType is a subtype of the given ValueType.
*
* @param target The target ValueType to check against
* @return true if this ValueType is a subtype of the target, false otherwise
*/
public boolean isSubtypeOf(ValueType<?> target) { public boolean isSubtypeOf(ValueType<?> target) {
return target.isSubtypeOf(getRawType()); return target.isSubtypeOf(getRawType());
} }
/**
* Checks if the given object is an instance of the type represented by this ValueType.
*
* @param obj The object to check
* @return true if the object is an instance of the type, false otherwise
*/
public boolean isInstance(Object obj) { public boolean isInstance(Object obj) {
return obj != null && getRawType().isInstance(obj); return obj != null && getRawType().isInstance(obj);
} }
/** /**
* 提取当前 ValueType 的原始类型(Class 对象)。 * Extracts the raw type from the generic type.
* *
* @return 对应的 Class 对象 * @return The raw type of the generic type
* @throws IllegalStateException 如果无法提取出原始类型 * @throws IllegalStateException if the type is not a Class or ParameterizedType
*/ */
public Class<?> getRawType() { @SuppressWarnings("unchecked")
public Class<T> getRawType() {
if (type instanceof Class<?>) { if (type instanceof Class<?>) {
return (Class<?>) type; return (Class<T>) type;
} }
if (type instanceof ParameterizedType) { if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type; ParameterizedType pt = (ParameterizedType) type;
Type raw = pt.getRawType(); Type raw = pt.getRawType();
if (raw instanceof Class<?>) { if (raw instanceof Class<?>) {
return (Class<?>) raw; return (Class<T>) raw;
} }
} }
throw new IllegalStateException("Unsupported type: " + type); throw new IllegalStateException("Unsupported type: " + type);
} }
/**
* Casts the object to the type represented by this ValueType.
*
* @param obj The object to cast
* @return The object cast to the type represented by this ValueType
*/
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public T cast(Object obj) { public T cast(Object obj) {
if (!isInstance(obj)) { if (!isInstance(obj)) {
@@ -149,6 +198,12 @@ public abstract class ValueType<T> {
return (T) obj; return (T) obj;
} }
/**
* Returns a string representation of the type.
* Like "{@code java.util.List<java.lang.String>}" or "java.lang.Integer".
*
* @return String representation of the type
*/
@Override @Override
public String toString() { public String toString() {
if (type instanceof Class<?>) { if (type instanceof Class<?>) {
@@ -5,6 +5,8 @@ import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.source.section.ConfigureSection; import cc.carm.lib.configuration.source.section.ConfigureSection;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.UUID;
import static cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapter.*; import static cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapter.*;
public interface StandardAdapters { public interface StandardAdapters {
@@ -17,6 +19,12 @@ public interface StandardAdapters {
@NotNull ValueAdapter<Enum<?>> ENUMS = PrimitiveAdapter.ofEnum(); @NotNull ValueAdapter<Enum<?>> ENUMS = PrimitiveAdapter.ofEnum();
@NotNull ValueAdapter<UUID> UUID = new ValueAdapter<>(
ValueType.of(UUID.class),
(provider, type, value) -> value.toString(),
(provider, type, value) -> java.util.UUID.fromString(value.toString())
);
@NotNull ValueAdapter<ConfigureSection> SECTIONS = new ValueAdapter<>( @NotNull ValueAdapter<ConfigureSection> SECTIONS = new ValueAdapter<>(
ValueType.of(ConfigureSection.class), ValueType.of(ConfigureSection.class),
(provider, type, value) -> value, (provider, type, value) -> value,
@@ -1,6 +1,8 @@
package cc.carm.lib.configuration.builder; package cc.carm.lib.configuration.builder;
import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.function.DataValidator;
import cc.carm.lib.configuration.function.ValueValidator;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder; import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
@@ -11,11 +13,12 @@ import org.jetbrains.annotations.Nullable;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier; import java.util.function.Supplier;
public abstract class AbstractConfigBuilder< public abstract class AbstractConfigBuilder<
TYPE, RESULT extends ConfigValue<TYPE>, HOLDER extends ConfigurationHolder<?>, TYPE, UNIT, RESULT extends ConfigValue<TYPE, UNIT>, HOLDER extends ConfigurationHolder<?>,
SELF extends AbstractConfigBuilder<TYPE, RESULT, HOLDER, SELF> SELF extends AbstractConfigBuilder<TYPE, UNIT, RESULT, HOLDER, SELF>
> { > {
protected final Class<? super HOLDER> providerClass; protected final Class<? super HOLDER> providerClass;
@@ -24,6 +27,7 @@ public abstract class AbstractConfigBuilder<
protected @Nullable HOLDER holder; protected @Nullable HOLDER holder;
protected @Nullable String path; protected @Nullable String path;
protected @NotNull ValueValidator<UNIT> valueValidator = ValueValidator.none();
protected @NotNull Supplier<@Nullable TYPE> defaultValueSupplier = () -> null; protected @NotNull Supplier<@Nullable TYPE> defaultValueSupplier = () -> null;
protected @NotNull BiConsumer<ConfigurationHolder<?>, String> initializer = (h, p) -> { protected @NotNull BiConsumer<ConfigurationHolder<?>, String> initializer = (h, p) -> {
}; };
@@ -37,54 +41,121 @@ public abstract class AbstractConfigBuilder<
return type; return type;
} }
protected abstract @NotNull SELF self(); protected abstract SELF self();
public abstract @NotNull RESULT build(); public abstract @NotNull RESULT build();
public @NotNull SELF holder(@Nullable HOLDER holder) { public SELF holder(@Nullable HOLDER holder) {
this.holder = holder; this.holder = holder;
return self(); return self();
} }
public @NotNull SELF path(@Nullable String path) { public SELF path(@Nullable String path) {
this.path = path; this.path = path;
return self(); return self();
} }
public @NotNull SELF initializer(@NotNull BiConsumer<ConfigurationHolder<?>, String> initializer) { /**
* Set the {@link ValueValidator} for the value.
*
* @param validator The validator to set.
* @return this builder
*/
public SELF validator(@NotNull ValueValidator<UNIT> validator) {
this.valueValidator = validator;
return self();
}
/**
* Set the {@link DataValidator} for the value.
*
* @param validator The validator to set.
* @return this builder
*/
public SELF validator(@NotNull DataValidator<? super UNIT> validator) {
return validator((h, value) -> validator.validate(value));
}
/**
* Validate the value with the specified condition.
*
* @param validator The validator to append.
* @return this builder
*/
public SELF validate(@NotNull ValueValidator<? super UNIT> validator) {
return validator(this.valueValidator.and(validator));
}
/**
* Validate the value with the specified condition.
*
* @param validator The validator to append.
* @return this builder
*/
public SELF validate(@NotNull DataValidator<? super UNIT> validator) {
return validate((h, value) -> validator.validate(value));
}
/**
* Validate the value with the specified condition.
*
* @param condition The condition to check, if the condition is false, an exception will be thrown.
* @param exception The exception to throw if the condition is false.
* @return this builder
*/
public SELF validate(@NotNull Predicate<? super UNIT> condition, @NotNull Exception exception) {
return validate((h, value) -> {
if (!condition.test(value)) throw exception;
});
}
/**
* Validate the value with the specified condition.
*
* @param condition The condition to check, if the condition is false, an exception will be thrown.
* @param msg The message to throw if the condition is false.
* @return this builder
*/
public SELF validate(@NotNull Predicate<? super UNIT> condition, @NotNull String msg) {
return validate((h, value) -> {
if (!condition.test(value)) throw new IllegalArgumentException(msg);
});
}
public SELF initializer(@NotNull BiConsumer<ConfigurationHolder<?>, String> initializer) {
this.initializer = initializer; this.initializer = initializer;
return self(); return self();
} }
public @NotNull SELF append(@NotNull BiConsumer<ConfigurationHolder<?>, String> initializer) { public SELF append(@NotNull BiConsumer<ConfigurationHolder<?>, String> initializer) {
return initializer(initializer.andThen(initializer)); return initializer(initializer.andThen(initializer));
} }
public @NotNull SELF append(@NotNull Consumer<ConfigurationHolder<?>> initializer) { public SELF append(@NotNull Consumer<ConfigurationHolder<?>> initializer) {
return append((provider, valuePath) -> initializer.accept(provider)); return append((provider, valuePath) -> initializer.accept(provider));
} }
public @NotNull SELF defaults(@Nullable TYPE defaultValue) { public SELF defaults(@Nullable TYPE defaultValue) {
return defaults(() -> defaultValue); return defaults(() -> defaultValue);
} }
public @NotNull SELF defaults(@NotNull Supplier<@Nullable TYPE> supplier) { public SELF defaults(@NotNull Supplier<@Nullable TYPE> supplier) {
this.defaultValueSupplier = supplier; this.defaultValueSupplier = supplier;
return self(); return self();
} }
public <M> @NotNull SELF meta(@NotNull Consumer<@NotNull ConfigurationMetaHolder> metaConsumer) { public SELF meta(@NotNull Consumer<@NotNull ConfigurationMetaHolder> metaConsumer) {
return append((h, p) -> metaConsumer.accept(h.metadata(p))); return append((h, p) -> metaConsumer.accept(h.metadata(p)));
} }
public <M> @NotNull SELF meta(@NotNull ConfigurationMetadata<M> type, @Nullable M value) { public <M> SELF meta(@NotNull ConfigurationMetadata<M> type, @Nullable M value) {
return meta(h -> h.set(type, value)); return meta(h -> h.set(type, value));
} }
protected @NotNull ValueManifest<TYPE> buildManifest() { protected @NotNull ValueManifest<TYPE, UNIT> buildManifest() {
return new ValueManifest<>( return new ValueManifest<>(
type(), this.defaultValueSupplier, this.initializer, type(), this.defaultValueSupplier, this.valueValidator,
this.holder, this.path this.initializer, this.holder, this.path
); );
} }
@@ -4,8 +4,11 @@ import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.ConfigValue;
public abstract class CommonConfigBuilder<TYPE, RESULT extends ConfigValue<TYPE>, SELF extends CommonConfigBuilder<TYPE, RESULT, SELF>> public abstract class CommonConfigBuilder<
extends AbstractConfigBuilder<TYPE, RESULT, ConfigurationHolder<?>, SELF> { TYPE, UNIT,
RESULT extends ConfigValue<TYPE, UNIT>,
SELF extends CommonConfigBuilder<TYPE, UNIT, RESULT, SELF>
> extends AbstractConfigBuilder<TYPE, UNIT, RESULT, ConfigurationHolder<?>, SELF> {
protected CommonConfigBuilder(ValueType<TYPE> type) { protected CommonConfigBuilder(ValueType<TYPE> type) {
super(ConfigurationHolder.class, type); super(ConfigurationHolder.class, type);
@@ -4,7 +4,7 @@ import cc.carm.lib.configuration.adapter.ValueAdapter;
import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.CommonConfigBuilder; import cc.carm.lib.configuration.builder.CommonConfigBuilder;
import cc.carm.lib.configuration.function.DataFunction; import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.function.ValueConsumer; import cc.carm.lib.configuration.function.ValueComposer;
import cc.carm.lib.configuration.function.ValueHandler; import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.source.section.ConfigureSection; import cc.carm.lib.configuration.source.section.ConfigureSection;
import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.ConfigValue;
@@ -14,47 +14,45 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
public abstract class AbstractSectionBuilder< public abstract class AbstractSectionBuilder<
TYPE, PARAM, TYPE, UNIT,
RESULT extends ConfigValue<TYPE>, RESULT extends ConfigValue<TYPE, UNIT>,
SELF extends AbstractSectionBuilder<TYPE, PARAM, RESULT, SELF> SELF extends AbstractSectionBuilder<TYPE, UNIT, RESULT, SELF>
> extends CommonConfigBuilder<TYPE, RESULT, SELF> { > extends CommonConfigBuilder<TYPE, UNIT, RESULT, SELF> {
protected final @NotNull ValueType<PARAM> paramType; protected final @NotNull ValueType<UNIT> paramType;
protected @NotNull ValueHandler<ConfigureSection, PARAM> parser; protected @NotNull ValueHandler<ConfigureSection, UNIT> parser;
protected @NotNull ValueHandler<PARAM, ? extends Map<String, Object>> serializer; protected @NotNull ValueHandler<UNIT, ? extends Map<String, Object>> serializer;
protected AbstractSectionBuilder(@NotNull ValueType<TYPE> type, @NotNull ValueType<PARAM> paramType, protected AbstractSectionBuilder(@NotNull ValueType<TYPE> type, @NotNull ValueType<UNIT> paramType,
@NotNull ValueHandler<ConfigureSection, PARAM> parser, @NotNull ValueHandler<ConfigureSection, UNIT> parser,
@NotNull ValueHandler<PARAM, ? extends Map<String, Object>> serializer) { @NotNull ValueHandler<UNIT, ? extends Map<String, Object>> serializer) {
super(type); super(type);
this.paramType = paramType; this.paramType = paramType;
this.parser = parser; this.parser = parser;
this.serializer = serializer; this.serializer = serializer;
} }
public @NotNull SELF parse(@NotNull DataFunction<ConfigureSection, PARAM> valueParser) { public @NotNull SELF parse(@NotNull DataFunction<ConfigureSection, UNIT> valueParser) {
return parse((p, section) -> valueParser.handle(section)); return parse((p, section) -> valueParser.handle(section));
} }
public @NotNull SELF parse(@NotNull ValueHandler<ConfigureSection, PARAM> valueParser) { public @NotNull SELF parse(@NotNull ValueHandler<ConfigureSection, UNIT> valueParser) {
this.parser = valueParser; this.parser = valueParser;
return self(); return self();
} }
public @NotNull SELF serialize(@NotNull ValueHandler<PARAM, ? extends Map<String, Object>> serializer) { public @NotNull SELF serialize(@NotNull ValueHandler<UNIT, ? extends Map<String, Object>> serializer) {
this.serializer = serializer; this.serializer = serializer;
return self(); return self();
} }
public @NotNull SELF serialize(@NotNull DataFunction<PARAM, ? extends Map<String, Object>> serializer) { public @NotNull SELF serialize(@NotNull DataFunction<UNIT, ? extends Map<String, Object>> serializer) {
return serialize((p, value) -> { return serialize((p, value) -> serializer.handle(value));
return serializer.handle(value);
});
} }
public @NotNull SELF serialize(@NotNull ValueConsumer<Map<String, Object>, PARAM> serializer) { public @NotNull SELF serialize(@NotNull ValueComposer<Map<String, Object>, UNIT> serializer) {
return serialize((h, value) -> { return serialize((h, value) -> {
Map<String, Object> map = new LinkedHashMap<>(); Map<String, Object> map = new LinkedHashMap<>();
serializer.accept(h, map, value); serializer.accept(h, map, value);
@@ -62,7 +60,7 @@ public abstract class AbstractSectionBuilder<
}); });
} }
protected ValueAdapter<PARAM> buildAdapter() { protected ValueAdapter<UNIT> buildAdapter() {
return new ValueAdapter<>(this.paramType) return new ValueAdapter<>(this.paramType)
.parser((p, type, data) -> { .parser((p, type, data) -> {
ConfigureSection section = p.deserialize(ConfigureSection.class, data); ConfigureSection section = p.deserialize(ConfigureSection.class, data);
@@ -9,19 +9,19 @@ import cc.carm.lib.configuration.value.ConfigValue;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public abstract class AbstractSourceBuilder< public abstract class AbstractSourceBuilder<
V, SOURCE, PARAM, RESULT extends ConfigValue<V>, V, SOURCE, UNIT, RESULT extends ConfigValue<V, UNIT>,
SELF extends AbstractSourceBuilder<V, SOURCE, PARAM, RESULT, SELF> SELF extends AbstractSourceBuilder<V, SOURCE, UNIT, RESULT, SELF>
> extends CommonConfigBuilder<V, RESULT, SELF> { > extends CommonConfigBuilder<V, UNIT, RESULT, SELF> {
protected final @NotNull ValueType<SOURCE> sourceType; protected final @NotNull ValueType<SOURCE> sourceType;
protected final @NotNull ValueType<PARAM> paramType; protected final @NotNull ValueType<UNIT> paramType;
protected @NotNull ValueHandler<SOURCE, PARAM> valueParser; protected @NotNull ValueHandler<SOURCE, UNIT> valueParser;
protected @NotNull ValueHandler<PARAM, SOURCE> valueSerializer; protected @NotNull ValueHandler<UNIT, SOURCE> valueSerializer;
protected AbstractSourceBuilder(@NotNull ValueType<V> type, protected AbstractSourceBuilder(@NotNull ValueType<V> type,
@NotNull ValueType<SOURCE> sourceType, @NotNull ValueType<PARAM> paramType, @NotNull ValueType<SOURCE> sourceType, @NotNull ValueType<UNIT> paramType,
@NotNull ValueHandler<SOURCE, PARAM> parser, @NotNull ValueHandler<SOURCE, UNIT> parser,
@NotNull ValueHandler<PARAM, SOURCE> serializer) { @NotNull ValueHandler<UNIT, SOURCE> serializer) {
super(type); super(type);
this.sourceType = sourceType; this.sourceType = sourceType;
this.paramType = paramType; this.paramType = paramType;
@@ -29,25 +29,25 @@ public abstract class AbstractSourceBuilder<
this.valueSerializer = serializer; this.valueSerializer = serializer;
} }
public @NotNull SELF parse(@NotNull DataFunction<SOURCE, PARAM> parser) { public @NotNull SELF parse(@NotNull DataFunction<SOURCE, UNIT> parser) {
return parse((p, source) -> parser.handle(source)); return parse((p, source) -> parser.handle(source));
} }
public @NotNull SELF parse(@NotNull ValueHandler<SOURCE, PARAM> parser) { public @NotNull SELF parse(@NotNull ValueHandler<SOURCE, UNIT> parser) {
this.valueParser = parser; this.valueParser = parser;
return self(); return self();
} }
public @NotNull SELF serialize(@NotNull ValueHandler<PARAM, SOURCE> serializer) { public @NotNull SELF serialize(@NotNull ValueHandler<UNIT, SOURCE> serializer) {
this.valueSerializer = serializer; this.valueSerializer = serializer;
return self(); return self();
} }
public @NotNull SELF serialize(@NotNull DataFunction<PARAM, SOURCE> serializer) { public @NotNull SELF serialize(@NotNull DataFunction<UNIT, SOURCE> serializer) {
return serialize((p, value) -> serializer.handle(value)); return serialize((p, value) -> serializer.handle(value));
} }
protected ValueAdapter<PARAM> buildAdapter() { protected ValueAdapter<UNIT> buildAdapter() {
return new ValueAdapter<>(this.paramType) return new ValueAdapter<>(this.paramType)
.parser((holder, type, data) -> { .parser((holder, type, data) -> {
SOURCE source = holder.deserialize(this.sourceType, data); SOURCE source = holder.deserialize(this.sourceType, data);
@@ -8,9 +8,11 @@ import cc.carm.lib.configuration.value.standard.ConfiguredList;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.*; import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
public class SectionListBuilder<V> extends AbstractSectionBuilder<List<V>, V, ConfiguredList<V>, SectionListBuilder<V>> { public class SectionListBuilder<V>
extends AbstractSectionBuilder<List<V>, V, ConfiguredList<V>, SectionListBuilder<V>> {
protected @NotNull Supplier<? extends List<V>> constructor; protected @NotNull Supplier<? extends List<V>> constructor;
@@ -32,6 +34,14 @@ public class SectionListBuilder<V> extends AbstractSectionBuilder<List<V>, V, Co
return defaults(new ArrayList<>(values)); return defaults(new ArrayList<>(values));
} }
public final @NotNull SectionListBuilder<V> defaults(@NotNull Consumer<List<V>> constructor) {
return defaults(() -> {
List<V> list = new ArrayList<>();
constructor.accept(list);
return list;
});
}
public SectionListBuilder<V> constructor(@NotNull Supplier<? extends List<V>> constructor) { public SectionListBuilder<V> constructor(@NotNull Supplier<? extends List<V>> constructor) {
this.constructor = constructor; this.constructor = constructor;
return this; return this;
@@ -10,6 +10,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
public class SourceListBuilder<SOURCE, V> public class SourceListBuilder<SOURCE, V>
@@ -34,6 +35,23 @@ public class SourceListBuilder<SOURCE, V>
return defaults(new ArrayList<>(values)); return defaults(new ArrayList<>(values));
} }
public final @NotNull SourceListBuilder<SOURCE, V> defaults(@NotNull Consumer<List<V>> constructor) {
return defaults(() -> {
List<V> list = new ArrayList<>();
constructor.accept(list);
return list;
});
}
public SourceListBuilder<SOURCE, V> constructor(@NotNull Supplier<? extends List<V>> constructor) {
this.constructor = constructor;
return this;
}
public <LIST extends List<V>> SourceListBuilder<SOURCE, V> construct(@NotNull LIST list) {
return constructor(() -> list);
}
@Override @Override
protected @NotNull SourceListBuilder<SOURCE, V> self() { protected @NotNull SourceListBuilder<SOURCE, V> self() {
return this; return this;
@@ -3,10 +3,7 @@ package cc.carm.lib.configuration.builder.map;
import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.ValueType;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.HashMap; import java.util.*;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Supplier; import java.util.function.Supplier;
public class ConfigMapCreator<K, V> { public class ConfigMapCreator<K, V> {
@@ -45,4 +42,8 @@ public class ConfigMapCreator<K, V> {
return constructor(TreeMap::new); return constructor(TreeMap::new);
} }
public @NotNull ConfigMapBuilder<TreeMap<K, V>, K, V> asTreeMap(@NotNull Comparator<? super K> comparator) {
return constructor(() -> new TreeMap<>(comparator));
}
} }
@@ -14,10 +14,7 @@ import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
public class SectionMapBuilder<MAP extends Map<K, V>, K, V> public class SectionMapBuilder<MAP extends Map<K, V>, K, V>
extends AbstractSectionBuilder< extends AbstractSectionBuilder<Map<K, V>, V, ConfiguredMap<K, V>, SectionMapBuilder<MAP, K, V>> {
Map<K, V>, V, ConfiguredMap<K, V>,
SectionMapBuilder<MAP, K, V>
> {
protected final @NotNull ValueType<K> keyType; protected final @NotNull ValueType<K> keyType;
@@ -75,6 +72,10 @@ public class SectionMapBuilder<MAP extends Map<K, V>, K, V>
}); });
} }
public @NotNull SectionMapBuilder<MAP, K, V> defaults(@NotNull K key, @NotNull V value) {
return defaults(map -> map.put(key, value));
}
public @NotNull ValueAdapter<K> buildKeyAdapter() { public @NotNull ValueAdapter<K> buildKeyAdapter() {
return new ValueAdapter<>(this.keyType) return new ValueAdapter<>(this.keyType)
.parser((holder, type, data) -> { .parser((holder, type, data) -> {
@@ -13,10 +13,7 @@ import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
public class SourceMapBuilder<MAP extends Map<K, V>, SOURCE, K, V> public class SourceMapBuilder<MAP extends Map<K, V>, SOURCE, K, V>
extends AbstractSourceBuilder< extends AbstractSourceBuilder<Map<K, V>, SOURCE, V, ConfiguredMap<K, V>, SourceMapBuilder<MAP, SOURCE, K, V>> {
Map<K, V>, SOURCE, V, ConfiguredMap<K, V>,
SourceMapBuilder<MAP, SOURCE, K, V>
> {
protected final @NotNull ValueType<K> keyType; protected final @NotNull ValueType<K> keyType;
@@ -53,6 +50,10 @@ public class SourceMapBuilder<MAP extends Map<K, V>, SOURCE, K, V>
}); });
} }
public @NotNull SourceMapBuilder<MAP, SOURCE, K, V> defaults(@NotNull K key, @NotNull V value) {
return defaults(map -> map.put(key, value));
}
public @NotNull SourceMapBuilder<MAP, SOURCE, K, V> parseKey(@NotNull DataFunction<String, K> keyParser) { public @NotNull SourceMapBuilder<MAP, SOURCE, K, V> parseKey(@NotNull DataFunction<String, K> keyParser) {
return parseKey((holder, data) -> keyParser.handle(data)); return parseKey((holder, data) -> keyParser.handle(data));
} }
@@ -1,7 +1,6 @@
package cc.carm.lib.configuration.builder.value; package cc.carm.lib.configuration.builder.value;
import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.impl.AbstractSectionBuilder;
import cc.carm.lib.configuration.function.ValueHandler; import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.source.section.ConfigureSection; import cc.carm.lib.configuration.source.section.ConfigureSection;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -6,7 +6,8 @@ import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class SourceValueBuilder<S, V> extends AbstractSourceBuilder<V, S, V, ConfiguredValue<V>, SourceValueBuilder<S, V>> { public class SourceValueBuilder<S, V>
extends AbstractSourceBuilder<V, S, V, ConfiguredValue<V>, SourceValueBuilder<S, V>> {
public SourceValueBuilder(@NotNull ValueType<S> sourceType, @NotNull ValueType<V> valueType, public SourceValueBuilder(@NotNull ValueType<S> sourceType, @NotNull ValueType<V> valueType,
@@ -0,0 +1,22 @@
package cc.carm.lib.configuration.function;
import org.jetbrains.annotations.NotNull;
@FunctionalInterface
public interface ConfigExceptionHandler {
void handle(@NotNull String path, @NotNull Throwable throwable);
static @NotNull ConfigExceptionHandler silence() {
return (path, throwable) -> {
};
}
static @NotNull ConfigExceptionHandler print() {
return (path, throwable) -> {
System.err.println("Error occurred at path: " + path);
throwable.printStackTrace();
};
}
}
@@ -0,0 +1,17 @@
package cc.carm.lib.configuration.function;
import org.jetbrains.annotations.Nullable;
@FunctionalInterface
public interface DataValidator<T> {
void validate(@Nullable T value) throws Exception;
default DataValidator<T> compose(DataValidator<? super T> other) {
return value -> {
validate(value);
other.validate(value);
};
}
}
@@ -0,0 +1,29 @@
package cc.carm.lib.configuration.function;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
@FunctionalInterface
public interface ValueComposer<T, U> {
/**
* Accept the value and the data, and then compose the value.
*
* @param holder The configuration holder
* @param type The value type, e.g. {@link java.util.List}, {@link java.util.Map}, etc.
* @param data The unit data
* @throws Exception If an error occurs
*/
void accept(@NotNull ConfigurationHolder<?> holder, @NotNull T type, @NotNull U data) throws Exception;
default ValueComposer<T, U> andThen(ValueComposer<? super T, ? super U> after) {
return (holder, unit, data) -> {
accept(holder, unit, data);
after.accept(holder, unit, data);
};
}
}
@@ -1,21 +0,0 @@
package cc.carm.lib.configuration.function;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
@FunctionalInterface
public interface ValueConsumer<U, T> {
void accept(@NotNull ConfigurationHolder<?> holder, @NotNull U unit, @NotNull T data) throws Exception;
default ValueConsumer<U, T> andThen(ValueConsumer<? super U, ? super T> after) {
return (holder, unit, data) -> {
accept(holder, unit, data);
after.accept(holder, unit, data);
};
}
}
@@ -0,0 +1,47 @@
package cc.carm.lib.configuration.function;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@FunctionalInterface
public interface ValueValidator<T> {
void validate(@NotNull ConfigurationHolder<?> holder, @Nullable T value) throws Exception;
default ValueValidator<T> and(ValueValidator<? super T> other) {
return (holder, value) -> {
validate(holder, value);
other.validate(holder, value);
};
}
static <V> ValueValidator<V> none() {
return (holder, data) -> {
};
}
static <V> ValueValidator<V> nonnull() {
return nonnull("Value cannot be null");
}
static <V> ValueValidator<V> nonnull(String message) {
return (holder, data) -> {
if (data == null) throw new IllegalArgumentException(message);
};
}
static <V extends Number> ValueValidator<V> range(V min, V max) {
return range(min, max, "Value must be in range [" + min + ", " + max + "]");
}
static <V extends Number> ValueValidator<V> range(V min, V max, String message) {
return (holder, data) -> {
if (data.doubleValue() < min.doubleValue() || data.doubleValue() > max.doubleValue()) {
throw new IllegalArgumentException(message);
}
};
}
}
@@ -2,7 +2,9 @@ package cc.carm.lib.configuration.source;
import cc.carm.lib.configuration.adapter.*; import cc.carm.lib.configuration.adapter.*;
import cc.carm.lib.configuration.adapter.strandard.StandardAdapters; import cc.carm.lib.configuration.adapter.strandard.StandardAdapters;
import cc.carm.lib.configuration.function.ConfigExceptionHandler;
import cc.carm.lib.configuration.function.DataFunction; import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.function.ValueValidator;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
import cc.carm.lib.configuration.source.loader.PathGenerator; import cc.carm.lib.configuration.source.loader.PathGenerator;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder; import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
@@ -33,15 +35,17 @@ public abstract class ConfigurationFactory<
SELF SELF
> { > {
protected ValueAdapterRegistry adapters = new ValueAdapterRegistry(); protected @NotNull ValueAdapterRegistry adapters = new ValueAdapterRegistry();
protected ConfigurationOptionHolder options = new ConfigurationOptionHolder(); protected @NotNull ConfigurationOptionHolder options = new ConfigurationOptionHolder();
protected @NotNull Map<String, ConfigurationMetaHolder> metadata = new HashMap<>(); protected @NotNull Map<String, ConfigurationMetaHolder> metadata = new HashMap<>();
protected ConfigurationInitializer initializer = new ConfigurationInitializer(); protected @NotNull ConfigurationInitializer initializer = new ConfigurationInitializer();
protected @NotNull ConfigExceptionHandler exceptionHandler = ConfigExceptionHandler.print();
public ConfigurationFactory() { protected ConfigurationFactory() {
this.adapters.register(StandardAdapters.PRIMITIVES); this.adapters.register(StandardAdapters.PRIMITIVES);
this.adapters.register(StandardAdapters.SECTIONS); this.adapters.register(StandardAdapters.SECTIONS);
this.adapters.register(StandardAdapters.ENUMS); this.adapters.register(StandardAdapters.ENUMS);
this.adapters.register(StandardAdapters.UUID);
} }
protected abstract SELF self(); protected abstract SELF self();
@@ -146,6 +150,11 @@ public abstract class ConfigurationFactory<
return self(); return self();
} }
public SELF exceptionally(@NotNull ConfigExceptionHandler handler) {
this.exceptionHandler = handler;
return self();
}
/** /**
* Supply the base path generator for this configuration holder * Supply the base path generator for this configuration holder
* *
@@ -153,9 +162,7 @@ public abstract class ConfigurationFactory<
* @return this * @return this
*/ */
public SELF pathGenerator(PathGenerator generator) { public SELF pathGenerator(PathGenerator generator) {
return initializer(loader -> { return initializer(loader -> loader.pathGenerator(generator));
loader.pathGenerator(generator);
});
} }
/** /**
@@ -174,6 +181,19 @@ public abstract class ConfigurationFactory<
return initializer(loader -> loader.registerAnnotation(annotation, metadata, extractor)); return initializer(loader -> loader.registerAnnotation(annotation, metadata, extractor));
} }
/**
* Register a new annotation for {@link ValueValidator} to the configuration loader
*
* @param annotation The {@link Annotation}
* @param builder The {@link Function} to build the {@link ValueValidator} from the annotation
* @param <A> The annotation type
* @return this
*/
public <A extends Annotation> SELF validAnnotation(@NotNull Class<A> annotation,
@NotNull Function<A, ValueValidator<Object>> builder) {
return initializer(loader -> loader.registerValidAnnotation(annotation, builder));
}
/** /**
* Build the configuration holder. * Build the configuration holder.
* *
@@ -3,6 +3,7 @@ package cc.carm.lib.configuration.source;
import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; import cc.carm.lib.configuration.adapter.ValueAdapterRegistry;
import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.function.ConfigExceptionHandler;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder; import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
@@ -12,7 +13,6 @@ import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder;
import cc.carm.lib.configuration.source.section.ConfigureSource; import cc.carm.lib.configuration.source.section.ConfigureSource;
import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.ConfigValue;
import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.ValueManifest;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnmodifiableView; import org.jetbrains.annotations.UnmodifiableView;
@@ -31,14 +31,25 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
protected final @NotNull ConfigurationInitializer initializer; protected final @NotNull ConfigurationInitializer initializer;
protected @NotNull ConfigExceptionHandler exceptionHandler;
public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters, public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters,
@NotNull ConfigurationOptionHolder options, @NotNull ConfigurationOptionHolder options,
@NotNull Map<String, ConfigurationMetaHolder> metadata, @NotNull Map<String, ConfigurationMetaHolder> metadata,
@NotNull ConfigurationInitializer initializer) { @NotNull ConfigurationInitializer initializer) {
this(adapters, options, metadata, initializer, ConfigExceptionHandler.print());
}
public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters,
@NotNull ConfigurationOptionHolder options,
@NotNull Map<String, ConfigurationMetaHolder> metadata,
@NotNull ConfigurationInitializer initializer,
@NotNull ConfigExceptionHandler exceptionHandler) {
this.initializer = initializer; this.initializer = initializer;
this.adapters = adapters; this.adapters = adapters;
this.options = options; this.options = options;
this.metadata = metadata; this.metadata = metadata;
this.exceptionHandler = exceptionHandler;
} }
public abstract @NotNull SOURCE config(); public abstract @NotNull SOURCE config();
@@ -75,7 +86,7 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
@NotNull @NotNull
@UnmodifiableView @UnmodifiableView
public <M> Map<String, M> extractMetadata(@NotNull ConfigurationMetadata<M> type, @NotNull Predicate<M> filter) { public <M> Map<String, M> extractMetadata(@NotNull ConfigurationMetadata<M> type, @NotNull Predicate<@Nullable M> filter) {
Map<String, M> metas = new LinkedHashMap<>(); Map<String, M> metas = new LinkedHashMap<>();
for (Map.Entry<String, ConfigurationMetaHolder> entry : this.metadata.entrySet()) { for (Map.Entry<String, ConfigurationMetaHolder> entry : this.metadata.entrySet()) {
M data = entry.getValue().get(type); M data = entry.getValue().get(type);
@@ -86,7 +97,7 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
@NotNull @NotNull
@UnmodifiableView @UnmodifiableView
public Map<String, ConfigValue<?>> registeredValues() { public Map<String, ConfigValue<?, ?>> registeredValues() {
return extractMetadata(StandardMeta.VALUE); return extractMetadata(StandardMeta.VALUE);
} }
@@ -98,17 +109,17 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
return initializer; return initializer;
} }
@Contract("_,null -> null") @Nullable
public <T> T deserialize(@NotNull Class<T> type, @Nullable Object source) throws Exception { public <T> T deserialize(@NotNull Class<T> type, @Nullable Object source) throws Exception {
return adapters().deserialize(this, type, source); return adapters().deserialize(this, type, source);
} }
@Contract("_,null -> null") @Nullable
public <T> T deserialize(@NotNull ValueType<T> type, @Nullable Object source) throws Exception { public <T> T deserialize(@NotNull ValueType<T> type, @Nullable Object source) throws Exception {
return adapters().deserialize(this, type, source); return adapters().deserialize(this, type, source);
} }
@Contract("null -> null") @Nullable
public <T> Object serialize(@Nullable T value) throws Exception { public <T> Object serialize(@Nullable T value) throws Exception {
return adapters().serialize(this, value); return adapters().serialize(this, value);
} }
@@ -117,7 +128,7 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
try { try {
initializer.initialize(this, configClass); initializer.initialize(this, configClass);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); throwing(configClass.getName(), e);
} }
} }
@@ -125,12 +136,20 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
try { try {
initializer.initialize(this, config); initializer.initialize(this, config);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); throwing(config.getClass().getName(), e);
} }
} }
public void initialize(@NotNull ValueManifest<?> value) { public void initialize(@NotNull ValueManifest<?, ?> value) {
value.holder(this); value.holder(this);
} }
public void throwing(@NotNull String path, @NotNull Throwable e) {
this.exceptionHandler.handle(path, e);
}
public void exceptionally(@NotNull ConfigExceptionHandler handler) {
this.exceptionHandler = handler;
}
} }
@@ -8,7 +8,7 @@ import org.jetbrains.annotations.Nullable;
public interface ConfigInitializeHandler<T, V> { public interface ConfigInitializeHandler<T, V> {
static <T, V> ConfigInitializeHandler<T, V> start() { static <T, V> ConfigInitializeHandler<T, V> start() {
return (provider, path, value, instace) -> { return (provider, path, value, instance) -> {
}; };
} }
@@ -1,6 +1,7 @@
package cc.carm.lib.configuration.source.loader; package cc.carm.lib.configuration.source.loader;
import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.function.ValueValidator;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
import cc.carm.lib.configuration.source.meta.StandardMeta; import cc.carm.lib.configuration.source.meta.StandardMeta;
@@ -21,7 +22,7 @@ import java.util.function.Function;
public class ConfigurationInitializer { public class ConfigurationInitializer {
protected @NotNull PathGenerator pathGenerator; protected @NotNull PathGenerator pathGenerator;
protected @NotNull ConfigInitializeHandler<Field, ConfigValue<?>> valueInitializer; protected @NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> valueInitializer;
protected @NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer; protected @NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer;
public ConfigurationInitializer() { public ConfigurationInitializer() {
@@ -29,7 +30,7 @@ public class ConfigurationInitializer {
} }
public ConfigurationInitializer(@NotNull PathGenerator pathGenerator, public ConfigurationInitializer(@NotNull PathGenerator pathGenerator,
@NotNull ConfigInitializeHandler<Field, ConfigValue<?>> valueInitializer, @NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> valueInitializer,
@NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer) { @NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer) {
this.pathGenerator = pathGenerator; this.pathGenerator = pathGenerator;
this.valueInitializer = valueInitializer; this.valueInitializer = valueInitializer;
@@ -44,11 +45,11 @@ public class ConfigurationInitializer {
return pathGenerator; return pathGenerator;
} }
public ConfigInitializeHandler<Field, ConfigValue<?>> fieldInitializer() { public ConfigInitializeHandler<Field, ConfigValue<?, ?>> fieldInitializer() {
return valueInitializer; return valueInitializer;
} }
public void fieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?>> fieldInitializer) { public void fieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> fieldInitializer) {
this.valueInitializer = fieldInitializer; this.valueInitializer = fieldInitializer;
} }
@@ -60,7 +61,7 @@ public class ConfigurationInitializer {
this.classInitializer = classInitializer; this.classInitializer = classInitializer;
} }
public void appendFieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?>> fieldInitializer) { public void appendFieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> fieldInitializer) {
this.valueInitializer = this.valueInitializer.andThen(fieldInitializer); this.valueInitializer = this.valueInitializer.andThen(fieldInitializer);
} }
@@ -95,6 +96,14 @@ public class ConfigurationInitializer {
registerFieldAnnotation(annotation, metadata, extractor); registerFieldAnnotation(annotation, metadata, extractor);
} }
public <A extends Annotation> void registerValidAnnotation(@NotNull Class<A> annotation,
@NotNull Function<A, ValueValidator<Object>> builder) {
appendFieldInitializer((holder, path, field, instance) -> {
A data = field.getAnnotation(annotation);
if (data == null) return;
instance.validate((h, t) -> builder.apply(data).validate(h, t));
});
}
public @Nullable String getFieldPath(@NotNull ConfigurationHolder<?> holder, @Nullable String parentPath, @NotNull Field field) { public @Nullable String getFieldPath(@NotNull ConfigurationHolder<?> holder, @Nullable String parentPath, @NotNull Field field) {
return pathGenerator.getFieldPath(holder, parentPath, field); return pathGenerator.getFieldPath(holder, parentPath, field);
@@ -125,7 +134,7 @@ public class ConfigurationInitializer {
try { try {
this.classInitializer.whenInitialize(holder, path, root.getClass(), root); this.classInitializer.whenInitialize(holder, path, root.getClass(), root);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); holder.throwing(path, e);
} }
Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(holder, root, field, path)); Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(holder, root, field, path));
} }
@@ -142,7 +151,7 @@ public class ConfigurationInitializer {
try { try {
this.classInitializer.whenInitialize(holder, path, (Class<? extends Configuration>) clazz, configField); this.classInitializer.whenInitialize(holder, path, (Class<? extends Configuration>) clazz, configField);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); holder.throwing(path, e);
} }
for (Field field : clazz.getDeclaredFields()) { for (Field field : clazz.getDeclaredFields()) {
@@ -163,9 +172,9 @@ public class ConfigurationInitializer {
field.setAccessible(true); field.setAccessible(true);
Object object = field.get(source); Object object = field.get(source);
// //
if (object instanceof ConfigValue<?>) { if (object instanceof ConfigValue<?, ?>) {
// 目标是 ConfigValue 实例,进行具体的初始化注入 // 目标是 ConfigValue 实例,进行具体的初始化注入
ConfigValue<?> value = (ConfigValue<?>) object; ConfigValue<?, ?> value = (ConfigValue<?, ?>) object;
String path = getFieldPath(holder, parent, field); String path = getFieldPath(holder, parent, field);
if (path == null) return; if (path == null) return;
value.initialize(holder, path); value.initialize(holder, path);
@@ -176,7 +185,7 @@ public class ConfigurationInitializer {
try { try {
this.valueInitializer.whenInitialize(holder, path, field, value); this.valueInitializer.whenInitialize(holder, path, field, value);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); holder.throwing(path, e);
} }
if (holder.option(StandardOptions.PRELOAD)) { if (holder.option(StandardOptions.PRELOAD)) {
value.get(); // Preload the value by calling #get method. value.get(); // Preload the value by calling #get method.
@@ -7,6 +7,6 @@ public interface StandardMeta {
/** /**
* To mark the {@link ConfigValue} instance of specific path. * To mark the {@link ConfigValue} instance of specific path.
*/ */
ConfigurationMetadata<ConfigValue<?>> VALUE = ConfigurationMetadata.of(); ConfigurationMetadata<ConfigValue<?, ?>> VALUE = ConfigurationMetadata.of();
} }
@@ -477,7 +477,7 @@ public interface ConfigureSection {
* @return The boolean if the path exists and is a boolean, otherwise false. * @return The boolean if the path exists and is a boolean, otherwise false.
*/ */
default boolean getBoolean(@NotNull String path) { default boolean getBoolean(@NotNull String path) {
return getBoolean(path, false); return getBoolean(path, null);
} }
/** /**
@@ -509,7 +509,7 @@ public interface ConfigureSection {
* @return The byte if the path exists and is a byte, otherwise 0. * @return The byte if the path exists and is a byte, otherwise 0.
*/ */
default @Nullable Byte getByte(@NotNull String path) { default @Nullable Byte getByte(@NotNull String path) {
return getByte(path, (byte) 0); return getByte(path, null);
} }
/** /**
@@ -541,7 +541,7 @@ public interface ConfigureSection {
* @return The short if the path exists and is a short, otherwise 0. * @return The short if the path exists and is a short, otherwise 0.
*/ */
default @Nullable Short getShort(@NotNull String path) { default @Nullable Short getShort(@NotNull String path) {
return getShort(path, (short) 0); return getShort(path, null);
} }
/** /**
@@ -573,7 +573,7 @@ public interface ConfigureSection {
* @return The int if the path exists and is an int, otherwise 0. * @return The int if the path exists and is an int, otherwise 0.
*/ */
default @Nullable Integer getInt(@NotNull String path) { default @Nullable Integer getInt(@NotNull String path) {
return getInt(path, 0); return getInt(path, null);
} }
/** /**
@@ -606,7 +606,7 @@ public interface ConfigureSection {
* @return The long if the path exists and is a long, otherwise 0. * @return The long if the path exists and is a long, otherwise 0.
*/ */
default @Nullable Long getLong(@NotNull String path) { default @Nullable Long getLong(@NotNull String path) {
return getLong(path, 0L); return getLong(path, null);
} }
/** /**
@@ -638,7 +638,7 @@ public interface ConfigureSection {
* @return The float if the path exists and is a float, otherwise 0. * @return The float if the path exists and is a float, otherwise 0.
*/ */
default @Nullable Float getFloat(@NotNull String path) { default @Nullable Float getFloat(@NotNull String path) {
return getFloat(path, 0.0F); return getFloat(path, null);
} }
/** /**
@@ -670,7 +670,7 @@ public interface ConfigureSection {
* @return The double if the path exists and is a double, otherwise 0. * @return The double if the path exists and is a double, otherwise 0.
*/ */
default @Nullable Double getDouble(@NotNull String path) { default @Nullable Double getDouble(@NotNull String path) {
return getDouble(path, 0.0D); return getDouble(path, null);
} }
/** /**
@@ -692,7 +692,7 @@ public interface ConfigureSection {
* @return True if the value is present and is a char, false otherwise. * @return True if the value is present and is a char, false otherwise.
*/ */
default boolean isChar(@NotNull String path) { default boolean isChar(@NotNull String path) {
return isType(path, Boolean.class); return isType(path, Character.class);
} }
/** /**
@@ -750,7 +750,7 @@ public interface ConfigureSection {
} }
/** /**
* Get a list of values from the section * Get a list of values from current section
* <p> * <p>
* If the path does not exist, an empty list will be returned * If the path does not exist, an empty list will be returned
* <br>Any changes please use {@link #set(String, Object)} after changes * <br>Any changes please use {@link #set(String, Object)} after changes
@@ -765,7 +765,7 @@ public interface ConfigureSection {
} }
/** /**
* Get a list of strings from the section * Get a list of strings from current section
* <p> Limitations see {@link #getList(String, DataFunction)} * <p> Limitations see {@link #getList(String, DataFunction)}
* *
* @param path The path to get the list from * @param path The path to get the list from
@@ -776,7 +776,7 @@ public interface ConfigureSection {
} }
/** /**
* Get a list of integer from the section * Get a list of integer from current section
* <p> Limitations see {@link #getList(String, DataFunction)} * <p> Limitations see {@link #getList(String, DataFunction)}
* *
* @param path The path to get the list from * @param path The path to get the list from
@@ -787,7 +787,7 @@ public interface ConfigureSection {
} }
/** /**
* Get a list of long from the section * Get a list of long from current section
* <p> Limitations see {@link #getList(String, DataFunction)} * <p> Limitations see {@link #getList(String, DataFunction)}
* *
* @param path The path to get the list from * @param path The path to get the list from
@@ -798,7 +798,7 @@ public interface ConfigureSection {
} }
/** /**
* Get a list of double from the section * Get a list of double from current section
* <p> Limitations see {@link #getList(String, DataFunction)} * <p> Limitations see {@link #getList(String, DataFunction)}
* *
* @param path The path to get the list from * @param path The path to get the list from
@@ -809,7 +809,7 @@ public interface ConfigureSection {
} }
/** /**
* Get a list of floats from the section * Get a list of floats from current section
* <p> Limitations see {@link #getList(String, DataFunction)} * <p> Limitations see {@link #getList(String, DataFunction)}
* *
* @param path The path to get the list from * @param path The path to get the list from
@@ -820,7 +820,7 @@ public interface ConfigureSection {
} }
/** /**
* Get a list of bytes from the section * Get a list of bytes from current section
* <p> Limitations see {@link #getList(String, DataFunction)} * <p> Limitations see {@link #getList(String, DataFunction)}
* *
* @param path The path to get the list from * @param path The path to get the list from
@@ -831,7 +831,7 @@ public interface ConfigureSection {
} }
/** /**
* Get a list of char from the section * Get a list of char from current section
* <p> Limitations see {@link #getList(String, DataFunction)} * <p> Limitations see {@link #getList(String, DataFunction)}
* *
* @param path The path to get the list from * @param path The path to get the list from
@@ -842,7 +842,22 @@ public interface ConfigureSection {
} }
/** /**
* Get the specific type of collection from the section. * Get a list of {@link ConfigureSection} from current section
*
* @param path The path to get the list from
* @return The list of {@link ConfigureSection}
*/
default @NotNull List<ConfigureSection> getSectionList(@NotNull String path) {
return getList(path, obj -> {
if (obj instanceof ConfigureSection) {
return (ConfigureSection) obj;
}
return null;
});
}
/**
* Get the specific type of collection from current section.
* *
* @param path The path to get the collection from * @param path The path to get the collection from
* @param constructor The constructor of the collection * @param constructor The constructor of the collection
@@ -858,7 +873,7 @@ public interface ConfigureSection {
} }
/** /**
* Get the specific type of steam from the section. * Get the specific type of steam from current section.
* *
* @param path The path to get the stream from * @param path The path to get the stream from
* @return The stream of values * @return The stream of values
@@ -869,7 +884,7 @@ public interface ConfigureSection {
} }
/** /**
* Get the specific type of steam from the section. * Get the specific type of steam from current section.
* *
* @param path The path to get the stream from * @param path The path to get the stream from
* @param parser The function to parse the values * @param parser The function to parse the values
@@ -33,9 +33,9 @@ import java.util.Optional;
* @see ValueManifest Base class providing metadata and default value handling * @see ValueManifest Base class providing metadata and default value handling
* @see ConfigurationHolder Responsible for configuration source persistence * @see ConfigurationHolder Responsible for configuration source persistence
*/ */
public abstract class ConfigValue<T> extends ValueManifest<T> { public abstract class ConfigValue<T, U> extends ValueManifest<T, U> {
protected ConfigValue(@NotNull ValueManifest<T> manifest) { protected ConfigValue(@NotNull ValueManifest<T, U> manifest) {
super(manifest); super(manifest);
} }
@@ -1,6 +1,7 @@
package cc.carm.lib.configuration.value; package cc.carm.lib.configuration.value;
import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.function.ValueValidator;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder; import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
import cc.carm.lib.configuration.source.section.ConfigureSource; import cc.carm.lib.configuration.source.section.ConfigureSource;
@@ -11,37 +12,48 @@ import org.jetbrains.annotations.Nullable;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Supplier; import java.util.function.Supplier;
public class ValueManifest<T> { public class ValueManifest<TYPE, UNIT> {
protected final @NotNull ValueType<T> type; protected final @NotNull ValueType<TYPE> type;
protected final @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer; protected final @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer;
protected @Nullable ConfigurationHolder<?> holder; protected @Nullable ConfigurationHolder<?> holder;
protected @Nullable String path; // Section path protected @Nullable String path; // Section path
protected @NotNull Supplier<@Nullable T> defaultSupplier; protected @NotNull ValueValidator<UNIT> validator;
protected @NotNull Supplier<@Nullable TYPE> defaultSupplier;
public ValueManifest(@NotNull ValueType<T> type) { public ValueManifest(@NotNull ValueType<TYPE> type) {
this(type, () -> null, EMPTY_INITIALIZER, null, null); this(type, () -> null, ValueValidator.none(), EMPTY_INITIALIZER, null, null);
} }
public ValueManifest(@NotNull T defaultValue) { public ValueManifest(@NotNull TYPE defaultValue) {
this(ValueType.of(defaultValue), () -> defaultValue); this(ValueType.of(defaultValue), () -> defaultValue);
} }
public ValueManifest(@NotNull ValueType<T> type, @NotNull Supplier<@Nullable T> defaultSupplier) { public ValueManifest(@NotNull ValueType<TYPE> type, @NotNull Supplier<@Nullable TYPE> defaultSupplier) {
this(type, defaultSupplier, EMPTY_INITIALIZER, null, null); this(type, defaultSupplier, ValueValidator.none(), EMPTY_INITIALIZER, null, null);
} }
public ValueManifest(@NotNull ValueType<T> type, @NotNull Supplier<@Nullable T> defaultSupplier, public ValueManifest(@NotNull ValueType<TYPE> type,
@NotNull Supplier<@Nullable TYPE> defaultSupplier,
@NotNull ValueValidator<UNIT> validator) {
this(type, defaultSupplier, validator, EMPTY_INITIALIZER, null, null);
}
public ValueManifest(@NotNull ValueType<TYPE> type, @NotNull Supplier<@Nullable TYPE> defaultSupplier,
@NotNull ValueValidator<UNIT> validator,
@NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer) { @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer) {
this(type, defaultSupplier, initializer, null, null); this(type, defaultSupplier, validator, initializer, null, null);
} }
public ValueManifest(@NotNull ValueType<T> type, @NotNull Supplier<@Nullable T> defaultSupplier, public ValueManifest(@NotNull ValueType<TYPE> type,
@NotNull Supplier<@Nullable TYPE> defaultSupplier,
@NotNull ValueValidator<UNIT> validator,
@NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer, @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer,
@Nullable ConfigurationHolder<?> holder, @Nullable String path) { @Nullable ConfigurationHolder<?> holder, @Nullable String path) {
this.type = type; this.type = type;
this.validator = validator;
this.initializer = initializer; this.initializer = initializer;
this.defaultSupplier = defaultSupplier; this.defaultSupplier = defaultSupplier;
this.holder = holder; this.holder = holder;
@@ -49,8 +61,8 @@ public class ValueManifest<T> {
initialize(); initialize();
} }
protected ValueManifest(@NotNull ValueManifest<T> manifest) { protected ValueManifest(@NotNull ValueManifest<TYPE, UNIT> manifest) {
this(manifest.type, manifest.defaultSupplier, manifest.initializer, manifest.holder, manifest.path); this(manifest.type, manifest.defaultSupplier, manifest.validator, manifest.initializer, manifest.holder, manifest.path);
} }
public void initialize(@NotNull ConfigurationHolder<?> holder, @NotNull String path) { public void initialize(@NotNull ConfigurationHolder<?> holder, @NotNull String path) {
@@ -63,7 +75,7 @@ public class ValueManifest<T> {
if (holder != null && path != null) this.initializer.accept(holder, path); if (holder != null && path != null) this.initializer.accept(holder, path);
} }
public @NotNull ValueType<T> type() { public @NotNull ValueType<TYPE> type() {
return this.type; return this.type;
} }
@@ -75,20 +87,37 @@ public class ValueManifest<T> {
this.path = path; this.path = path;
} }
public @Nullable T defaults() { public @Nullable TYPE defaults() {
return this.defaultSupplier.get(); return this.defaultSupplier.get();
} }
public void defaults(@Nullable T defaultValue) { public void defaults(@Nullable TYPE defaultValue) {
defaults(() -> defaultValue); defaults(() -> defaultValue);
} }
public void defaults(@NotNull Supplier<@Nullable T> defaultValue) { public void defaults(@NotNull Supplier<@Nullable TYPE> defaultValue) {
this.defaultSupplier = defaultValue; this.defaultSupplier = defaultValue;
} }
public boolean hasDefaults() { public boolean hasDefaults() {
return this.defaultSupplier.get() != null; return defaults() != null;
}
public @NotNull ValueValidator<UNIT> validator() {
return this.validator;
}
public void validator(@NotNull ValueValidator<UNIT> validator) {
this.validator = validator;
}
public void validate(@NotNull ValueValidator<UNIT> validator) {
validator(this.validator.and(validator));
}
protected UNIT withValidated(@Nullable UNIT value) throws Exception {
validator.validate(holder(), value);
return value;
} }
public @NotNull String path() { public @NotNull String path() {
@@ -105,12 +134,12 @@ public class ValueManifest<T> {
return holder().config(); return holder().config();
} }
public ConfigurationMetaHolder metadata() { public @NotNull ConfigurationMetaHolder metadata() {
return holder().metadata(path()); return holder().metadata(path());
} }
@ApiStatus.Internal @ApiStatus.Internal
protected Object getData() { protected @Nullable Object getData() {
return config().get(path()); return config().get(path());
} }
@@ -119,6 +148,15 @@ public class ValueManifest<T> {
config().set(path(), value); config().set(path(), value);
} }
protected void throwing(@NotNull Throwable throwable) {
throwing(path, throwable);
}
protected void throwing(@NotNull String path, @NotNull Throwable throwable) {
if (holder == null) throwable.printStackTrace();
else holder.throwing(path, throwable);
}
private static final @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> EMPTY_INITIALIZER = (provider, valuePath) -> { private static final @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> EMPTY_INITIALIZER = (provider, valuePath) -> {
}; };
@@ -9,12 +9,12 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public abstract class CachedConfigValue<T> extends ConfigValue<T> { public abstract class CachedConfigValue<T, U> extends ConfigValue<T, U> {
protected @Nullable T cachedValue; protected @Nullable T cachedValue;
protected long parsedTime = -1; protected long parsedTime = -1;
protected CachedConfigValue(@NotNull ValueManifest<T> manifest) { protected CachedConfigValue(@NotNull ValueManifest<T, U> manifest) {
super(manifest); super(manifest);
} }
@@ -5,6 +5,7 @@ import cc.carm.lib.configuration.adapter.ValueParser;
import cc.carm.lib.configuration.adapter.ValueSerializer; import cc.carm.lib.configuration.adapter.ValueSerializer;
import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.list.ConfigListBuilder; import cc.carm.lib.configuration.builder.list.ConfigListBuilder;
import cc.carm.lib.configuration.builder.list.SourceListBuilder;
import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.ValueManifest;
import cc.carm.lib.configuration.value.impl.CachedConfigValue; import cc.carm.lib.configuration.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -15,7 +16,7 @@ import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements List<V> { public class ConfiguredList<V> extends CachedConfigValue<List<V>, V> implements List<V> {
public static <T> @NotNull ConfigListBuilder<T> builderOf(@NotNull Class<T> type) { public static <T> @NotNull ConfigListBuilder<T> builderOf(@NotNull Class<T> type) {
return builderOf(ValueType.of(type)); return builderOf(ValueType.of(type));
@@ -25,10 +26,26 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements Lis
return new ConfigListBuilder<>(type); return new ConfigListBuilder<>(type);
} }
public static <T> @NotNull SourceListBuilder<T, T> with(@NotNull Class<T> registeredType) {
return with(ValueType.of(registeredType));
}
public static <T> @NotNull SourceListBuilder<T, T> with(@NotNull ValueType<T> registeredType) {
return new ConfigListBuilder<>(registeredType).from(registeredType);
}
@SafeVarargs
public static <T> @NotNull ConfiguredList<T> of(@NotNull T value, @NotNull T... values) {
List<T> list = new ArrayList<>();
list.add(value);
Collections.addAll(list, values);
return with(ValueType.of(value)).defaults(list).build();
}
protected final @NotNull Supplier<? extends List<V>> constructor; protected final @NotNull Supplier<? extends List<V>> constructor;
protected final @NotNull ValueAdapter<V> paramAdapter; protected final @NotNull ValueAdapter<V> paramAdapter;
public ConfiguredList(@NotNull ValueManifest<List<V>> manifest, public ConfiguredList(@NotNull ValueManifest<List<V>, V> manifest,
@NotNull Supplier<? extends List<V>> constructor, @NotNull Supplier<? extends List<V>> constructor,
@NotNull ValueAdapter<V> paramAdapter) { @NotNull ValueAdapter<V> paramAdapter) {
super(manifest); super(manifest);
@@ -70,40 +87,46 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements Lis
if (!cacheExpired()) return getCachedOrDefault(createList()); if (!cacheExpired()) return getCachedOrDefault(createList());
// Data that is outdated and needs to be parsed again. // Data that is outdated and needs to be parsed again.
List<V> list = createList(); List<V> list = createList();
try {
List<?> data = config().contains(path()) ? config().getList(path()) : null; List<?> data = config().contains(path()) ? config().getList(path()) : null;
if (data == null) return getDefaultFirst(list); if (data == null) return getDefaultFirst(list);
ValueParser<V> parser = parser(); ValueParser<V> parser = parser();
if (parser == null) return getDefaultFirst(list); if (parser == null) return getDefaultFirst(list);
int i = 0;
for (Object dataVal : data) { for (Object dataVal : data) {
if (dataVal == null) continue; if (dataVal == null) continue;
try { try {
list.add(parser.parse(holder(), paramType(), dataVal)); list.add(withValidated(parser.parse(holder(), paramType(), dataVal)));
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); throwing(path + "[" + i + "]", e);
} }
} }
} catch (Exception ex) {
throwing(ex);
}
return updateCache(list); return updateCache(list);
} }
@Override @Override
public void set(@Nullable List<V> value) { public void set(@Nullable List<V> list) {
updateCache(value); updateCache(list);
if (value == null) { if (list == null) {
setData(null); setData(null);
return; return;
} }
ValueSerializer<V> serializer = serializer(); ValueSerializer<V> serializer = serializer();
if (serializer == null) return; if (serializer == null) return;
List<Object> data = new ArrayList<>(); List<Object> data = new ArrayList<>();
for (V val : value) { for (V val : list) {
if (val == null) continue; if (val == null) continue;
try { try {
data.add(serializer.serialize(holder(), paramType(), val)); data.add(serializer.serialize(holder(), paramType(), withValidated(val)));
} catch (Exception ex) { } catch (Exception ex) {
ex.printStackTrace(); throwing(ex);
} }
} }
setData(data); setData(data);
@@ -17,7 +17,11 @@ import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements Map<K, V> { public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>, V> implements Map<K, V> {
public static <V> ConfigMapCreator<String, V> builderOf(@NotNull Class<V> valueType) {
return builderOf(String.class, valueType);
}
public static <K, V> ConfigMapCreator<K, V> builderOf(@NotNull ValueType<K> keyType, @NotNull ValueType<V> valueType) { public static <K, V> ConfigMapCreator<K, V> builderOf(@NotNull ValueType<K> keyType, @NotNull ValueType<V> valueType) {
return new ConfigMapCreator<>(keyType, valueType); return new ConfigMapCreator<>(keyType, valueType);
@@ -38,7 +42,7 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
protected final @NotNull ValueAdapter<K> keyAdapter; protected final @NotNull ValueAdapter<K> keyAdapter;
protected final @NotNull ValueAdapter<V> valueAdapter; protected final @NotNull ValueAdapter<V> valueAdapter;
public ConfiguredMap(@NotNull ValueManifest<Map<K, V>> manifest, public ConfiguredMap(@NotNull ValueManifest<Map<K, V>, V> manifest,
@NotNull Supplier<? extends Map<K, V>> constructor, @NotNull Supplier<? extends Map<K, V>> constructor,
@NotNull ValueAdapter<K> keyAdapter, @NotNull ValueAdapter<V> valueAdapter) { @NotNull ValueAdapter<K> keyAdapter, @NotNull ValueAdapter<V> valueAdapter) {
super(manifest); super(manifest);
@@ -73,6 +77,7 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
// If the value is expired, we need to update it // If the value is expired, we need to update it
Map<K, V> map = createMap(); Map<K, V> map = createMap();
try {
ConfigureSection section = config().getSection(path()); ConfigureSection section = config().getSection(path());
if (section == null) return getDefaultFirst(map); if (section == null) return getDefaultFirst(map);
@@ -80,8 +85,9 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
if (keys.isEmpty()) return getDefaultFirst(map); if (keys.isEmpty()) return getDefaultFirst(map);
ValueParser<K> keyParser = parserFor(keyAdapter); ValueParser<K> keyParser = parserFor(keyAdapter);
if (keyParser == null) return getDefaultFirst(map);
ValueParser<V> valueParser = parserFor(valueAdapter); ValueParser<V> valueParser = parserFor(valueAdapter);
if (keyParser == null || valueParser == null) return getDefaultFirst(map); if (valueParser == null) return getDefaultFirst(map);
for (String dataKey : keys) { for (String dataKey : keys) {
Object dataVal = section.get(dataKey); Object dataVal = section.get(dataKey);
@@ -89,11 +95,14 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
try { try {
K key = keyParser.parse(holder(), keyType(), dataKey); K key = keyParser.parse(holder(), keyType(), dataKey);
V value = valueParser.parse(holder(), valueType(), dataVal); V value = valueParser.parse(holder(), valueType(), dataVal);
map.put(key, value); map.put(key, withValidated(value));
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); throwing(path + "." + dataKey, e);
} }
} }
} catch (Exception ex) {
throwing(ex);
}
return updateCache(map); return updateCache(map);
} }
@@ -115,9 +124,11 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
return; return;
} }
try {
ValueSerializer<K> keySerializer = serializerFor(keyAdapter); ValueSerializer<K> keySerializer = serializerFor(keyAdapter);
if (keySerializer == null) return;
ValueSerializer<V> valueSerializer = serializerFor(valueAdapter); ValueSerializer<V> valueSerializer = serializerFor(valueAdapter);
if (keySerializer == null || valueSerializer == null) return; if (valueSerializer == null) return;
Map<Object, Object> data = new LinkedHashMap<>(); Map<Object, Object> data = new LinkedHashMap<>();
@@ -125,13 +136,16 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
try { try {
data.put( data.put(
keySerializer.serialize(holder(), keyType(), entry.getKey()), keySerializer.serialize(holder(), keyType(), entry.getKey()),
valueSerializer.serialize(holder(), valueType(), entry.getValue()) valueSerializer.serialize(holder(), valueType(), withValidated(entry.getValue()))
); );
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); throwing(path + "." + entry.getKey(), e);
} }
} }
setData(data); setData(data);
} catch (Exception ex) {
throwing(ex);
}
} }
public <T> @NotNull T handle(Function<Map<K, V>, T> function) { public <T> @NotNull T handle(Function<Map<K, V>, T> function) {
@@ -5,6 +5,8 @@ import cc.carm.lib.configuration.adapter.ValueParser;
import cc.carm.lib.configuration.adapter.ValueSerializer; import cc.carm.lib.configuration.adapter.ValueSerializer;
import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.value.ConfigValueBuilder; import cc.carm.lib.configuration.builder.value.ConfigValueBuilder;
import cc.carm.lib.configuration.builder.value.SourceValueBuilder;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.ValueManifest;
import cc.carm.lib.configuration.value.impl.CachedConfigValue; import cc.carm.lib.configuration.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -12,16 +14,54 @@ import org.jetbrains.annotations.Nullable;
import java.util.function.Supplier; import java.util.function.Supplier;
public class ConfiguredValue<V> extends CachedConfigValue<V> { public class ConfiguredValue<V> extends CachedConfigValue<V, V> {
/**
* Create a new value builder.
*
* @param type The type of the value.
* @param <V> The type of the value.
* @return a {@link ConfigValueBuilder} with the specified type.
*/
public static <V> ConfigValueBuilder<V> builderOf(@NotNull Class<V> type) { public static <V> ConfigValueBuilder<V> builderOf(@NotNull Class<V> type) {
return new ConfigValueBuilder<>(ValueType.of(type)); return new ConfigValueBuilder<>(ValueType.of(type));
} }
/**
* Create a new value builder.
*
* @param type The type of the value.
* @param <V> The type of the value.
* @return a {@link ConfigValueBuilder} with the specified type.
*/
public static <V> ConfigValueBuilder<V> builderOf(@NotNull ValueType<V> type) { public static <V> ConfigValueBuilder<V> builderOf(@NotNull ValueType<V> type) {
return new ConfigValueBuilder<>(type); return new ConfigValueBuilder<>(type);
} }
/**
* Create a new value builder with the specified {@link ConfigurationHolder#registeredValues()} type.
*
* @param registeredType The type of the value.
* @param <V> The type of the value.
* @return a {@link SourceValueBuilder} with the specified registered type.
* @see ValueAdapter
*/
public static <V> SourceValueBuilder<V, V> with(@NotNull Class<V> registeredType) {
return with(ValueType.of(registeredType));
}
/**
* Create a new value builder with the specified {@link ConfigurationHolder#registeredValues()} type.
*
* @param registeredType The type of the value.
* @param <V> The type of the value.
* @return a {@link SourceValueBuilder} with the specified registered type.
* @see ValueAdapter
*/
public static <V> SourceValueBuilder<V, V> with(@NotNull ValueType<V> registeredType) {
return new ConfigValueBuilder<>(registeredType).from(registeredType);
}
public static <V> ConfiguredValue<V> of(@NotNull V defaults) { public static <V> ConfiguredValue<V> of(@NotNull V defaults) {
return of(ValueType.of(defaults), () -> defaults); return of(ValueType.of(defaults), () -> defaults);
} }
@@ -51,7 +91,7 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
); );
} }
public static <V> ConfiguredValue<V> of(@NotNull ValueManifest<V> manifest, public static <V> ConfiguredValue<V> of(@NotNull ValueManifest<V, V> manifest,
@Nullable ValueParser<V> parser, @Nullable ValueParser<V> parser,
@Nullable ValueSerializer<V> serializer) { @Nullable ValueSerializer<V> serializer) {
ValueAdapter<V> adapter = new ValueAdapter<>(manifest.type()); ValueAdapter<V> adapter = new ValueAdapter<>(manifest.type());
@@ -60,13 +100,13 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
return of(manifest, adapter); return of(manifest, adapter);
} }
public static <V> ConfiguredValue<V> of(@NotNull ValueManifest<V> manifest, @NotNull ValueAdapter<V> adapter) { public static <V> ConfiguredValue<V> of(@NotNull ValueManifest<V, V> manifest, @NotNull ValueAdapter<V> adapter) {
return new ConfiguredValue<>(manifest, adapter); return new ConfiguredValue<>(manifest, adapter);
} }
protected final @NotNull ValueAdapter<V> adapter; protected final @NotNull ValueAdapter<V> adapter;
public ConfiguredValue(@NotNull ValueManifest<V> manifest, @NotNull ValueAdapter<V> adapter) { public ConfiguredValue(@NotNull ValueManifest<V, V> manifest, @NotNull ValueAdapter<V> adapter) {
super(manifest); super(manifest);
this.adapter = adapter; this.adapter = adapter;
} }
@@ -97,18 +137,19 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
if (!cacheExpired()) return getCachedOrDefault(); if (!cacheExpired()) return getCachedOrDefault();
// Data that is outdated and needs to be parsed again. // Data that is outdated and needs to be parsed again.
try {
Object data = getData(); Object data = getData();
if (data == null) return defaults(); if (data == null) return defaults();
ValueParser<V> parser = parser(); ValueParser<V> parser = parser();
if (parser == null) return defaults(); // No parser, return default value. if (parser == null) return defaults(); // No parser, return default value.
try {
// If there are no errors, update the cache and return. // If there are no errors, update the cache and return.
return updateCache(parser.parse(holder(), type(), data)); V parsed = parser.parse(holder(), type(), data);
return updateCache(withValidated(parsed));
} catch (Exception e) { } catch (Exception e) {
// There was a parsing error, prompted and returned the default value. // There was a validate or parsing error, prompted and returned the default value.
e.printStackTrace(); throwing(e);
return defaults(); return defaults();
} }
@@ -121,20 +162,20 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
* @param value The value to be set * @param value The value to be set
*/ */
@Override @Override
public void set(V value) { public void set(@Nullable V value) {
updateCache(value); // Update cache updateCache(value); // Update cache
if (value == null) { if (value == null) {
setData(null); setData(null);
return; return;
} }
try {
ValueSerializer<V> serializer = serializer(); ValueSerializer<V> serializer = serializer();
if (serializer == null) return; // No serializer, do nothing. if (serializer == null) return; // No serializer, do nothing.
try { setData(serializer.serialize(holder(), type(), withValidated(value)));
setData(serializer.serialize(holder(), type(), value));
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); throwing(e);
} }
} }
@@ -9,7 +9,7 @@
//import java.util.LinkedList; //import java.util.LinkedList;
//import java.util.List; //import java.util.List;
// //
///** /// **
// * @author Chris2018998 // * @author Chris2018998
// */ // */
//public class OffsetUtil { //public class OffsetUtil {
@@ -25,15 +25,15 @@
// } catch (NoSuchFieldException | IllegalAccessException e) { // } catch (NoSuchFieldException | IllegalAccessException e) {
// e.printStackTrace(); // e.printStackTrace();
// } // }
//// try { /// / try {
//// unsafe = AccessController.doPrivileged((PrivilegedExceptionAction<Unsafe>) () -> { /// / unsafe = AccessController.doPrivileged((PrivilegedExceptionAction<Unsafe>) () -> {
//// Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); /// / Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
//// theUnsafe.setAccessible(true); /// / theUnsafe.setAccessible(true);
//// return (Unsafe) theUnsafe.get(null); /// / return (Unsafe) theUnsafe.get(null);
//// }); /// / });
//// } catch (Throwable e) { /// / } catch (Throwable e) {
//// System.err.println("Unable to load unsafe"); /// / System.err.println("Unable to load unsafe");
//// } /// / }
// } // }
// //
// public static List<FieldOffset> getClassMemberOffset(Class<?> beanClass) { // public static List<FieldOffset> getClassMemberOffset(Class<?> beanClass) {
+164 -13
View File
@@ -3,9 +3,9 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>4.0.11</version> <version>4.1.7</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<properties> <properties>
@@ -13,41 +13,127 @@
<maven.compiler.target>${project.jdk.version}</maven.compiler.target> <maven.compiler.target>${project.jdk.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<maven.javadoc.skip>true</maven.javadoc.skip>
<maven.deploy.skip>true</maven.deploy.skip>
<deps.mysql-driver.version>8.0.33</deps.mysql-driver.version>
<log4j.version>2.25.0</log4j.version>
</properties> </properties>
<artifactId>easyconfiguration-demo</artifactId> <artifactId>configured-demo</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-commentable</artifactId> <artifactId>configured-feature-commentable</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-versioned</artifactId> <artifactId>configured-feature-versioned</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> </dependency>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>configured-feature-validators</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>configured-feature-kotlin</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>configured-yaml</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>configured-gson</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>configured-sql</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easysql-beecp</artifactId>
<version>0.4.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${deps.mysql-driver.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>configured-mongodb</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>configured-hocon</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j.version}</version>
<scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
@@ -60,6 +146,71 @@
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sourceDirs>
<source>src/main/java</source>
<source>target/generated-sources/annotations</source>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<jvmTarget>1.8</jvmTarget>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</build> </build>
@@ -3,7 +3,6 @@ package cc.carm.lib.configuration.demo;
import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.annotation.ConfigPath; import cc.carm.lib.configuration.annotation.ConfigPath;
import cc.carm.lib.configuration.annotation.HeaderComments; import cc.carm.lib.configuration.annotation.HeaderComments;
import cc.carm.lib.configuration.value.ConfigValue;
import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue;
@HeaderComments({"", "数据库配置", " 用于提供数据库连接,进行数据库操作。"}) @HeaderComments({"", "数据库配置", " 用于提供数据库连接,进行数据库操作。"})
@@ -16,17 +15,17 @@ public interface DatabaseConfiguration extends Configuration {
"- MySQL(新): com.mysql.cj.jdbc.Driver", "- MySQL(新): com.mysql.cj.jdbc.Driver",
"- MariaDB(推荐): org.mariadb.jdbc.Driver", "- MariaDB(推荐): org.mariadb.jdbc.Driver",
}) })
ConfigValue<String> DRIVER_NAME = ConfiguredValue.of( ConfiguredValue<String> DRIVER_NAME = ConfiguredValue.of(
String.class, "com.mysql.cj.jdbc.Driver" String.class, "com.mysql.cj.jdbc.Driver"
); );
ConfigValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1"); ConfiguredValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1");
ConfigValue<Integer> PORT = ConfiguredValue.of(Integer.class, 3306); ConfiguredValue<Integer> PORT = ConfiguredValue.of(Integer.class, 3306);
ConfigValue<String> DATABASE = ConfiguredValue.of(String.class, "minecraft"); ConfiguredValue<String> DATABASE = ConfiguredValue.of(String.class, "minecraft");
ConfigValue<String> USERNAME = ConfiguredValue.of(String.class, "root"); ConfiguredValue<String> USERNAME = ConfiguredValue.of(String.class, "root");
ConfigValue<String> PASSWORD = ConfiguredValue.of(String.class, "password"); ConfiguredValue<String> PASSWORD = ConfiguredValue.of(String.class, "password");
ConfigValue<String> EXTRA = ConfiguredValue.of(String.class, "?useSSL=false"); ConfiguredValue<String> EXTRA = ConfiguredValue.of(String.class, "?useSSL=false");
static String buildJDBC() { static String buildJDBC() {
return String.format("jdbc:mysql://%s:%s/%s%s", HOST.get(), PORT.get(), DATABASE.get(), EXTRA.get()); return String.format("jdbc:mysql://%s:%s/%s%s", HOST.get(), PORT.get(), DATABASE.get(), EXTRA.get());
@@ -1,11 +1,13 @@
package cc.carm.lib.configuration.demo.tests; package cc.carm.lib.configuration.demo.tests;
import cc.carm.lib.configuration.demo.tests.conf.DemoConfiguration; import cc.carm.lib.configuration.demo.tests.conf.DemoConfiguration;
import cc.carm.lib.configuration.demo.tests.conf.KotlinConfiguration;
import cc.carm.lib.configuration.demo.tests.conf.RegistryConfig; import cc.carm.lib.configuration.demo.tests.conf.RegistryConfig;
import cc.carm.lib.configuration.demo.tests.model.UserRecord; import cc.carm.lib.configuration.demo.tests.model.UserRecord;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.TestOnly; import org.jetbrains.annotations.TestOnly;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -80,6 +82,22 @@ public class ConfigurationTest {
} }
public static void testKotlin(ConfigurationHolder<?> provider) {
provider.initialize(KotlinConfiguration.class);
System.out.println("> Test Kotlin value before:");
System.out.println(KotlinConfiguration.INSTANCE.getLINKED_MAP().get());
LinkedHashMap<String, String> map = new LinkedHashMap<>();
map.put("Language", "Kotlin");
System.out.println("> Test Kotlin value -> " + map);
KotlinConfiguration.INSTANCE.getLINKED_MAP().set(map);
System.out.println("> Test Kotlin value after:");
System.out.println(KotlinConfiguration.INSTANCE.getLINKED_MAP().get());
}
public static void save(ConfigurationHolder<?> provider) { public static void save(ConfigurationHolder<?> provider) {
try { try {
provider.save(); provider.save();
@@ -4,7 +4,6 @@ import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.annotation.*; import cc.carm.lib.configuration.annotation.*;
import cc.carm.lib.configuration.demo.tests.model.ItemStack; import cc.carm.lib.configuration.demo.tests.model.ItemStack;
import cc.carm.lib.configuration.demo.tests.model.UserRecord; import cc.carm.lib.configuration.demo.tests.model.UserRecord;
import cc.carm.lib.configuration.value.ConfigValue;
import cc.carm.lib.configuration.value.standard.ConfiguredList; import cc.carm.lib.configuration.value.standard.ConfiguredList;
import cc.carm.lib.configuration.value.standard.ConfiguredMap; import cc.carm.lib.configuration.value.standard.ConfiguredMap;
import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue;
@@ -20,21 +19,21 @@ import java.util.UUID;
"------------------------------------------------", "------------------------------------------------",
"此处内容将显示在配置文件的最下方", "此处内容将显示在配置文件的最下方",
"可用于显示版权信息等", "可用于显示版权信息等",
"感谢您使用 https://github.com/CarmJos/EasyConfiguration !" "感谢您使用 https://github.com/CarmJos/configured !"
}) })
public interface DemoConfiguration extends Configuration { public interface DemoConfiguration extends Configuration {
@ConfigPath(root = true) @ConfigPath(root = true)
@ConfigVersion(2) @ConfigVersion(2)
ConfigValue<Double> VERSION = ConfiguredValue.of(Double.class, 2.0D); ConfiguredValue<Double> VERSION = ConfiguredValue.of(Double.class, 2.0D);
@ConfigPath(root = true) @ConfigPath(root = true)
@FooterComments({"此处内容将显示在配置条目的下方", "可用于补充说明,但一般不建议使用"}) @FooterComments({"此处内容将显示在配置条目的下方", "可用于补充说明,但一般不建议使用"})
ConfigValue<Long> TEST_NUMBER = ConfiguredValue.of(1000000L); ConfiguredValue<Long> TEST_NUMBER = ConfiguredValue.with(Long.class).defaults(123456789L).build();
@HeaderComments({"枚举类型测试"}) @HeaderComments({"枚举类型测试"})
@FooterComments({"上述的枚举内容本质上是通过STRING解析的"}) @FooterComments({"上述的枚举内容本质上是通过STRING解析的"})
ConfigValue<ChronoUnit> TEST_ENUM = ConfiguredValue.of(ChronoUnit.class, ChronoUnit.DAYS); ConfiguredValue<ChronoUnit> TEST_ENUM = ConfiguredValue.of(ChronoUnit.class, ChronoUnit.DAYS);
@HeaderComments({"空值测试"}) @HeaderComments({"空值测试"})
@InlineComment("空值Inline注释") @InlineComment("空值Inline注释")
@@ -72,7 +71,7 @@ public interface DemoConfiguration extends Configuration {
class SUB implements Configuration { class SUB implements Configuration {
@ConfigPath(value = "uuid-value", root = true) @ConfigPath(value = "uuid-value", root = true)
public static final ConfigValue<UUID> UUID_CONFIG_VALUE = ConfiguredValue public static final ConfiguredValue<UUID> UUID_CONFIG_VALUE = ConfiguredValue
.builderOf(UUID.class).fromString() .builderOf(UUID.class).fromString()
.parse((holder, data) -> UUID.fromString(data)) .parse((holder, data) -> UUID.fromString(data))
.build(); .build();
@@ -2,12 +2,13 @@ package cc.carm.lib.configuration.demo.tests.conf;
import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.annotation.HeaderComments; import cc.carm.lib.configuration.annotation.HeaderComments;
import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.annotation.ValueRange;
import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue;
@HeaderComments("Inner Test") @HeaderComments("service")
public class InstanceConfig implements Configuration { public class InstanceConfig implements Configuration {
public final ConfigValue<Double> STATUS = ConfiguredValue.of(1.0D); @ValueRange(min = 0, max = 100, message = "The value must be between 0 and 100")
public final ConfiguredValue<Double> STATUS = ConfiguredValue.of(1.0D);
} }
@@ -0,0 +1,32 @@
package cc.carm.lib.configuration.demo.tests.conf
import cc.carm.lib.configuration.Configuration
import cc.carm.lib.configuration.annotation.ConfigPath
import cc.carm.lib.configuration.annotation.ConfigVersion
import cc.carm.lib.configuration.kotlin.value.*
@ConfigPath(root = true)
object KotlinConfiguration : Configuration {
@ConfigVersion(1)
val VERSION = valueFrom(Double::class) {
defaults(1.0)
}
val USER_LIST = listFrom(String::class) {
defaults("Carm Jos")
}
val NICKNAME = mapFrom(String::class, ::mutableMapOf) {
defaultMap(mapOf("Carm Jos" to "Carm"))
parse { v -> v }
serialize { v -> v }
}
val LINKED_MAP = linkedMapFrom(String::class) {
parse { value ->
value
}
serialize { v -> v }
defaults("key", "value")
}
}
@@ -6,7 +6,6 @@ import cc.carm.lib.configuration.annotation.FooterComments;
import cc.carm.lib.configuration.annotation.HeaderComments; import cc.carm.lib.configuration.annotation.HeaderComments;
import cc.carm.lib.configuration.annotation.InlineComment; import cc.carm.lib.configuration.annotation.InlineComment;
import cc.carm.lib.configuration.demo.tests.model.UserRecord; import cc.carm.lib.configuration.demo.tests.model.UserRecord;
import cc.carm.lib.configuration.value.ConfigValue;
import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue;
import java.util.UUID; import java.util.UUID;
@@ -20,7 +19,7 @@ public class RegistryConfig implements Configuration {
@FooterComments({"12313213212"}) @FooterComments({"12313213212"})
@InlineComment(value = "用户名(匹配注释)", regex = "name") // 通过注解给配置添加注释。 @InlineComment(value = "用户名(匹配注释)", regex = "name") // 通过注解给配置添加注释。
@InlineComment(value = "信息", regex = {"info.*", "info.game.*"}) // 通过注解给配置添加注释。 @InlineComment(value = "信息", regex = {"info.*", "info.game.*"}) // 通过注解给配置添加注释。
public final ConfigValue<UserRecord> OWNER = ConfiguredValue.builderOf(UserRecord.class).fromSection() public final ConfiguredValue<UserRecord> OWNER = ConfiguredValue.builderOf(UserRecord.class).fromSection()
.defaults(new UserRecord("Carm", UUID.randomUUID())) .defaults(new UserRecord("Carm", UUID.randomUUID()))
.parse((holder, section) -> UserRecord.deserialize(section)) .parse((holder, section) -> UserRecord.deserialize(section))
.serialize((holder, data) -> data.serialize()).build(); .serialize((holder, data) -> data.serialize()).build();
@@ -33,11 +33,11 @@ public class ItemStack {
return amount; return amount;
} }
public String getName() { public @Nullable String getName() {
return name; return name;
} }
public List<String> getLore() { public @Nullable List<String> getLore() {
return lore; return lore;
} }
@@ -49,11 +49,11 @@ public class ItemStack {
this.amount = amount; this.amount = amount;
} }
public void setName(String name) { public void setName(@Nullable String name) {
this.name = name; this.name = name;
} }
public void setLore(List<String> lore) { public void setLore(@Nullable List<String> lore) {
this.lore = lore; this.lore = lore;
} }
@@ -1,15 +1,13 @@
package config; package cc.carm.lib.configuration.tests.test;
import cc.carm.lib.configuration.demo.tests.ConfigurationTest; import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
import cc.carm.lib.configuration.source.json.JSONConfigFactory;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.source.json.JSONConfigFactory;
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
import org.junit.Test; import org.junit.Test;
import java.io.File; import java.io.File;
public class JSONConfigTest { public class JSONConfigTests {
protected final ConfigurationHolder<?> holder = JSONConfigFactory protected final ConfigurationHolder<?> holder = JSONConfigFactory
.from(new File("target"), "config.json") .from(new File("target"), "config.json")
@@ -18,12 +16,6 @@ public class JSONConfigTest {
@Test @Test
public void onTest() { public void onTest() {
ConfigValue<Boolean> EXAMPLE = ConfiguredValue.of(false);
EXAMPLE.initialize(this.holder, "example");
System.out.println("Example: " + EXAMPLE.get());
ConfigurationTest.testDemo(this.holder); ConfigurationTest.testDemo(this.holder);
ConfigurationTest.testInner(this.holder); ConfigurationTest.testInner(this.holder);
@@ -1,11 +1,11 @@
package yaml.test; package cc.carm.lib.configuration.tests.test;
import cc.carm.lib.configuration.commentable.Commentable;
import cc.carm.lib.configuration.commentable.CommentableMeta; import cc.carm.lib.configuration.commentable.CommentableMeta;
import cc.carm.lib.configuration.demo.tests.ConfigurationTest; import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.yaml.YAMLConfigFactory; import cc.carm.lib.configuration.source.yaml.YAMLConfigFactory;
import cc.carm.lib.configuration.source.yaml.YAMLSource; import cc.carm.lib.configuration.source.yaml.YAMLSource;
import cc.carm.lib.configuration.validators.Validators;
import org.junit.Test; import org.junit.Test;
import java.util.List; import java.util.List;
@@ -14,11 +14,13 @@ import java.util.Map;
public class YamlTests { public class YamlTests {
@Test @Test
public void test() { public void test() throws Exception {
ConfigurationHolder<YAMLSource> holder = YAMLConfigFactory.from("target/tests.yml") ConfigurationHolder<YAMLSource> holder = YAMLConfigFactory.from("target/tests.yml")
.resourcePath("configs/sample.yml").build(); .resourcePath("configs/sample.yml").build();
Validators.activate(holder);
ConfigurationTest.testDemo(holder); ConfigurationTest.testDemo(holder);
ConfigurationTest.testInner(holder); ConfigurationTest.testInner(holder);
@@ -42,5 +44,13 @@ public class YamlTests {
ConfigurationTest.save(holder); ConfigurationTest.save(holder);
} }
@Test
public void testKotlin() {
ConfigurationHolder<YAMLSource> holder = YAMLConfigFactory.from("target/kotlin.yml").build();
ConfigurationTest.testKotlin(holder);
ConfigurationTest.save(holder);
}
} }
@@ -1,4 +1,4 @@
package config; package cc.carm.lib.configuration.tests.test.mongodb;
import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue;
@@ -1,4 +1,4 @@
package config; package cc.carm.lib.configuration.tests.test.mongodb;
import cc.carm.lib.configuration.demo.tests.ConfigurationTest; import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
@@ -1,4 +1,4 @@
package config; package cc.carm.lib.configuration.tests.test.sql;
import cc.carm.lib.configuration.demo.DatabaseConfiguration; import cc.carm.lib.configuration.demo.DatabaseConfiguration;
import cc.carm.lib.configuration.demo.tests.ConfigurationTest; import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="config.SQLConfigTest"> <Configuration status="WARN" packages="cc.carm.lib.configuration.tests">
<Appenders> <Appenders>
<console name="Console" target="SYSTEM_OUT"> <console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg%n"/> <PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg%n"/>
+4 -4
View File
@@ -5,8 +5,8 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<version>4.0.11</version> <version>4.1.7</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -16,13 +16,13 @@
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties> </properties>
<artifactId>easyconfiguration-feature-commentable</artifactId> <artifactId>configured-feature-commentable</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
+4 -4
View File
@@ -5,8 +5,8 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<version>4.0.11</version> <version>4.1.7</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -16,13 +16,13 @@
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties> </properties>
<artifactId>easyconfiguration-feature-file</artifactId> <artifactId>configured-feature-file</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
@@ -1,7 +1,5 @@
package cc.carm.lib.configuration.source.option; package cc.carm.lib.configuration.source.option;
import cc.carm.lib.configuration.source.option.ConfigurationOption;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
+120
View File
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-parent</artifactId>
<version>4.1.7</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<kotlin.version>2.2.0</kotlin.version>
</properties>
<artifactId>configured-feature-kotlin</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>configured-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<jvmTarget>1.8</jvmTarget>
</configuration>
</plugin>
<plugin>
<groupId>org.jetbrains.dokka</groupId>
<artifactId>dokka-maven-plugin</artifactId>
<version>2.0.0</version>
<executions>
<execution>
<phase>pre-site</phase>
<goals>
<goal>dokka</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,29 @@
package cc.carm.lib.configuration.kotlin.value
import cc.carm.lib.configuration.adapter.ValueType
import cc.carm.lib.configuration.builder.list.SourceListBuilder
import cc.carm.lib.configuration.value.standard.ConfiguredList
import kotlin.reflect.KClass
inline fun <S : Any, reified V> listFrom(
clazz: KClass<S>, block: (SourceListBuilder<S, V>.() -> Unit)
): ConfiguredList<V> {
return listFrom(clazz.java, block)
}
inline fun <S : Any, reified V> listFrom(
clazz: Class<S>, block: (SourceListBuilder<S, V>.() -> Unit)
): ConfiguredList<V> {
return listFrom(ValueType.of(clazz), block)
}
inline fun <S : Any, reified V> listFrom(
valueType: ValueType<S>, block: (SourceListBuilder<S, V>.() -> Unit)
): ConfiguredList<V> {
val configBuilder = ConfiguredList.builderOf(V::class.java)
val sourceValueBuilder: SourceListBuilder<S, V> = if (valueType.rawType == String::class.java) {
@Suppress("UNCHECKED_CAST")
configBuilder.fromString() as SourceListBuilder<S, V>
} else configBuilder.from(valueType)
return sourceValueBuilder.also(block).build()
}
@@ -0,0 +1,107 @@
package cc.carm.lib.configuration.kotlin.value
import cc.carm.lib.configuration.adapter.ValueType
import cc.carm.lib.configuration.builder.map.SourceMapBuilder
import cc.carm.lib.configuration.value.standard.ConfiguredMap
import java.util.*
import kotlin.reflect.KClass
inline fun <S : Any, reified K, reified V> hashmapFrom(
clazz: KClass<S>,
block: SourceMapBuilder<HashMap<K, V>, S, K, V>.() -> Unit
): ConfiguredMap<K, V> {
return hashmapFrom(clazz.java, block)
}
inline fun <S : Any, reified K, reified V> hashmapFrom(
clazz: Class<S>,
block: SourceMapBuilder<HashMap<K, V>, S, K, V>.() -> Unit
): ConfiguredMap<K, V> {
return hashmapFrom(ValueType.of(clazz), block)
}
inline fun <S : Any, reified K, reified V> hashmapFrom(
valueType: ValueType<S>,
block: SourceMapBuilder<HashMap<K, V>, S, K, V>.() -> Unit
): ConfiguredMap<K, V> {
val mapCreator = ConfiguredMap.builderOf(K::class.java, V::class.java)
val sourceValueBuilder: SourceMapBuilder<HashMap<K, V>, S, K, V> = mapCreator.asHashMap().from(valueType)
return sourceValueBuilder.also(block).build()
}
inline fun <S : Any, reified K, reified V> linkedMapFrom(
clazz: KClass<S>,
block: SourceMapBuilder<LinkedHashMap<K, V>, S, K, V>.() -> Unit
): ConfiguredMap<K, V> {
return linkedMapFrom(clazz.java, block)
}
inline fun <S : Any, reified K, reified V> linkedMapFrom(
clazz: Class<S>,
block: SourceMapBuilder<LinkedHashMap<K, V>, S, K, V>.() -> Unit
): ConfiguredMap<K, V> {
return linkedMapFrom(ValueType.of(clazz), block)
}
inline fun <S : Any, reified K, reified V> linkedMapFrom(
valueType: ValueType<S>,
block: SourceMapBuilder<LinkedHashMap<K, V>, S, K, V>.() -> Unit
): ConfiguredMap<K, V> {
val mapCreator = ConfiguredMap.builderOf(K::class.java, V::class.java)
val sourceValueBuilder: SourceMapBuilder<LinkedHashMap<K, V>, S, K, V> = mapCreator.asLinkedMap().from(valueType)
return sourceValueBuilder.also(block).build()
}
inline fun <S : Any, reified K, reified V> treeMapFrom(
clazz: KClass<S>,
block: SourceMapBuilder<TreeMap<K, V>, S, K, V>.() -> Unit
): ConfiguredMap<K, V> {
return treeMapFrom(clazz.java, block)
}
inline fun <S : Any, reified K, reified V> treeMapFrom(
clazz: Class<S>,
block: SourceMapBuilder<TreeMap<K, V>, S, K, V>.() -> Unit
): ConfiguredMap<K, V> {
return treeMapFrom(ValueType.of(clazz), block)
}
inline fun <S : Any, reified K, reified V> treeMapFrom(
valueType: ValueType<S>,
block: SourceMapBuilder<TreeMap<K, V>, S, K, V>.() -> Unit
): ConfiguredMap<K, V> {
val mapCreator = ConfiguredMap.builderOf(K::class.java, V::class.java)
val sourceValueBuilder: SourceMapBuilder<TreeMap<K, V>, S, K, V> = mapCreator.asTreeMap().from(valueType)
return sourceValueBuilder.also(block).build()
}
inline fun <reified MAP : Map<K, V>, S : Any, reified K, reified V> mapFrom(
clazz: KClass<S>,
noinline map: () -> MAP,
block: SourceMapBuilder<MAP, S, K, V>.() -> Unit
): ConfiguredMap<K, V> {
return mapFrom(clazz.java, map, block)
}
inline fun <reified MAP : Map<K, V>, S : Any, reified K, reified V> mapFrom(
clazz: Class<S>,
noinline map: () -> MAP,
block: SourceMapBuilder<MAP, S, K, V>.() -> Unit
): ConfiguredMap<K, V> {
return mapFrom(ValueType.of(clazz), map, block)
}
inline fun <reified MAP : Map<K, V>, S : Any, reified K, reified V> mapFrom(
valueType: ValueType<S>,
noinline map: () -> MAP,
block: SourceMapBuilder<MAP, S, K, V>.() -> Unit
): ConfiguredMap<K, V> {
val mapCreator = ConfiguredMap.builderOf(K::class.java, V::class.java)
val sourceValueBuilder: SourceMapBuilder<MAP, S, K, V> = mapCreator.constructor(map).from(valueType)
return sourceValueBuilder.also(block).build()
}
fun <MAP : Map<K, V>, S, K, V> SourceMapBuilder<MAP, S, K, V>.defaultMap(map: MAP): SourceMapBuilder<MAP, S, K, V> {
return defaults(map)
}
@@ -0,0 +1,36 @@
package cc.carm.lib.configuration.kotlin.value
import cc.carm.lib.configuration.adapter.ValueType
import cc.carm.lib.configuration.builder.value.SourceValueBuilder
import cc.carm.lib.configuration.value.standard.ConfiguredValue
import kotlin.reflect.KClass
inline fun <S : Any, reified T> valueFrom(
clazz: KClass<S>, block: (SourceValueBuilder<S, T>.() -> Unit)
): ConfiguredValue<T> {
return valueFrom(clazz.java, block)
}
inline fun <S : Any, reified V> valueFrom(
clazz: Class<S>, block: (SourceValueBuilder<S, V>.() -> Unit)
): ConfiguredValue<V> {
return valueFrom(ValueType.of(clazz), block)
}
inline fun <S : Any, reified V> valueFrom(
valueType: ValueType<S>, block: (SourceValueBuilder<S, V>.() -> Unit)
): ConfiguredValue<V> {
val configBuilder = ConfiguredValue.builderOf(V::class.java)
val sourceValueBuilder: SourceValueBuilder<S, V> = if (valueType.rawType == String::class.java) {
@Suppress("UNCHECKED_CAST")
configBuilder.fromString() as SourceValueBuilder<S, V>
} else configBuilder.from(valueType)
sourceValueBuilder.parse { holder, data ->
holder.deserialize(V::class.java, data)
}
sourceValueBuilder.serialize { holder, data ->
@Suppress("UNCHECKED_CAST")
holder.serialize(data) as? S
}
return sourceValueBuilder.also(block).build()
}
+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());
}
}
}
}
+4 -4
View File
@@ -5,8 +5,8 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<version>4.0.11</version> <version>4.1.7</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -16,13 +16,13 @@
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties> </properties>
<artifactId>easyconfiguration-feature-section</artifactId> <artifactId>configured-feature-section</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
@@ -74,7 +74,7 @@ public class ImmutableSection implements ConfigureSection {
@Override @Override
public @Nullable ConfigureSection getSection(@NotNull String path) { public @Nullable ConfigureSection getSection(@NotNull String path) {
ConfigureSection get = raw().getSection(path); ConfigureSection get = raw().getSection(path);
if (get != null && !(get instanceof ImmutableSection)) { if (!(get instanceof ImmutableSection)) {
return new ImmutableSection(this, get); return new ImmutableSection(this, get);
} }
return get; return get;
@@ -166,12 +166,12 @@ public class ImmutableSection implements ConfigureSection {
} }
@Override @Override
public <T> @Nullable T get(@NotNull String path, @Nullable T defaults, @NotNull Class<T> clazz) { public <T> @Nullable T get(@NotNull String path, T defaults, @NotNull Class<T> clazz) {
return raw().get(path, defaults, clazz); return raw().get(path, defaults, clazz);
} }
@Override @Override
public <T> @Nullable T get(@NotNull String path, @Nullable T defaultValue, @NotNull DataFunction<Object, T> parser) { public <T> @Nullable T get(@NotNull String path, T defaultValue, @NotNull DataFunction<Object, T> parser) {
return raw().get(path, defaultValue, parser); return raw().get(path, defaultValue, parser);
} }
@@ -350,6 +350,11 @@ public class ImmutableSection implements ConfigureSection {
return raw().getCharList(path); return raw().getCharList(path);
} }
@Override
public @NotNull List<ConfigureSection> getSectionList(@NotNull String path) {
return raw().getSectionList(path);
}
@Override @Override
public <T, C extends Collection<T>> @NotNull C getCollection(@NotNull String path, @NotNull Supplier<C> constructor, @NotNull DataFunction<Object, T> parser) { public <T, C extends Collection<T>> @NotNull C getCollection(@NotNull String path, @NotNull Supplier<C> constructor, @NotNull DataFunction<Object, T> parser) {
return raw().getCollection(path, constructor, parser); return raw().getCollection(path, constructor, parser);
+5 -5
View File
@@ -5,8 +5,8 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<version>4.0.11</version> <version>4.1.7</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -16,20 +16,20 @@
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties> </properties>
<artifactId>easyconfiguration-feature-text</artifactId> <artifactId>configured-feature-text</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>easyconfiguration-gson</artifactId> <artifactId>configured-gson</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@@ -7,7 +7,6 @@ import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.ValueManifest;
import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue;
import cc.carm.lib.configuration.value.text.data.TextContents; import cc.carm.lib.configuration.value.text.data.TextContents;
import cc.carm.lib.configuration.value.text.function.TextDispatcher;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -22,7 +21,7 @@ import java.util.function.Consumer;
*/ */
public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents> { public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents> {
public static <M, R> Builder<M, R, ?> builder() { public static <M, R> Builder<M, R, ?> create() {
return new StardardBuilder<>(); return new StardardBuilder<>();
} }
@@ -38,7 +37,7 @@ public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents>
protected final @NotNull String[] params; // The parameters of the message. protected final @NotNull String[] params; // The parameters of the message.
public ConfiguredText(@NotNull ValueManifest<TextContents> manifest, public ConfiguredText(@NotNull ValueManifest<TextContents, TextContents> manifest,
@NotNull BiFunction<RECEIVER, String, String> parser, @NotNull BiFunction<RECEIVER, String, String> parser,
@NotNull BiFunction<RECEIVER, String, MSG> compiler, @NotNull BiFunction<RECEIVER, String, MSG> compiler,
@NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher, @NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher,
@@ -50,7 +49,7 @@ public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents>
this.params = params; this.params = params;
} }
public TextDispatcher<MSG, RECEIVER, ?> prepare(@NotNull Object... values) { public PreparedText<MSG, RECEIVER> prepare(@NotNull Object... values) {
return new PreparedText<MSG, RECEIVER>(resolve(), this.params) return new PreparedText<MSG, RECEIVER>(resolve(), this.params)
.parser(this.parser).compiler(this.compiler) .parser(this.parser).compiler(this.compiler)
.dispatcher(this.dispatcher).placeholders(values); .dispatcher(this.dispatcher).placeholders(values);
@@ -121,7 +120,7 @@ public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents>
} }
public abstract static class Builder<MSG, RECEIVER, SELF extends Builder<MSG, RECEIVER, SELF>> public abstract static class Builder<MSG, RECEIVER, SELF extends Builder<MSG, RECEIVER, SELF>>
extends AbstractConfigBuilder<TextContents, ConfiguredText<MSG, RECEIVER>, ConfigurationHolder<?>, SELF> { extends AbstractConfigBuilder<TextContents, TextContents, ConfiguredText<MSG, RECEIVER>, ConfigurationHolder<?>, SELF> {
protected @NotNull TextContents.Builder defaultBuilder = TextContents.builder(); protected @NotNull TextContents.Builder defaultBuilder = TextContents.builder();
protected @NotNull String[] params = new String[0]; protected @NotNull String[] params = new String[0];
@@ -1,52 +1,27 @@
package cc.carm.lib.configuration.value.text.function; package cc.carm.lib.configuration.value.text.function;
import cc.carm.lib.configuration.value.text.data.TextContents; import cc.carm.lib.configuration.value.text.data.TextContents;
import cc.carm.lib.configuration.value.text.function.common.AppendLineInserter;
import cc.carm.lib.configuration.value.text.function.common.OptionalLineInserter;
import cc.carm.lib.configuration.value.text.function.common.ParamReplacer;
import cc.carm.lib.configuration.value.text.function.inserter.ContentInserter;
import cc.carm.lib.configuration.value.text.function.inserter.Insertable;
import cc.carm.lib.configuration.value.text.function.replacer.ContentReplacer;
import cc.carm.lib.configuration.value.text.function.replacer.Replaceable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.*; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.IntStream;
public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEIVER, SELF>> { public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEIVER, SELF>>
implements Replaceable<RECEIVER, SELF>, Insertable<RECEIVER, SELF> {
/**
* Used to match the message insertion.
* <p>
* format:
* <br>- to insert parsed line {prefix}#content-id#{offset-above,offset-down}
* <br>- to insert original line {prefix}@content-id@{offset-above,offset-down}
* <br> original lines will not be parsed
* <br> example:
* <ul>
* <li>{- }#content-id#{1,1}</li>
* <li>@content-id@{1,1}</li>
* </ul>
*/
public static final @NotNull Pattern INSERT_PATTERN = Pattern.compile(
"^(?:\\{(?<prefix>.*)})?(?<type>[#@])(?<id>.*)[#@](?:\\{(?<above>-?\\d+)(?:,(?<down>-?\\d+))?})?$"
);
/**
* Used to match the message which can be inserted
* <p>
* format:
* <br>- ?[id]Message content
* <br> example:
* <ul>
* <li>?[click]Click to use this item!</li>
* </ul>
*/
public static final @NotNull Pattern ENABLE_PATTERN = Pattern.compile(
"^\\?\\[(?<id>.+)](?<content>.*)$"
);
public static final @NotNull UnaryOperator<String> DEFAULT_PARAM_BUILDER = s -> "%(" + s + ")";
protected BiFunction<RECEIVER, String, String> parser = (receiver, value) -> value; protected BiFunction<RECEIVER, String, String> parser = (receiver, value) -> value;
protected String lineSeparator = System.lineSeparator(); protected String lineSeparator = System.lineSeparator();
@@ -54,16 +29,24 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
/** /**
* Used to store the placeholders of the message * Used to store the placeholders of the message
*/ */
protected @NotNull Map<String, Object> placeholders = new HashMap<>(); protected @NotNull ParamReplacer<RECEIVER> paramReplacer = ParamReplacer.defaults();
protected @NotNull UnaryOperator<String> paramFormatter = DEFAULT_PARAM_BUILDER;
protected @NotNull String[] params; protected @NotNull String[] params;
protected @NotNull List<ContentReplacer<RECEIVER>> replacers = new ArrayList<>();
protected @NotNull List<ContentInserter<RECEIVER>> inserters = new ArrayList<>();
/** /**
* Used to store the insertion of the message * Used to store the insertion of the message
*/ */
protected @NotNull Map<String, @Nullable Function<RECEIVER, List<String>>> insertion = new HashMap<>(); protected final @NotNull Map<String, @Nullable Function<RECEIVER, List<String>>> insertion = new HashMap<>();
protected boolean disableInsertion = false; protected boolean disableInsertion = false;
public ContentHandler() {
inserters.add(new AppendLineInserter<>(0));
inserters.add(new OptionalLineInserter<>(0));
}
public abstract SELF self(); public abstract SELF self();
/** /**
@@ -87,6 +70,11 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
return self(); return self();
} }
@Override
public boolean noneInsertion() {
return this.insertion.isEmpty();
}
/** /**
* Set the line separator for the text. * Set the line separator for the text.
* *
@@ -106,7 +94,7 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
* @return the current {@link ContentHandler} instance * @return the current {@link ContentHandler} instance
*/ */
public SELF placeholders(@NotNull Map<String, Object> placeholders) { public SELF placeholders(@NotNull Map<String, Object> placeholders) {
this.placeholders = placeholders; this.paramReplacer.set(placeholders);
return self(); return self();
} }
@@ -117,7 +105,7 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
* @return the current {@link ContentHandler} instance * @return the current {@link ContentHandler} instance
*/ */
public SELF placeholders(@NotNull Consumer<Map<String, Object>> consumer) { public SELF placeholders(@NotNull Consumer<Map<String, Object>> consumer) {
consumer.accept(this.placeholders); consumer.accept(this.paramReplacer.placeholders());
return self(); return self();
} }
@@ -128,7 +116,8 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
* @return the current {@link ContentHandler} instance * @return the current {@link ContentHandler} instance
*/ */
public SELF placeholders(@Nullable Object... values) { public SELF placeholders(@Nullable Object... values) {
return placeholders(map -> map.putAll(buildParams(this.paramFormatter, this.params, values))); this.paramReplacer.putAll(this.params, values);
return self();
} }
/** /**
@@ -139,7 +128,7 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
* @return the current {@link ContentHandler} instance * @return the current {@link ContentHandler} instance
*/ */
public SELF placeholder(@NotNull String key, @Nullable Object value) { public SELF placeholder(@NotNull String key, @Nullable Object value) {
this.placeholders.put(paramFormatter.apply(key), value); this.paramReplacer.put(key, value);
return self(); return self();
} }
@@ -155,49 +144,57 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
return self(); return self();
} }
/** @Override
* Insert the specific contents by the id. public List<ContentReplacer<RECEIVER>> replacers() {
* return this.replacers;
* @param id the id of the insertion text }
* @return the current {@link ContentHandler} instance
*/ @Override
public SELF insert(@NotNull String id) { public SELF replacer(@NotNull ContentReplacer<RECEIVER> replacer) {
this.insertion.put(id, null); this.replacers.add(replacer);
this.replacers.sort(ContentReplacer::compareTo);
return self(); return self();
} }
/** public SELF paramReplacer(@NotNull ParamReplacer<RECEIVER> paramReplacer) {
* Insert the specific contents by the id. this.paramReplacer = paramReplacer;
*
* @param id the id of the insertion text
* @param linesSupplier to supply the lines to insert
* @return the current {@link ContentHandler} instance
*/
public SELF insert(@NotNull String id, @NotNull Function<RECEIVER, List<String>> linesSupplier) {
this.insertion.put(id, linesSupplier);
return self(); return self();
} }
/** @Override
* Insert the specific contents by the id. public List<ContentInserter<RECEIVER>> inserters() {
* return this.inserters;
* @param id the id of the insertion text
* @param lines the lines to insert
* @return the current {@link ContentHandler} instance
*/
public SELF insert(@NotNull String id, @NotNull String... lines) {
return insert(id, Arrays.asList(lines));
} }
/** @Override
* Insert the specific contents by the id. public SELF inserter(@NotNull ContentInserter<RECEIVER> inserter) {
* this.inserters.add(inserter);
* @param id the id of the insertion text this.inserters.sort(ContentInserter::compareTo);
* @param lines the lines to insert return self();
* @return the current {@link ContentHandler} instance }
*/
public SELF insert(@NotNull String id, @NotNull List<String> lines) { @Override
return insert(id, receiver -> lines); public SELF insert(@NotNull String id, @Nullable Function<RECEIVER, List<String>> supplier) {
this.insertion.put(id, supplier);
return self();
}
@Override
public boolean inserting(@NotNull String id) {
return this.insertion.keySet().stream().anyMatch(key -> key.equalsIgnoreCase(id));
}
@Override
public @Nullable List<String> getInsertion(@NotNull String id, @Nullable RECEIVER receiver) {
Function<RECEIVER, List<String>> function = this.insertion.get(id);
if (function == null) return null;
return function.apply(receiver);
}
@Override
public SELF removeInsert(@NotNull String id) {
this.insertion.remove(id);
return self();
} }
/** /**
@@ -219,63 +216,41 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
* @return the parsed text * @return the parsed text
*/ */
protected @Nullable String parse(@Nullable RECEIVER receiver, @NotNull String text) { protected @Nullable String parse(@Nullable RECEIVER receiver, @NotNull String text) {
return this.parser.apply(receiver, setPlaceholders(text, this.placeholders)); text = applyReplacements(receiver, text); // First, apply the custom replacements
text = this.paramReplacer.replace(text, receiver); // Then, apply the static placeholders
return this.parser.apply(receiver, text); // Finally, parse the text
} }
public void handle(@NotNull TextContents contents, @Nullable RECEIVER receiver, public void handle(@NotNull TextContents contents, @Nullable RECEIVER receiver,
@NotNull Consumer<String> lineConsumer) { @NotNull Consumer<String> lineConsumer) {
if (contents.isEmpty()) return; // Nothing to parse if (contents.isEmpty()) return; // Nothing to parse
if (this.disableInsertion) { if (this.disableInsertion || noneInsertion()) {
contents.lines().forEach(line -> lineConsumer.accept(parse(receiver, line))); contents.lines().forEach(line -> lineConsumer.accept(parse(receiver, line)));
return; // Simple parsed return; // Simple parsed
} }
// Set the default insertion of the text
for (Map.Entry<String, @Nullable Function<RECEIVER, List<String>>> entry : this.insertion.entrySet()) {
if (entry.getValue() != null) continue;
List<String> lines = contents.optionalLines().get(entry.getKey());
if (lines == null) continue;
entry.setValue(r -> lines);
}
lines:
for (String line : contents.lines()) { for (String line : contents.lines()) {
Matcher insertMatcher = INSERT_PATTERN.matcher(line); for (ContentInserter<RECEIVER> inserter : inserters) {
if (insertMatcher.matches()) { List<String> inserted = inserter.handle(receiver, line, this);
doInsert(insertMatcher, receiver, lineConsumer); if (inserted != null) { // Found the insertion
continue; inserted.forEach(l -> lineConsumer.accept(parse(receiver, l)));
continue lines; // Go to the next line
} }
Matcher enableMatcher = ENABLE_PATTERN.matcher(line);
if (enableMatcher.matches()) {
if (this.insertion.containsKey(enableMatcher.group("id"))) {
lineConsumer.accept(parse(receiver, enableMatcher.group("content")));
} }
continue;
}
lineConsumer.accept(parse(receiver, line)); lineConsumer.accept(parse(receiver, line));
} }
} }
private void doInsert(Matcher matcher, @Nullable RECEIVER receiver,
@NotNull Consumer<String> lineConsumer) {
String id = matcher.group("id");
List<String> values = Optional.ofNullable(this.insertion.get(id))
.map(f -> f.apply(receiver))
.orElse(null);
if (values == null || values.isEmpty()) return; // No values to insert
String prefix = matcher.group("prefix");
String type = matcher.group("type");
boolean original = type.equals("@");
int offsetAbove = Optional.ofNullable(matcher.group("above"))
.map(Integer::parseInt).orElse(0);
int offsetDown = Optional.ofNullable(matcher.group("down"))
.map(Integer::parseInt).orElse(offsetAbove); // If offsetDown is not set, use offsetAbove
IntStream.range(0, Math.max(0, offsetAbove)).mapToObj(i -> "").forEach(lineConsumer);
String prefixContent = Optional.ofNullable(prefix).map(p -> parse(receiver, p)).orElse("");
if (original) {
values.stream().map(value -> prefixContent + value).forEach(lineConsumer);
} else {
values.stream().map(value -> prefixContent + parse(receiver, value)).forEach(lineConsumer);
}
IntStream.range(0, Math.max(0, offsetDown)).mapToObj(i -> "").forEach(lineConsumer);
}
public static String setPlaceholders(@NotNull String messages, public static String setPlaceholders(@NotNull String messages,
@NotNull Map<String, Object> placeholders) { @NotNull Map<String, Object> placeholders) {
if (messages.isEmpty()) return messages; if (messages.isEmpty()) return messages;
@@ -1,6 +1,5 @@
package cc.carm.lib.configuration.value.text.function; package cc.carm.lib.configuration.value.text.function;
import cc.carm.lib.configuration.value.text.data.TextContents;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Arrays; import java.util.Arrays;
@@ -0,0 +1,67 @@
package cc.carm.lib.configuration.value.text.function.common;
import cc.carm.lib.configuration.value.text.function.inserter.ContentInserter;
import cc.carm.lib.configuration.value.text.function.inserter.Insertable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.IntStream;
public class AppendLineInserter<RECEIVER> extends ContentInserter<RECEIVER> {
/**
* Used to match the message insertion.
* <p>
* format:
* <br>- to insert parsed line {prefix}#content-id#{offset-above,offset-down}
* <br>- to insert original line {prefix}@content-id@{offset-above,offset-down}
* <br> original lines will not be parsed
* <br> example:
* <ul>
* <li>{- }#content-id#{1,1}</li>
* <li>@content-id@{1,1}</li>
* </ul>
*/
public static final @NotNull Pattern APPEND_PATTERN = Pattern.compile(
"^(?:\\{(?<prefix>.*)})?#(?<id>.*)#(?:\\{(?<above>-?\\d+)(?:,(?<down>-?\\d+))?})?$"
);
public AppendLineInserter(int priority) {
super(priority, APPEND_PATTERN);
}
@Override
protected @Nullable String extractID(@NotNull Matcher matcher) {
return matcher.group("id");
}
@Override
protected @NotNull List<String> get(@Nullable RECEIVER receiver, @NotNull Matcher matcher,
@NotNull Insertable<RECEIVER, ?> insertion) {
String id = extractID(matcher);
List<String> values = insertion.getInsertion(id, receiver);
if (values == null || values.isEmpty()) return Collections.emptyList(); // No values to insert
String prefix = Optional.ofNullable(matcher.group("prefix")).orElse("");
int offsetAbove = Optional.ofNullable(matcher.group("above"))
.map(Integer::parseInt).orElse(0);
int offsetDown = Optional.ofNullable(matcher.group("down"))
.map(Integer::parseInt).orElse(offsetAbove); // If offsetDown is not set, use offsetAbove
List<String> contents = new ArrayList<>();
IntStream.range(0, Math.max(0, offsetAbove)).mapToObj(i -> "").forEach(contents::add);
values.stream().map(value -> prefix + value).forEach(contents::add);
IntStream.range(0, Math.max(0, offsetDown)).mapToObj(i -> "").forEach(contents::add);
return contents;
}
}
@@ -0,0 +1,46 @@
package cc.carm.lib.configuration.value.text.function.common;
import cc.carm.lib.configuration.value.text.function.inserter.ContentInserter;
import cc.carm.lib.configuration.value.text.function.inserter.Insertable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class OptionalLineInserter<RECEIVER> extends ContentInserter<RECEIVER> {
/**
* Used to match the message which can be inserted
* <p>
* format:
* <br>- ?[id]Message content
* <br> example:
* <ul>
* <li>?[click]Click to use this item!</li>
* </ul>
*/
public static final @NotNull Pattern OPTIONAL_PATTERN = Pattern.compile(
"^\\?\\[(?<id>.+)](?<content>.*)$"
);
public OptionalLineInserter(int priority) {
super(priority, OPTIONAL_PATTERN);
}
@Override
protected @Nullable String extractID(@NotNull Matcher matcher) {
return matcher.group("id");
}
@Override
protected @NotNull List<String> get(@Nullable RECEIVER receiver, @NotNull Matcher matcher,
@NotNull Insertable<RECEIVER, ?> insertion) {
String content = matcher.group("content");
if (content == null) return Collections.emptyList();
return Collections.singletonList(content);
}
}
@@ -0,0 +1,71 @@
package cc.carm.lib.configuration.value.text.function.common;
import cc.carm.lib.configuration.value.text.function.replacer.ContentReplacer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ParamReplacer<RECEIVER> extends ContentReplacer<RECEIVER> {
public static final @NotNull Pattern DEFAULT_PARAM_PATTERN = Pattern.compile("%\\((?<id>[^)]+)\\)");
public static <R> ParamReplacer<R> defaults() {
return create(DEFAULT_PARAM_PATTERN, m -> m.group("id"));
}
public static <R> ParamReplacer<R> create(@NotNull Pattern pattern, @NotNull Function<Matcher, String> extractor) {
return new ParamReplacer<>(0, pattern, extractor);
}
protected final @NotNull Function<Matcher, @Nullable String> extractor;
protected @NotNull Map<String, Object> placeholders = new HashMap<>();
public ParamReplacer(int priority, @NotNull Pattern pattern, @NotNull Function<Matcher, String> extractor) {
super(priority, pattern);
this.extractor = extractor;
}
public @NotNull Map<String, Object> placeholders() {
return placeholders;
}
@Override
protected @Nullable String get(@NotNull RECEIVER receiver, @NotNull Matcher matcher) {
@Nullable String id = extractor.apply(matcher);
if (id == null) return null;
Object value = placeholders.get(id);
if (value == null) return null;
return value.toString();
}
public void set(@NotNull Map<String, Object> placeholders) {
this.placeholders = placeholders;
}
public void put(@NotNull String id, @Nullable Object value) {
placeholders.put(id, value);
}
public void remove(@NotNull String id) {
placeholders.remove(id);
}
public void putAll(@NotNull Map<String, Object> placeholders) {
this.placeholders.putAll(placeholders);
}
public void putAll(@NotNull String[] params, @NotNull Object[] values) {
for (int i = 0; i < params.length; i++) {
placeholders.put(params[i], (values != null && values.length > i) ? values[i] : "?");
}
}
public void clear() {
placeholders.clear();
}
}
@@ -0,0 +1,51 @@
package cc.carm.lib.configuration.value.text.function.inserter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class ContentInserter<RECEIVER> implements Comparable<ContentInserter<RECEIVER>> {
protected final int priority;
protected @NotNull Pattern pattern;
public ContentInserter(int priority, @NotNull Pattern pattern) {
this.priority = priority;
this.pattern = pattern;
}
public int priority() {
return priority;
}
public void setPattern(@NotNull Pattern pattern) {
this.pattern = pattern;
}
public @NotNull Matcher matcher(@NotNull String text) {
return pattern.matcher(text);
}
protected abstract @Nullable String extractID(@NotNull Matcher matcher);
protected abstract @NotNull List<String> get(@Nullable RECEIVER receiver, @NotNull Matcher matcher,
@NotNull Insertable<RECEIVER, ?> insertions);
public @Nullable List<String> handle(@Nullable RECEIVER receiver, @NotNull String line,
@NotNull Insertable<RECEIVER, ?> insertions) {
Matcher matcher = matcher(line);
if (!matcher.matches()) return null;
if (!insertions.inserting(extractID(matcher))) return Collections.emptyList();
return get(receiver, matcher, insertions);
}
@Override
public int compareTo(@NotNull ContentInserter<RECEIVER> o) {
return Integer.compare(o.priority, priority);
}
}
@@ -0,0 +1,66 @@
package cc.carm.lib.configuration.value.text.function.inserter;
import cc.carm.lib.configuration.value.text.function.ContentHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
public interface Insertable<RECEIVER, SELF> {
List<ContentInserter<RECEIVER>> inserters();
SELF inserter(@NotNull ContentInserter<RECEIVER> inserter);
boolean noneInsertion();
boolean inserting(@NotNull String id);
@Nullable List<String> getInsertion(@NotNull String id, @Nullable RECEIVER receiver);
/**
* Insert the specific contents by the id.
*
* @param id the id of the insertion text
* @param supplier to supply the lines to insert
* @return the current {@link ContentHandler} instance
*/
SELF insert(@NotNull String id, @Nullable Function<RECEIVER, List<String>> supplier);
/**
* Insert the specific contents by the id.
*
* @param id the id of the insertion text
* @return the current {@link ContentHandler} instance
*/
default SELF insert(@NotNull String id) {
return insert(id, (Function<RECEIVER, List<String>>) null);
}
/**
* Insert the specific contents by the id.
*
* @param id the id of the insertion text
* @param contents the lines to insert
* @return the current {@link ContentHandler} instance
*/
default SELF insert(@NotNull String id, @NotNull List<String> contents) {
return insert(id, receiver -> contents);
}
/**
* Insert the specific contents by the id.
*
* @param id the id of the insertion text
* @param contents the lines to insert
* @return the current {@link ContentHandler} instance
*/
default SELF insert(@NotNull String id, @NotNull String... contents) {
return insert(id, Arrays.asList(contents));
}
SELF removeInsert(@NotNull String id);
}
@@ -0,0 +1,105 @@
package cc.carm.lib.configuration.value.text.function.replacer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class ContentReplacer<RECEIVER> implements Comparable<ContentReplacer<RECEIVER>> {
public static <R> ContentReplacer.Builder<R> match(@NotNull Pattern pattern) {
return new Builder<>(pattern);
}
public static <R> ContentReplacer.Builder<R> match(@NotNull String pattern) {
return match(Pattern.compile(pattern));
}
public static <R> ContentReplacer.Builder<R> replace(@NotNull String text) {
return match(Pattern.quote(text));
}
protected final int priority;
protected @NotNull Pattern pattern;
public ContentReplacer(int priority, @NotNull Pattern pattern) {
this.priority = priority;
this.pattern = pattern;
}
public int priority() {
return priority;
}
public void pattern(@NotNull Pattern pattern) {
this.pattern = pattern;
}
public @NotNull Matcher matcher(@NotNull String text) {
return pattern.matcher(text);
}
public String replace(@NotNull String text, @Nullable RECEIVER receiver) {
Matcher matcher = matcher(text);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
String replaced = get(receiver, matcher);
matcher.appendReplacement(sb, replaced == null ? "" : replaced);
}
matcher.appendTail(sb);
return sb.toString();
}
protected abstract @Nullable String get(@Nullable RECEIVER receiver, @NotNull Matcher matcher);
@Override
public int compareTo(@NotNull ContentReplacer<RECEIVER> o) {
return Integer.compare(o.priority, this.priority);
}
public static class Builder<R> {
protected final @NotNull Pattern pattern;
protected int priority = 0;
public Builder(@NotNull Pattern pattern) {
this.pattern = pattern;
}
public @NotNull Builder<R> priority(int priority) {
this.priority = priority;
return this;
}
public @NotNull ContentReplacer<R> to(BiFunction<@Nullable R, @NotNull Matcher, @Nullable String> supplier) {
return new ContentReplacer<R>(this.priority, this.pattern) {
@Override
protected @Nullable String get(@NotNull R receiver, @NotNull Matcher matcher) {
return supplier.apply(receiver, matcher);
}
};
}
public @NotNull ContentReplacer<R> to(Function<@Nullable R, @Nullable String> supplier) {
return to((receiver, matchedParam) -> supplier.apply(receiver));
}
public @NotNull ContentReplacer<R> to(Supplier<@Nullable String> supplier) {
return to((receiver, matchedParam) -> supplier.get());
}
public @NotNull ContentReplacer<R> to(@NotNull String content) {
return to(() -> content);
}
}
@FunctionalInterface
public interface Constructor<R> extends Function<ContentReplacer.Builder<R>, ContentReplacer<R>> {
}
}
@@ -0,0 +1,63 @@
package cc.carm.lib.configuration.value.text.function.replacer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public interface Replaceable<RECEIVER, SELF> {
List<ContentReplacer<RECEIVER>> replacers();
default String applyReplacements(@Nullable RECEIVER receiver, @NotNull String text) {
for (ContentReplacer<RECEIVER> replacer : replacers()) {
text = replacer.replace(text, receiver);
}
return text;
}
SELF replacer(@NotNull ContentReplacer<RECEIVER> replacer);
default SELF replacer(@NotNull Pattern pattern, @NotNull ContentReplacer.Constructor<RECEIVER> constructor) {
ContentReplacer.Builder<RECEIVER> builder = ContentReplacer.match(pattern);
return replacer(constructor.apply(builder));
}
default SELF replace(@NotNull Pattern pattern,
@NotNull BiFunction<@Nullable RECEIVER, @NotNull Matcher, @Nullable String> supplier) {
return replacer(pattern, builder -> builder.to(supplier));
}
default SELF replace(@NotNull Pattern pattern,
@NotNull Function<@Nullable RECEIVER, @Nullable String> supplier) {
return replacer(pattern, builder -> builder.to(supplier));
}
default SELF replace(@NotNull Pattern pattern,
@NotNull Supplier<@Nullable String> supplier) {
return replacer(pattern, builder -> builder.to(supplier));
}
default SELF replace(@NotNull Pattern pattern, @NotNull String replacement) {
return replacer(pattern, builder -> builder.to(replacement));
}
default SELF replace(@NotNull String text, @NotNull String replacement) {
return replacer(Pattern.compile(Pattern.quote(text)), builder -> builder.to(replacement));
}
default SELF replace(@NotNull String text, @NotNull Supplier<@Nullable String> supplier) {
return replacer(Pattern.compile(Pattern.quote(text)), builder -> builder.to(supplier));
}
default SELF replace(@NotNull String text,
@NotNull Function<@Nullable RECEIVER, @Nullable String> supplier) {
return replacer(Pattern.compile(Pattern.quote(text)), builder -> builder.to(supplier));
}
}
@@ -7,17 +7,16 @@ import cc.carm.lib.configuration.value.text.tests.conf.AppMessages;
import org.junit.Test; import org.junit.Test;
import java.io.File; import java.io.File;
import java.util.List;
public class ConfigTest { public class ConfigTest {
public static final String[] WEBSITES = new String[]{ public static final String[] WEBSITES = new String[]{
"https://carm.cc", "https://carm.cc",
"https://www.baidu.com", "https://www.baidu.com",
"https://www.google.com" "https://www.google.com"
}; };
@Test @Test
public void test() { public void test() {
@@ -27,11 +26,11 @@ public class ConfigTest {
System.out.println("--------------------------"); System.out.println("--------------------------");
AppMessages.WELCOME.prepare() List<String> str = AppMessages.WELCOME.prepare()
.placeholders("Carm") .placeholders("Carm")
.insert("guidance") .insert("guidance")
.insert("websites", WEBSITES) .insert("websites", WEBSITES)
.to(System.out); .compile(System.out);
System.out.println("--------------------------"); System.out.println("--------------------------");
@@ -7,6 +7,7 @@ import org.junit.Test;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.*; import java.util.*;
public class ParseTest { public class ParseTest {
@@ -18,13 +19,15 @@ public class ParseTest {
lines.add("#more-creating#{1}"); lines.add("#more-creating#{1}");
lines.add("This is a test message"); lines.add("This is a test message");
lines.add("#guidance#"); lines.add("#guidance#");
lines.add("{- }#websites#{0,1}"); lines.add("{ - }#websites#{0,1}");
lines.add("Thanks for your reading!"); lines.add("Thanks for your reading!");
lines.add("uuid: $UUID$");
lines.add("?[click]"); lines.add("?[click]");
lines.add("?[click]Click to see more!"); lines.add("?[click]Click to see more!");
lines.add("?[hidden]This entry should be hidden!");
Map<String, List<String>> optional = new HashMap<>(); Map<String, List<String>> optional = new HashMap<>();
optional.put("guidance", Arrays.asList("To get more information for %(name), see:")); optional.put("guidance", Arrays.asList("To get more information for %(name),", " see:"));
optional.put("websites", Arrays.asList("https://www.baidu.com", "https://www.google.com")); optional.put("websites", Arrays.asList("https://www.baidu.com", "https://www.google.com"));
TextContents textContents = new TextContents(lines, optional); TextContents textContents = new TextContents(lines, optional);
@@ -32,13 +35,17 @@ public class ParseTest {
PreparedText<String, PrintStream> msg = new PreparedText<String, PrintStream>(textContents) PreparedText<String, PrintStream> msg = new PreparedText<String, PrintStream>(textContents)
.dispatcher((p, s) -> s.forEach(p::println)) .dispatcher((p, s) -> s.forEach(p::println))
.parser((p, s) -> s) .parser((p, s) -> s)
.compiler((p, s) -> s); .compiler((p, s) -> s)
.replace( // Custom replacer, replace $UUID$ with Random UUID
"$UUID$", () -> UUID.randomUUID().toString()
);
msg.placeholder("name", "Carm") msg.placeholder("name", "Carm")
.insert("guidance") .insert("guidance")
.insert("click") .insert("click")
.insert("websites", "Baidu", "Bilibili", "Google"); .insert("websites", "Baidu", "Bilibili", "Google");
System.out.println("----------------------------"); System.out.println("----------------------------");
msg.to(System.out); msg.to(System.out);
System.out.println("----------------------------"); System.out.println("----------------------------");
@@ -17,7 +17,8 @@ public class ConfiguredMsg extends ConfiguredText<String, PrintStream> {
return builder().defaults(text).build(); return builder().defaults(text).build();
} }
public ConfiguredMsg(@NotNull ValueManifest<TextContents> manifest, @NotNull String[] params) { public ConfiguredMsg(@NotNull ValueManifest<TextContents, TextContents> manifest,
@NotNull String[] params) {
super( super(
manifest, manifest,
(p, s) -> s, (p, s) -> s,
+51
View File
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-parent</artifactId>
<version>4.1.7</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties>
<artifactId>configured-feature-validators</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>configured-core</artifactId>
<version>${project.version}</version>
</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,16 @@
package cc.carm.lib.configuration.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValuePattern {
String value();
String message() default "Invalid value format!";
}
@@ -0,0 +1,18 @@
package cc.carm.lib.configuration.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValueRange {
long min() default Long.MIN_VALUE;
long max() default Long.MAX_VALUE;
String message() default "Value out of range.";
}
@@ -0,0 +1,44 @@
package cc.carm.lib.configuration.validators;
import cc.carm.lib.configuration.annotation.ValuePattern;
import cc.carm.lib.configuration.annotation.ValueRange;
import cc.carm.lib.configuration.function.ValueValidator;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.regex.Pattern;
public class Validators {
private Validators() {
throw new UnsupportedOperationException("API Register.");
}
public static void activate(ConfigurationHolder<?> holder) {
holder.initializer().registerValidAnnotation(ValueRange.class, r -> (ho, value) -> {
if (!(value instanceof Number)) {
throw new IllegalArgumentException("Value is not a number: " + value);
}
Number number = (Number) value;
if (number.doubleValue() < r.min() || number.doubleValue() > r.max()) {
throw new IllegalArgumentException(r.message());
}
});
holder.initializer().registerValidAnnotation(ValuePattern.class, r -> new ValueValidator<Object>() {
private final Pattern pattern = Pattern.compile(r.value());
@Override
public void validate(@NotNull ConfigurationHolder<?> holder, @Nullable Object value) throws Exception {
if (value == null) return;
if (!pattern.matcher(value.toString()).matches()) {
throw new IllegalArgumentException(r.message());
}
}
});
}
}
+4 -4
View File
@@ -5,8 +5,8 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<version>4.0.11</version> <version>4.1.7</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -16,13 +16,13 @@
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties> </properties>
<artifactId>easyconfiguration-feature-versioned</artifactId> <artifactId>configured-feature-versioned</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>

Some files were not shown because too many files have changed in this diff Show More