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

Compare commits

..

242 Commits

Author SHA1 Message Date
carm 04eaf6606d feat: Jump to 4.0.11 2025-03-06 18:19:25 +08:00
carm e558e93410 feat(sql): Support custom sql table schema 2025-03-06 18:19:06 +08:00
flowerinsnow e55fe3a8d5 feat: hocon supported 2025-03-06 18:03:27 +08:00
carm 8f075b99b5 chore(deps): use parent dependencies' version 2025-03-04 11:58:01 +08:00
carm 09a0b3c373 chore(deps): use parent dependencies' version 2025-03-04 11:34:16 +08:00
carm 4df4977733 feat(msg): add enhanced text support 2025-03-04 04:21:58 +08:00
carm 6434feb980 fix(sql): Fixed sql table format 2025-03-04 01:57:04 +08:00
carm bc3e4b3e6f fix(comment): Fixed yaml comments 2025-03-04 01:24:12 +08:00
carm c2a9e2254c feat(section): Add ConfigureSection#asMap function 2025-03-04 01:06:21 +08:00
carm 251dd208af feat(sql): Support SQL sources 2025-03-03 19:00:28 +08:00
carm afd1bbfc0f feat(sql): Support SQL sources 2025-03-03 18:52:41 +08:00
carm a699f6c164 feat(sql): Support SQL sources 2025-03-03 18:51:21 +08:00
carm 844cbfab53 feat(sql): Try to implement sql source 2025-02-27 13:32:12 +08:00
carm f74d5d29f9 feat(mongo): Finished source for MongoDB #105 2025-02-27 00:46:44 +08:00
carm 6f28abebb9 feat(section): Add #path and #fullPath for sections 2025-02-25 00:04:24 +08:00
LSeng 842cd78ce3 feat(section): Implement createSection() for ShadedSection 2025-02-22 23:56:45 +08:00
carm 11f1f36a15 docs: Change logo file 2025-02-22 10:13:54 +08:00
renovate[bot] ee9f29ba30 chore(deps): update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.14.0 2025-02-22 09:57:51 +08:00
carm f5bccdaad5 chore: Upgraded to 4.0.6 2025-02-22 09:57:24 +08:00
carm f5f70ff69b chore(source): Add more pre implemented functions 2025-02-22 09:56:59 +08:00
carm 3e221740bc feat(section): Implement shaded sections 2025-02-22 09:55:28 +08:00
LSeng 96d09be977 feat(section): support ShadedSection 2025-02-21 20:48:37 +08:00
carm 5d7c946db5 feat(section): Implement more sections 2025-02-21 18:45:15 +08:00
carm 9e008ff4cd feat(section): Add shaded section 2025-02-21 17:31:05 +08:00
carm df19da170b feat(section): Add #contains and #containsValue methods 2025-02-21 17:15:16 +08:00
carm 3473ef2247 feat: Implement more sections functions 2025-02-21 16:17:12 +08:00
carm d543530305 feat: Implement more sections functions 2025-02-21 16:09:58 +08:00
carm d81855697c feat: Implement more sections functions 2025-02-21 11:27:03 +08:00
carm 5c16e98f30 feat(section): Implement more sections 2025-02-21 03:20:11 +08:00
carm 3f1ffadeff feat(section): Implement more sections 2025-02-21 03:07:43 +08:00
carm d8191b7c6d feat(section): Add original method 2025-02-21 02:00:36 +08:00
carm ba66220f92 docs(sponsor): Add sponsors banner 2025-02-21 01:00:27 +08:00
carm 730d6d7e9c docs(sponsor): Add sponsors banner 2025-02-21 00:58:32 +08:00
carm 4523190cb0 feat: Upgraded to 4.0.5 2025-02-20 16:50:07 +08:00
carm 2a49e2ee6b docs: Fixed quantity usage 2025-02-20 16:49:36 +08:00
carm 77b223b2cb feat: Add stream functions 2025-02-20 16:38:49 +08:00
carm 8e7ac263e7 feat: Split MapSection and MemorySection 2025-02-20 03:01:45 +08:00
carm 80f03ec501 feat: Split MapSection and MemorySection 2025-02-20 02:52:19 +08:00
carm 1c002ae535 feat: Split MapSection and MemorySection 2025-02-20 02:50:00 +08:00
carm a4659c5c9f docs: Englished documents 2025-02-20 00:11:06 +08:00
carm 1c27c2f881 fix: Fixed the missing implements of #remove 2025-02-19 00:57:17 +08:00
carm 476cb79e2f feat: Support standard "pre-load" option 2025-02-18 21:47:58 +08:00
carm bf716b06ae docs: Add more javadocs 2025-02-18 17:33:28 +08:00
carm 00170e6d77 feat: Simplify the ConfigureSection functions to support more different usages. 2025-02-18 17:08:12 +08:00
carm 1bac201427 chore: Add more limitations for inline comments 2025-02-18 14:12:28 +08:00
carm cd77639df5 docs: Add examples 2025-02-17 18:37:16 +08:00
renovate[bot] 5ae756929a fix(deps): update dependency cc.carm.lib:yamlcommentwriter to v1.2.0 2025-02-17 18:28:00 +08:00
carm a9e80aecce fix(text): Fixed wrong type of text 2025-02-17 18:28:00 +08:00
carm 477f0d11bc fix(text): Fixed wrong type of text 2025-02-17 06:43:30 +08:00
renovate[bot] 53ff38a76f fix(deps): update dependency cc.carm.lib:yamlcommentwriter to v1.2.0 2025-02-17 05:24:09 +08:00
carm c32bea3864 fix(builder): Fixed wrong type of serializer 2025-02-17 04:48:15 +08:00
carm 15823bb076 fix(builder): Fixed wrong type of serializer 2025-02-17 04:47:23 +08:00
renovate[bot] f303f56199 fix(deps): update dependency cc.carm.lib:yamlcommentwriter to v1.2.0 2025-02-17 04:27:50 +08:00
carm 22f2674e7c feat(text): Separated the text handler 2025-02-17 04:26:22 +08:00
carm 9eb9c9e13d feat(parser): Supported more insert functions 2025-02-17 03:14:40 +08:00
carm 616314c7f0 feat(parser): Supported more insert functions 2025-02-17 03:13:35 +08:00
carm 05f504a347 feat(parser): Supported parse functions 2025-02-17 02:46:18 +08:00
carm bf6ea97b99 feaT(unit): Add unit meta 2025-02-17 01:40:41 +08:00
carm 9847399e56 feat: Version update to 4.0.1 2025-02-17 00:33:41 +08:00
carm 18515d4a78 refactor(comment): Extract common comment functions 2025-02-17 00:12:29 +08:00
carm 9f1fc5bf90 refactor(comment): Extract common comment functions 2025-02-17 00:11:56 +08:00
carm e7847b2166 feat: Version update to 4.0.1 2025-02-16 23:51:18 +08:00
carm 69cec281be feat: Version update to 4.0.1 2025-02-16 23:47:22 +08:00
carm 28dc9b9e55 feat(text): Implement the ConfiguredText for simply text/msg functions. 2025-02-16 23:46:31 +08:00
LSeng c60ba074d9 fix(comment): Fixed wrong behavior of inline regex comments 2025-02-16 21:59:03 +08:00
carm e88bf301cc ci(javadoc): Fixed javadoc deployment 2025-02-16 02:31:10 +08:00
carm f2c9750c35 chore: Remove wip modules 2025-02-16 02:19:52 +08:00
carm c0f0e989c6 docs: Add missing javadocs 2025-02-16 02:17:49 +08:00
carm 6490edf65e docs: Add missing javadocs 2025-02-16 02:17:31 +08:00
carm 14a5f41649 docs: Add missing javadocs 2025-02-16 02:14:15 +08:00
renovate[bot] 0b16ae08db fix(deps): update dependency org.mongodb:mongodb-driver-sync to v5.3.1 2025-02-16 02:07:12 +08:00
renovate[bot] 020d0df3a3 fix(deps): update dependency cc.carm.lib:yamlcommentwriter to v1.1.0 2025-02-16 02:07:02 +08:00
carm f3bdff1560 ci(deploy): Update central deployment ci 2025-02-16 02:06:11 +08:00
carm d3ec93cef2 feat(source): Update sources' original type 2025-02-16 02:04:31 +08:00
carm 96ed604cd9 feat(source): Update sources' original type 2025-02-16 02:04:14 +08:00
carm eff91b0496 feat(db): Add databased providers assumptions 2025-02-16 01:36:37 +08:00
carm 8db7ecf539 chore(yaml): Simply the yaml dumper 2025-02-15 23:35:21 +08:00
renovate[bot] 1b49e466a9 fix(deps): update dependency org.yaml:snakeyaml to v2.4 2025-02-15 23:12:25 +08:00
carm 6df9f2ce42 feat(factory): Add more options 2025-02-15 07:32:34 +08:00
carm aedc6cb439 feat(map): Finished Map value builders. 2025-02-15 07:20:59 +08:00
carm c79b94b719 feat: Comment resources support #104 2025-02-15 06:06:31 +08:00
carm 3a3533ce81 feat: Optimized comments & sections behavior 2025-02-15 05:56:00 +08:00
carm 4cdd184fe6 feat(yaml): Try implement yaml comments 2025-02-13 22:12:08 +08:00
carm 18199cd1cf feat(yaml): Try implement yaml comments 2025-02-13 07:12:55 +08:00
carm 47e2a4854c feat(yaml): Finished YAML Provider 2025-02-13 06:48:58 +08:00
carm 5b95824bb0 Merge branch '4.0.0'
# Conflicts:
#	providers/yaml/pom.xml
2025-02-13 04:49:17 +08:00
carm 2cda4ae11c chore(sql): Add readme descriptions 2025-02-13 04:46:27 +08:00
carm e840f6bd50 feat(versioned): Add versioned feature 2025-02-13 04:42:49 +08:00
carm 90407dcd0d feat(json): Finished json version's provider 2025-02-13 04:34:52 +08:00
carm 79f59bafe6 feat(json): Finished json version's provider 2025-02-13 01:30:10 +08:00
carm 05ff61a9d9 feat(json): Implement json sources 2025-02-12 04:25:29 +08:00
carm c68d2371ee feat(comment): Support regex inline comments 2025-02-12 02:35:59 +08:00
carm 2093091923 feat!(core): Update files sources 2025-02-10 03:16:48 +08:00
carm 45ca8b02d4 feat!(core): Finished the design of core module 2025-02-09 03:49:37 +08:00
dependabot[bot] 7f09e6cdf7 chore(deps): Bump com.google.code.gson:gson from 2.11.0 to 2.12.1
Bumps [com.google.code.gson:gson](https://github.com/google/gson) from 2.11.0 to 2.12.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.11.0...gson-parent-2.12.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-06 16:33:49 +08:00
carm 205db6e5b9 feat!(value): Finished the standard configured values 2025-02-02 23:59:13 +08:00
carm 8ac1faf300 feat!(value): Finished the standard configured values 2025-02-02 23:11:16 +08:00
carm 374a6198d8 feat!(value): Redesigned the Configuration api 2025-02-02 22:29:18 +08:00
renovate[bot] 6ee23ded3b fix(deps): update dependency org.jetbrains:annotations to v26.0.2 2025-01-23 03:46:31 +08:00
renovate[bot] 0c7cc5c156 chore(deps): update actions/upload-artifact action to v4 2025-01-18 05:58:43 +08:00
renovate[bot] 4988bb15ae chore(deps): update github/codeql-action action to v3 2025-01-18 05:58:40 +08:00
renovate[bot] 8b24e8dbff chore(deps): update actions/checkout action to v4 2025-01-18 03:54:31 +08:00
renovate[bot] ce9d858f6c chore(deps): update actions/setup-java action to v4 2025-01-18 03:54:28 +08:00
renovate[bot] efc837b6f0 chore(deps): update codacy/codacy-analysis-cli-action digest to 0991600 2025-01-18 03:38:40 +08:00
renovate[bot] 44e864ef0f fix(deps): update dependency org.bspfsystems:yamlconfiguration to v3.0.2 2025-01-18 03:38:36 +08:00
renovate[bot] ce33d8ff9d Add renovate.json 2025-01-18 00:00:45 +08:00
dependabot[bot] de70c11f21 chore(deps): Bump org.apache.maven.plugins:maven-surefire-plugin
Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.5.1 to 3.5.2.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.1...surefire-3.5.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-03 22:41:24 +08:00
dependabot[bot] a182b9af99 chore(deps): Bump org.apache.maven.plugins:maven-javadoc-plugin
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.10.1 to 3.11.2.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.10.1...maven-javadoc-plugin-3.11.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-03 22:41:16 +08:00
dependabot[bot] c56499c0e9 chore(deps-dev): Bump log4j.version from 2.24.2 to 2.24.3
Bumps `log4j.version` from 2.24.2 to 2.24.3.

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

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

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

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-23 23:22:15 +08:00
dependabot[bot] c9150ecb50 chore(deps-dev): Bump log4j.version from 2.24.1 to 2.24.2
Bumps `log4j.version` from 2.24.1 to 2.24.2.

Updates `org.apache.logging.log4j:log4j-api` from 2.24.1 to 2.24.2

Updates `org.apache.logging.log4j:log4j-core` from 2.24.1 to 2.24.2

Updates `org.apache.logging.log4j:log4j-slf4j-impl` from 2.24.1 to 2.24.2

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-25 02:28:51 +08:00
dependabot[bot] 5075a4c96d chore(deps): Bump org.apache.maven.plugins:maven-gpg-plugin
Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.6 to 3.2.7.
- [Release notes](https://github.com/apache/maven-gpg-plugin/releases)
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.6...maven-gpg-plugin-3.2.7)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-gpg-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-23 16:43:42 +08:00
dependabot[bot] 30a9f3634f chore(deps-dev): Bump log4j.version from 2.24.0 to 2.24.1
Bumps `log4j.version` from 2.24.0 to 2.24.1.

Updates `org.apache.logging.log4j:log4j-api` from 2.24.0 to 2.24.1

Updates `org.apache.logging.log4j:log4j-core` from 2.24.0 to 2.24.1

Updates `org.apache.logging.log4j:log4j-slf4j-impl` from 2.24.0 to 2.24.1

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-23 16:42:40 +08:00
dependabot[bot] 022acb97a5 chore(deps): Bump org.apache.maven.plugins:maven-javadoc-plugin
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.10.0 to 3.10.1.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.10.0...maven-javadoc-plugin-3.10.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-23 16:39:43 +08:00
dependabot[bot] 97eda55ec7 chore(deps): Bump org.apache.maven.plugins:maven-surefire-plugin
Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.5.0 to 3.5.1.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.0...surefire-3.5.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-23 16:38:00 +08:00
dependabot[bot] 7fe77b1363 chore(deps): Bump org.jetbrains:annotations from 25.0.0 to 26.0.1
Bumps [org.jetbrains:annotations](https://github.com/JetBrains/java-annotations) from 25.0.0 to 26.0.1.
- [Release notes](https://github.com/JetBrains/java-annotations/releases)
- [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md)
- [Commits](https://github.com/JetBrains/java-annotations/compare/25.0.0...26.0.1)

---
updated-dependencies:
- dependency-name: org.jetbrains:annotations
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-18 16:08:06 +08:00
dependabot[bot] 9f9f02df51 chore(deps): Bump org.jetbrains:annotations from 24.1.0 to 25.0.0
Bumps [org.jetbrains:annotations](https://github.com/JetBrains/java-annotations) from 24.1.0 to 25.0.0.
- [Release notes](https://github.com/JetBrains/java-annotations/releases)
- [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md)
- [Commits](https://github.com/JetBrains/java-annotations/compare/24.1.0...25.0.0)

---
updated-dependencies:
- dependency-name: org.jetbrains:annotations
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-27 21:21:58 +08:00
dependabot[bot] 41a53b1c89 chore(deps): Bump org.apache.maven.plugins:maven-gpg-plugin
Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.5 to 3.2.6.
- [Release notes](https://github.com/apache/maven-gpg-plugin/releases)
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.5...maven-gpg-plugin-3.2.6)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-gpg-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-19 20:05:09 +08:00
dependabot[bot] 9626ed8f49 chore(deps): Bump org.apache.maven.plugins:maven-gpg-plugin
Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.4 to 3.2.5.
- [Release notes](https://github.com/apache/maven-gpg-plugin/releases)
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.4...maven-gpg-plugin-3.2.5)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-gpg-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-14 22:50:32 +08:00
dependabot[bot] 119f93f234 chore(deps-dev): Bump log4j.version from 2.23.1 to 2.24.0
Bumps `log4j.version` from 2.23.1 to 2.24.0.

Updates `org.apache.logging.log4j:log4j-api` from 2.23.1 to 2.24.0

Updates `org.apache.logging.log4j:log4j-core` from 2.23.1 to 2.24.0

Updates `org.apache.logging.log4j:log4j-slf4j-impl` from 2.23.1 to 2.24.0

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-14 22:49:11 +08:00
dependabot[bot] f2b6069389 chore(deps): Bump org.bspfsystems:yamlconfiguration from 2.0.2 to 3.0.1
Bumps [org.bspfsystems:yamlconfiguration](https://github.com/bspfsystems/YamlConfiguration) from 2.0.2 to 3.0.1.
- [Release notes](https://github.com/bspfsystems/YamlConfiguration/releases)
- [Commits](https://github.com/bspfsystems/YamlConfiguration/compare/v2.0.2...v3.0.1)

---
updated-dependencies:
- dependency-name: org.bspfsystems:yamlconfiguration
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-14 22:49:04 +08:00
dependabot[bot] 6e2808380a chore(deps): Bump org.apache.maven.plugins:maven-javadoc-plugin
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.8.0 to 3.10.0.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.8.0...maven-javadoc-plugin-3.10.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-14 22:48:45 +08:00
dependabot[bot] 3ca44aa233 chore(deps): Bump org.apache.maven.plugins:maven-surefire-plugin
Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.3.1 to 3.5.0.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.3.1...surefire-3.5.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-11 15:25:09 +08:00
dependabot[bot] 4de9ebd118 chore(deps): Bump org.apache.maven.plugins:maven-javadoc-plugin
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.7.0 to 3.8.0.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.7.0...maven-javadoc-plugin-3.8.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-31 07:29:56 +08:00
dependabot[bot] 217cd66bfd chore(deps): Bump org.apache.maven.plugins:maven-release-plugin (#83) 2024-07-16 23:00:30 +00:00
dependabot[bot] f1f9a55e01 chore(deps): Bump org.apache.maven.plugins:maven-release-plugin
Bumps [org.apache.maven.plugins:maven-release-plugin](https://github.com/apache/maven-release) from 3.0.1 to 3.1.0.
- [Release notes](https://github.com/apache/maven-release/releases)
- [Commits](https://github.com/apache/maven-release/compare/maven-release-3.0.1...maven-release-3.1.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-release-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-12 00:14:31 +08:00
dependabot[bot] 530d7b3391 chore(deps): Bump org.apache.maven.plugins:maven-surefire-plugin
Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.2.5 to 3.3.1.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.2.5...surefire-3.3.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-12 00:05:47 +08:00
dependabot[bot] 2d381c3ce4 chore(deps): Bump org.apache.maven.plugins:maven-jar-plugin
Bumps [org.apache.maven.plugins:maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.4.1 to 3.4.2.
- [Release notes](https://github.com/apache/maven-jar-plugin/releases)
- [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.4.1...maven-jar-plugin-3.4.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-jar-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-22 07:58:29 +08:00
dependabot[bot] 08626ae8c2 chore(deps): Bump org.bspfsystems:yamlconfiguration from 2.0.1 to 2.0.2
Bumps [org.bspfsystems:yamlconfiguration](https://github.com/bspfsystems/YamlConfiguration) from 2.0.1 to 2.0.2.
- [Release notes](https://github.com/bspfsystems/YamlConfiguration/releases)
- [Commits](https://github.com/bspfsystems/YamlConfiguration/compare/v2.0.1...v2.0.2)

---
updated-dependencies:
- dependency-name: org.bspfsystems:yamlconfiguration
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-04 12:21:34 +08:00
dependabot[bot] 7fe2e74582 chore(deps): Bump org.apache.maven.plugins:maven-shade-plugin
Bumps [org.apache.maven.plugins:maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.5.3 to 3.6.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.5.3...maven-shade-plugin-3.6.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-04 12:21:07 +08:00
dependabot[bot] a49180bb1d chore(deps): Bump org.apache.maven.plugins:maven-javadoc-plugin
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.6.3 to 3.7.0.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.6.3...maven-javadoc-plugin-3.7.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-04 12:20:11 +08:00
dependabot[bot] 69a4b5e918 chore(deps): Bump com.google.code.gson:gson from 2.10.1 to 2.11.0
Bumps [com.google.code.gson:gson](https://github.com/google/gson) from 2.10.1 to 2.11.0.
- [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.10.1...gson-parent-2.11.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-21 00:36:37 +08:00
dependabot[bot] 27c3c7803c chore(deps): Bump org.apache.maven.plugins:maven-jar-plugin
Bumps [org.apache.maven.plugins:maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.4.0 to 3.4.1.
- [Release notes](https://github.com/apache/maven-jar-plugin/releases)
- [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.4.0...maven-jar-plugin-3.4.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-jar-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-25 08:52:18 +08:00
dependabot[bot] c95b1ae4d4 chore(deps): Bump org.apache.maven.plugins:maven-gpg-plugin
Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.3 to 3.2.4.
- [Release notes](https://github.com/apache/maven-gpg-plugin/releases)
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.3...maven-gpg-plugin-3.2.4)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-gpg-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-25 08:52:10 +08:00
dependabot[bot] c7f928686d chore(deps): Bump org.apache.maven.plugins:maven-shade-plugin
Bumps [org.apache.maven.plugins:maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.5.2 to 3.5.3.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.5.2...maven-shade-plugin-3.5.3)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-25 08:50:00 +08:00
dependabot[bot] 4ab84cfc71 chore(deps): Bump org.apache.maven.plugins:maven-jar-plugin
Bumps [org.apache.maven.plugins:maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/apache/maven-jar-plugin/releases)
- [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.3.0...maven-jar-plugin-3.4.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-jar-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-16 16:15:41 +08:00
dependabot[bot] d347d3de23 chore(deps): Bump org.apache.maven.plugins:maven-gpg-plugin
Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.2 to 3.2.3.
- [Release notes](https://github.com/apache/maven-gpg-plugin/releases)
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.2...maven-gpg-plugin-3.2.3)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-gpg-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-16 16:11:16 +08:00
dependabot[bot] 2b48e3146b chore(deps): Bump org.apache.maven.plugins:maven-source-plugin
Bumps [org.apache.maven.plugins:maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.3.0 to 3.3.1.
- [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.3.0...maven-source-plugin-3.3.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-source-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-11 11:48:11 +08:00
dependabot[bot] d35958a943 chore(deps): Bump org.apache.maven.plugins:maven-gpg-plugin (#68)
Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.1 to 3.2.2.
- [Release notes](https://github.com/apache/maven-gpg-plugin/releases)
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.1...maven-gpg-plugin-3.2.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-gpg-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-28 09:03:53 +08:00
dependabot[bot] b7990d4de3 chore(deps): Bump org.apache.maven.plugins:maven-compiler-plugin (#66)
Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.12.1 to 3.13.0.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.12.1...maven-compiler-plugin-3.13.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-compiler-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-20 00:11:23 +08:00
dependabot[bot] f01a15a19d chore(deps): Bump org.apache.maven.plugins:maven-gpg-plugin (#67)
Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.0 to 3.2.1.
- [Release notes](https://github.com/apache/maven-gpg-plugin/releases)
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.0...maven-gpg-plugin-3.2.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-gpg-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-20 00:11:15 +08:00
dependabot[bot] 85625bfe05 chore(deps-dev): Bump log4j.version from 2.23.0 to 2.23.1 (#64)
Bumps `log4j.version` from 2.23.0 to 2.23.1.

Updates `org.apache.logging.log4j:log4j-api` from 2.23.0 to 2.23.1

Updates `org.apache.logging.log4j:log4j-core` from 2.23.0 to 2.23.1

Updates `org.apache.logging.log4j:log4j-slf4j-impl` from 2.23.0 to 2.23.1

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-12 09:36:09 +08:00
dependabot[bot] cb59471f9b chore(deps): Bump org.apache.maven.plugins:maven-gpg-plugin (#65)
Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.1.0 to 3.2.0.
- [Release notes](https://github.com/apache/maven-gpg-plugin/releases)
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.1.0...maven-gpg-plugin-3.2.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-gpg-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-12 09:35:52 +08:00
dependabot[bot] 112803342a chore(deps): Bump org.apache.maven.plugins:maven-shade-plugin (#63)
Bumps [org.apache.maven.plugins:maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.5.1 to 3.5.2.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.5.1...maven-shade-plugin-3.5.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-22 01:37:24 +08:00
dependabot[bot] fc1792113d chore(deps-dev): Bump log4j.version from 2.22.1 to 2.23.0 (#62)
Bumps `log4j.version` from 2.22.1 to 2.23.0.

Updates `org.apache.logging.log4j:log4j-api` from 2.22.1 to 2.23.0

Updates `org.apache.logging.log4j:log4j-core` from 2.22.1 to 2.23.0

Updates `org.apache.logging.log4j:log4j-slf4j-impl` from 2.22.1 to 2.23.0

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-22 01:37:12 +08:00
carm da3d4d1fd2 feat(loader): Refactor loaders and metadata. 2024-01-30 18:01:36 +08:00
carm b912ea369c feat(loader): Refactor loaders and metadata. 2024-01-16 23:25:21 +08:00
carm 2df33e3458 feat(adapter): Finished adapters registry 2024-01-16 03:50:08 +08:00
carm d041828717 feat(adapter): Use registry to manage value adapters 2024-01-16 02:59:21 +08:00
carm c7fb51d6b2 feat(adapter): Use registry to manage value adapters 2024-01-16 02:45:27 +08:00
carm 2ef1471f59 feat(parser): abstract value processor and parsers 2024-01-15 23:32:18 +08:00
carm 20a6eaefcd docs(url): Fixed url 2024-01-14 01:44:05 +08:00
dependabot[bot] e419e2498f chore(deps): Bump org.apache.maven.plugins:maven-surefire-plugin (#61)
Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.2.3 to 3.2.5.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.2.3...surefire-3.2.5)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-11 22:33:46 +08:00
dependabot[bot] 6ef4f9aebd chore(deps): Bump org.bspfsystems:yamlconfiguration from 2.0.0 to 2.0.1 (#60)
Bumps [org.bspfsystems:yamlconfiguration](https://github.com/bspfsystems/YamlConfiguration) from 2.0.0 to 2.0.1.
- [Release notes](https://github.com/bspfsystems/YamlConfiguration/releases)
- [Commits](https://github.com/bspfsystems/YamlConfiguration/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: org.bspfsystems:yamlconfiguration
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-07 00:05:52 +08:00
carm 21a8906ad9 chore(map): Optimize Map builders. 2024-01-05 01:26:50 +08:00
carm c91794c611 chore: optimize some codes 2024-01-04 22:38:45 +08:00
carm 3769cf4438 chore: optimize some codes 2024-01-04 22:08:12 +08:00
carm 34bc7601ee docs(sample): Add sample codes. 🍎 2024-01-04 21:29:06 +08:00
carm 0d19dc236e docs(sample): Add sample codes. 🥚 2024-01-04 21:20:56 +08:00
carm 9647591b0d docs(sample): Add sample codes. 🥚 2024-01-04 21:18:26 +08:00
carm 97db8204dc docs(sample): Add sample codes. 🥚 2024-01-03 23:33:39 +08:00
carm 48050a52a2 docs(sample): Add sample codes. 🥚 2024-01-03 23:28:36 +08:00
carm e42de0eee7 docs(sample): Add sample codes. 🥚 2024-01-03 23:24:59 +08:00
carm 814dae2278 docs(sample): Add sample codes. 🥚 2024-01-03 23:13:25 +08:00
carm db19531c13 docs(sample): Add sample codes. 🥚 2024-01-03 23:09:28 +08:00
dependabot[bot] d0af3e436f chore(deps-dev): Bump log4j.version from 2.22.0 to 2.22.1 (#58)
Bumps `log4j.version` from 2.22.0 to 2.22.1.

Updates `org.apache.logging.log4j:log4j-api` from 2.22.0 to 2.22.1

Updates `org.apache.logging.log4j:log4j-core` from 2.22.0 to 2.22.1

Updates `org.apache.logging.log4j:log4j-slf4j-impl` from 2.22.0 to 2.22.1

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-28 01:11:02 +08:00
dependabot[bot] 1252baab76 chore(deps): Bump org.apache.maven.plugins:maven-compiler-plugin (#57)
Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.12.0 to 3.12.1.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.12.0...maven-compiler-plugin-3.12.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-compiler-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-26 11:34:16 +08:00
carm 83037baf10 build(plugin): Fixed build plugins missing. 2023-12-24 21:10:27 +08:00
carm adf90a983b build(plugin): Fixed build plugins missing. 2023-12-24 21:09:13 +08:00
carm 02d816cd8d docs(readme): Relocated contents. 2023-12-24 21:01:09 +08:00
carm 5d5626bff2 build(plugin): Fixed build plugins missing. 2023-12-24 20:59:50 +08:00
carm 363c1e7ed8 docs(readme): listed all supported formats. 2023-12-24 05:16:59 +08:00
carm 7884d49309 docs(readme): listed all supported formats. 2023-12-24 05:11:56 +08:00
carm b77e64e6e6 docs(readme): listed all supported formats. 2023-12-24 05:02:59 +08:00
carm 505b86ec9c feat(sql): Support sql based configuration provider. 2023-12-24 04:52:56 +08:00
carm 374f646f9e feat(sql): Support sql based configuration provider. 2023-12-24 04:52:28 +08:00
carm aa50345329 feat(interface): Support interface root configurations. 2023-12-23 22:25:16 +08:00
carm db8b227317 feat(interface): Support interface root configurations. 2023-12-23 22:24:34 +08:00
carm 60eed8a14d docs(readme): Add English version of README files. 2023-12-23 21:24:45 +08:00
carm d41630be72 docs(readme): Add English version of README files. 2023-12-23 21:24:15 +08:00
carm 1c3a2b01ea docs(readme): Add English version of README files. 2023-12-23 21:18:50 +08:00
carm 1ede74c692 docs(readme): Add English version of README files. 2023-12-23 21:18:20 +08:00
carm 67456a8aac docs(readme): Add English version of README files. 2023-12-23 21:17:43 +08:00
carm f422900fb5 docs(readme): Add English version of README files. 2023-12-23 21:16:00 +08:00
carm b3e0007eba docs(readme): Add English version of README files. 2023-12-23 21:15:15 +08:00
carm 89c8ec8adf fix(type): 修复部分原生类型无法转换的问题。#54 2023-12-21 20:47:13 +08:00
huanmeng_qwq e8f49bf8bc fix(core): 解决 #54 的问题 (#55) 2023-12-21 20:43:15 +08:00
dependabot[bot] 8ac980fdbb chore(deps): Bump org.apache.maven.plugins:maven-compiler-plugin (#53)
Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.11.0 to 3.12.0.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.11.0...maven-compiler-plugin-3.12.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-compiler-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-19 22:51:35 +08:00
dependabot[bot] 9f2e4bc0cb chore(deps): Bump org.apache.maven.plugins:maven-surefire-plugin (#52)
Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.2.2 to 3.2.3.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.2.2...surefire-3.2.3)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-15 18:16:48 +08:00
dependabot[bot] ae16d131c3 chore(deps): Bump org.apache.maven.plugins:maven-javadoc-plugin (#51)
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.6.2 to 3.6.3.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.6.2...maven-javadoc-plugin-3.6.3)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-05 08:24:39 +08:00
dependabot[bot] bd8470a6e8 chore(deps): Bump org.jetbrains:annotations from 24.0.1 to 24.1.0 (#50)
Bumps [org.jetbrains:annotations](https://github.com/JetBrains/java-annotations) from 24.0.1 to 24.1.0.
- [Release notes](https://github.com/JetBrains/java-annotations/releases)
- [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md)
- [Commits](https://github.com/JetBrains/java-annotations/compare/24.0.1...24.1.0)

---
updated-dependencies:
- dependency-name: org.jetbrains:annotations
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-16 23:32:53 +08:00
dependabot[bot] 6af2d3fef5 chore(deps): Bump org.apache.maven.plugins:maven-javadoc-plugin (#48)
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.6.0 to 3.6.2.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.6.0...maven-javadoc-plugin-3.6.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-09 14:17:49 +08:00
dependabot[bot] 00f83002c5 chore(deps): Bump org.apache.maven.plugins:maven-surefire-plugin (#49)
Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.2.1 to 3.2.2.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.2.1...surefire-3.2.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-09 14:17:24 +08:00
dependabot[bot] 0aa548cbbf chore(deps): Bump org.bspfsystems:yamlconfiguration from 1.4.0 to 2.0.0 (#47)
Bumps [org.bspfsystems:yamlconfiguration](https://github.com/bspfsystems/YamlConfiguration) from 1.4.0 to 2.0.0.
- [Release notes](https://github.com/bspfsystems/YamlConfiguration/releases)
- [Commits](https://github.com/bspfsystems/YamlConfiguration/compare/v1.4.0...v2.0.0)

---
updated-dependencies:
- dependency-name: org.bspfsystems:yamlconfiguration
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-02 15:23:03 +08:00
dependabot[bot] 9c0ed1c5c2 chore(deps): Bump org.apache.maven.plugins:maven-surefire-plugin (#46)
Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.1.2 to 3.2.1.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.1.2...surefire-3.2.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-25 22:49:50 +08:00
dependabot[bot] bb0998cbac chore(deps): Bump com.typesafe:config from 1.4.2 to 1.4.3 (#45)
Bumps [com.typesafe:config](https://github.com/lightbend/config) from 1.4.2 to 1.4.3.
- [Release notes](https://github.com/lightbend/config/releases)
- [Changelog](https://github.com/lightbend/config/blob/main/NEWS.md)
- [Commits](https://github.com/lightbend/config/compare/v1.4.2...v1.4.3)

---
updated-dependencies:
- dependency-name: com.typesafe:config
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-17 23:40:40 +08:00
dependabot[bot] 1eb16f00b6 chore(deps): Bump org.bspfsystems:yamlconfiguration from 1.3.3 to 1.4.0 (#44)
Bumps [org.bspfsystems:yamlconfiguration](https://github.com/bspfsystems/YamlConfiguration) from 1.3.3 to 1.4.0.
- [Release notes](https://github.com/bspfsystems/YamlConfiguration/releases)
- [Commits](https://github.com/bspfsystems/YamlConfiguration/compare/v1.3.3...v1.4.0)

---
updated-dependencies:
- dependency-name: org.bspfsystems:yamlconfiguration
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-14 15:19:19 +08:00
dependabot[bot] 5ccf63b423 chore(deps): Bump org.apache.maven.plugins:maven-shade-plugin (#43)
Bumps [org.apache.maven.plugins:maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.5.0 to 3.5.1.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.5.0...maven-shade-plugin-3.5.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-26 12:48:04 +08:00
dependabot[bot] f1c0c74574 chore(deps): Bump org.apache.maven.plugins:maven-javadoc-plugin (#42)
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.5.0 to 3.6.0.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.5.0...maven-javadoc-plugin-3.6.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-19 12:16:10 +08:00
carm 8ee074474c fix(init): 添加文件初始化测试 #40 2023-08-29 02:39:38 +08:00
carm 27a68ead7c feat(map): 支持通过ConfigurationSection创建MapValue。 2023-08-28 17:00:56 +08:00
carm c6cce5208f fix(init): 尝试修复初始化创建无用文件的问题 #40 2023-08-10 02:00:46 +08:00
carm bc67de06f6 fix(init): 尝试修复初始化创建无用文件的问题 #40 2023-08-10 01:57:15 +08:00
carm b668794f5d feat(parse): 新增两种忽略默认值的parseValue方法。 2023-08-07 22:06:03 +08:00
carm 07424284b7 fix(file): 修复 FileConfigProvider#saveResource 文件创建异常的问题。#39 2023-07-18 00:25:40 +08:00
carm 81e024e309 fix(file): 修复 FileConfigProvider#saveResource 文件创建异常的问题。#39 2023-07-18 00:20:31 +08:00
carm 763fc7c758 fix(file): 修复 FileConfigProvider#saveResource 文件创建异常的问题。#39 2023-07-18 00:20:20 +08:00
carm 56557221a4 feat(list): 添加快速获取副本列表的方法 2023-07-17 17:34:34 +08:00
冬花ice e4435bf883 修复路径截取错误导致无法拥有内部object类型的问题 (#38)
* 修复路径截取错误导致无法拥有内部object类型的问题

* 移除测试输出
2023-07-10 12:32:24 +08:00
carm eee4a278d9 feat(value): 支持对Enum对象的快速解析 2023-06-23 14:06:56 +08:00
冬花ice 3a0a8e79b9 feat(hocon): 完成对 HOCON 格式的支持 (#36) 2023-06-21 19:54:30 +08:00
dependabot[bot] 3b2b1b27cc chore(deps): Bump maven-shade-plugin from 3.4.1 to 3.5.0 (#35)
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.4.1 to 3.5.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.4.1...maven-shade-plugin-3.5.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-20 01:35:02 +08:00
dependabot[bot] d84ea1b7da chore(deps): Bump maven-surefire-plugin from 3.1.0 to 3.1.2 (#34)
Bumps [maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.1.0 to 3.1.2.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.1.0...surefire-3.1.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-09 13:37:21 +08:00
dependabot[bot] a1f2cdca04 chore(deps): Bump yamlconfiguration from 1.3.2 to 1.3.3 (#33)
Bumps [yamlconfiguration](https://github.com/bspfsystems/YamlConfiguration) from 1.3.2 to 1.3.3.
- [Release notes](https://github.com/bspfsystems/YamlConfiguration/releases)
- [Commits](https://github.com/bspfsystems/YamlConfiguration/compare/v1.3.2...v1.3.3)

---
updated-dependencies:
- dependency-name: org.bspfsystems:yamlconfiguration
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-09 13:37:12 +08:00
dependabot[bot] c52183aadd chore(deps): Bump maven-release-plugin from 3.0.0 to 3.0.1 (#32)
Bumps [maven-release-plugin](https://github.com/apache/maven-release) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/apache/maven-release/releases)
- [Commits](https://github.com/apache/maven-release/compare/maven-release-3.0.0...maven-release-3.0.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-release-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-06 03:44:21 +08:00
dependabot[bot] d71aabad2d chore(deps): Bump maven-source-plugin from 3.2.1 to 3.3.0 (#31)
Bumps [maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.2.1 to 3.3.0.
- [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.2.1...maven-source-plugin-3.3.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-source-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-23 02:51:34 +08:00
carm 6a007c5187 refactor(api): 🤖 修改部分构造方法名称(破坏性更新) 2023-05-20 09:37:15 +08:00
carm 43b00f2b69 refactor(api): 🤖 优化代码命名逻辑,补充部分Javadoc。 2023-05-20 09:34:30 +08:00
carm 2e61e66cdb refactor(api): 🤖 优化代码命名逻辑,补充部分Javadoc。 2023-05-20 09:21:49 +08:00
dependabot[bot] 39f946c28e chore(deps): Bump maven-gpg-plugin from 3.0.1 to 3.1.0 (#30)
Bumps [maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.0.1 to 3.1.0.
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.0.1...maven-gpg-plugin-3.1.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-gpg-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-09 00:24:43 +08:00
dependabot[bot] 25931ffd7e chore(deps): Bump maven-surefire-plugin from 3.0.0 to 3.1.0 (#29)
Bumps [maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.0.0 to 3.1.0.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.0.0...surefire-3.1.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-09 00:12:17 +08:00
dependabot[bot] de103da879 chore(deps): Bump yamlconfiguration from 1.3.1 to 1.3.2 (#28)
Bumps [yamlconfiguration](https://github.com/bspfsystems/YamlConfiguration) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/bspfsystems/YamlConfiguration/releases)
- [Commits](https://github.com/bspfsystems/YamlConfiguration/compare/v1.3.1...v1.3.2)

---
updated-dependencies:
- dependency-name: org.bspfsystems:yamlconfiguration
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-15 12:39:03 +08:00
dependabot[bot] 457c22d461 chore(deps): Bump maven-release-plugin from 2.5.3 to 3.0.0 (#27)
Bumps [maven-release-plugin](https://github.com/apache/maven-release) from 2.5.3 to 3.0.0.
- [Release notes](https://github.com/apache/maven-release/releases)
- [Commits](https://github.com/apache/maven-release/compare/maven-release-2.5.3...maven-release-3.0.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-release-plugin
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-22 11:57:50 +08:00
carm aa4225dbba build: 修改Java版本的标签名 2023-03-20 20:17:23 +08:00
carm ddd33154be chore(yaml): 独立 YAMLCommentWriter 项目 2023-03-20 20:11:23 +08:00
carm 727c26a2fb feat(value): 单独提出 ”ValueManifest“ 以解决每个实现类中初始参数复杂的问题,方便后续开发。 2023-03-15 22:24:08 +08:00
dependabot[bot] 9c95a16d90 chore(deps): Bump maven-surefire-plugin from 2.22.2 to 3.0.0 (#26)
Bumps [maven-surefire-plugin](https://github.com/apache/maven-surefire) from 2.22.2 to 3.0.0.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-2.22.2...surefire-3.0.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-15 14:01:18 +08:00
dependabot[bot] 92c05f1a59 chore(deps): Bump annotations from 24.0.0 to 24.0.1 (#25)
Bumps [annotations](https://github.com/JetBrains/java-annotations) from 24.0.0 to 24.0.1.
- [Release notes](https://github.com/JetBrains/java-annotations/releases)
- [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md)
- [Commits](https://github.com/JetBrains/java-annotations/commits)

---
updated-dependencies:
- dependency-name: org.jetbrains:annotations
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-05 12:09:12 +08:00
dependabot[bot] 739ed41885 chore(deps): Bump maven-compiler-plugin from 3.10.1 to 3.11.0 (#24)
Bumps [maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.10.1 to 3.11.0.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.10.1...maven-compiler-plugin-3.11.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-compiler-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-01 00:07:08 +08:00
carm a66da01996 style: improve code readability. 2023-02-19 19:54:08 +08:00
carm 6dc0447502 test(map): 添加新版ConfiguredMap测试 2023-02-19 17:19:39 +08:00
carm c49d904665 feat(value): 为ConfiguredList 与 ConfiguredMap 实现相关基础方法 2023-02-19 17:17:33 +08:00
冬花ice b756074ddc fix(list): 允许出现长度为0的List (#23) 2023-02-19 16:49:25 +08:00
dependabot[bot] 9e3dff3e95 chore(deps): Bump maven-javadoc-plugin from 3.4.1 to 3.5.0 (#22)
Bumps [maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.4.1 to 3.5.0.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.4.1...maven-javadoc-plugin-3.5.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-16 23:59:23 +08:00
carm fd01d9b7ef feat(builder): 为 ConfiguredMap 提供更便利的defaults方法。 2023-02-11 21:45:00 +08:00
carm 0f8383bbf3 Merge remote-tracking branch 'origin/master' 2023-01-16 19:26:13 +08:00
carm 1232c7c4da feat(builder): 提供Functional形式提供defaultValue的方法。 2023-01-16 19:26:07 +08:00
dependabot[bot] 7ac39da4e9 chore(deps): Bump annotations from 23.1.0 to 24.0.0 (#21)
Bumps [annotations](https://github.com/JetBrains/java-annotations) from 23.1.0 to 24.0.0.
- [Release notes](https://github.com/JetBrains/java-annotations/releases)
- [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md)
- [Commits](https://github.com/JetBrains/java-annotations/compare/23.1.0...24.0.0)

---
updated-dependencies:
- dependency-name: org.jetbrains:annotations
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-12 22:16:19 +08:00
dependabot[bot] bf89f583db chore(deps): Bump gson from 2.10 to 2.10.1 (#20)
Bumps [gson](https://github.com/google/gson) from 2.10 to 2.10.1.
- [Release notes](https://github.com/google/gson/releases)
- [Changelog](https://github.com/google/gson/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/gson/compare/gson-parent-2.10...gson-parent-2.10.1)

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

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-10 01:02:32 +08:00
dependabot[bot] 03c69ba3a2 chore(deps): Bump yamlconfiguration from 1.3.0 to 1.3.1 (#19)
Bumps [yamlconfiguration](https://github.com/bspfsystems/YamlConfiguration) from 1.3.0 to 1.3.1.
- [Release notes](https://github.com/bspfsystems/YamlConfiguration/releases)
- [Commits](https://github.com/bspfsystems/YamlConfiguration/compare/v1.3.0...v1.3.1)

---
updated-dependencies:
- dependency-name: org.bspfsystems:yamlconfiguration
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-30 23:07:40 +08:00
dependabot[bot] d9cbd1a283 chore(deps): Bump annotations from 23.0.0 to 23.1.0 (#18)
Bumps [annotations](https://github.com/JetBrains/java-annotations) from 23.0.0 to 23.1.0.
- [Release notes](https://github.com/JetBrains/java-annotations/releases)
- [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md)
- [Commits](https://github.com/JetBrains/java-annotations/compare/23.0.0...23.1.0)

---
updated-dependencies:
- dependency-name: org.jetbrains:annotations
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-12 22:49:54 +08:00
carm 96e90dd71b chore 2022-12-11 19:10:50 +08:00
carm a9f3d829bd build(javadoc): 修复Demo项目缺失的javadoc 2022-12-11 02:30:47 +08:00
194 changed files with 10817 additions and 3749 deletions
+16
View File
@@ -0,0 +1,16 @@
# 欢迎使用 EasyConfiguration
这个项目刚刚创建,详细的Javadoc与开发指南还在补充,请给我一点时间~
## 基本定义
Value: 实际配置的单例值。
Manifest: 用于描述值基本配置的对象。
Provider: 用于提供配置文件的接口。
Wrapper: 用于包装配置文件的接口。
Initializer: 用于初始化的接口
-3
View File
@@ -1,3 +0,0 @@
# 欢迎使用 EasyConfiguration
这个项目刚刚创建,详细的Javadoc与开发指南还在补充,请给我一点时间~
+3 -3
View File
@@ -29,11 +29,11 @@ jobs:
steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout code
uses: actions/checkout@v2
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@d840f886c4bd4edc059706d09c6a1586111c540b
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
@@ -49,6 +49,6 @@ jobs:
# Upload the SARIF file generated in the previous step
- name: Upload SARIF results file
uses: github/codeql-action/upload-sarif@v1
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
+4 -4
View File
@@ -38,11 +38,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -53,7 +53,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v3
# ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -67,4 +67,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v3
+8 -8
View File
@@ -16,9 +16,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: "Set up JDK"
uses: actions/setup-java@v2
uses: actions/setup-java@v4
with:
java-version: '11'
distribution: 'adopt'
@@ -40,8 +40,8 @@ jobs:
run: |
rm -rf docs
mkdir -vp docs
cp -vrf core/target/apidocs/* docs/
cp -vrf .documentation/JAVADOC-README.md docs/README.md
cp -vrf core/target/reports/apidocs/* docs/
cp -vrf .doc/JAVADOC-README.md docs/README.md
- name: "Generate the Javadoc sitemap"
id: sitemap
@@ -87,21 +87,21 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: "Set up JDK"
uses: actions/setup-java@v2
uses: actions/setup-java@v4
with:
java-version: '11'
distribution: 'adopt'
cache: maven
server-id: ossrh
server-id: central
server-username: MAVEN_USERNAME
server-password: MAVEN_PASSWORD
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import
gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase
- name: "Central Deploy"
run: mvn -B -Possrh deploy --file pom.xml -DskipTests
run: mvn -B -Pcentral deploy --file pom.xml -DskipTests
env:
MAVEN_USERNAME: ${{ secrets.OSSRH_USER }}
MAVEN_PASSWORD: ${{ secrets.OSSRH_PASS }}
+3 -3
View File
@@ -15,9 +15,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: "Set up JDK"
uses: actions/setup-java@v2
uses: actions/setup-java@v4
with:
java-version: '11'
distribution: 'adopt'
@@ -26,7 +26,7 @@ jobs:
- name: "Target Stage"
run: mkdir staging && cp */target/*.jar staging
- name: "Upload artifact"
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: Artifact
path: staging
+1 -1
View File
@@ -1,3 +1,3 @@
/.idea/
.idea/
**/target/
**.iml
+142 -49
View File
@@ -6,6 +6,8 @@
/___/ /___/
```
README LANGUAGES [ [**English**](README.md) | [中文](README_CN.md) ]
# EasyConfiguration
[![version](https://img.shields.io/github/v/release/CarmJos/EasyConfiguration)](https://github.com/CarmJos/EasyConfiguration/releases)
@@ -15,29 +17,122 @@
![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!**
## 优势
A simple, easy-to-use and universal solution for managing configuration files.
Enjoy the ease of use with customizable formats for loading, reading, and updating your configuration files.
- 基于类的配置文件初始化、加载、获取与更新机制,方便快捷。
- 支持复杂配置的手动序列化、反序列化。
- 提供多种builder形式,快速构建 `ConfigValue<?>` 对象。
- 支持通过注解规定配置对应的路径、注释等信息。
## Features & Advantages
## 开发
Supported [YAML](impl/yaml), [JSON](impl/json), [HOCON](impl/hocon) and [SQL](impl/sql) based configuration files
format.
详细开发介绍请 [点击这里](.documentation/README.md) , JavaDoc(最新Release) 请 [点击这里](https://CarmJos.github.io/EasyConfiguration) 。
- Class-based mechanism for initializing, loading, retrieving, and updating configuration files, ensuring convenience
and efficiency.
- Supports manual serialization and deserialization of complex configurations.
- Offers multiple builder forms for rapid construction of `ConfigValue<?>` objects.
- Enables specification of configuration paths, comments, and more via annotations.
### 示例代码
## Development
您可以 [点击这里](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java) 查看部分代码演示,更多演示详见 [开发介绍](.documentation/README.md) 。
For the latest JavaDoc release, [CLICK HERE](https://CarmJos.github.io/EasyConfiguration).
### 依赖方式
For a detailed development guide, [CLICK HERE](.doc/README.md).
#### Maven 依赖
### Code Samples
To quickly demonstrate the applicability of the project, here are a few practical demonstrations:
- [Database configuration.](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java)
- [Demonstration of all types of configuration instance classes.](demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java)
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).
```java
@ConfigPath(root = true)
@HeaderComments("Configurations for sample")
public interface SampleConfig extends Configuration {
@InlineComment("Enabled?") // Inline comment
ConfiguredValue<Boolean> ENABLED = ConfiguredValue.of(true);
@HeaderComments("Server configurations") // Header comment
ConfiguredValue<Integer> PORT = ConfiguredValue.of(Integer.class);
@HeaderComments({"[ UUID >-----------------------------------", "A lot of UUIDs"})
@FooterComments("[ UUID >-----------------------------------")
ConfiguredList<UUID> UUIDS = ConfiguredList.builderOf(UUID.class).fromString()
.parse(UUID::fromString).serialize(UUID::toString)
.defaults(
UUID.fromString("00000000-0000-0000-0000-000000000000"),
UUID.fromString("00000000-0000-0000-0000-000000000001")
).build();
@ConfigPath("info") // Custom path
interface INFO extends Configuration {
@HeaderComments("Configure your name!") // Header comment
ConfiguredValue<String> NAME = ConfiguredValue.of("Joker");
@ConfigPath("how-old-are-you") // Custom path
ConfiguredValue<Integer> AGE = ConfiguredValue.of(24);
}
}
```
```java
public class Sample {
public static void main(String[] args) {
// 1. Make a configuration provider from a file.
ConfigurationHolder<?> holder = YAMLConfigFactory.from("target/config.yml")
.resourcePath("configs/sample.yml")
.indent(4) // Optional: Set the indentation of the configuration file.
.build();
// 2. Initialize the configuration classes or instances.
holder.initialize(SampleConfig.class);
// 3. Enjoy using the configuration!
System.out.println("Enabled? -> " + SampleConfig.ENABLED.resolve());
SampleConfig.ENABLED.set(false);
System.out.println("And now? -> " + SampleConfig.ENABLED.resolve());
// 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() + ")!");
}
}
```
```yaml
# Configurations for sample
enabled: true #Enabled?
# Server configurations
port:
# [ UUID >-----------------------------------
# A lot of UUIDs
uuids:
- 00000000-0000-0000-0000-000000000000
- 00000000-0000-0000-0000-000000000001
# [ UUID >-----------------------------------
info:
# Configure your name!
name: Joker
how-old-are-you: 24
```
### Dependencies
#### Maven Dependency
<details>
<summary>远程库配置</summary>
<summary>Remote Repository Configuration</summary>
```xml
@@ -45,26 +140,19 @@
<repositories>
<repository>
<!--采用Maven中心库,安全稳定,但版本更新需要等待同步-->
<!-- Using Maven Central Repository for secure and stable updates, though synchronization might be needed. -->
<id>maven</id>
<name>Maven Central</name>
<url>https://repo1.maven.org/maven2</url>
</repository>
<repository>
<!--采用github依赖库,实时更新,但需要配置 (推荐) -->
<!-- Using GitHub dependencies for real-time updates, configuration required (recommended). -->
<id>EasyConfiguration</id>
<name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url>
</repository>
<repository>
<!--采用我的私人依赖库,简单方便,但可能因为变故而无法使用-->
<id>carm-repo</id>
<name>Carm's Repo</name>
<url>https://repo.carm.cc/repository/maven-public/</url>
</repository>
</repositories>
</project>
```
@@ -72,13 +160,13 @@
</details>
<details>
<summary>通用原生依赖</summary>
<summary>Generic Native Dependency</summary>
```xml
<project>
<dependencies>
<!--基础实现部分,需要自行实现“Provider”“Wrapper”-->
<!-- Basic implementation part, requiring custom implementation of “Provider” and “Wrapper”. -->
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-core</artifactId>
@@ -86,7 +174,7 @@
<scope>compile</scope>
</dependency>
<!--基于YAML文件的实现版本,可用于全部Java环境。-->
<!-- YAML file-based implementation, compatible with all Java environments. -->
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-yaml</artifactId>
@@ -94,11 +182,10 @@
<scope>compile</scope>
</dependency>
<!--基于JSON文件的实现版本,可用于全部Java环境。-->
<!--需要注意的是,JSON不支持文件注释。-->
<!-- JSON file-based implementation, compatible with all Java environments. -->
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-json</artifactId>
<artifactId>easyconfiguration-gson</artifactId>
<version>[LATEST RELEASE]</version>
<scope>compile</scope>
</dependency>
@@ -109,66 +196,72 @@
</details>
#### Gradle 依赖
#### Gradle Dependency
<details>
<summary>远程库配置</summary>
<summary>Remote Repository Configuration</summary>
```groovy
repositories {
// 采用Maven中心库,安全稳定,但版本更新需要等待同步
// Using Maven Central Repository for secure and stable updates, though synchronization might be needed.
mavenCentral()
// 采用github依赖库,实时更新,但需要配置 (推荐)
// Using GitHub dependencies for real-time updates, configuration required (recommended).
maven { url 'https://maven.pkg.github.com/CarmJos/EasyConfiguration' }
// 采用我的私人依赖库,简单方便,但可能因为变故而无法使用
maven { url 'https://repo.carm.cc/repository/maven-public/' }
}
```
</details>
<details>
<summary>通用原生依赖</summary>
<summary>Generic Native Dependency</summary>
```groovy
dependencies {
//基础实现部分,需要自行实现“Provider”“Wrapper”
// Basic implementation part, requiring custom implementation of “Provider” and “Wrapper”.
api "cc.carm.lib:easyconfiguration-core:[LATEST RELEASE]"
//基于YAML文件的实现版本,可用于全部Java环境。
// YAML file-based implementation, compatible with all Java environments.
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]"
//基于JSON文件的实现版本,可用于全部Java环境。
//需要注意的是,JSON不支持文件注释。
api "cc.carm.lib:easyconfiguration-json:[LATEST RELEASE]"
// JSON file-based implementation, compatible with all Java environments.
api "cc.carm.lib:easyconfiguration-gson:[LATEST RELEASE]"
}
```
</details>
## 衍生项目
## Derived Projects
### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos)
EasyConfiguration for MineCraft!
开始在 MineCraft 相关服务器平台上轻松(做)配置吧!
Easily manage configurations on MineCraft-related server platforms.
目前支持 BungeeCord, Bukkit(Spigot) 服务端,后续将支持更多平台。
Currently, it supports BungeeCord, Velocity, Bukkit (Spigot) servers,
with more platforms to be supported soon.
## 支持与捐赠
## Support and Donation
若您觉得本插件做的不错,您可以通过捐赠支持我!
If you appreciate this plugin, consider supporting me with a donation!
感谢您对开源项目的支持!
Thank you for supporting open-source projects!
<img height=25% width=25% src="https://raw.githubusercontent.com/CarmJos/CarmJos/main/img/donate-code.jpg" alt=""/>
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)
本项目源码采用 [GNU LESSER GENERAL PUBLIC LICENSE](https://www.gnu.org/licenses/lgpl-3.0.html) 开源协议。
Many thanks to [ArtformGames](https://github.com/ArtformGames) for their
strong support and active contribution to this project!
<img src="https://raw.githubusercontent.com/ArtformGames/.github/master/logo/logo_full.svg" width="317px" height="117px" alt="ArtformGames">
## Open Source License
This project's source code is licensed under
the [GNU LESSER GENERAL PUBLIC LICENSE](https://www.gnu.org/licenses/lgpl-3.0.html).
+287
View File
@@ -0,0 +1,287 @@
```text
____ _____ ____ __ _
/ __/__ ____ __ __ / ___/__ ___ / _(_)__ ___ _________ _/ /_(_)__ ___
/ _// _ `(_-</ // / / /__/ _ \/ _ \/ _/ / _ `/ // / __/ _ `/ __/ / _ \/ _ \
/___/\_,_/___/\_, / \___/\___/_//_/_//_/\_, /\_,_/_/ \_,_/\__/_/\___/_//_/
/___/ /___/
```
README LANGUAGES [ [English](README.md) | [**中文**](README_CN.md) ]
# EasyConfiguration
[![version](https://img.shields.io/github/v/release/CarmJos/EasyConfiguration)](https://github.com/CarmJos/EasyConfiguration/releases)
[![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)
**轻松(做)配置!**
一款简单便捷的通用配置文件加载、读取与更新工具,可自定义配置的格式。
## 特性 & 优势
支持 [YAML](impl/yaml), [JSON](impl/json), [HOCON](impl/hocon) 和 [SQL](impl/sql) 等多种配置文件格式。
- 基于类的配置文件初始化、加载、获取与更新机制,方便快捷。
- 支持复杂配置的手动序列化、反序列化。
- 提供多种builder形式,快速构建 `ConfigValue<?>` 对象。
- 支持通过注解规定配置对应的路径、注释等信息。
## 开发
详细开发介绍请 [点击这里](.doc/README.md) , JavaDoc(最新Release)
请 [点击这里](https://CarmJos.github.io/EasyConfiguration) 。
### 示例代码
为快速的展示该项目的适用性,这里有几个实际演示:
- [数据库配置文件实例](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java)
- [全种类配置实例类演示](demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java)
您可以 [点击这里](demo/src/main/java/cc/carm/lib/configuration/demo)
直接查看现有的代码演示,更多复杂情况演示详见 [开发介绍](.doc/README.md) 。
```java
@ConfigPath(root = true)
@HeaderComments("Configurations for sample")
public interface SampleConfig extends Configuration {
@InlineComment("Enabled?") // 行后注释
ConfiguredValue<Boolean> ENABLED = ConfiguredValue.of(true);
@HeaderComments("Server configurations") // 头部注释
ConfiguredValue<Integer> PORT = ConfiguredValue.of(Integer.class);
@HeaderComments({"[ UUID >-----------------------------------", "A lot of UUIDs"})
@FooterComments("[ UUID >-----------------------------------")
ConfiguredList<UUID> UUIDS = ConfiguredList.builderOf(UUID.class).fromString()
.parse(UUID::fromString).serialize(UUID::toString)
.defaults(
UUID.fromString("00000000-0000-0000-0000-000000000000"),
UUID.fromString("00000000-0000-0000-0000-000000000001")
).build();
interface INFO extends Configuration {
@HeaderComments("Configure your name!") // Header comment
ConfiguredValue<String> NAME = ConfiguredValue.of("Joker");
@ConfigPath("how-old-are-you") // 自定义路径
ConfiguredValue<Integer> AGE = ConfiguredValue.of(24);
}
}
```
```java
public class Sample {
public static void main(String[] args) {
// 1. 生成一个 “holder” 用于给配置类提供源配置的文件。
ConfigurationHolder<?> holder = YAMLConfigFactory.from("target/config.yml")
.resourcePath("configs/sample.yml")
.indent(4) // Optional: Set the indentation of the configuration file.
.build();
// 2. 通过 “holder” 初始化配置类或配置实例。
holder.initialize(SampleConfig.class);
// 3. 现在可以享受快捷方便的配置文件使用方式了~
System.out.println("Enabled? -> " + SampleConfig.ENABLED.resolve());
SampleConfig.ENABLED.set(false);
System.out.println("And now? -> " + SampleConfig.ENABLED.resolve());
// p.s. 在本示例里的更改未保存,因此启用值在下次运行中仍将为 true。
}
}
```
```yaml
# Configurations for sample
enabled: true #Enabled?
# Server configurations
port:
# [ UUID >-----------------------------------
# A lot of UUIDs
uuids:
- 00000000-0000-0000-0000-000000000000
- 00000000-0000-0000-0000-000000000001
# [ UUID >-----------------------------------
info:
# Configure your name!
name: Joker
how-old-are-you: 24
```
### 依赖方式
#### Maven 依赖
<details>
<summary>远程库配置</summary>
```xml
<project>
<repositories>
<repository>
<!--采用Maven中心库,安全稳定,但版本更新需要等待同步-->
<id>maven</id>
<name>Maven Central</name>
<url>https://repo1.maven.org/maven2</url>
</repository>
<repository>
<!--采用github依赖库,实时更新,但需要配置 (推荐) -->
<id>EasyConfiguration</id>
<name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url>
</repository>
<repository>
<!--采用我的私人依赖库,简单方便,但可能因为变故而无法使用-->
<id>carm-repo</id>
<name>Carm's Repo</name>
<url>https://repo.carm.cc/repository/maven-public/</url>
</repository>
</repositories>
</project>
```
</details>
<details>
<summary>通用原生依赖</summary>
```xml
<project>
<dependencies>
<!--基础实现部分,需要自行实现“Provider”与“Wrapper”。-->
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-core</artifactId>
<version>[LATEST RELEASE]</version>
<scope>compile</scope>
</dependency>
<!--基于YAML文件的实现版本,可用于全部Java环境。-->
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-yaml</artifactId>
<version>[LATEST RELEASE]</version>
<scope>compile</scope>
</dependency>
<!--基于JSON文件的实现版本,可用于全部Java环境。-->
<!--需要注意的是,JSON不支持文件注释。-->
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-gson</artifactId>
<version>[LATEST RELEASE]</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-hocon</artifactId>
<version>[LATEST RELEASE]</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-sql</artifactId>
<version>[LATEST RELEASE]</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
```
</details>
#### Gradle 依赖
<details>
<summary>远程库配置</summary>
```groovy
repositories {
// 采用Maven中心库,安全稳定,但版本更新需要等待同步
mavenCentral()
// 采用github依赖库,实时更新,但需要配置 (推荐)
maven { url 'https://maven.pkg.github.com/CarmJos/EasyConfiguration' }
// 采用我的私人依赖库,简单方便,但可能因为变故而无法使用
maven { url 'https://repo.carm.cc/repository/maven-public/' }
}
```
</details>
<details>
<summary>通用原生依赖</summary>
```groovy
dependencies {
//基础实现部分,需要自行实现“Provider”与“Wrapper”。
api "cc.carm.lib:easyconfiguration-core:[LATEST RELEASE]"
//基于YAML文件的实现版本,可用于全部Java环境。
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]"
//基于JSON文件的实现版本,可用于全部Java环境。
//需要注意的是,JSON不支持文件注释。
api "cc.carm.lib:easyconfiguration-gson:[LATEST RELEASE]"
api "cc.carm.lib:easyconfiguration-hocon:[LATEST RELEASE]"
api "cc.carm.lib:easyconfiguration-sql:[LATEST RELEASE]"
}
```
</details>
## 衍生项目
### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos )
EasyConfiguration for MineCraft!
开始在 MineCraft 相关服务器平台上轻松(做)配置吧!
目前支持 BungeeCord, Bukkit(Spigot) 服务端,后续将支持更多平台。
## 支持与捐赠
若您觉得本插件做的不错,您可以通过捐赠支持我!
感谢您对开源项目的支持!
万分感谢 Jetbrains 为我们提供了从事此项目和其他开源项目的许可!
[![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/CarmJos/EasyConfiguration)
万分感谢来自 [ArtformGames](https://github.com/ArtformGames) 对本项目的大力支持与积极贡献!
<img src="https://raw.githubusercontent.com/ArtformGames/.github/master/logo/logo_full.svg" width="317px" height="117px" alt="ArtformGames">
## 开源协议
本项目源码采用 [GNU LESSER GENERAL PUBLIC LICENSE](https://www.gnu.org/licenses/lgpl-3.0.html) 开源协议。
+3 -3
View File
@@ -5,12 +5,12 @@
<parent>
<artifactId>easyconfiguration-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>3.3.0</version>
<version>4.0.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<properties>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<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>
@@ -0,0 +1,7 @@
package cc.carm.lib.configuration;
/**
* The root interface of the configuration file interfaces,
* which is used to label a class as a configuration.
*/
public interface Configuration { }
@@ -0,0 +1,79 @@
package cc.carm.lib.configuration.adapter;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
/**
* Value adapter, used to convert the value of the configuration file into the objects.
*
* @param <TYPE> The type of the target value
*/
public class ValueAdapter<TYPE>
implements ValueSerializer<TYPE>, ValueParser<TYPE> {
protected final @NotNull ValueType<TYPE> type;
protected @Nullable ValueSerializer<TYPE> serializer;
protected @Nullable ValueParser<TYPE> deserializer;
public ValueAdapter(@NotNull ValueType<TYPE> type) {
this(type, null, null);
}
public ValueAdapter(@NotNull ValueType<TYPE> type,
@Nullable ValueSerializer<TYPE> serializer,
@Nullable ValueParser<TYPE> parser) {
this.type = type;
this.serializer = serializer;
this.deserializer = parser;
}
public @NotNull ValueType<TYPE> type() {
return type;
}
public @Nullable ValueSerializer<TYPE> serializer() {
return serializer;
}
public @Nullable ValueParser<TYPE> parser() {
return deserializer;
}
public ValueAdapter<TYPE> serializer(@Nullable ValueSerializer<TYPE> serializer) {
this.serializer = serializer;
return this;
}
public ValueAdapter<TYPE> parser(@Nullable ValueParser<TYPE> deserializer) {
this.deserializer = deserializer;
return this;
}
@Override
public 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");
return serializer.serialize(holder, type, value);
}
@Override
public 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");
return deserializer.parse(holder, type, value);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ValueAdapter)) return false;
ValueAdapter<?> that = (ValueAdapter<?>) o;
return Objects.equals(type, that.type);
}
@Override
public int hashCode() {
return Objects.hashCode(type);
}
}
@@ -0,0 +1,126 @@
package cc.carm.lib.configuration.adapter;
import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class ValueAdapterRegistry {
protected final Set<ValueAdapter<?>> adapters = new HashSet<>();
public <FROM, TO> void register(@NotNull Class<FROM> from, @NotNull Class<TO> to,
@Nullable DataFunction<FROM, TO> parser,
@Nullable DataFunction<TO, FROM> serializer) {
register(ValueType.of(from), ValueType.of(to), parser, serializer);
}
public <FROM, TO> void register(@NotNull ValueType<FROM> from, @NotNull ValueType<TO> to,
@Nullable DataFunction<FROM, TO> parser,
@Nullable DataFunction<TO, FROM> serializer) {
ValueAdapter<FROM> fromAdapter = adapterOf(from);
if (fromAdapter == null) throw new IllegalArgumentException("No adapter for type " + from);
register(to,
serializer == null ? null : (provider, type, value) -> fromAdapter.serialize(provider, from, serializer.handle(value)),
parser == null ? null : (provider, type, data) -> parser.handle(fromAdapter.parse(provider, from, data))
);
}
public void register(@NotNull ValueAdapter<?>... adapter) {
adapters.addAll(Arrays.asList(adapter));
}
public <T> void register(@NotNull Class<T> type, @NotNull ValueSerializer<T> serializer) {
register(ValueType.of(type), serializer);
}
public <T> void register(@NotNull ValueType<T> type, @NotNull ValueSerializer<T> serializer) {
ValueAdapter<T> existing = adapterOf(type);
if (existing != null) {
existing.serializer(serializer);
} else {
register(new ValueAdapter<>(type, serializer, null));
}
}
public <T> void register(@NotNull Class<T> type, @NotNull ValueParser<T> deserializer) {
register(ValueType.of(type), deserializer);
}
public <T> void register(@NotNull ValueType<T> type, @NotNull ValueParser<T> deserializer) {
ValueAdapter<T> existing = adapterOf(type);
if (existing != null) {
existing.parser(deserializer);
} else {
register(new ValueAdapter<>(type, null, deserializer));
}
}
public <T> void register(@NotNull ValueType<T> type, @Nullable ValueSerializer<T> serializer, @Nullable ValueParser<T> deserializer) {
if (serializer == null && deserializer == null) return;
ValueAdapter<T> existing = adapterOf(type);
if (existing != null) {
if (serializer != null) existing.serializer(serializer);
if (deserializer != null) existing.parser(deserializer);
} else {
register(new ValueAdapter<>(type, serializer, deserializer));
}
}
public void unregister(@NotNull Class<?> type) {
unregister(ValueType.of(type));
}
public void unregister(@NotNull ValueType<?> type) {
adapters.removeIf(adapter -> adapter.type().equals(type));
}
@SuppressWarnings("unchecked")
public <T> @Nullable ValueAdapter<T> adapterOf(@NotNull ValueType<T> type) {
ValueAdapter<?> matched = adapters.stream().filter(adapter -> adapter.type().equals(type)).findFirst().orElse(null);
if (matched != null) return (ValueAdapter<T>) matched;
// If no adapter found, try to find the adapter for the super type
return (ValueAdapter<T>) adapters.stream()
.filter(adapter -> adapter.type().isSubtypeOf(type))
.findFirst().orElse(null);
}
public <T> ValueAdapter<T> adapterOf(@NotNull T value) {
return adapterOf(ValueType.of(value));
}
public <T> ValueAdapter<T> adapterOf(@NotNull Class<T> 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 {
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 {
if (source == null) return null; // Null check
if (type.isInstance(source)) return type.cast(source); // Not required to deserialize
ValueAdapter<T> adapter = adapterOf(type);
if (adapter == null) throw new RuntimeException("No adapter for type " + type);
return adapter.parse(holder, type, source);
}
@Contract("_,null -> null")
public <T> Object serialize(@NotNull ConfigurationHolder<?> holder, @Nullable T value) throws Exception {
if (value == null) return null; // Null check
ValueType<T> type = ValueType.of(value);
ValueAdapter<T> adapter = adapterOf(type);
if (adapter == null) return value; // No adapters, try to return the original value
return adapter.serialize(holder, type, value);
}
}
@@ -0,0 +1,19 @@
package cc.carm.lib.configuration.adapter;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
/**
* Value deserializer, convert base data to target value.
*
* @param <TYPE> The type of target value
*/
@FunctionalInterface
public interface ValueParser<TYPE> {
TYPE parse(
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type, @NotNull Object data
) throws Exception;
}
@@ -0,0 +1,19 @@
package cc.carm.lib.configuration.adapter;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
/**
* Value serializer, convert target value to base data.
*
* @param <TYPE> The type of value
*/
@FunctionalInterface
public interface ValueSerializer<TYPE> {
Object serialize(
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type, @NotNull TYPE value
) throws Exception;
}
@@ -0,0 +1,193 @@
package cc.carm.lib.configuration.adapter;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Used to get the generic type.
*/
public abstract class ValueType<T> {
public static final ValueType<String> STRING = ofPrimitiveType(String.class);
public static final ValueType<Integer> INTEGER = ofPrimitiveType(Integer.class);
public static final ValueType<Integer> INTEGER_TYPE = ofPrimitiveType(int.class);
public static final ValueType<Long> LONG = ofPrimitiveType(Long.class);
public static final ValueType<Long> LONG_TYPE = ofPrimitiveType(long.class);
public static final ValueType<Double> DOUBLE = ofPrimitiveType(Double.class);
public static final ValueType<Double> DOUBLE_TYPE = ofPrimitiveType(double.class);
public static final ValueType<Float> FLOAT = ofPrimitiveType(Float.class);
public static final ValueType<Float> FLOAT_TYPE = ofPrimitiveType(float.class);
public static final ValueType<Boolean> BOOLEAN = ofPrimitiveType(Boolean.class);
public static final ValueType<Boolean> BOOLEAN_TYPE = ofPrimitiveType(boolean.class);
public static final ValueType<Byte> BYTE = ofPrimitiveType(Byte.class);
public static final ValueType<Byte> BYTE_TYPE = ofPrimitiveType(byte.class);
public static final ValueType<Short> SHORT = ofPrimitiveType(Short.class);
public static final ValueType<Short> SHORT_TYPE = ofPrimitiveType(short.class);
public static final ValueType<Character> CHAR = ofPrimitiveType(Character.class);
public static final ValueType<Character> CHAR_TYPE = ofPrimitiveType(char.class);
public static final ValueType<?>[] PRIMITIVE_TYPES = {
STRING, INTEGER, LONG, DOUBLE, FLOAT, BOOLEAN, BYTE, SHORT, CHAR,
INTEGER_TYPE, LONG_TYPE, DOUBLE_TYPE, FLOAT_TYPE, BOOLEAN_TYPE, BYTE_TYPE, SHORT_TYPE, CHAR_TYPE
};
@SuppressWarnings("unchecked")
public static <T> ValueType<T> of(@NotNull T value) {
return of((Class<T>) value.getClass());
}
@SuppressWarnings("unchecked")
public static <T> ValueType<T> of(final Type type) {
if (type == null) throw new NullPointerException("Type cannot be null");
if (type instanceof Class<?>) { // Try handle primitive types
Class<?> clazz = (Class<?>) type;
for (ValueType<?> valueType : PRIMITIVE_TYPES) {
if (valueType.getRawType() == clazz) {
return (ValueType<T>) valueType;
}
}
}
return new ValueType<T>(type) {
};
}
public static <T> ValueType<T> of(final Class<T> clazz) {
return of((Type) clazz);
}
/**
* Get the generic type of the complex type.
*
* @param rawType The raw type
* @param types The type arguments
* @param <T> The type
* @return The {@link ValueType}
*/
public static <T> ValueType<T> of(final Class<?> rawType, final Type... types) {
ParameterizedType parameterizedType = new ParameterizedType() {
@Override
public @NotNull Type @NotNull [] getActualTypeArguments() {
return types;
}
@Override
public @NotNull Type getRawType() {
return rawType;
}
@Override
public Type getOwnerType() {
return null;
}
};
return of(parameterizedType);
}
private static <T> ValueType<T> ofPrimitiveType(Class<T> clazz) {
return new ValueType<T>(clazz) {
};
}
private final Type type;
protected ValueType() {
this.type = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
private ValueType(Type type) {
this.type = type;
}
public Type getType() {
return type;
}
public boolean isSubtypeOf(Class<?> target) {
Class<?> rawType = getRawType();
return target.isAssignableFrom(rawType);
}
public boolean isSubtypeOf(ValueType<?> target) {
return target.isSubtypeOf(getRawType());
}
public boolean isInstance(Object obj) {
return obj != null && getRawType().isInstance(obj);
}
/**
* 提取当前 ValueType 的原始类型(Class 对象)。
*
* @return 对应的 Class 对象
* @throws IllegalStateException 如果无法提取出原始类型
*/
public Class<?> getRawType() {
if (type instanceof Class<?>) {
return (Class<?>) type;
}
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
Type raw = pt.getRawType();
if (raw instanceof Class<?>) {
return (Class<?>) raw;
}
}
throw new IllegalStateException("Unsupported type: " + type);
}
@SuppressWarnings("unchecked")
public T cast(Object obj) {
if (!isInstance(obj)) {
throw new ClassCastException("Cannot cast object " + obj + " to type " + this);
}
return (T) obj;
}
@Override
public String toString() {
if (type instanceof Class<?>) {
return ((Class<?>) type).getName();
}
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
Type raw = pt.getRawType();
StringBuilder sb = new StringBuilder();
sb.append(raw.getClass().getName());
sb.append('<');
Type[] args = pt.getActualTypeArguments();
for (int i = 0; i < args.length; i++) {
if (i > 0) {
sb.append(", ");
}
sb.append(args[i].getTypeName());
}
sb.append('>');
return sb.toString();
}
return type.getTypeName();
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj instanceof ValueType) {
return Objects.equals(type, ((ValueType<?>) obj).type);
}
if (obj instanceof Type) {
return Objects.equals(type, obj);
}
return false;
}
@Override
public int hashCode() {
return Objects.hashCode(type);
}
}
@@ -0,0 +1,119 @@
package cc.carm.lib.configuration.adapter.strandard;
import cc.carm.lib.configuration.adapter.ValueAdapter;
import cc.carm.lib.configuration.adapter.ValueParser;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.function.DataFunction;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
public class PrimitiveAdapter<T> extends ValueAdapter<T> {
public static final String[] TRUE_VALUES = new String[]{
"true", "yes", "on", "1", "enabled", "enable", "active"
};
public static final String[] FALSE_VALUES = new String[]{
"false", "no", "off", "0", "disabled", "disable", "inactive"
};
@SuppressWarnings({"unchecked", "rawtypes"})
public static ValueAdapter<Enum<?>> ofEnum() {
ValueAdapter<Enum<?>> adapter = new ValueAdapter<>(new ValueType<Enum<?>>() {
});
adapter.parser((provider, type, data) -> Enum.valueOf((Class<Enum>) type.getRawType(), data.toString()));
adapter.serializer((provider, type, value) -> value.name());
return adapter;
}
public static PrimitiveAdapter<String> ofString() {
return of(String.class, o -> o instanceof String ? (String) o : o.toString());
}
public static PrimitiveAdapter<Boolean> ofBoolean() {
return of(Boolean.class, data -> {
if (data instanceof Boolean) return (Boolean) data;
String v = data.toString().trim();
if (Arrays.stream(TRUE_VALUES).anyMatch(v::equalsIgnoreCase)) return true;
else if (Arrays.stream(FALSE_VALUES).anyMatch(v::equalsIgnoreCase)) return false;
else throw new IllegalArgumentException("Cannot parse boolean from " + data);
});
}
public static PrimitiveAdapter<Boolean> ofBooleanType() {
return of(boolean.class, o -> o instanceof Boolean ? (Boolean) o : Boolean.parseBoolean(o.toString()));
}
public static PrimitiveAdapter<Character> ofCharacter() {
return of(Character.class, o -> o instanceof Character ? (Character) o : o.toString().charAt(0));
}
public static PrimitiveAdapter<Character> ofCharacterType() {
return of(char.class, o -> o instanceof Character ? (Character) o : o.toString().charAt(0));
}
public static PrimitiveAdapter<Integer> ofInteger() {
return ofNumber(Integer.class, Number::intValue, Integer::parseInt);
}
public static PrimitiveAdapter<Integer> ofIntegerType() {
return ofNumber(int.class, Number::intValue, Integer::parseInt);
}
public static PrimitiveAdapter<Long> ofLong() {
return ofNumber(Long.class, Number::longValue, Long::parseLong);
}
public static PrimitiveAdapter<Long> ofLongType() {
return ofNumber(long.class, Number::longValue, Long::parseLong);
}
public static PrimitiveAdapter<Double> ofDouble() {
return ofNumber(Double.class, Number::doubleValue, Double::parseDouble);
}
public static PrimitiveAdapter<Double> ofDoubleType() {
return ofNumber(double.class, Number::doubleValue, Double::parseDouble);
}
public static PrimitiveAdapter<Float> ofFloat() {
return ofNumber(Float.class, Number::floatValue, Float::parseFloat);
}
public static PrimitiveAdapter<Float> ofFloatType() {
return ofNumber(float.class, Number::floatValue, Float::parseFloat);
}
public static PrimitiveAdapter<Short> ofShort() {
return ofNumber(Short.class, Number::shortValue, Short::parseShort);
}
public static PrimitiveAdapter<Short> ofShortType() {
return ofNumber(short.class, Number::shortValue, Short::parseShort);
}
public static PrimitiveAdapter<Byte> ofByte() {
return ofNumber(Byte.class, Number::byteValue, Byte::parseByte);
}
public static PrimitiveAdapter<Byte> ofByteType() {
return ofNumber(byte.class, Number::byteValue, Byte::parseByte);
}
public static <T> PrimitiveAdapter<T> of(@NotNull Class<T> clazz,
@NotNull DataFunction<Object, T> function) {
return new PrimitiveAdapter<>(clazz, (p, type, data) -> function.handle(data));
}
public static <T extends Number> PrimitiveAdapter<T> ofNumber(@NotNull Class<T> numberClass,
@NotNull DataFunction<Number, T> castFunction,
@NotNull DataFunction<String, T> parseFunction) {
return of(numberClass, o -> o instanceof Number ? castFunction.handle((Number) o) : parseFunction.handle(o.toString()));
}
protected PrimitiveAdapter(@NotNull Class<T> valueType, @NotNull ValueParser<T> deserializer) {
super(ValueType.of(valueType), (provider, type, value) -> value, deserializer);
}
}
@@ -0,0 +1,30 @@
package cc.carm.lib.configuration.adapter.strandard;
import cc.carm.lib.configuration.adapter.ValueAdapter;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import org.jetbrains.annotations.NotNull;
import static cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapter.*;
public interface StandardAdapters {
@NotNull PrimitiveAdapter<?>[] PRIMITIVES = new PrimitiveAdapter[]{
ofString(), ofBoolean(), ofBooleanType(), ofCharacter(), ofCharacterType(),
ofInteger(), ofIntegerType(), ofLong(), ofLongType(), ofDouble(), ofDoubleType(),
ofFloat(), ofFloatType(), ofShort(), ofShortType(), ofByte(), ofByteType()
};
@NotNull ValueAdapter<Enum<?>> ENUMS = PrimitiveAdapter.ofEnum();
@NotNull ValueAdapter<ConfigureSection> SECTIONS = new ValueAdapter<>(
ValueType.of(ConfigureSection.class),
(provider, type, value) -> value,
(provider, type, value) -> {
if (value instanceof ConfigureSection) {
return (ConfigureSection) value;
} else throw new IllegalArgumentException("Value is not a ConfigurationSection");
}
);
}
@@ -0,0 +1,32 @@
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;
/**
* The configuration path used to mark the corresponding class or parameter.
*/
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ConfigPath {
/**
* The path value of the current configuration.
* If not set,will generate the path by {@link cc.carm.lib.configuration.source.loader.PathGenerator}.
*
* @return The path value of the current configuration
*/
String value() default "";
/**
* Whether to start with the root node.
* <br>If false, the previous path (if any) to the node is automatically added.
* <br>If true, the path will be set directly from the root node.
*
* @return Whether to start directly from the root path without inheriting the previous path
*/
boolean root() default false;
}
@@ -0,0 +1,91 @@
package cc.carm.lib.configuration.builder;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
import cc.carm.lib.configuration.value.ConfigValue;
import cc.carm.lib.configuration.value.ValueManifest;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;
public abstract class AbstractConfigBuilder<
TYPE, RESULT extends ConfigValue<TYPE>, HOLDER extends ConfigurationHolder<?>,
SELF extends AbstractConfigBuilder<TYPE, RESULT, HOLDER, SELF>
> {
protected final Class<? super HOLDER> providerClass;
protected final ValueType<TYPE> type;
protected @Nullable HOLDER holder;
protected @Nullable String path;
protected @NotNull Supplier<@Nullable TYPE> defaultValueSupplier = () -> null;
protected @NotNull BiConsumer<ConfigurationHolder<?>, String> initializer = (h, p) -> {
};
protected AbstractConfigBuilder(Class<? super HOLDER> providerClass, ValueType<TYPE> type) {
this.providerClass = providerClass;
this.type = type;
}
public @NotNull ValueType<TYPE> type() {
return type;
}
protected abstract @NotNull SELF self();
public abstract @NotNull RESULT build();
public @NotNull SELF holder(@Nullable HOLDER holder) {
this.holder = holder;
return self();
}
public @NotNull SELF path(@Nullable String path) {
this.path = path;
return self();
}
public @NotNull SELF initializer(@NotNull BiConsumer<ConfigurationHolder<?>, String> initializer) {
this.initializer = initializer;
return self();
}
public @NotNull SELF append(@NotNull BiConsumer<ConfigurationHolder<?>, String> initializer) {
return initializer(initializer.andThen(initializer));
}
public @NotNull SELF append(@NotNull Consumer<ConfigurationHolder<?>> initializer) {
return append((provider, valuePath) -> initializer.accept(provider));
}
public @NotNull SELF defaults(@Nullable TYPE defaultValue) {
return defaults(() -> defaultValue);
}
public @NotNull SELF defaults(@NotNull Supplier<@Nullable TYPE> supplier) {
this.defaultValueSupplier = supplier;
return self();
}
public <M> @NotNull SELF meta(@NotNull Consumer<@NotNull ConfigurationMetaHolder> metaConsumer) {
return append((h, p) -> metaConsumer.accept(h.metadata(p)));
}
public <M> @NotNull SELF meta(@NotNull ConfigurationMetadata<M> type, @Nullable M value) {
return meta(h -> h.set(type, value));
}
protected @NotNull ValueManifest<TYPE> buildManifest() {
return new ValueManifest<>(
type(), this.defaultValueSupplier, this.initializer,
this.holder, this.path
);
}
}
@@ -0,0 +1,14 @@
package cc.carm.lib.configuration.builder;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.value.ConfigValue;
public abstract class CommonConfigBuilder<TYPE, RESULT extends ConfigValue<TYPE>, SELF extends CommonConfigBuilder<TYPE, RESULT, SELF>>
extends AbstractConfigBuilder<TYPE, RESULT, ConfigurationHolder<?>, SELF> {
protected CommonConfigBuilder(ValueType<TYPE> type) {
super(ConfigurationHolder.class, type);
}
}
@@ -0,0 +1,78 @@
package cc.carm.lib.configuration.builder.impl;
import cc.carm.lib.configuration.adapter.ValueAdapter;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.CommonConfigBuilder;
import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.function.ValueConsumer;
import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import cc.carm.lib.configuration.value.ConfigValue;
import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashMap;
import java.util.Map;
public abstract class AbstractSectionBuilder<
TYPE, PARAM,
RESULT extends ConfigValue<TYPE>,
SELF extends AbstractSectionBuilder<TYPE, PARAM, RESULT, SELF>
> extends CommonConfigBuilder<TYPE, RESULT, SELF> {
protected final @NotNull ValueType<PARAM> paramType;
protected @NotNull ValueHandler<ConfigureSection, PARAM> parser;
protected @NotNull ValueHandler<PARAM, ? extends Map<String, Object>> serializer;
protected AbstractSectionBuilder(@NotNull ValueType<TYPE> type, @NotNull ValueType<PARAM> paramType,
@NotNull ValueHandler<ConfigureSection, PARAM> parser,
@NotNull ValueHandler<PARAM, ? extends Map<String, Object>> serializer) {
super(type);
this.paramType = paramType;
this.parser = parser;
this.serializer = serializer;
}
public @NotNull SELF parse(@NotNull DataFunction<ConfigureSection, PARAM> valueParser) {
return parse((p, section) -> valueParser.handle(section));
}
public @NotNull SELF parse(@NotNull ValueHandler<ConfigureSection, PARAM> valueParser) {
this.parser = valueParser;
return self();
}
public @NotNull SELF serialize(@NotNull ValueHandler<PARAM, ? extends Map<String, Object>> serializer) {
this.serializer = serializer;
return self();
}
public @NotNull SELF serialize(@NotNull DataFunction<PARAM, ? extends Map<String, Object>> serializer) {
return serialize((p, value) -> {
return serializer.handle(value);
});
}
public @NotNull SELF serialize(@NotNull ValueConsumer<Map<String, Object>, PARAM> serializer) {
return serialize((h, value) -> {
Map<String, Object> map = new LinkedHashMap<>();
serializer.accept(h, map, value);
return map;
});
}
protected ValueAdapter<PARAM> buildAdapter() {
return new ValueAdapter<>(this.paramType)
.parser((p, type, data) -> {
ConfigureSection section = p.deserialize(ConfigureSection.class, data);
if (section == null) return null;
return this.parser.handle(p, section);
})
.serializer((p, type, data) -> {
Map<String, Object> map = this.serializer.handle(p, data);
return map == null || map.isEmpty() ? null : map;
});
}
}
@@ -0,0 +1,63 @@
package cc.carm.lib.configuration.builder.impl;
import cc.carm.lib.configuration.adapter.ValueAdapter;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.CommonConfigBuilder;
import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.value.ConfigValue;
import org.jetbrains.annotations.NotNull;
public abstract class AbstractSourceBuilder<
V, SOURCE, PARAM, RESULT extends ConfigValue<V>,
SELF extends AbstractSourceBuilder<V, SOURCE, PARAM, RESULT, SELF>
> extends CommonConfigBuilder<V, RESULT, SELF> {
protected final @NotNull ValueType<SOURCE> sourceType;
protected final @NotNull ValueType<PARAM> paramType;
protected @NotNull ValueHandler<SOURCE, PARAM> valueParser;
protected @NotNull ValueHandler<PARAM, SOURCE> valueSerializer;
protected AbstractSourceBuilder(@NotNull ValueType<V> type,
@NotNull ValueType<SOURCE> sourceType, @NotNull ValueType<PARAM> paramType,
@NotNull ValueHandler<SOURCE, PARAM> parser,
@NotNull ValueHandler<PARAM, SOURCE> serializer) {
super(type);
this.sourceType = sourceType;
this.paramType = paramType;
this.valueParser = parser;
this.valueSerializer = serializer;
}
public @NotNull SELF parse(@NotNull DataFunction<SOURCE, PARAM> parser) {
return parse((p, source) -> parser.handle(source));
}
public @NotNull SELF parse(@NotNull ValueHandler<SOURCE, PARAM> parser) {
this.valueParser = parser;
return self();
}
public @NotNull SELF serialize(@NotNull ValueHandler<PARAM, SOURCE> serializer) {
this.valueSerializer = serializer;
return self();
}
public @NotNull SELF serialize(@NotNull DataFunction<PARAM, SOURCE> serializer) {
return serialize((p, value) -> serializer.handle(value));
}
protected ValueAdapter<PARAM> buildAdapter() {
return new ValueAdapter<>(this.paramType)
.parser((holder, type, data) -> {
SOURCE source = holder.deserialize(this.sourceType, data);
return this.valueParser.handle(holder, source);
})
.serializer((holder, type, data) -> {
SOURCE source = this.valueSerializer.handle(holder, data);
return holder.serialize(source);
});
}
}
@@ -0,0 +1,44 @@
package cc.carm.lib.configuration.builder.list;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.function.ValueHandler;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
public class ConfigListBuilder<V> {
protected final @NotNull ValueType<V> type;
public ConfigListBuilder(@NotNull ValueType<V> type) {
this.type = type;
}
public <S> @NotNull SourceListBuilder<S, V> from(@NotNull Class<S> sourceType) {
return from(ValueType.of(sourceType));
}
public <S> @NotNull SourceListBuilder<S, V> from(@NotNull ValueType<S> sourceType) {
return new SourceListBuilder<>(
ArrayList::new, sourceType, type,
ValueHandler.required(type),
ValueHandler.required(sourceType)
);
}
public @NotNull SourceListBuilder<String, V> fromString() {
return new SourceListBuilder<>(
ArrayList::new, ValueType.STRING, type,
ValueHandler.required(type), ValueHandler.stringValue()
);
}
public @NotNull SectionListBuilder<V> fromSection() {
return new SectionListBuilder<>(
ArrayList::new, type,
ValueHandler.required(type), ValueHandler.required()
);
}
}
@@ -0,0 +1,53 @@
package cc.carm.lib.configuration.builder.list;
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.source.section.ConfigureSection;
import cc.carm.lib.configuration.value.standard.ConfiguredList;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.function.Supplier;
public class SectionListBuilder<V> extends AbstractSectionBuilder<List<V>, V, ConfiguredList<V>, SectionListBuilder<V>> {
protected @NotNull Supplier<? extends List<V>> constructor;
public SectionListBuilder(@NotNull Supplier<? extends List<V>> constructor,
@NotNull ValueType<V> paramType,
@NotNull ValueHandler<ConfigureSection, V> parser,
@NotNull ValueHandler<V, ? extends Map<String, Object>> serializer) {
super(new ValueType<List<V>>() {
}, paramType, parser, serializer);
this.constructor = constructor;
}
@SafeVarargs
public final @NotNull SectionListBuilder<V> defaults(@NotNull V... values) {
return defaults(new ArrayList<>(Arrays.asList(values)));
}
public final @NotNull SectionListBuilder<V> defaults(@NotNull Collection<V> values) {
return defaults(new ArrayList<>(values));
}
public SectionListBuilder<V> constructor(@NotNull Supplier<? extends List<V>> constructor) {
this.constructor = constructor;
return this;
}
public <LIST extends List<V>> SectionListBuilder<V> construct(@NotNull LIST list) {
return constructor(() -> list);
}
@Override
protected @NotNull SectionListBuilder<V> self() {
return this;
}
@Override
public @NotNull ConfiguredList<V> build() {
return new ConfiguredList<>(buildManifest(), constructor, buildAdapter());
}
}
@@ -0,0 +1,47 @@
package cc.carm.lib.configuration.builder.list;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.impl.AbstractSourceBuilder;
import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.value.standard.ConfiguredList;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.Supplier;
public class SourceListBuilder<SOURCE, V>
extends AbstractSourceBuilder<List<V>, SOURCE, V, ConfiguredList<V>, SourceListBuilder<SOURCE, V>> {
protected @NotNull Supplier<? extends List<V>> constructor;
public SourceListBuilder(@NotNull Supplier<? extends List<V>> constructor,
@NotNull ValueType<SOURCE> sourceType, @NotNull ValueType<V> paramType,
@NotNull ValueHandler<SOURCE, V> parser, @NotNull ValueHandler<V, SOURCE> serializer) {
super(new ValueType<List<V>>() {
}, sourceType, paramType, parser, serializer);
this.constructor = constructor;
}
@SafeVarargs
public final @NotNull SourceListBuilder<SOURCE, V> defaults(@NotNull V... values) {
return defaults(new ArrayList<>(Arrays.asList(values)));
}
public final @NotNull SourceListBuilder<SOURCE, V> defaults(@NotNull Collection<V> values) {
return defaults(new ArrayList<>(values));
}
@Override
protected @NotNull SourceListBuilder<SOURCE, V> self() {
return this;
}
@Override
public @NotNull ConfiguredList<V> build() {
return new ConfiguredList<>(buildManifest(), this.constructor, buildAdapter());
}
}
@@ -0,0 +1,80 @@
package cc.carm.lib.configuration.builder.map;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.function.Supplier;
public class ConfigMapBuilder<M extends Map<K, V>, K, V> {
protected final @NotNull Supplier<@NotNull M> constructor;
protected final @NotNull ValueType<K> keyType;
protected final @NotNull ValueType<V> valueType;
public ConfigMapBuilder(@NotNull Supplier<@NotNull M> constructor,
@NotNull ValueType<K> keyType, @NotNull ValueType<V> valueType) {
this.constructor = constructor;
this.keyType = keyType;
this.valueType = valueType;
}
public <W extends Map<K, V>> ConfigMapBuilder<W, K, V> constructor(@NotNull Supplier<W> supplier) {
return new ConfigMapBuilder<>(supplier, keyType, valueType);
}
public @NotNull <S> SourceMapBuilder<M, S, K, V> from(@NotNull Class<S> clazz) {
return from(ValueType.of(clazz));
}
public @NotNull <S> SourceMapBuilder<M, S, K, V> from(@NotNull ValueType<S> sourceType) {
return from(
sourceType,
ValueHandler.required(keyType), ValueHandler.stringValue(),
ValueHandler.required(valueType), ValueHandler.required()
);
}
public <S> @NotNull SourceMapBuilder<M, S, K, V> from(@NotNull ValueType<S> sourceType,
@NotNull ValueHandler<String, K> keyParser,
@NotNull ValueHandler<K, String> keySerializer,
@NotNull ValueHandler<S, V> valueParser,
@NotNull ValueHandler<V, S> valueSerializer) {
return new SourceMapBuilder<>(
this.constructor, sourceType, keyType, valueType,
keyParser, keySerializer, valueParser, valueSerializer
);
}
public @NotNull SourceMapBuilder<M, String, K, V> fromString() {
return from(
ValueType.STRING,
ValueHandler.required(keyType), ValueHandler.stringValue(),
ValueHandler.required(valueType), ValueHandler.stringValue()
);
}
public @NotNull SectionMapBuilder<M, K, V> fromSection() {
return fromSection(
ValueHandler.required(keyType), ValueHandler.stringValue(),
ValueHandler.required(valueType), ValueHandler.required()
);
}
public @NotNull SectionMapBuilder<M, K, V> fromSection(
@NotNull ValueHandler<String, K> keyParser,
@NotNull ValueHandler<K, String> keySerializer,
@NotNull ValueHandler<ConfigureSection, V> valueParser,
@NotNull ValueHandler<V, Map<String, Object>> valueSerializer
) {
return new SectionMapBuilder<>(
this.constructor, keyType, valueType,
keyParser, keySerializer, valueParser, valueSerializer
);
}
}
@@ -0,0 +1,48 @@
package cc.carm.lib.configuration.builder.map;
import cc.carm.lib.configuration.adapter.ValueType;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Supplier;
public class ConfigMapCreator<K, V> {
protected final @NotNull ValueType<K> keyType;
protected final @NotNull ValueType<V> valueType;
public ConfigMapCreator(@NotNull ValueType<K> keyType, @NotNull ValueType<V> valueType) {
this.keyType = keyType;
this.valueType = valueType;
}
public <M extends Map<K, V>> @NotNull ConfigMapBuilder<M, K, V> constructor(@NotNull Supplier<@NotNull M> mapSuppler) {
return new ConfigMapBuilder<>(mapSuppler, keyType, valueType);
}
public <W extends Map<K, V>> @NotNull ConfigMapBuilder<W, K, V> constructor(@NotNull Class<W> type) {
return constructor(() -> {
try {
return type.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
public @NotNull ConfigMapBuilder<HashMap<K, V>, K, V> asHashMap() {
return constructor(HashMap::new);
}
public @NotNull ConfigMapBuilder<LinkedHashMap<K, V>, K, V> asLinkedMap() {
return constructor(LinkedHashMap::new);
}
public @NotNull ConfigMapBuilder<TreeMap<K, V>, K, V> asTreeMap() {
return constructor(TreeMap::new);
}
}
@@ -0,0 +1,95 @@
package cc.carm.lib.configuration.builder.map;
import cc.carm.lib.configuration.adapter.ValueAdapter;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.impl.AbstractSectionBuilder;
import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import cc.carm.lib.configuration.value.standard.ConfiguredMap;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class SectionMapBuilder<MAP extends Map<K, V>, K, V>
extends AbstractSectionBuilder<
Map<K, V>, V, ConfiguredMap<K, V>,
SectionMapBuilder<MAP, K, V>
> {
protected final @NotNull ValueType<K> keyType;
protected @NotNull Supplier<? extends MAP> constructor;
protected @NotNull ValueHandler<String, K> keyParser;
protected @NotNull ValueHandler<K, String> keySerializer;
public SectionMapBuilder(@NotNull Supplier<? extends MAP> constructor,
@NotNull ValueType<K> keyType, @NotNull ValueType<V> valueType,
@NotNull ValueHandler<String, K> keyParser,
@NotNull ValueHandler<K, String> keySerializer,
@NotNull ValueHandler<ConfigureSection, V> valueParser,
@NotNull ValueHandler<V, Map<String, Object>> valueSerializer) {
super(new ValueType<Map<K, V>>() {
}, valueType, valueParser, valueSerializer);
this.keyType = keyType;
this.constructor = constructor;
this.keyParser = keyParser;
this.keySerializer = keySerializer;
}
@Override
protected @NotNull SectionMapBuilder<MAP, K, V> self() {
return this;
}
public @NotNull SectionMapBuilder<MAP, K, V> parseKey(@NotNull DataFunction<String, K> keyParser) {
return parseKey((holder, data) -> keyParser.handle(data));
}
public @NotNull SectionMapBuilder<MAP, K, V> parseKey(@NotNull ValueHandler<String, K> keyParser) {
this.keyParser = keyParser;
return this;
}
public @NotNull SectionMapBuilder<MAP, K, V> serializeKey(@NotNull DataFunction<K, String> keySerializer) {
return serializeKey((holder, data) -> keySerializer.handle(data));
}
public @NotNull SectionMapBuilder<MAP, K, V> serializeKey(@NotNull ValueHandler<K, String> keySerializer) {
this.keySerializer = keySerializer;
return this;
}
public @NotNull SectionMapBuilder<MAP, K, V> defaults(@NotNull MAP defaults) {
return defaults(() -> defaults);
}
public @NotNull SectionMapBuilder<MAP, K, V> defaults(@NotNull Consumer<MAP> defaults) {
return defaults(() -> {
MAP map = this.constructor.get();
defaults.accept(map);
return map;
});
}
public @NotNull ValueAdapter<K> buildKeyAdapter() {
return new ValueAdapter<>(this.keyType)
.parser((holder, type, data) -> {
String source = holder.deserialize(String.class, data);
return this.keyParser.handle(holder, source);
})
.serializer((holder, type, data) -> {
String source = this.keySerializer.handle(holder, data);
return holder.serialize(source);
});
}
@Override
public @NotNull ConfiguredMap<K, V> build() {
return new ConfiguredMap<>(buildManifest(), this.constructor, buildKeyAdapter(), this.buildAdapter());
}
}
@@ -0,0 +1,91 @@
package cc.carm.lib.configuration.builder.map;
import cc.carm.lib.configuration.adapter.ValueAdapter;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.impl.AbstractSourceBuilder;
import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.value.standard.ConfiguredMap;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class SourceMapBuilder<MAP extends Map<K, V>, SOURCE, K, V>
extends AbstractSourceBuilder<
Map<K, V>, SOURCE, V, ConfiguredMap<K, V>,
SourceMapBuilder<MAP, SOURCE, K, V>
> {
protected final @NotNull ValueType<K> keyType;
protected @NotNull Supplier<? extends MAP> constructor;
protected @NotNull ValueHandler<String, K> keyParser;
protected @NotNull ValueHandler<K, String> keySerializer;
public SourceMapBuilder(@NotNull Supplier<? extends MAP> constructor, @NotNull ValueType<SOURCE> sourceType,
@NotNull ValueType<K> keyType, @NotNull ValueType<V> valueType,
@NotNull ValueHandler<String, K> keyParser, @NotNull ValueHandler<K, String> keySerializer,
@NotNull ValueHandler<SOURCE, V> valueParser, @NotNull ValueHandler<V, SOURCE> valueSerializer) {
super(new ValueType<Map<K, V>>() {
}, sourceType, valueType, valueParser, valueSerializer);
this.keyType = keyType;
this.constructor = constructor;
this.keyParser = keyParser;
this.keySerializer = keySerializer;
}
@Override
protected @NotNull SourceMapBuilder<MAP, SOURCE, K, V> self() {
return this;
}
public @NotNull SourceMapBuilder<MAP, SOURCE, K, V> defaults(@NotNull MAP defaults) {
return defaults(() -> defaults);
}
public @NotNull SourceMapBuilder<MAP, SOURCE, K, V> defaults(@NotNull Consumer<MAP> defaults) {
return defaults(() -> {
MAP map = this.constructor.get();
defaults.accept(map);
return map;
});
}
public @NotNull SourceMapBuilder<MAP, SOURCE, K, V> parseKey(@NotNull DataFunction<String, K> keyParser) {
return parseKey((holder, data) -> keyParser.handle(data));
}
public @NotNull SourceMapBuilder<MAP, SOURCE, K, V> parseKey(@NotNull ValueHandler<String, K> keyParser) {
this.keyParser = keyParser;
return this;
}
public @NotNull SourceMapBuilder<MAP, SOURCE, K, V> serializeKey(@NotNull DataFunction<K, String> keySerializer) {
return serializeKey((holder, data) -> keySerializer.handle(data));
}
public @NotNull SourceMapBuilder<MAP, SOURCE, K, V> serializeKey(@NotNull ValueHandler<K, String> keySerializer) {
this.keySerializer = keySerializer;
return this;
}
public @NotNull ValueAdapter<K> buildKeyAdapter() {
return new ValueAdapter<>(this.keyType)
.parser((holder, type, data) -> {
String source = holder.deserialize(String.class, data);
return this.keyParser.handle(holder, source);
})
.serializer((holder, type, data) -> {
String source = this.keySerializer.handle(holder, data);
return holder.serialize(source);
});
}
@Override
public @NotNull ConfiguredMap<K, V> build() {
return new ConfiguredMap<>(buildManifest(), this.constructor, buildKeyAdapter(), this.buildAdapter());
}
}
@@ -0,0 +1,48 @@
package cc.carm.lib.configuration.builder.value;
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.source.section.ConfigureSection;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public class ConfigValueBuilder<V> {
protected final @NotNull ValueType<V> type;
public ConfigValueBuilder(@NotNull ValueType<V> type) {
this.type = type;
}
public @NotNull <S> SourceValueBuilder<S, V> from(@NotNull Class<S> clazz) {
return from(ValueType.of(clazz));
}
public @NotNull <S> SourceValueBuilder<S, V> from(@NotNull ValueType<S> sourceType) {
return from(sourceType, ValueHandler.required(type), ValueHandler.required(sourceType));
}
public @NotNull <S> SourceValueBuilder<S, V> from(@NotNull ValueType<S> sourceType,
@NotNull ValueHandler<S, V> valueParser,
@NotNull ValueHandler<V, S> valueSerializer) {
return new SourceValueBuilder<>(sourceType, this.type, valueParser, valueSerializer);
}
public @NotNull SourceValueBuilder<String, V> fromString() {
return from(ValueType.STRING, ValueHandler.required(type), ValueHandler.stringValue());
}
public @NotNull SectionValueBuilder<V> fromSection() {
return fromSection(ValueHandler.required(type), ValueHandler.required());
}
public @NotNull SectionValueBuilder<V> fromSection(
@NotNull ValueHandler<ConfigureSection, V> valueParser,
@NotNull ValueHandler<V, ? extends Map<String, Object>> valueSerializer
) {
return new SectionValueBuilder<>(this.type, valueParser, valueSerializer);
}
}
@@ -0,0 +1,30 @@
package cc.carm.lib.configuration.builder.value;
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.source.section.ConfigureSection;
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public class SectionValueBuilder<V> extends AbstractSectionBuilder<V, V, ConfiguredValue<V>, SectionValueBuilder<V>> {
public SectionValueBuilder(@NotNull ValueType<V> type,
@NotNull ValueHandler<ConfigureSection, V> parser,
@NotNull ValueHandler<V, ? extends Map<String, Object>> serializer) {
super(type, type, parser, serializer);
}
@Override
protected @NotNull SectionValueBuilder<V> self() {
return this;
}
@Override
public @NotNull ConfiguredValue<V> build() {
return ConfiguredValue.of(buildManifest(), buildAdapter());
}
}
@@ -0,0 +1,27 @@
package cc.carm.lib.configuration.builder.value;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.impl.AbstractSourceBuilder;
import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
import org.jetbrains.annotations.NotNull;
public class SourceValueBuilder<S, V> extends AbstractSourceBuilder<V, S, V, ConfiguredValue<V>, SourceValueBuilder<S, V>> {
public SourceValueBuilder(@NotNull ValueType<S> sourceType, @NotNull ValueType<V> valueType,
@NotNull ValueHandler<S, V> parser, @NotNull ValueHandler<V, S> serializer) {
super(valueType, sourceType, valueType, parser, serializer);
}
@Override
protected @NotNull SourceValueBuilder<S, V> self() {
return this;
}
@Override
public @NotNull ConfiguredValue<V> build() {
return new ConfiguredValue<>(buildManifest(), buildAdapter());
}
}
@@ -1,275 +0,0 @@
package cc.carm.lib.configuration.core;
import cc.carm.lib.configuration.core.annotation.ConfigPath;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.annotation.InlineComment;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.value.ConfigValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
/**
* 配置文件类初始化方法
* 用于初始化 {@link ConfigurationRoot} 中的每个 {@link ConfigValue} 对象
*
* @param <T> {@link ConfigurationProvider} 配置文件的数据来源
* @author CarmJos
*/
public class ConfigInitializer<T extends ConfigurationProvider<?>> {
protected final @NotNull T provider;
public ConfigInitializer(@NotNull T provider) {
this.provider = provider;
}
/**
* 初始化指定类以及其子类的所有 {@link ConfigValue} 对象。
*
* @param clazz 配置文件类,须继承于 {@link ConfigurationRoot} 。
* @param saveDefaults 是否写入默认值(默认为 true)。
*/
public void initialize(@NotNull Class<? extends ConfigurationRoot> clazz, boolean saveDefaults) {
initialize(clazz, saveDefaults, true);
}
/**
* 初始化指定类的所有 {@link ConfigValue} 对象。
*
* @param clazz 配置文件类,须继承于 {@link ConfigurationRoot} 。
* @param saveDefaults 是否写入默认值(默认为 true)。
* @param loadSubClasses 是否加载内部子类(默认为 true)。
*/
public void initialize(@NotNull Class<? extends ConfigurationRoot> clazz,
boolean saveDefaults, boolean loadSubClasses) {
initializeStaticClass(
clazz, null, null,
null, null, null,
saveDefaults, loadSubClasses
);
if (saveDefaults) {
try {
provider.save();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link ConfigurationRoot} 对象。
*
* @param config 配置文件实例类,须实现 {@link ConfigurationRoot} 。
*/
public void initialize(@NotNull ConfigurationRoot config) {
initialize(config, true);
}
/**
* 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link ConfigurationRoot} 对象。
*
* @param config 配置文件实例类,须实现 {@link ConfigurationRoot} 。
* @param saveDefaults 是否写入默认值(默认为 true)。
*/
public void initialize(@NotNull ConfigurationRoot config, boolean saveDefaults) {
initializeInstance(
config, null, null,
null, null, null,
saveDefaults
);
if (saveDefaults) {
try {
provider.save();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 针对实例类的初始化方法
private void initializeInstance(@NotNull ConfigurationRoot root,
@Nullable String parentPath, @Nullable String fieldName,
@Nullable ConfigPath fieldPath,
@Nullable HeaderComment fieldHeaderComments,
@Nullable InlineComment fieldInlineComments,
boolean saveDefaults) {
String path = getClassPath(root.getClass(), parentPath, fieldName, fieldPath);
this.provider.setHeaderComment(path, getClassHeaderComments(root.getClass(), fieldHeaderComments));
if (path != null) this.provider.setInlineComment(path, readInlineComments(fieldInlineComments));
for (Field field : root.getClass().getDeclaredFields()) {
initializeField(root, field, path, saveDefaults, false);
}
}
// 针对静态类的初始化方法
private void initializeStaticClass(@NotNull Class<?> clazz,
@Nullable String parentPath, @Nullable String fieldName,
@Nullable ConfigPath fieldPath,
@Nullable HeaderComment fieldHeaderComments,
@Nullable InlineComment fieldInlineComments,
boolean saveDefaults, boolean loadSubClasses) {
if (!ConfigurationRoot.class.isAssignableFrom(clazz)) return; // 只解析继承了 ConfigurationRoot 的类
String path = getClassPath(clazz, parentPath, fieldName, fieldPath);
this.provider.setHeaderComment(path, getClassHeaderComments(clazz, fieldHeaderComments));
if (path != null) this.provider.setInlineComment(path, readInlineComments(fieldInlineComments));
for (Field field : clazz.getDeclaredFields()) {
initializeField(clazz, field, path, saveDefaults, loadSubClasses);
}
if (!loadSubClasses) return;
Class<?>[] classes = clazz.getDeclaredClasses();
for (int i = classes.length - 1; i >= 0; i--) { // 逆向加载,保持顺序。
initializeStaticClass(
classes[i], path, classes[i].getSimpleName(),
null, null, null,
saveDefaults, true
);
}
}
private void initializeField(@NotNull Object source, @NotNull Field field,
@Nullable String parent, boolean saveDefaults, boolean loadSubClasses) {
try {
field.setAccessible(true);
Object object = field.get(source);
if (object instanceof ConfigValue<?>) {
initializeValue(
(ConfigValue<?>) object, getFieldPath(field, parent),
field.getAnnotation(HeaderComment.class),
field.getAnnotation(InlineComment.class),
saveDefaults
);
} else if (source instanceof ConfigurationRoot && object instanceof ConfigurationRoot) {
// 当且仅当 源字段与字段 均为ConfigurationRoot实例时,才对目标字段进行下一步初始化加载。
initializeInstance(
(ConfigurationRoot) object, parent, field.getName(),
field.getAnnotation(ConfigPath.class),
field.getAnnotation(HeaderComment.class),
field.getAnnotation(InlineComment.class),
saveDefaults
);
} else if (source instanceof Class<?> && object instanceof Class<?>) {
// 当且仅当 源字段与字段 均为静态类时,才对目标字段进行下一步初始化加载。
initializeStaticClass(
(Class<?>) object, parent, field.getName(),
field.getAnnotation(ConfigPath.class),
field.getAnnotation(HeaderComment.class),
field.getAnnotation(InlineComment.class),
saveDefaults, loadSubClasses
);
}
// 以上判断实现以下规范:
// - 实例类中仅加载 ConfigValue实例 与 ConfigurationRoot实例
// - 静态类中仅加载 静态ConfigValue实例 与 静态ConfigurationRoot类
} catch (IllegalAccessException ignored) {
}
}
protected void initializeValue(@NotNull ConfigValue<?> value, @NotNull String path,
@Nullable HeaderComment fieldHeaderComment,
@Nullable InlineComment fieldInlineComment,
boolean saveDefaults) {
value.initialize(
provider, saveDefaults, path,
readHeaderComments(fieldHeaderComment),
readInlineComments(fieldInlineComment)
);
}
protected static @Nullable List<String> getClassHeaderComments(@NotNull Class<?> clazz,
@Nullable HeaderComment fieldAnnotation) {
List<String> classComments = readHeaderComments(clazz.getAnnotation(HeaderComment.class));
if (classComments != null) return classComments;
else return readHeaderComments(fieldAnnotation);
}
protected static List<String> readHeaderComments(@Nullable HeaderComment annotation) {
if (annotation == null) return null;
String[] value = annotation.value();
return value.length > 0 ? Arrays.asList(value) : null;
}
protected static @Nullable String readInlineComments(@Nullable InlineComment annotation) {
if (annotation == null) return null;
String value = annotation.value();
return value.length() > 0 ? value : null;
}
protected static @Nullable String getClassPath(@Nullable Class<?> clazz,
@Nullable String parentPath,
@Nullable String filedName,
@Nullable ConfigPath fieldAnnotation) {
@NotNull String parent = parentPath != null ? parentPath + "." : "";
boolean fromRoot = false;
// 先获取 Class 对应的路径注解 其优先度最高。
if (clazz != null) {
ConfigPath clazzAnnotation = clazz.getAnnotation(ConfigPath.class);
if (clazzAnnotation != null) {
fromRoot = clazzAnnotation.root();
if (clazzAnnotation.value().length() > 0) {
return (fromRoot ? "" : parent) + clazzAnnotation.value();
}
}
}
if (fieldAnnotation != null) {
fromRoot = fromRoot || fieldAnnotation.root();
if (fieldAnnotation.value().length() > 0) {
return (fromRoot ? "" : parent) + fieldAnnotation.value();
}
}
// 再由 fieldName 获取路径
if (filedName != null) return (fromRoot ? "" : parent) + getPathFromName(filedName);
else return null; // 不满足上述条件 且 无 fieldName,则说明是根路径。
}
protected static @NotNull String getFieldPath(@NotNull Field field, @Nullable String parentPath) {
@NotNull String parent = parentPath != null ? parentPath + "." : "";
boolean fromRoot = false;
// 先获取 Field 对应的路径注解 其优先度最高。
ConfigPath pathAnnotation = field.getAnnotation(ConfigPath.class);
if (pathAnnotation != null) {
fromRoot = pathAnnotation.root();
if (pathAnnotation.value().length() > 0) {
return (fromRoot ? "" : parent) + pathAnnotation.value();
}
}
// 最后再通过 fieldName 自动生成路径
return (fromRoot ? "" : parent) + getPathFromName(field.getName());
}
/**
* 得到指定元素的配置名称。
* 采用 全小写,以“-”链接 的命名规则。
*
* @param name 源名称
* @return 全小写,以“-”链接 的 路径名称
*/
public static String getPathFromName(String name) {
return name.replaceAll("[A-Z]", "-$0") // 将驼峰转换为蛇形;
.replaceAll("-(.*)", "$1") // 若首字母也为大写,则也会被转换,需要去掉第一个横线
.replaceAll("_-([A-Z])", "_$1") // 因为命名中可能包含 _,因此需要被特殊处理一下
.replaceAll("([a-z])-([A-Z])", "$1_$2") // 然后将非全大写命名的内容进行转换
.replace("-", "") // 移除掉多余的横线
.replace("_", "-") // 将下划线替换为横线
.toLowerCase(); // 最后转为全小写
}
}
@@ -1,7 +0,0 @@
package cc.carm.lib.configuration.core;
/**
* 配置文件类的根节点,用于标注该类用于记录配置文件中的配置信息。
*/
public abstract class ConfigurationRoot {
}
@@ -1,34 +0,0 @@
package cc.carm.lib.configuration.core.annotation;
import cc.carm.lib.configuration.core.ConfigInitializer;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于标记对应类或参数的配置路径
*/
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ConfigPath {
/**
* 指定路径的值。
* 若不指定,则会通过 {@link ConfigInitializer#getPathFromName(String)} 自动生成当前路径的值。
*
* @return 路径的值
*/
String value() default "";
/**
* 是否从根节点开始。
* <br>若为 false,则会自动添加上一个路径(如果有)到本节点的路径。
* <br>若为 true,则会从根节点开始直接设置本路径。
*
* @return 是否不继承上一路径,直接从根路径为开始
*/
boolean root() default false;
}
@@ -1,33 +0,0 @@
package cc.carm.lib.configuration.core.annotation;
import org.jetbrains.annotations.NotNull;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 行内注释,用于给对应配置的所在行添加注释,便于使用者阅读查看。
* 如:
* <blockquote><pre>
* foo: "bar" # 注释内容
* </pre></blockquote>
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface InlineComment {
/**
* 注释内容,若内容长度为0则不会添加注释
* <p> 如 <b>"foobar"</b> 将被设定为
* <blockquote><pre>
* foo: "bar" # foobar
* </pre></blockquote>
*
* @return 注释内容
*/
@NotNull
String value() default "";
}
@@ -1,64 +0,0 @@
package cc.carm.lib.configuration.core.builder;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.value.ConfigValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
public abstract class AbstractConfigBuilder<T, B extends AbstractConfigBuilder<T, B, P>, P extends ConfigurationProvider<?>> {
protected final Class<? super P> providerClass;
protected @Nullable P provider;
protected @Nullable String path;
protected @Nullable List<String> headerComments;
protected @Nullable String inlineComment;
protected @Nullable T defaultValue;
public AbstractConfigBuilder(Class<? super P> providerClass) {
this.providerClass = providerClass;
}
protected abstract @NotNull B getThis();
public abstract @NotNull ConfigValue<?> build();
public @NotNull B from(@Nullable P provider) {
this.provider = provider;
return getThis();
}
public @NotNull B path(@Nullable String path) {
this.path = path;
return getThis();
}
public @NotNull B comments(@NotNull String... comments) {
return headerComments(comments);
}
public @NotNull B headerComments(@NotNull String... comments) {
return headerComments(Arrays.asList(comments));
}
public @NotNull B headerComments(@NotNull List<String> comments) {
this.headerComments = comments;
return getThis();
}
public @NotNull B inlineComment(@NotNull String comment) {
this.inlineComment = comment;
return getThis();
}
public @NotNull B defaults(@Nullable T defaultValue) {
this.defaultValue = defaultValue;
return getThis();
}
}
@@ -1,12 +0,0 @@
package cc.carm.lib.configuration.core.builder;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
public abstract class CommonConfigBuilder<T, B extends CommonConfigBuilder<T, B>>
extends AbstractConfigBuilder<T, B, ConfigurationProvider<?>> {
public CommonConfigBuilder() {
super(ConfigurationProvider.class);
}
}
@@ -1,42 +0,0 @@
package cc.carm.lib.configuration.core.builder;
import cc.carm.lib.configuration.core.builder.list.ConfigListBuilder;
import cc.carm.lib.configuration.core.builder.map.ConfigMapBuilder;
import cc.carm.lib.configuration.core.builder.value.ConfigValueBuilder;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.TreeMap;
public class ConfigBuilder {
public <V> @NotNull ConfigValueBuilder<V> asValue(@NotNull Class<V> valueClass) {
return new ConfigValueBuilder<>(valueClass);
}
public <V> @NotNull ConfigListBuilder<V> asList(@NotNull Class<V> valueClass) {
return new ConfigListBuilder<>(valueClass);
}
public <K, V> @NotNull ConfigMapBuilder<LinkedHashMap<K, V>, K, V> asMap(@NotNull Class<K> keyClass,
@NotNull Class<V> valueClass) {
return new ConfigMapBuilder<>(LinkedHashMap::new, keyClass, valueClass);
}
public <K, V> @NotNull ConfigMapBuilder<HashMap<K, V>, K, V> asHashMap(@NotNull Class<K> keyClass,
@NotNull Class<V> valueClass) {
return asMap(keyClass, valueClass).supplier(HashMap::new);
}
public <K, V> @NotNull ConfigMapBuilder<LinkedHashMap<K, V>, K, V> asLinkedMap(@NotNull Class<K> keyClass,
@NotNull Class<V> valueClass) {
return asMap(keyClass, valueClass);
}
public <K extends Comparable<K>, V> @NotNull ConfigMapBuilder<TreeMap<K, V>, K, V> asTreeMap(@NotNull Class<K> keyClass,
@NotNull Class<V> valueClass) {
return asMap(keyClass, valueClass).supplier(TreeMap::new);
}
}
@@ -1,48 +0,0 @@
package cc.carm.lib.configuration.core.builder.list;
import cc.carm.lib.configuration.core.annotation.InlineComment;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import org.jetbrains.annotations.NotNull;
public class ConfigListBuilder<V> {
protected final @NotNull Class<V> valueClass;
public ConfigListBuilder(@NotNull Class<V> valueClass) {
this.valueClass = valueClass;
}
public @NotNull <S> SourceListBuilder<S, V> from(@NotNull Class<S> sourceClass,
@NotNull ConfigDataFunction<Object, S> sourceParser,
@NotNull ConfigDataFunction<S, V> valueParser,
@NotNull ConfigDataFunction<V, S> valueSerializer,
@NotNull ConfigDataFunction<S, Object> sourceSerializer) {
return new SourceListBuilder<>(sourceClass, sourceParser, this.valueClass, valueParser, valueSerializer, sourceSerializer);
}
public @NotNull <S> SourceListBuilder<S, V> from(Class<S> sourceClass) {
return from(sourceClass,
ConfigDataFunction.required(), ConfigDataFunction.required(),
ConfigDataFunction.required(), ConfigDataFunction.required()
);
}
public @NotNull SourceListBuilder<Object, V> fromObject() {
return from(
Object.class, ConfigDataFunction.identity(),
ConfigDataFunction.castObject(valueClass),
ConfigDataFunction.toObject(), ConfigDataFunction.toObject()
);
}
public @NotNull SourceListBuilder<String, V> fromString() {
return from(
String.class, ConfigDataFunction.castToString(),
ConfigDataFunction.castFromString(this.valueClass),
ConfigDataFunction.castToString(), ConfigDataFunction.toObject()
);
}
}
@@ -1,77 +0,0 @@
package cc.carm.lib.configuration.core.builder.list;
import cc.carm.lib.configuration.core.builder.CommonConfigBuilder;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.core.value.type.ConfiguredList;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class SourceListBuilder<S, V> extends CommonConfigBuilder<List<V>, SourceListBuilder<S, V>> {
protected final @NotNull Class<S> sourceClass;
protected @NotNull ConfigDataFunction<Object, S> sourceParser;
protected final @NotNull Class<V> valueClass;
protected @NotNull ConfigDataFunction<S, V> valueParser;
protected @NotNull ConfigDataFunction<V, S> valueSerializer;
protected @NotNull ConfigDataFunction<S, Object> sourceSerializer;
public SourceListBuilder(@NotNull Class<S> sourceClass, @NotNull ConfigDataFunction<Object, S> sourceParser,
@NotNull Class<V> valueClass, @NotNull ConfigDataFunction<S, V> valueParser,
@NotNull ConfigDataFunction<V, S> valueSerializer,
@NotNull ConfigDataFunction<S, Object> sourceSerializer) {
this.sourceClass = sourceClass;
this.sourceParser = sourceParser;
this.sourceSerializer = sourceSerializer;
this.valueClass = valueClass;
this.valueParser = valueParser;
this.valueSerializer = valueSerializer;
}
@SafeVarargs
public final @NotNull SourceListBuilder<S, V> defaults(@NotNull V... values) {
return defaults(new ArrayList<>(Arrays.asList(values)));
}
public @NotNull SourceListBuilder<S, V> parseSource(ConfigDataFunction<Object, S> sourceParser) {
this.sourceParser = sourceParser;
return this;
}
public @NotNull SourceListBuilder<S, V> parseValue(ConfigDataFunction<S, V> valueParser) {
this.valueParser = valueParser;
return this;
}
public @NotNull SourceListBuilder<S, V> serializeValue(ConfigDataFunction<V, S> serializer) {
this.valueSerializer = serializer;
return this;
}
public @NotNull SourceListBuilder<S, V> serializeSource(ConfigDataFunction<S, Object> serializer) {
this.sourceSerializer = serializer;
return this;
}
@Override
protected @NotNull SourceListBuilder<S, V> getThis() {
return this;
}
@Override
public @NotNull ConfiguredList<V> build() {
return new ConfiguredList<>(
this.provider, this.path,
this.headerComments, this.inlineComment,
this.valueClass, this.defaultValue,
this.sourceParser.andThen(this.valueParser),
this.valueSerializer.andThen(sourceSerializer)
);
}
}
@@ -1,60 +0,0 @@
package cc.carm.lib.configuration.core.builder.map;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.function.Supplier;
public class ConfigMapBuilder<M extends Map<K, V>, K, V> {
protected final @NotNull Supplier<@NotNull M> supplier;
protected final @NotNull Class<K> keyClass;
protected final @NotNull Class<V> valueClass;
public ConfigMapBuilder(@NotNull Supplier<@NotNull M> supplier, @NotNull Class<K> keyClass, @NotNull Class<V> valueClass) {
this.supplier = supplier;
this.keyClass = keyClass;
this.valueClass = valueClass;
}
public <MAP extends Map<K, V>> ConfigMapBuilder<MAP, K, V> supplier(@NotNull Supplier<MAP> supplier) {
return new ConfigMapBuilder<>(supplier, keyClass, valueClass);
}
public <S> SourceMapBuilder<M, S, K, V> from(@NotNull Class<S> sourceClass,
@NotNull ConfigDataFunction<S, V> valueParser,
@NotNull ConfigDataFunction<V, S> valueSerializer) {
return new SourceMapBuilder<>(supplier,
keyClass, ConfigDataFunction.castFromString(this.keyClass), // #String -> key
sourceClass, ConfigDataFunction.castObject(sourceClass), // #Object -> source
valueClass, valueParser, // source -> value
ConfigDataFunction.castToString(), // key -> #String
valueSerializer/*value -> source*/,
ConfigDataFunction.toObject()/* source -> #Object */
);
}
public <S> SourceMapBuilder<M, S, K, V> from(@NotNull Class<S> sourceClass) {
return from(sourceClass, ConfigDataFunction.required(), ConfigDataFunction.required());
}
public SourceMapBuilder<M, String, K, V> fromString(@NotNull ConfigDataFunction<String, V> valueParser) {
return from(String.class, valueParser, ConfigDataFunction.castToString());
}
public SourceMapBuilder<M, String, K, V> fromString() {
return fromString(ConfigDataFunction.castFromString(this.valueClass));
}
public SourceMapBuilder<M, Object, K, V> fromObject(@NotNull ConfigDataFunction<Object, V> valueParser) {
return from(Object.class, valueParser, ConfigDataFunction.toObject());
}
public SourceMapBuilder<M, Object, K, V> fromObject() {
return fromObject(ConfigDataFunction.required());
}
}
@@ -1,101 +0,0 @@
package cc.carm.lib.configuration.core.builder.map;
import cc.carm.lib.configuration.core.builder.CommonConfigBuilder;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.core.value.type.ConfiguredMap;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.function.Supplier;
public class SourceMapBuilder<M extends Map<K, V>, S, K, V> extends CommonConfigBuilder<M, SourceMapBuilder<M, S, K, V>> {
protected final @NotNull Supplier<@NotNull M> supplier;
protected final @NotNull Class<K> keyClass;
protected @NotNull ConfigDataFunction<String, K> keyParser;
protected final @NotNull Class<S> sourceClass;
protected @NotNull ConfigDataFunction<Object, S> sourceParser;
protected final @NotNull Class<V> valueClass;
protected @NotNull ConfigDataFunction<S, V> valueParser;
protected @NotNull ConfigDataFunction<K, String> keySerializer;
protected @NotNull ConfigDataFunction<V, S> valueSerializer;
protected @NotNull ConfigDataFunction<S, Object> sourceSerializer;
public SourceMapBuilder(@NotNull Supplier<@NotNull M> supplier,
@NotNull Class<K> keyClass, @NotNull ConfigDataFunction<String, K> keyParser,
@NotNull Class<S> sourceClass, @NotNull ConfigDataFunction<Object, S> sourceParser,
@NotNull Class<V> valueClass, @NotNull ConfigDataFunction<S, V> valueParser,
@NotNull ConfigDataFunction<K, String> keySerializer,
@NotNull ConfigDataFunction<V, S> valueSerializer,
@NotNull ConfigDataFunction<S, Object> sourceSerializer) {
this.supplier = supplier;
this.keyClass = keyClass;
this.keyParser = keyParser;
this.valueClass = valueClass;
this.valueParser = valueParser;
this.sourceClass = sourceClass;
this.sourceParser = sourceParser;
this.keySerializer = keySerializer;
this.valueSerializer = valueSerializer;
this.sourceSerializer = sourceSerializer;
}
public <MAP extends Map<K, V>> SourceMapBuilder<MAP, S, K, V> supplier(@NotNull Supplier<MAP> supplier) {
return new SourceMapBuilder<>(supplier,
keyClass, keyParser, sourceClass, sourceParser, valueClass, valueParser,
keySerializer, valueSerializer, sourceSerializer
);
}
public @NotNull SourceMapBuilder<M, S, K, V> parseKey(@NotNull ConfigDataFunction<String, K> parser) {
this.keyParser = parser;
return this;
}
public @NotNull SourceMapBuilder<M, S, K, V> parseSource(@NotNull ConfigDataFunction<Object, S> parser) {
this.sourceParser = parser;
return this;
}
public @NotNull SourceMapBuilder<M, S, K, V> parseValue(@NotNull ConfigDataFunction<S, V> parser) {
this.valueParser = parser;
return this;
}
public @NotNull SourceMapBuilder<M, S, K, V> serializeKey(@NotNull ConfigDataFunction<K, String> serializer) {
this.keySerializer = serializer;
return this;
}
public @NotNull SourceMapBuilder<M, S, K, V> serializeValue(@NotNull ConfigDataFunction<V, S> serializer) {
this.valueSerializer = serializer;
return this;
}
public @NotNull SourceMapBuilder<M, S, K, V> serializeSource(@NotNull ConfigDataFunction<S, Object> serializer) {
this.sourceSerializer = serializer;
return this;
}
@Override
protected @NotNull SourceMapBuilder<M, S, K, V> getThis() {
return this;
}
@Override
public @NotNull ConfiguredMap<K, V> build() {
return new ConfiguredMap<>(
this.provider, this.path,
this.headerComments, this.inlineComment,
this.defaultValue, this.supplier,
this.keyClass, this.keyParser,
this.valueClass, this.sourceParser.andThen(this.valueParser),
this.keySerializer, this.valueSerializer.andThen(this.sourceSerializer)
);
}
}
@@ -1,61 +0,0 @@
package cc.carm.lib.configuration.core.builder.value;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.core.function.ConfigValueParser;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public class ConfigValueBuilder<V> {
protected final @NotNull Class<V> valueClass;
public ConfigValueBuilder(@NotNull Class<V> valueClass) {
this.valueClass = valueClass;
}
public @NotNull SectionValueBuilder<V> fromSection() {
return fromSection(ConfigValueParser.required(), ConfigDataFunction.required());
}
public @NotNull SectionValueBuilder<V> fromSection(@NotNull ConfigValueParser<ConfigurationWrapper<?>, V> valueParser,
@NotNull ConfigDataFunction<V, ? extends Map<String, Object>> valueSerializer) {
return new SectionValueBuilder<>(this.valueClass, valueParser, valueSerializer);
}
public @NotNull <S> SourceValueBuilder<S, V> from(Class<S> sourceClass) {
return from(
sourceClass, ConfigDataFunction.required(), ConfigValueParser.required(),
ConfigDataFunction.required(), ConfigDataFunction.required()
);
}
public @NotNull <S> SourceValueBuilder<S, V> from(@NotNull Class<S> sourceClass,
@NotNull ConfigDataFunction<Object, S> sourceParser,
@NotNull ConfigValueParser<S, V> valueParser,
@NotNull ConfigDataFunction<V, S> valueSerializer,
@NotNull ConfigDataFunction<S, Object> sourceSerializer) {
return new SourceValueBuilder<>(
sourceClass, sourceParser, this.valueClass, valueParser,
valueSerializer, sourceSerializer
);
}
public @NotNull SourceValueBuilder<Object, V> fromObject() {
return from(
Object.class, ConfigDataFunction.identity(),
ConfigValueParser.castObject(valueClass),
ConfigDataFunction.toObject(), ConfigDataFunction.toObject()
);
}
public @NotNull SourceValueBuilder<String, V> fromString() {
return from(
String.class, ConfigDataFunction.castToString(),
ConfigValueParser.parseString(this.valueClass),
ConfigDataFunction.castToString(), ConfigDataFunction.toObject()
);
}
}
@@ -1,55 +0,0 @@
package cc.carm.lib.configuration.core.builder.value;
import cc.carm.lib.configuration.core.builder.CommonConfigBuilder;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.core.function.ConfigValueParser;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import cc.carm.lib.configuration.core.value.type.ConfiguredSection;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public class SectionValueBuilder<V>
extends CommonConfigBuilder<V, SectionValueBuilder<V>> {
protected final @NotNull Class<V> valueClass;
protected @NotNull ConfigValueParser<ConfigurationWrapper<?>, V> parser;
protected @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer;
public SectionValueBuilder(@NotNull Class<V> valueClass,
@NotNull ConfigValueParser<ConfigurationWrapper<?>, V> parser,
@NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer) {
this.valueClass = valueClass;
this.parser = parser;
this.serializer = serializer;
}
@Override
protected @NotNull SectionValueBuilder<V> getThis() {
return this;
}
public @NotNull SectionValueBuilder<V> parseValue(ConfigValueParser<ConfigurationWrapper<?>, V> valueParser) {
this.parser = valueParser;
return this;
}
public @NotNull SectionValueBuilder<V> serializeValue(ConfigDataFunction<V, ? extends Map<String, Object>> serializer) {
this.serializer = serializer;
return this;
}
@Override
public @NotNull ConfiguredSection<V> build() {
return new ConfiguredSection<>(
this.provider, this.path,
this.headerComments, this.inlineComment,
this.valueClass, this.defaultValue,
this.parser, this.serializer
);
}
}
@@ -1,68 +0,0 @@
package cc.carm.lib.configuration.core.builder.value;
import cc.carm.lib.configuration.core.builder.CommonConfigBuilder;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.core.function.ConfigValueParser;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
import org.jetbrains.annotations.NotNull;
public class SourceValueBuilder<S, V> extends CommonConfigBuilder<V, SourceValueBuilder<S, V>> {
protected final @NotNull Class<S> sourceClass;
protected @NotNull ConfigDataFunction<Object, S> sourceParser;
protected final @NotNull Class<V> valueClass;
protected @NotNull ConfigValueParser<S, V> valueParser;
protected @NotNull ConfigDataFunction<S, Object> sourceSerializer;
protected @NotNull ConfigDataFunction<V, S> valueSerializer;
public SourceValueBuilder(@NotNull Class<S> sourceClass, @NotNull ConfigDataFunction<Object, S> sourceParser,
@NotNull Class<V> valueClass, @NotNull ConfigValueParser<S, V> valueParser,
@NotNull ConfigDataFunction<V, S> valueSerializer,
@NotNull ConfigDataFunction<S, Object> sourceSerializer) {
this.sourceClass = sourceClass;
this.sourceParser = sourceParser;
this.valueClass = valueClass;
this.valueParser = valueParser;
this.sourceSerializer = sourceSerializer;
this.valueSerializer = valueSerializer;
}
@Override
protected @NotNull SourceValueBuilder<S, V> getThis() {
return this;
}
public @NotNull SourceValueBuilder<S, V> parseSource(@NotNull ConfigDataFunction<Object, S> sourceParser) {
this.sourceParser = sourceParser;
return this;
}
public @NotNull SourceValueBuilder<S, V> parseValue(@NotNull ConfigValueParser<S, V> valueParser) {
this.valueParser = valueParser;
return this;
}
public @NotNull SourceValueBuilder<S, V> serializeValue(@NotNull ConfigDataFunction<V, S> serializer) {
this.valueSerializer = serializer;
return this;
}
public @NotNull SourceValueBuilder<S, V> serializeSource(@NotNull ConfigDataFunction<S, Object> serializer) {
this.sourceSerializer = serializer;
return this;
}
@Override
public @NotNull ConfiguredValue<V> build() {
return new ConfiguredValue<>(
this.provider, this.path,
this.headerComments, this.inlineComment,
this.valueClass, this.defaultValue,
this.valueParser.compose(this.sourceParser),
this.valueSerializer.andThen(sourceSerializer)
);
}
}
@@ -1,68 +0,0 @@
package cc.carm.lib.configuration.core.function;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
@FunctionalInterface
public interface ConfigDataFunction<T, R> {
@NotNull R parse(@NotNull T data) throws Exception;
default <V> @NotNull ConfigDataFunction<T, V> andThen(@NotNull ConfigDataFunction<? super R, V> after) {
Objects.requireNonNull(after);
return ((data) -> after.parse(parse(data)));
}
@Contract(pure = true)
static <T> @NotNull ConfigDataFunction<T, T> identity() {
return (input) -> input;
}
@Contract(pure = true)
static <T> @NotNull ConfigDataFunction<T, T> identity(Class<T> type) {
return (input) -> input;
}
@Contract(pure = true)
static <T, V> @NotNull ConfigDataFunction<T, V> required() {
return (input) -> {
throw new IllegalArgumentException("Please specify the value parser.");
};
}
@Contract(pure = true)
static <T> @NotNull ConfigDataFunction<T, Object> toObject() {
return (input) -> input;
}
@Contract(pure = true)
static <V> @NotNull ConfigDataFunction<Object, V> castObject(Class<V> valueClass) {
return (input) -> {
if (valueClass.isInstance(input)) return valueClass.cast(input);
else throw new IllegalArgumentException("Cannot cast value to " + valueClass.getName());
};
}
@Contract(pure = true)
static <V> @NotNull ConfigDataFunction<String, V> castFromString(Class<V> valueClass) {
return (input) -> {
if (valueClass.isInstance(input)) return valueClass.cast(input);
else throw new IllegalArgumentException("Cannot cast string to " + valueClass.getName());
};
}
@Contract(pure = true)
static <T> @NotNull ConfigDataFunction<T, String> castToString() {
return (input) -> {
if (input instanceof String) return (String) input;
else return input.toString();
};
}
}
@@ -1,183 +0,0 @@
package cc.carm.lib.configuration.core.function;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
@FunctionalInterface
public interface ConfigValueParser<T, R> {
@Nullable R parse(@NotNull T data, @Nullable R defaultValue) throws Exception;
default <V> ConfigValueParser<T, V> andThen(@NotNull ConfigValueParser<R, V> after) {
Objects.requireNonNull(after);
return ((data, defaultValue) -> {
R result = parse(data, null);
if (result == null) return defaultValue;
else return after.parse(result, defaultValue);
});
}
default <V> ConfigValueParser<V, R> compose(@NotNull ConfigDataFunction<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return ((data, defaultValue) -> {
T result = before.parse(data);
return parse(result, defaultValue);
});
}
@Contract(pure = true)
static <T> @NotNull ConfigValueParser<T, T> identity() {
return (input, defaultValue) -> input;
}
@Contract(pure = true)
static <T> @NotNull ConfigValueParser<T, Object> toObject() {
return (input, defaultValue) -> input;
}
@Contract(pure = true)
static <T, V> @NotNull ConfigValueParser<T, V> required() {
return (input, defaultValue) -> {
throw new IllegalArgumentException("Please specify the value parser.");
};
}
@Contract(pure = true)
static <V> @NotNull ConfigValueParser<Object, V> castObject(Class<V> valueClass) {
return (input, defaultValue) -> {
if (Number.class.isAssignableFrom(valueClass)) {
if (Long.class.isAssignableFrom(valueClass)) {
input = longValue().parse(input, (Long) defaultValue);
} else if (Integer.class.isAssignableFrom(valueClass)) {
input = intValue().parse(input, (Integer) defaultValue);
} else if (Float.class.isAssignableFrom(valueClass)) {
input = floatValue().parse(input, (Float) defaultValue);
} else if (Double.class.isAssignableFrom(valueClass)) {
input = doubleValue().parse(input, (Double) defaultValue);
} else if (Byte.class.isAssignableFrom(valueClass)) {
input = byteValue().parse(input, (Byte) defaultValue);
} else if (Short.class.isAssignableFrom(valueClass)) {
input = shortValue().parse(input, (Short) defaultValue);
}
} else if (Boolean.class.isAssignableFrom(valueClass)) {
input = booleanValue().parse(input, (Boolean) defaultValue);
}
if (valueClass.isInstance(input)) return valueClass.cast(input);
else throw new IllegalArgumentException("Cannot cast value to " + valueClass.getName());
};
}
@Contract(pure = true)
static <V> @NotNull ConfigValueParser<String, V> parseString(Class<V> valueClass) {
return (input, defaultValue) -> {
if (valueClass.isInstance(input)) return valueClass.cast(input);
else throw new IllegalArgumentException("Cannot cast string to " + valueClass.getName());
};
}
@Contract(pure = true)
static @NotNull ConfigValueParser<Object, String> castToString() {
return (input, defaultValue) -> {
if (input instanceof String) return (String) input;
else return input.toString();
};
}
@Contract(pure = true)
static @NotNull <T> ConfigValueParser<T, String> castToString(Class<T> clazz) {
return (input, defaultValue) -> {
if (input instanceof String) return (String) input;
else return input.toString();
};
}
@Contract(pure = true)
static @NotNull ConfigValueParser<Object, Integer> intValue() {
return (input, defaultValue) -> {
if (input instanceof Integer) {
return (Integer) input;
} else if (input instanceof Number) {
return ((Number) input).intValue();
} else throw new IllegalArgumentException("Cannot cast value to " + Integer.class.getName());
};
}
@Contract(pure = true)
static @NotNull ConfigValueParser<Object, Short> shortValue() {
return (input, defaultValue) -> {
if (input instanceof Short) {
return (Short) input;
} else if (input instanceof Number) {
return ((Number) input).shortValue();
} else throw new IllegalArgumentException("Cannot cast value to " + Short.class.getName());
};
}
@Contract(pure = true)
static @NotNull ConfigValueParser<Object, Double> doubleValue() {
return (input, defaultValue) -> {
if (input instanceof Double) {
return (Double) input;
} else if (input instanceof Number) {
return ((Number) input).doubleValue();
} else throw new IllegalArgumentException("Cannot cast value to " + Double.class.getName());
};
}
@Contract(pure = true)
static @NotNull ConfigValueParser<Object, Byte> byteValue() {
return (input, defaultValue) -> {
if (input instanceof Byte) {
return (Byte) input;
} else if (input instanceof Number) {
return ((Number) input).byteValue();
} else throw new IllegalArgumentException("Cannot cast value to " + Byte.class.getName());
};
}
@Contract(pure = true)
static @NotNull ConfigValueParser<Object, Float> floatValue() {
return (input, defaultValue) -> {
if (input instanceof Float) {
return (Float) input;
} else if (input instanceof Number) {
return ((Number) input).floatValue();
} else throw new IllegalArgumentException("Cannot cast value to " + Float.class.getName());
};
}
@Contract(pure = true)
static @NotNull ConfigValueParser<Object, Long> longValue() {
return (input, defaultValue) -> {
if (input instanceof Long) {
return (Long) input;
} else if (input instanceof Number) {
return ((Number) input).longValue();
} else throw new IllegalArgumentException("Cannot cast value to " + Long.class.getName());
};
}
@Contract(pure = true)
static @NotNull ConfigValueParser<Object, Boolean> booleanValue() {
return (input, defaultValue) -> {
if (input instanceof Boolean) {
return (Boolean) input;
} else if (input instanceof String) {
String s = (String) input;
return Boolean.parseBoolean(s) || "yes".equalsIgnoreCase(s);
} else if (input instanceof Integer) {
return ((Integer) input) == 1;
} else throw new IllegalArgumentException("Cannot cast value to " + Boolean.class.getName());
};
}
}
@@ -1,51 +0,0 @@
package cc.carm.lib.configuration.core.source;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.util.*;
public abstract class ConfigurationComments {
protected final @NotNull Map<String, List<String>> headerComments = new HashMap<>();
protected final @NotNull Map<String, String> inlineComments = new HashMap<>();
protected @NotNull Map<String, List<String>> getHeaderComments() {
return headerComments;
}
protected @NotNull Map<String, String> getInlineComments() {
return inlineComments;
}
public void setHeaderComments(@Nullable String path, @Nullable List<String> comments) {
if (comments == null) {
getHeaderComments().remove(path);
} else {
getHeaderComments().put(path, comments);
}
}
public void setInlineComment(@NotNull String path, @Nullable String comment) {
if (comment == null) {
getInlineComments().remove(path);
} else {
getInlineComments().put(path, comment);
}
}
@Nullable
@Unmodifiable
public List<String> getHeaderComment(@Nullable String path) {
return Optional.ofNullable(getHeaderComments().get(path)).map(Collections::unmodifiableList).orElse(null);
}
public @Nullable String getInlineComment(@NotNull String path) {
return getInlineComments().get(path);
}
}
@@ -1,145 +0,0 @@
package cc.carm.lib.configuration.core.source;
import cc.carm.lib.configuration.core.ConfigInitializer;
import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.util.List;
import java.util.Optional;
public abstract class ConfigurationProvider<W extends ConfigurationWrapper<?>> {
protected long updateTime;
public ConfigurationProvider() {
this.updateTime = System.currentTimeMillis();
}
/**
* 得到配置文件的更新(最后加载)时间。
*
* @return 更新时间
*/
public long getUpdateTime() {
return updateTime;
}
/**
* 用于 {@link CachedConfigValue} 判断缓存值是否过期(即缓存的时间早于配置文件的最后加载时间)。
*
* @param time 缓存值时的时间戳
* @return 缓存值是否过期
*/
public boolean isExpired(long time) {
return getUpdateTime() > time;
}
/**
* 得到配置文件的原生功能类。
*
* @return 原生类
*/
public abstract @NotNull W getConfiguration();
/**
* 重载当前配置文件。(将不会保存已修改的内容)
*
* @throws Exception 当重载出现错误时抛出
*/
public void reload() throws Exception {
onReload(); // 调用重写的Reload方法
this.updateTime = System.currentTimeMillis();
}
/**
* 将当前对配置文件的更改进行保存。
*
* @throws Exception 当保存出现错误时抛出
*/
public abstract void save() throws Exception;
/**
* 针对于不同配置文件类型所执行的重载操作。
*
* @throws Exception 当操作出现错误时抛出。
*/
protected abstract void onReload() throws Exception;
public abstract @Nullable ConfigurationComments getComments();
public void setHeaderComment(@Nullable String path, @Nullable List<String> comments) {
if (getComments() == null) return;
getComments().setHeaderComments(path, comments);
}
public void setInlineComment(@NotNull String path, @Nullable String comment) {
if (getComments() == null) return;
getComments().setInlineComment(path, comment);
}
@Nullable
@Unmodifiable
public List<String> getHeaderComment(@Nullable String path) {
return Optional.ofNullable(getComments()).map(c -> c.getHeaderComment(path)).orElse(null);
}
public @Nullable String getInlineComment(@NotNull String path) {
return Optional.ofNullable(getComments()).map(c -> c.getInlineComment(path)).orElse(null);
}
public abstract @NotNull ConfigInitializer<? extends ConfigurationProvider<W>> getInitializer();
/**
* 初始化指定类以及其子类的所有 {@link ConfigValue} 对象。
*
* @param configClazz 配置文件类,须继承于 {@link ConfigurationRoot} 。
*/
public void initialize(Class<? extends ConfigurationRoot> configClazz) {
initialize(configClazz, true);
}
/**
* 初始化指定类以及其子类的所有 {@link ConfigValue} 对象。
*
* @param configClazz 配置文件类,须继承于 {@link ConfigurationRoot} 。
* @param saveDefaults 是否写入默认值(默认为 true)。
*/
public void initialize(Class<? extends ConfigurationRoot> configClazz, boolean saveDefaults) {
this.getInitializer().initialize(configClazz, saveDefaults);
}
/**
* 初始化指定类的所有 {@link ConfigValue} 对象。
*
* @param configClazz 配置文件类,须继承于 {@link ConfigurationRoot} 。
* @param saveDefaults 是否写入默认值(默认为 true)。
* @param loadSubClasses 是否加载内部子类(默认为 true)。
*/
public void initialize(Class<? extends ConfigurationRoot> configClazz, boolean saveDefaults, boolean loadSubClasses) {
this.getInitializer().initialize(configClazz, saveDefaults, loadSubClasses);
}
/**
* 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link ConfigurationRoot} 对象。
*
* @param config 配置文件实例类,须实现 {@link ConfigurationRoot} 。
*/
public void initialize(@NotNull ConfigurationRoot config) {
this.getInitializer().initialize(config, true);
}
/**
* 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link ConfigurationRoot} 对象。
*
* @param config 配置文件实例类,须实现 {@link ConfigurationRoot} 。
* @param saveDefaults 是否写入默认值(默认为 true)。
*/
public void initialize(@NotNull ConfigurationRoot config, boolean saveDefaults) {
this.getInitializer().initialize(config, saveDefaults);
}
}
@@ -1,190 +0,0 @@
package cc.carm.lib.configuration.core.source;
import cc.carm.lib.configuration.core.function.ConfigValueParser;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
interface ConfigurationReader {
ConfigurationWrapper<?> getWrapper();
default boolean isBoolean(@NotNull String path) {
return getWrapper().isType(path, Boolean.class);
}
default boolean getBoolean(@NotNull String path) {
return getBoolean(path, false);
}
@Contract("_, !null -> !null")
default @Nullable Boolean getBoolean(@NotNull String path, @Nullable Boolean def) {
return getWrapper().get(path, def, ConfigValueParser.booleanValue());
}
default @Nullable Boolean isByte(@NotNull String path) {
return getWrapper().isType(path, Byte.class);
}
default @Nullable Byte getByte(@NotNull String path) {
return getByte(path, (byte) 0);
}
@Contract("_, !null -> !null")
default @Nullable Byte getByte(@NotNull String path, @Nullable Byte def) {
return getWrapper().get(path, def, ConfigValueParser.byteValue());
}
default boolean isShort(@NotNull String path) {
return getWrapper().isType(path, Short.class);
}
default @Nullable Short getShort(@NotNull String path) {
return getShort(path, (short) 0);
}
@Contract("_, !null -> !null")
default @Nullable Short getShort(@NotNull String path, @Nullable Short def) {
return getWrapper().get(path, def, ConfigValueParser.shortValue());
}
default boolean isInt(@NotNull String path) {
return getWrapper().isType(path, Integer.class);
}
default @Nullable Integer getInt(@NotNull String path) {
return getInt(path, 0);
}
@Contract("_, !null -> !null")
default @Nullable Integer getInt(@NotNull String path, @Nullable Integer def) {
return getWrapper().get(path, def, ConfigValueParser.intValue());
}
default boolean isLong(@NotNull String path) {
return getWrapper().isType(path, Long.class);
}
default @Nullable Long getLong(@NotNull String path) {
return getLong(path, 0L);
}
@Contract("_, !null -> !null")
default @Nullable Long getLong(@NotNull String path, @Nullable Long def) {
return getWrapper().get(path, def, ConfigValueParser.longValue());
}
default boolean isFloat(@NotNull String path) {
return getWrapper().isType(path, Float.class);
}
default @Nullable Float getFloat(@NotNull String path) {
return getFloat(path, 0.0F);
}
@Contract("_, !null -> !null")
default @Nullable Float getFloat(@NotNull String path, @Nullable Float def) {
return getWrapper().get(path, def, ConfigValueParser.floatValue());
}
default boolean isDouble(@NotNull String path) {
return getWrapper().isType(path, Double.class);
}
default @Nullable Double getDouble(@NotNull String path) {
return getDouble(path, 0.0D);
}
@Contract("_, !null -> !null")
default @Nullable Double getDouble(@NotNull String path, @Nullable Double def) {
return getWrapper().get(path, def, ConfigValueParser.doubleValue());
}
default boolean isChar(@NotNull String path) {
return getWrapper().isType(path, Boolean.class);
}
default @Nullable Character getChar(@NotNull String path) {
return getChar(path, null);
}
@Contract("_, !null -> !null")
default @Nullable Character getChar(@NotNull String path, @Nullable Character def) {
return getWrapper().get(path, def, Character.class);
}
default boolean isString(@NotNull String path) {
return getWrapper().isType(path, String.class);
}
default @Nullable String getString(@NotNull String path) {
return getString(path, null);
}
@Contract("_, !null -> !null")
default @Nullable String getString(@NotNull String path, @Nullable String def) {
return getWrapper().get(path, def, String.class);
}
@Unmodifiable
default @NotNull List<String> getStringList(@NotNull String path) {
return parseList(getWrapper().getList(path), ConfigValueParser.castToString());
}
@Unmodifiable
default @NotNull List<Integer> getIntegerList(@NotNull String path) {
return parseList(getWrapper().getList(path), ConfigValueParser.intValue());
}
@Unmodifiable
default @NotNull List<Long> getLongList(@NotNull String path) {
return parseList(getWrapper().getList(path), ConfigValueParser.longValue());
}
@Unmodifiable
default @NotNull List<Double> getDoubleList(@NotNull String path) {
return parseList(getWrapper().getList(path), ConfigValueParser.doubleValue());
}
@Unmodifiable
default @NotNull List<Float> getFloatList(@NotNull String path) {
return parseList(getWrapper().getList(path), ConfigValueParser.floatValue());
}
@Unmodifiable
default @NotNull List<Byte> getByteList(@NotNull String path) {
return parseList(getWrapper().getList(path), ConfigValueParser.byteValue());
}
@Unmodifiable
default @NotNull List<Character> getCharList(@NotNull String path) {
return parseList(getWrapper().getList(path), ConfigValueParser.castObject(Character.class));
}
@Unmodifiable
static <T> @NotNull List<T> parseList(@Nullable List<?> list, ConfigValueParser<Object, T> parser) {
if (list == null) return Collections.emptyList();
List<T> values = new ArrayList<>();
for (Object o : list) {
try {
T parsed = parser.parse(o, null);
if (parsed != null) values.add(parsed);
} catch (Exception ignored) {
}
}
return values;
}
}
@@ -1,73 +0,0 @@
package cc.carm.lib.configuration.core.source;
import cc.carm.lib.configuration.core.function.ConfigValueParser;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
import java.util.Set;
public interface ConfigurationWrapper<S> extends ConfigurationReader {
@Override
default ConfigurationWrapper<S> getWrapper() {
return this;
}
@NotNull S getSource();
@NotNull
Set<String> getKeys(boolean deep);
@NotNull
Map<String, Object> getValues(boolean deep);
void set(@NotNull String path, @Nullable Object value);
boolean contains(@NotNull String path);
default <T> boolean isType(@NotNull String path, @NotNull Class<T> typeClass) {
return typeClass.isInstance(get(path));
}
@Nullable Object get(@NotNull String path);
default @Nullable <T> T get(@NotNull String path, @NotNull Class<T> clazz) {
return get(path, null, clazz);
}
default @Nullable <T> T get(@NotNull String path, @NotNull ConfigValueParser<Object, T> parser) {
return get(path, null, parser);
}
@Contract("_,!null,_->!null")
default @Nullable <T> T get(@NotNull String path, @Nullable T defaultValue, @NotNull Class<T> clazz) {
return get(path, defaultValue, ConfigValueParser.castObject(clazz));
}
@Contract("_,!null,_->!null")
default @Nullable <T> T get(@NotNull String path, @Nullable T defaultValue,
@NotNull ConfigValueParser<Object, T> parser) {
Object value = get(path);
if (value != null) {
try {
return parser.parse(value, defaultValue);
} catch (Exception e) {
e.printStackTrace();
}
}
return defaultValue;
}
boolean isList(@NotNull String path);
@Nullable List<?> getList(@NotNull String path);
boolean isConfigurationSection(@NotNull String path);
@Nullable
ConfigurationWrapper<S> getConfigurationSection(@NotNull String path);
}
@@ -1,89 +0,0 @@
package cc.carm.lib.configuration.core.source.impl;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.Objects;
public abstract class FileConfigProvider<W extends ConfigurationWrapper<?>> extends ConfigurationProvider<W> {
protected final @NotNull File file;
public FileConfigProvider(@NotNull File file) {
this.file = file;
}
public @NotNull File getFile() {
return file;
}
public void initializeFile(@Nullable String sourcePath) throws IOException {
if (this.file.exists()) return;
File parent = this.file.getParentFile();
if (parent != null && !parent.exists() && !parent.mkdirs()) {
throw new IOException("Failed to create directory " + file.getParentFile().getAbsolutePath());
}
if (!this.file.createNewFile()) {
throw new IOException("Failed to create file " + file.getAbsolutePath());
}
if (sourcePath != null) {
try {
saveResource(sourcePath, true);
} catch (Exception ignored) {
}
}
}
public void saveResource(@NotNull String resourcePath, boolean replace)
throws NullPointerException, IOException, IllegalArgumentException {
Objects.requireNonNull(resourcePath, "ResourcePath cannot be null");
if (resourcePath.equals("")) throw new IllegalArgumentException("ResourcePath cannot be empty");
resourcePath = resourcePath.replace('\\', '/');
InputStream in = getResource(resourcePath);
if (in == null) throw new IllegalArgumentException("The resource '" + resourcePath + "' not exists");
int lastIndex = resourcePath.lastIndexOf('/');
File outDir = new File(file, resourcePath.substring(0, Math.max(lastIndex, 0)));
if (!outDir.exists() && !outDir.mkdirs()) throw new IOException("Failed to create directory " + outDir);
if (!file.exists() || replace) {
try {
OutputStream out = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
out.close();
in.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
@Nullable
public InputStream getResource(@NotNull String filename) {
try {
URL url = this.getClass().getClassLoader().getResource(filename);
if (url == null) return null;
URLConnection connection = url.openConnection();
connection.setUseCaches(false);
return connection.getInputStream();
} catch (IOException ex) {
return null;
}
}
}
@@ -1,67 +0,0 @@
package cc.carm.lib.configuration.core.util;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
public class MapFactory<S extends Map<K, V>, K, V> {
private final S map;
protected MapFactory(S map) {
this.map = map;
}
public MapFactory<S, K, V> put(K key, V value) {
this.map.put(key, value);
return this;
}
public MapFactory<S, K, V> remove(K key) {
this.map.remove(key);
return this;
}
public MapFactory<S, K, V> clear() {
this.map.clear();
return this;
}
public S build() {
return get();
}
public S get() {
return map;
}
public static <K, V> MapFactory<HashMap<K, V>, K, V> hashMap() {
return new MapFactory<>(new HashMap<>());
}
public static <K, V> MapFactory<HashMap<K, V>, K, V> hashMap(K firstKey, V firstValue) {
return MapFactory.<K, V>hashMap().put(firstKey, firstValue);
}
public static <K, V> MapFactory<LinkedHashMap<K, V>, K, V> linkedMap() {
return of(new LinkedHashMap<>());
}
public static <K, V> MapFactory<LinkedHashMap<K, V>, K, V> linkedMap(K firstKey, V firstValue) {
return MapFactory.<K, V>linkedMap().put(firstKey, firstValue);
}
public static <K extends Comparable<K>, V> MapFactory<TreeMap<K, V>, K, V> treeMap() {
return of(new TreeMap<>());
}
public static <K extends Comparable<K>, V> MapFactory<TreeMap<K, V>, K, V> treeMap(K firstKey, V firstValue) {
return MapFactory.<K, V>treeMap().put(firstKey, firstValue);
}
public static <M extends Map<K, V>, K, V> MapFactory<M, K, V> of(M map) {
return new MapFactory<>(map);
}
}
@@ -1,169 +0,0 @@
package cc.carm.lib.configuration.core.value;
import cc.carm.lib.configuration.core.builder.ConfigBuilder;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
public abstract class ConfigValue<T> {
public static @NotNull ConfigBuilder builder() {
return new ConfigBuilder();
}
protected @Nullable ConfigurationProvider<?> provider;
protected @Nullable String configPath;
protected @Nullable List<String> headerComments;
protected @Nullable String inlineComments;
protected @Nullable T defaultValue;
public ConfigValue(@Nullable ConfigurationProvider<?> provider, @Nullable String configPath,
@Nullable List<String> headerComments, @Nullable String inlineComments,
@Nullable T defaultValue) {
this.provider = provider;
this.configPath = configPath;
this.headerComments = headerComments;
this.inlineComments = inlineComments;
this.defaultValue = defaultValue;
}
public void initialize(@NotNull ConfigurationProvider<?> provider, boolean saveDefault, @NotNull String configPath,
@Nullable List<String> headerComments, @Nullable String inlineComments) {
if (this.provider == null) this.provider = provider;
if (this.configPath == null) this.configPath = configPath;
if (this.headerComments == null) this.headerComments = headerComments;
if (this.inlineComments == null) this.inlineComments = inlineComments;
if (saveDefault) setDefault();
if (getHeaderComments() != null) {
this.provider.setHeaderComment(getConfigPath(), getHeaderComments());
}
if (getInlineComments() != null) {
this.provider.setInlineComment(getConfigPath(), getInlineComments());
}
}
public @Nullable T getDefaultValue() {
return defaultValue;
}
public void setDefaultValue(@Nullable T defaultValue) {
this.defaultValue = defaultValue;
}
/**
* 得到该配置的设定值(即读取到的值)。
* <br> 若初始化时未写入默认值,则可以通过 {@link #getOrDefault()} 方法在该设定值为空时获取默认值。
*
* @return 设定值
*/
public abstract @Nullable T get();
/**
* 得到该配置的设定值,若不存在,则返回默认值。
*
* @return 设定值或默认值
*/
public @Nullable T getOrDefault() {
return getOptional().orElse(getDefaultValue());
}
/**
* 得到该配置的非空值。
*
* @return 非空值
* @throws NullPointerException 对应数据为空时抛出
*/
public @NotNull T getNotNull() {
return Objects.requireNonNull(getOrDefault(), "Value(" + configPath + ") is null.");
}
public @NotNull Optional<@Nullable T> getOptional() {
return Optional.ofNullable(get());
}
/**
* 设定该配置的值。
* <br> 设定后,不会自动保存配置文件;若需要保存,请调用 {@link ConfigurationProvider#save()} 方法。
*
* @param value 配置的值
*/
public abstract void set(@Nullable T value);
/**
* 初始化该配置的默认值。
* <br> 设定后,不会自动保存配置文件;若需要保存,请调用 {@link ConfigurationProvider#save()} 方法。
*/
public void setDefault() {
setDefault(false);
}
/**
* 将该配置的值设置为默认值。
* <br> 设定后,不会自动保存配置文件;若需要保存,请调用 {@link ConfigurationProvider#save()} 方法。
*
* @param override 是否覆盖已设定的值
*/
public void setDefault(boolean override) {
if (!override && getConfiguration().contains(getConfigPath())) return;
Optional.ofNullable(getDefaultValue()).ifPresent(this::set);
}
/**
* 判断加载的配置是否与默认值相同。
*
* @return 获取当前值是否为默认值。
*/
public boolean isDefault() {
T defaultValue = getDefaultValue();
T value = get();
if (defaultValue == null && value == null) return true;
else if (defaultValue != null && value != null) return defaultValue.equals(value);
else return false;
}
public @NotNull ConfigurationProvider<?> getProvider() {
return Optional.ofNullable(this.provider)
.orElseThrow(() -> new IllegalStateException("Value(" + configPath + ") does not have a provider."));
}
public final @NotNull ConfigurationWrapper<?> getConfiguration() {
try {
return getProvider().getConfiguration();
} catch (Exception ex) {
throw new IllegalStateException("Value(" + configPath + ") has not been initialized", ex);
}
}
public @NotNull String getConfigPath() {
return Optional.ofNullable(this.configPath)
.orElseThrow(() -> new IllegalStateException("No section path provided."));
}
protected Object getValue() {
return getConfiguration().get(getConfigPath());
}
protected void setValue(@Nullable Object value) {
getConfiguration().set(getConfigPath(), value);
}
public @Nullable String getInlineComments() {
return inlineComments;
}
@Unmodifiable
public @Nullable List<String> getHeaderComments() {
return headerComments;
}
}
@@ -1,43 +0,0 @@
package cc.carm.lib.configuration.core.value.impl;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.value.ConfigValue;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public abstract class CachedConfigValue<T> extends ConfigValue<T> {
protected @Nullable T cachedValue;
protected long parsedTime = -1;
public CachedConfigValue(@Nullable ConfigurationProvider<?> provider, @Nullable String sectionPath,
@Nullable List<String> headerComments, @Nullable String inlineComments,
@Nullable T defaultValue) {
super(provider, sectionPath, headerComments, inlineComments, defaultValue);
}
protected T updateCache(T value) {
this.parsedTime = System.currentTimeMillis();
this.cachedValue = value;
return getCachedValue();
}
public @Nullable T getCachedValue() {
return cachedValue;
}
public boolean isExpired() {
return this.parsedTime <= 0 || getProvider().isExpired(this.parsedTime);
}
protected final T useDefault() {
return useOrDefault(null);
}
protected final T useOrDefault(@Nullable T value) {
return updateCache(this.defaultValue == null ? value : this.defaultValue);
}
}
@@ -1,76 +0,0 @@
package cc.carm.lib.configuration.core.value.type;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.builder.list.ConfigListBuilder;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class ConfiguredList<V> extends CachedConfigValue<List<V>> {
public static <V> @NotNull ConfigListBuilder<V> builder(@NotNull Class<V> valueClass) {
return builder().asList(valueClass);
}
@HeaderComment
protected final @NotNull Class<V> valueClass;
protected final @NotNull ConfigDataFunction<Object, V> parser;
protected final @NotNull ConfigDataFunction<V, Object> serializer;
public ConfiguredList(@Nullable ConfigurationProvider<?> provider, @Nullable String sectionPath,
@Nullable List<String> headerComments, @Nullable String inlineComments,
@NotNull Class<V> valueClass, @Nullable List<V> defaultValue,
@NotNull ConfigDataFunction<Object, V> parser,
@NotNull ConfigDataFunction<V, Object> serializer) {
super(provider, sectionPath, headerComments, inlineComments, defaultValue);
this.valueClass = valueClass;
this.parser = parser;
this.serializer = serializer;
}
@Override
public @NotNull List<V> get() {
if (isExpired()) { // 已过时的数据,需要重新解析一次。
List<V> list = new ArrayList<>();
List<?> data = getConfiguration().getList(getConfigPath());
if (data == null || data.isEmpty()) return useOrDefault(list);
for (Object dataVal : data) {
if (dataVal == null) continue;
try {
list.add(parser.parse(dataVal));
} catch (Exception e) {
e.printStackTrace();
}
}
return updateCache(list);
} else if (getCachedValue() != null) return getCachedValue();
else if (getDefaultValue() != null) return getDefaultValue();
else return new ArrayList<>();
}
@Override
public void set(@Nullable List<V> value) {
updateCache(value);
if (value == null) setValue(null);
else {
List<Object> data = new ArrayList<>();
for (V val : value) {
if (val == null) continue;
try {
data.add(serializer.parse(val));
} catch (Exception ex) {
ex.printStackTrace();
}
}
setValue(data);
}
}
}
@@ -1,126 +0,0 @@
package cc.carm.lib.configuration.core.value.type;
import cc.carm.lib.configuration.core.builder.map.ConfigMapBuilder;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import cc.carm.lib.configuration.core.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> {
public static <K, V> @NotNull ConfigMapBuilder<LinkedHashMap<K, V>, K, V> builder(@NotNull Class<K> keyClass,
@NotNull Class<V> valueClass) {
return builder().asMap(keyClass, valueClass);
}
protected final @NotNull Supplier<? extends Map<K, V>> supplier;
protected final @NotNull Class<K> keyClass;
protected final @NotNull Class<V> valueClass;
protected final @NotNull ConfigDataFunction<String, K> keyParser;
protected final @NotNull ConfigDataFunction<Object, V> valueParser;
protected final @NotNull ConfigDataFunction<K, String> keySerializer;
protected final @NotNull ConfigDataFunction<V, Object> valueSerializer;
public ConfiguredMap(@Nullable ConfigurationProvider<?> provider, @Nullable String sectionPath,
@Nullable List<String> headerComments, @Nullable String inlineComments,
@Nullable Map<K, V> defaultValue, @NotNull Supplier<? extends Map<K, V>> supplier,
@NotNull Class<K> keyClass, @NotNull ConfigDataFunction<String, K> keyParser,
@NotNull Class<V> valueClass, @NotNull ConfigDataFunction<Object, V> valueParser,
@NotNull ConfigDataFunction<K, String> keySerializer,
@NotNull ConfigDataFunction<V, Object> valueSerializer) {
super(provider, sectionPath, headerComments, inlineComments, defaultValue);
this.supplier = supplier;
this.keyClass = keyClass;
this.valueClass = valueClass;
this.keyParser = keyParser;
this.valueParser = valueParser;
this.keySerializer = keySerializer;
this.valueSerializer = valueSerializer;
}
public @NotNull Class<K> getKeyClass() {
return keyClass;
}
public @NotNull Class<V> getValueClass() {
return valueClass;
}
public @NotNull ConfigDataFunction<String, K> getKeyParser() {
return keyParser;
}
public @NotNull ConfigDataFunction<Object, V> getValueParser() {
return valueParser;
}
public @NotNull ConfigDataFunction<K, String> getKeySerializer() {
return keySerializer;
}
public @NotNull ConfigDataFunction<V, Object> getValueSerializer() {
return valueSerializer;
}
@Override
public @NotNull Map<K, V> get() {
if (isExpired()) { // 已过时的数据,需要重新解析一次。
Map<K, V> map = supplier.get();
ConfigurationWrapper<?> section = getConfiguration().getConfigurationSection(getConfigPath());
if (section == null) return useOrDefault(map);
Set<String> keys = section.getKeys(false);
if (keys.isEmpty()) return useOrDefault(map);
for (String dataKey : keys) {
Object dataVal = section.get(dataKey);
if (dataVal == null) continue;
try {
K key = keyParser.parse(dataKey);
V value = valueParser.parse(dataVal);
map.put(key, value);
} catch (Exception e) {
e.printStackTrace();
}
}
return updateCache(map);
} else if (getCachedValue() != null) return getCachedValue();
else if (getDefaultValue() != null) return getDefaultValue();
else return supplier.get();
}
@Override
public void set(Map<K, V> value) {
updateCache(value);
if (value == null) setValue(null);
else {
Map<String, Object> data = new LinkedHashMap<>();
for (Map.Entry<K, V> entry : value.entrySet()) {
try {
data.put(
keySerializer.parse(entry.getKey()),
valueSerializer.parse(entry.getValue())
);
} catch (Exception e) {
e.printStackTrace();
}
}
setValue(data);
}
}
}
@@ -1,80 +0,0 @@
package cc.carm.lib.configuration.core.value.type;
import cc.carm.lib.configuration.core.builder.value.SectionValueBuilder;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.core.function.ConfigValueParser;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import cc.carm.lib.configuration.core.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class ConfiguredSection<V> extends CachedConfigValue<V> {
public static <V> @NotNull SectionValueBuilder<V> builder(@NotNull Class<V> valueClass) {
return builder().asValue(valueClass).fromSection();
}
protected final @NotNull Class<V> valueClass;
protected final @NotNull ConfigValueParser<ConfigurationWrapper<?>, V> parser;
protected final @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer;
public ConfiguredSection(@Nullable ConfigurationProvider<?> provider, @Nullable String sectionPath,
@Nullable List<String> headerComments, @Nullable String inlineComments,
@NotNull Class<V> valueClass, @Nullable V defaultValue,
@NotNull ConfigValueParser<ConfigurationWrapper<?>, V> parser,
@NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer) {
super(provider, sectionPath, headerComments, inlineComments, defaultValue);
this.valueClass = valueClass;
this.parser = parser;
this.serializer = serializer;
}
public @NotNull Class<V> getValueClass() {
return valueClass;
}
public @NotNull ConfigValueParser<ConfigurationWrapper<?>, V> getParser() {
return parser;
}
public @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> getSerializer() {
return serializer;
}
@Override
public @Nullable V get() {
if (isExpired()) { // 已过时的数据,需要重新解析一次。
ConfigurationWrapper<?> section = getConfiguration().getConfigurationSection(getConfigPath());
if (section == null) return useDefault();
try {
// 若未出现错误,则直接更新缓存并返回。
return updateCache(this.parser.parse(section, this.defaultValue));
} catch (Exception e) {
// 出现了解析错误,提示并返回默认值。
e.printStackTrace();
return useDefault();
}
} else return Optional.ofNullable(getCachedValue()).orElse(defaultValue);
}
@Override
public void set(V value) {
updateCache(value);
if (value == null) setValue(null);
else {
try {
setValue(serializer.parse(value));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@@ -1,83 +0,0 @@
package cc.carm.lib.configuration.core.value.type;
import cc.carm.lib.configuration.core.builder.value.ConfigValueBuilder;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.core.function.ConfigValueParser;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Optional;
public class ConfiguredValue<V> extends CachedConfigValue<V> {
public static <V> ConfigValueBuilder<V> builder(Class<V> valueClass) {
return builder().asValue(valueClass);
}
public static <V> ConfiguredValue<V> of(Class<V> valueClass) {
return of(valueClass, null);
}
public static <V> ConfiguredValue<V> of(Class<V> valueClass, @Nullable V defaultValue) {
return builder(valueClass).fromObject().defaults(defaultValue).build();
}
protected final @NotNull Class<V> valueClass;
protected final @NotNull ConfigValueParser<Object, V> parser;
protected final @NotNull ConfigDataFunction<V, Object> serializer;
public ConfiguredValue(@Nullable ConfigurationProvider<?> provider, @Nullable String sectionPath,
@Nullable List<String> headerComments, @Nullable String inlineComments,
@NotNull Class<V> valueClass, @Nullable V defaultValue,
@NotNull ConfigValueParser<Object, V> parser,
@NotNull ConfigDataFunction<V, Object> serializer) {
super(provider, sectionPath, headerComments, inlineComments, defaultValue);
this.valueClass = valueClass;
this.parser = parser;
this.serializer = serializer;
}
public @NotNull Class<V> getValueClass() {
return valueClass;
}
public @NotNull ConfigValueParser<Object, V> getParser() {
return parser;
}
@Override
public V get() {
if (isExpired()) { // 已过时的数据,需要重新解析一次。
Object value = getValue();
if (value == null) return useDefault(); // 获取的值不存在,直接使用默认值。
try {
// 若未出现错误,则直接更新缓存并返回。
return updateCache(this.parser.parse(value, this.defaultValue));
} catch (Exception e) {
// 出现了解析错误,提示并返回默认值。
e.printStackTrace();
return useDefault();
}
} else return Optional.ofNullable(getCachedValue()).orElse(defaultValue);
}
@Override
public void set(V value) {
updateCache(value);
if (value == null) setValue(null);
else {
try {
setValue(serializer.parse(value));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@@ -0,0 +1,18 @@
package cc.carm.lib.configuration.function;
import org.jetbrains.annotations.NotNull;
@FunctionalInterface
public interface DataConsumer<T> {
void accept(@NotNull T data) throws Exception;
default DataConsumer<T> andThen(DataConsumer<? super T> after) {
return (T t) -> {
accept(t);
after.accept(t);
};
}
}
@@ -0,0 +1,157 @@
package cc.carm.lib.configuration.function;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
@FunctionalInterface
public interface DataFunction<T, R> {
@NotNull R handle(@NotNull T data) throws Exception;
default <V> @NotNull DataFunction<T, V> andThen(@NotNull DataFunction<? super R, V> after) {
Objects.requireNonNull(after);
return data -> after.handle(handle(data));
}
@Contract(pure = true)
static <T> @NotNull DataFunction<T, T> identity() {
return input -> input;
}
@Contract(pure = true)
static <T> @NotNull DataFunction<T, T> identity(Class<T> type) {
return input -> input;
}
@Contract(pure = true)
static <T, V> @NotNull DataFunction<T, V> required() {
return input -> {
throw new IllegalArgumentException("Please specify the value parser.");
};
}
@Contract(pure = true)
static <T> @NotNull DataFunction<T, Object> toObject() {
return input -> input;
}
@Contract(pure = true)
static <V> @NotNull DataFunction<Object, V> castObject(Class<V> valueClass) {
return input -> {
if (valueClass.isInstance(input)) return valueClass.cast(input);
else throw new IllegalArgumentException("Cannot cast value to " + valueClass.getName());
};
}
@Contract(pure = true)
static <V> @NotNull DataFunction<String, V> castFromString(Class<V> valueClass) {
return input -> {
if (valueClass.isInstance(input)) return valueClass.cast(input);
else throw new IllegalArgumentException("Cannot cast string to " + valueClass.getName());
};
}
@Contract(pure = true)
static <T> @NotNull DataFunction<T, String> castToString() {
return input -> {
if (input instanceof String) return (String) input;
else if (input instanceof Enum<?>) return ((Enum<?>) input).name();
else return input.toString();
};
}
@Contract(pure = true)
static <V> @NotNull DataFunction<String, V> parseString(Class<V> valueClass) {
return input -> {
if (valueClass.isInstance(input)) return valueClass.cast(input);
else throw new IllegalArgumentException("Cannot cast string to " + valueClass.getName());
};
}
@Contract(pure = true)
static @NotNull DataFunction<Object, Integer> intValue() {
return input -> {
if (input instanceof Integer) {
return (Integer) input;
} else if (input instanceof Number) {
return ((Number) input).intValue();
} else throw new IllegalArgumentException("Cannot cast value to " + Integer.class.getName());
};
}
@Contract(pure = true)
static @NotNull DataFunction<Object, Short> shortValue() {
return input -> {
if (input instanceof Short) {
return (Short) input;
} else if (input instanceof Number) {
return ((Number) input).shortValue();
} else throw new IllegalArgumentException("Cannot cast value to " + Short.class.getName());
};
}
@Contract(pure = true)
static @NotNull DataFunction<Object, Double> doubleValue() {
return input -> {
if (input instanceof Double) {
return (Double) input;
} else if (input instanceof Number) {
return ((Number) input).doubleValue();
} else throw new IllegalArgumentException("Cannot cast value to " + Double.class.getName());
};
}
@Contract(pure = true)
static @NotNull DataFunction<Object, Byte> byteValue() {
return input -> {
if (input instanceof Byte) {
return (Byte) input;
} else if (input instanceof Number) {
return ((Number) input).byteValue();
} else throw new IllegalArgumentException("Cannot cast value to " + Byte.class.getName());
};
}
@Contract(pure = true)
static @NotNull DataFunction<Object, Float> floatValue() {
return input -> {
if (input instanceof Float) {
return (Float) input;
} else if (input instanceof Number) {
return ((Number) input).floatValue();
} else throw new IllegalArgumentException("Cannot cast value to " + Float.class.getName());
};
}
@Contract(pure = true)
static @NotNull DataFunction<Object, Long> longValue() {
return input -> {
if (input instanceof Long) {
return (Long) input;
} else if (input instanceof Number) {
return ((Number) input).longValue();
} else throw new IllegalArgumentException("Cannot cast value to " + Long.class.getName());
};
}
@Contract(pure = true)
static @NotNull DataFunction<Object, Boolean> booleanValue() {
return input -> {
if (input instanceof Boolean) {
return (Boolean) input;
} else if (input instanceof String) {
String s = (String) input;
return Boolean.parseBoolean(s) || "yes".equalsIgnoreCase(s);
} else if (input instanceof Integer) {
return (Integer) input == 1;
} else throw new IllegalArgumentException("Cannot cast value to " + Boolean.class.getName());
};
}
}
@@ -0,0 +1,21 @@
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,79 @@
package cc.carm.lib.configuration.function;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
@FunctionalInterface
public interface ValueHandler<T, R> {
@Nullable R handle(@NotNull ConfigurationHolder<?> holder, @NotNull T data) throws Exception;
default <V> ValueHandler<T, V> andThen(@NotNull ValueHandler<R, V> after) {
Objects.requireNonNull(after);
return ((provider, data) -> {
R result = handle(provider, data);
if (result == null) return null;
else return after.handle(provider, result);
});
}
default <V> ValueHandler<V, R> compose(@NotNull ValueHandler<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return ((provider, data) -> {
T result = before.handle(provider, data);
if (result == null) return null;
return handle(provider, result);
});
}
default <V> ValueHandler<V, R> compose(@NotNull DataFunction<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return ((provider, data) -> {
T result = before.handle(data);
return handle(provider, result);
});
}
@Contract(pure = true)
static <T> @NotNull ValueHandler<T, T> identity() {
return (provider, input) -> input;
}
@Contract(pure = true)
static <T> @NotNull ValueHandler<T, Object> toObject() {
return ConfigurationHolder::serialize;
}
@Contract(pure = true)
static <T> @NotNull ValueHandler<T, String> stringValue() {
return (provider, input) -> String.valueOf(input);
}
@Contract(pure = true)
static <O, T> @NotNull ValueHandler<O, T> deserialize(ValueType<T> to) {
return (provider, input) -> provider.deserialize(to, input);
}
@Contract(pure = true)
static <T, V> @NotNull ValueHandler<T, V> required() {
return (provider, input) -> {
throw new IllegalArgumentException("Please specify the value parser.");
};
}
@Contract(pure = true)
static <T, V> @NotNull ValueHandler<T, V> required(ValueType<V> type) {
return (provider, input) -> {
if (type.isInstance(input)) return type.cast(input); // Simple cast
throw new IllegalArgumentException("Please specify the value parser.");
};
}
}
@@ -0,0 +1,184 @@
package cc.carm.lib.configuration.source;
import cc.carm.lib.configuration.adapter.*;
import cc.carm.lib.configuration.adapter.strandard.StandardAdapters;
import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
import cc.carm.lib.configuration.source.loader.PathGenerator;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
import cc.carm.lib.configuration.source.option.ConfigurationOption;
import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder;
import cc.carm.lib.configuration.source.section.ConfigureSource;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* ConfigurationFactory, used to create configuration holder.
*
* @param <SOURCE> The {@link ConfigureSource} type
* @param <HOLDER> The {@link ConfigurationHolder} type.
* @param <SELF> Self builder, for further implement support.
*/
public abstract class ConfigurationFactory<
SOURCE extends ConfigureSource<?, ?, SOURCE>,
HOLDER extends ConfigurationHolder<SOURCE>,
SELF
> {
protected ValueAdapterRegistry adapters = new ValueAdapterRegistry();
protected ConfigurationOptionHolder options = new ConfigurationOptionHolder();
protected @NotNull Map<String, ConfigurationMetaHolder> metadata = new HashMap<>();
protected ConfigurationInitializer initializer = new ConfigurationInitializer();
public ConfigurationFactory() {
this.adapters.register(StandardAdapters.PRIMITIVES);
this.adapters.register(StandardAdapters.SECTIONS);
this.adapters.register(StandardAdapters.ENUMS);
}
protected abstract SELF self();
public SELF adapters(ValueAdapterRegistry adapters) {
this.adapters = adapters;
return self();
}
public SELF adapter(Consumer<ValueAdapterRegistry> adapterRegistryConsumer) {
adapterRegistryConsumer.accept(adapters);
return self();
}
public <T> SELF adapter(@NotNull ValueAdapter<T> adapter) {
return adapter(a -> a.register(adapter));
}
public <T> SELF adapter(@NotNull ValueType<T> type, @NotNull ValueSerializer<T> serializer) {
return adapter(a -> a.register(type, serializer));
}
public <T> SELF adapter(@NotNull ValueType<T> type, @NotNull ValueParser<T> parser) {
return adapter(a -> a.register(type, parser));
}
public <FROM, TO> SELF adapter(@NotNull Class<FROM> from, @NotNull Class<TO> to,
@NotNull DataFunction<FROM, TO> parser,
@NotNull DataFunction<TO, FROM> serializer) {
return adapter(a -> a.register(from, to, parser, serializer));
}
public <FROM, TO> SELF adapter(@NotNull ValueType<FROM> from, @NotNull ValueType<TO> to,
@NotNull DataFunction<FROM, TO> parser,
@NotNull DataFunction<TO, FROM> serializer) {
return adapter(a -> a.register(from, to, parser, serializer));
}
public <T> SELF adapter(@NotNull ValueType<T> type, @NotNull ValueSerializer<T> serializer, @NotNull ValueParser<T> parser) {
return adapter(a -> a.register(type, serializer, parser));
}
public <T> SELF adapter(@NotNull Class<T> type, @NotNull ValueSerializer<T> serializer, @NotNull ValueParser<T> parser) {
return adapter(ValueType.of(type), serializer, parser);
}
public SELF options(ConfigurationOptionHolder options) {
this.options = options;
return self();
}
public SELF option(Consumer<ConfigurationOptionHolder> modifier) {
modifier.accept(options);
return self();
}
public <O> SELF option(ConfigurationOption<O> type, O value) {
return option(o -> o.set(type, value));
}
public <O> SELF option(ConfigurationOption<O> type, Supplier<O> value) {
return option(type, value.get());
}
public <O> SELF option(ConfigurationOption<O> type, Consumer<O> modifier) {
return option(holder -> {
O current = holder.get(type);
modifier.accept(current);
holder.set(type, current);
});
}
public SELF metadata(@NotNull Map<String, ConfigurationMetaHolder> metadata) {
this.metadata = metadata;
return self();
}
public SELF metadata(@NotNull Consumer<Map<String, ConfigurationMetaHolder>> handler) {
handler.accept(this.metadata);
return self();
}
public SELF metadata(@Nullable String path, @NotNull ConfigurationMetaHolder meta) {
return metadata(m -> m.put(path, meta));
}
public SELF metadata(@Nullable String path, @NotNull Consumer<ConfigurationMetaHolder> handler) {
return metadata(map -> {
ConfigurationMetaHolder meta = map.computeIfAbsent(path, k -> new ConfigurationMetaHolder());
handler.accept(meta);
});
}
public SELF initializer(ConfigurationInitializer initializer) {
this.initializer = initializer;
return self();
}
public SELF initializer(Consumer<ConfigurationInitializer> initializerConsumer) {
initializerConsumer.accept(initializer);
return self();
}
/**
* Supply the base path generator for this configuration holder
*
* @param generator {@link PathGenerator}
* @return this
*/
public SELF pathGenerator(PathGenerator generator) {
return initializer(loader -> {
loader.pathGenerator(generator);
});
}
/**
* Register a new annotation for metadata to the configuration loader
*
* @param annotation The {@link Annotation}
* @param metadata The {@link ConfigurationMetadata} type
* @param extractor The {@link Function} to extract the metadata from the annotation
* @param <M> The metadata type
* @param <A> The annotation type
* @return this
*/
public <M, A extends Annotation> SELF metaAnnotation(@NotNull Class<A> annotation,
@NotNull ConfigurationMetadata<M> metadata,
@NotNull Function<A, M> extractor) {
return initializer(loader -> loader.registerAnnotation(annotation, metadata, extractor));
}
/**
* Build the configuration holder.
*
* @return The configuration holder
*/
public abstract @NotNull HOLDER build();
}
@@ -0,0 +1,136 @@
package cc.carm.lib.configuration.source;
import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.adapter.ValueAdapterRegistry;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
import cc.carm.lib.configuration.source.meta.StandardMeta;
import cc.carm.lib.configuration.source.option.ConfigurationOption;
import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder;
import cc.carm.lib.configuration.source.section.ConfigureSource;
import cc.carm.lib.configuration.value.ConfigValue;
import cc.carm.lib.configuration.value.ValueManifest;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnmodifiableView;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, SOURCE>> {
protected final @NotNull ValueAdapterRegistry adapters;
protected final @NotNull ConfigurationOptionHolder options;
protected final @NotNull Map<String, ConfigurationMetaHolder> metadata;
protected final @NotNull ConfigurationInitializer initializer;
public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters,
@NotNull ConfigurationOptionHolder options,
@NotNull Map<String, ConfigurationMetaHolder> metadata,
@NotNull ConfigurationInitializer initializer) {
this.initializer = initializer;
this.adapters = adapters;
this.options = options;
this.metadata = metadata;
}
public abstract @NotNull SOURCE config();
public void reload() throws Exception {
config().reload();
}
public void save() throws Exception {
config().save();
}
public ConfigurationOptionHolder options() {
return options;
}
public <O> @NotNull O option(@NotNull ConfigurationOption<O> option) {
return options().get(option);
}
public @NotNull Map<String, ConfigurationMetaHolder> metadata() {
return this.metadata;
}
public @NotNull ConfigurationMetaHolder metadata(@Nullable String path) {
return metadata().computeIfAbsent(path, k -> new ConfigurationMetaHolder());
}
@NotNull
@UnmodifiableView
public <M> Map<String, M> extractMetadata(@NotNull ConfigurationMetadata<M> type) {
return extractMetadata(type, Objects::nonNull);
}
@NotNull
@UnmodifiableView
public <M> Map<String, M> extractMetadata(@NotNull ConfigurationMetadata<M> type, @NotNull Predicate<M> filter) {
Map<String, M> metas = new LinkedHashMap<>();
for (Map.Entry<String, ConfigurationMetaHolder> entry : this.metadata.entrySet()) {
M data = entry.getValue().get(type);
if (filter.test(data)) metas.put(entry.getKey(), data);
}
return Collections.unmodifiableMap(metas);
}
@NotNull
@UnmodifiableView
public Map<String, ConfigValue<?>> registeredValues() {
return extractMetadata(StandardMeta.VALUE);
}
public ValueAdapterRegistry adapters() {
return this.adapters;
}
public ConfigurationInitializer initializer() {
return initializer;
}
@Contract("_,null -> null")
public <T> T deserialize(@NotNull Class<T> type, @Nullable Object source) throws Exception {
return adapters().deserialize(this, type, source);
}
@Contract("_,null -> null")
public <T> T deserialize(@NotNull ValueType<T> type, @Nullable Object source) throws Exception {
return adapters().deserialize(this, type, source);
}
@Contract("null -> null")
public <T> Object serialize(@Nullable T value) throws Exception {
return adapters().serialize(this, value);
}
public void initialize(Class<? extends Configuration> configClass) {
try {
initializer.initialize(this, configClass);
} catch (Exception e) {
e.printStackTrace();
}
}
public void initialize(@NotNull Configuration config) {
try {
initializer.initialize(this, config);
} catch (Exception e) {
e.printStackTrace();
}
}
public void initialize(@NotNull ValueManifest<?> value) {
value.holder(this);
}
}
@@ -0,0 +1,33 @@
package cc.carm.lib.configuration.source.loader;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@FunctionalInterface
public interface ConfigInitializeHandler<T, V> {
static <T, V> ConfigInitializeHandler<T, V> start() {
return (provider, path, value, instace) -> {
};
}
void whenInitialize(@NotNull ConfigurationHolder<?> holder, @Nullable String path,
@NotNull T value, @Nullable V instance) throws Exception;
default ConfigInitializeHandler<T, V> andThen(ConfigInitializeHandler<T, V> after) {
return (provider, path, value, instance) -> {
whenInitialize(provider, path, value, instance);
after.whenInitialize(provider, path, value, instance);
};
}
default ConfigInitializeHandler<T, V> compose(ConfigInitializeHandler<T, V> before) {
return (provider, path, value, instance) -> {
before.whenInitialize(provider, path, value, instance);
whenInitialize(provider, path, value, instance);
};
}
}
@@ -0,0 +1,200 @@
package cc.carm.lib.configuration.source.loader;
import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
import cc.carm.lib.configuration.source.meta.StandardMeta;
import cc.carm.lib.configuration.source.option.StandardOptions;
import cc.carm.lib.configuration.value.ConfigValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.function.Function;
/**
* Configuration initializer,
* used to initialize {@link ConfigValue}s from {@link Configuration} classes.
*/
public class ConfigurationInitializer {
protected @NotNull PathGenerator pathGenerator;
protected @NotNull ConfigInitializeHandler<Field, ConfigValue<?>> valueInitializer;
protected @NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer;
public ConfigurationInitializer() {
this(PathGenerator.of(), ConfigInitializeHandler.start(), ConfigInitializeHandler.start());
}
public ConfigurationInitializer(@NotNull PathGenerator pathGenerator,
@NotNull ConfigInitializeHandler<Field, ConfigValue<?>> valueInitializer,
@NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer) {
this.pathGenerator = pathGenerator;
this.valueInitializer = valueInitializer;
this.classInitializer = classInitializer;
}
public void pathGenerator(@NotNull PathGenerator pathGenerator) {
this.pathGenerator = pathGenerator;
}
public @NotNull PathGenerator pathGenerator() {
return pathGenerator;
}
public ConfigInitializeHandler<Field, ConfigValue<?>> fieldInitializer() {
return valueInitializer;
}
public void fieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?>> fieldInitializer) {
this.valueInitializer = fieldInitializer;
}
public ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer() {
return classInitializer;
}
public void classInitializer(@NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer) {
this.classInitializer = classInitializer;
}
public void appendFieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?>> fieldInitializer) {
this.valueInitializer = this.valueInitializer.andThen(fieldInitializer);
}
public void appendClassInitializer(@NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer) {
this.classInitializer = this.classInitializer.andThen(classInitializer);
}
public <T, A extends Annotation> void registerClassAnnotation(@NotNull Class<A> annotation,
@NotNull ConfigurationMetadata<T> metadata,
@NotNull Function<A, T> extractor) {
appendClassInitializer((holder, path, clazz, instance) -> {
A data = clazz.getAnnotation(annotation);
if (data == null) return;
holder.metadata(path).setIfAbsent(metadata, extractor.apply(data));
});
}
public <T, A extends Annotation> void registerFieldAnnotation(@NotNull Class<A> annotation,
@NotNull ConfigurationMetadata<T> metadata,
@NotNull Function<A, T> extractor) {
appendFieldInitializer((holder, path, field, instance) -> {
A data = field.getAnnotation(annotation);
if (data == null) return;
holder.metadata(path).setIfAbsent(metadata, extractor.apply(data));
});
}
public <T, A extends Annotation> void registerAnnotation(@NotNull Class<A> annotation,
@NotNull ConfigurationMetadata<T> metadata,
@NotNull Function<A, T> extractor) {
registerClassAnnotation(annotation, metadata, extractor);
registerFieldAnnotation(annotation, metadata, extractor);
}
public @Nullable String getFieldPath(@NotNull ConfigurationHolder<?> holder, @Nullable String parentPath, @NotNull Field field) {
return pathGenerator.getFieldPath(holder, parentPath, field);
}
public @Nullable String getClassPath(@NotNull ConfigurationHolder<?> holder, @Nullable String parentPath,
@NotNull Class<?> clazz, @Nullable Field clazzField) {
return pathGenerator.getClassPath(holder, parentPath, clazz, clazzField);
}
public void initialize(@NotNull ConfigurationHolder<?> holder,
@NotNull Configuration config) throws Exception {
initializeInstance(holder, config, null, null);
if (holder.option(StandardOptions.SET_DEFAULTS)) holder.save();
}
public void initialize(@NotNull ConfigurationHolder<?> holder,
@NotNull Class<? extends Configuration> clazz) throws Exception {
initializeStaticClass(holder, clazz, null, null);
if (holder.option(StandardOptions.SET_DEFAULTS)) holder.save();
}
// 针对实例类的初始化方法
protected void initializeInstance(@NotNull ConfigurationHolder<?> holder, @NotNull Configuration root,
@Nullable String parentPath, @Nullable Field configField) {
String path = getClassPath(holder, parentPath, root.getClass(), configField);
try {
this.classInitializer.whenInitialize(holder, path, root.getClass(), root);
} catch (Exception e) {
e.printStackTrace();
}
Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(holder, root, field, path));
}
// 针对静态类的初始化方法
@SuppressWarnings("unchecked")
protected void initializeStaticClass(@NotNull ConfigurationHolder<?> holder,
@NotNull Class<?> clazz,
@Nullable String parentPath, @Nullable Field configField) {
if (!Configuration.class.isAssignableFrom(clazz)) return; // Only Configuration class can be initialized.
String path = getClassPath(holder, parentPath, clazz, configField);
try {
this.classInitializer.whenInitialize(holder, path, (Class<? extends Configuration>) clazz, configField);
} catch (Exception e) {
e.printStackTrace();
}
for (Field field : clazz.getDeclaredFields()) {
initializeField(holder, clazz, field, path);
}
if (holder.option(StandardOptions.LOAD_SUB_CLASSES)) {
Class<?>[] classes = clazz.getDeclaredClasses();
for (int i = classes.length - 1; i >= 0; i--) { // 逆向加载,保持顺序。
initializeStaticClass(holder, classes[i], path, null);
}
}
}
protected void initializeField(@NotNull ConfigurationHolder<?> holder,
@NotNull Object source, @NotNull Field field, @Nullable String parent) {
try {
field.setAccessible(true);
Object object = field.get(source);
//
if (object instanceof ConfigValue<?>) {
// 目标是 ConfigValue 实例,进行具体的初始化注入
ConfigValue<?> value = (ConfigValue<?>) object;
String path = getFieldPath(holder, parent, field);
if (path == null) return;
value.initialize(holder, path);
holder.metadata(path).set(StandardMeta.VALUE, value); // Mark the minimal config value unit.
if (holder.option(StandardOptions.SET_DEFAULTS)) {
value.setDefault(); // Set default value.
}
try {
this.valueInitializer.whenInitialize(holder, path, field, value);
} catch (Exception e) {
e.printStackTrace();
}
if (holder.option(StandardOptions.PRELOAD)) {
value.get(); // Preload the value by calling #get method.
}
} else if (source instanceof Configuration && object instanceof Configuration) {
// 当且仅当 源字段与字段 均为Configuration实例时,才对目标字段进行下一步初始化加载。
initializeInstance(holder, (Configuration) object, parent, field);
} else if (source instanceof Class<?> && object instanceof Class<?>) {
// 当且仅当 源字段与字段 均为静态类时,才对目标字段进行下一步初始化加载。
initializeStaticClass(holder, (Class<?>) object, parent, field);
}
// 以上判断实现以下规范:
// - 实例类中仅加载 ConfigValue实例 与 Configuration实例
// - 静态类中仅加载 静态ConfigValue实例 与 静态Configuration类
} catch (IllegalAccessException ignored) {
}
}
}
@@ -0,0 +1,121 @@
package cc.carm.lib.configuration.source.loader;
import cc.carm.lib.configuration.annotation.ConfigPath;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.option.StandardOptions;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.util.function.UnaryOperator;
/**
* Path generator for configuration.
* <p>
* Path generator is a utility class that helps to generate the path of the configuration.
* It can be used to generate the path of the field or class.
*/
public class PathGenerator {
public static PathGenerator of() {
return of(PathGenerator::covertPathName);
}
public static PathGenerator of(UnaryOperator<String> pathConverter) {
return new PathGenerator(pathConverter);
}
protected UnaryOperator<String> pathConverter;
public PathGenerator(UnaryOperator<String> pathConverter) {
this.pathConverter = pathConverter;
}
public @NotNull UnaryOperator<String> getPathConverter() {
return pathConverter;
}
public void setPathConverter(UnaryOperator<String> pathConverter) {
this.pathConverter = pathConverter;
}
public String covertPath(String name) {
return pathConverter.apply(name);
}
public @Nullable String getFieldPath(@NotNull ConfigurationHolder<?> holder,
@Nullable String parentPath, @NotNull Field field) {
ConfigPath path = field.getAnnotation(ConfigPath.class);
if (path == null)
return link(holder, parentPath, false, covertPath(field.getName())); // No annotation, use field name.
else return link(holder, parentPath, path.root(), select(path.value(), covertPath(field.getName())));
}
public @Nullable String getClassPath(@NotNull ConfigurationHolder<?> holder,
@Nullable String parentPath, @NotNull Class<?> clazz, @Nullable Field clazzField) {
// For standard path generator, we generate path following by:
// 1. Check if the class has a ConfigPath annotation, if so, use the root and value as the path.
// 2. If the class defined as a field, check if the field has a ConfigPath annotation,
// and use filed information.
ConfigPath clazzPath = clazz.getAnnotation(ConfigPath.class);
if (clazzPath != null) return link(holder, parentPath, clazzPath.root(), clazzPath.value());
if (clazzField != null) {
ConfigPath fieldPath = clazzField.getAnnotation(ConfigPath.class);
if (fieldPath == null) return link(holder, parentPath, false, covertPath(clazzField.getName()));
else return getFieldPath(holder, parentPath, clazzField);
}
return link(holder, parentPath, false, covertPath(clazz.getSimpleName())); // No field, use class name.
}
protected String select(String path, String defaultValue) {
if (path == null || path.isEmpty()) return defaultValue;
else return isBlank(path) ? null : path;
}
protected @Nullable String link(@NotNull ConfigurationHolder<?> holder,
@Nullable String parent, boolean root, @Nullable String path) {
if (path == null || path.isEmpty()) return root ? null : parent;
return (root || parent == null) ? path : (parent + pathSeparator(holder) + path);
}
public static boolean isBlank(String path) {
return path == null || path.replace(" ", "").isEmpty();
}
public static char pathSeparator(ConfigurationHolder<?> holder) {
return holder.option(StandardOptions.PATH_SEPARATOR);
}
/**
* Get the configuration name of the specified element.
* Use the naming convention of all lowercase and "-" links.
* <p>
* e.g. "SOME_NAME" will be "some-name"
*
* @param name source name
* @return the final path
*/
public static String covertPathName(String name) {
return name
// Replace all uppercase letters with dashes
.replaceAll("[A-Z]", "=$0")
// If the first letter is also capitalized,
// it will also be converted and the first dash will need to be removed
.replaceAll("^=(.*)$", "$1")
// Because the name may contain _, it needs to be treated a little differently
.replaceAll("_=([A-Z])", "_$1")
// The content that is not named in all caps is then converted
.replaceAll("([a-z])=([A-Z])", "$1_$2")
// Remove any extra horizontal lines
.replace("=", "")
// Replace the underscore with a dash
.replace("_", "-")
// Finally, convert it to all lowercase
.toLowerCase();
}
}
@@ -0,0 +1,125 @@
package cc.carm.lib.configuration.source.meta;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
public class ConfigurationMetaHolder {
protected final @NotNull Map<ConfigurationMetadata<?>, Object> values;
public ConfigurationMetaHolder() {
this(new ConcurrentHashMap<>());
}
public ConfigurationMetaHolder(@NotNull Map<ConfigurationMetadata<?>, Object> values) {
this.values = values;
}
public @NotNull Map<ConfigurationMetadata<?>, Object> values() {
return values;
}
/**
* Get the value of option.
*
* @param type {@link ConfigurationMetadata}
* @param defaultValue Default value if the value of option is not set.
* @param <V> Value type
* @return Value of option
*/
@SuppressWarnings("unchecked")
@Contract("_,!null -> !null")
public <V> @Nullable V get(@NotNull ConfigurationMetadata<V> type, @Nullable V defaultValue) {
return (V) values().getOrDefault(type, type.defaultOrSupply(defaultValue));
}
/**
* Get the value of option.
*
* @param type {@link ConfigurationMetadata}
* @param defaultValue Default value if the value of option is not set.
* @param <V> Value type
* @return Value of option
*/
@SuppressWarnings("unchecked")
@Contract("_,!null -> !null")
public <V> @Nullable V get(@NotNull ConfigurationMetadata<V> type, Supplier<@Nullable V> defaultValue) {
return (V) values().getOrDefault(type, type.defaultOrSupply(defaultValue));
}
/**
* Get the value of option.
*
* @param type {@link ConfigurationMetadata}
* @param <V> Value type
* @return Value of option
*/
public <V> @Nullable V get(@NotNull ConfigurationMetadata<V> type) {
return get(type, (V) null);
}
public boolean contains(@NotNull ConfigurationMetadata<?> type) {
return values().containsKey(type) || type.hasDefaults();
}
/**
* Set the value of meta, if the value is null, the meta will be removed.
* <br> Will only be changed in current holder.
*
* @param type {@link ConfigurationMetadata}
* @param value Value of meta
* @param <V> Value type
* @return Previous value of meta
*/
@SuppressWarnings("unchecked")
public <V> @Nullable V set(@NotNull ConfigurationMetadata<V> type, @Nullable V value) {
if (value == null || type.isDefault(value)) {
return (V) values().remove(type);
} else {
return (V) values().put(type, value);
}
}
/**
* Set the value of meta, if the value is null, the meta will not be changed.
* <br> Will only be changed in current holder.
*
* @param type {@link ConfigurationMetadata}
* @param value Value of meta
* @param <V> Value type
*/
public <V> void setIfAbsent(@NotNull ConfigurationMetadata<V> type, @Nullable V value) {
if (value == null || type.isDefault(value)) {
values().remove(type);
} else {
values().putIfAbsent(type, value);
}
}
/**
* Set the value of meta, if the value is null, the meta will not be changed.
* <br> Will only be changed in current holder.
*
* @param type {@link ConfigurationMetadata}
* @param value Value of meta
* @param <V> Value type
* @return Previous value of meta
*/
@SuppressWarnings("unchecked")
public <V> @Nullable V setIfPresent(@NotNull ConfigurationMetadata<V> type, @Nullable V value) {
Object exists = values().get(type);
if (exists == null) return null;
if (value == null || type.isDefault(value)) {
return (V) values().remove(type);
} else {
return (V) values().put(type, value);
}
}
}
@@ -0,0 +1,57 @@
package cc.carm.lib.configuration.source.meta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Supplier;
public class ConfigurationMetadata<T> {
public static <T> ConfigurationMetadata<T> of() {
return of(() -> null);
}
public static <T> ConfigurationMetadata<T> of(T defaults) {
return of(() -> defaults);
}
public static <T> ConfigurationMetadata<T> of(@NotNull Supplier<@Nullable T> defaults) {
return new ConfigurationMetadata<>(defaults);
}
protected Supplier<@Nullable T> defaultsSupplier;
public ConfigurationMetadata(@NotNull Supplier<@Nullable T> defaults) {
this.defaultsSupplier = defaults;
}
public boolean isDefault(@NotNull T value) {
return value.equals(defaults());
}
public boolean hasDefaults() {
return defaults() != null;
}
public T defaultOrSupply(@Nullable T suppliedValue) {
return defaultOrSupply(() -> suppliedValue);
}
public T defaultOrSupply(Supplier<@Nullable T> suppliedValue) {
T defaults = defaults();
return defaults == null ? suppliedValue.get() : defaults;
}
public @Nullable T defaults() {
return defaultsSupplier.get();
}
public void setDefaults(Supplier<T> defaultFunction) {
this.defaultsSupplier = defaultFunction;
}
public void setDefaults(T value) {
setDefaults(() -> value);
}
}
@@ -0,0 +1,12 @@
package cc.carm.lib.configuration.source.meta;
import cc.carm.lib.configuration.value.ConfigValue;
public interface StandardMeta {
/**
* To mark the {@link ConfigValue} instance of specific path.
*/
ConfigurationMetadata<ConfigValue<?>> VALUE = ConfigurationMetadata.of();
}
@@ -0,0 +1,40 @@
package cc.carm.lib.configuration.source.option;
import org.jetbrains.annotations.NotNull;
import java.util.function.Supplier;
public class ConfigurationOption<V> {
public static <T> ConfigurationOption<T> of(@NotNull T defaultValue) {
return new ConfigurationOption<>(defaultValue);
}
public static <T> ConfigurationOption<T> of(@NotNull Supplier<T> defaultValue) {
return of(defaultValue.get());
}
private @NotNull V defaultValue;
public ConfigurationOption(@NotNull V defaultValue) {
this.defaultValue = defaultValue;
}
public @NotNull V defaults() {
return defaultValue;
}
/**
* Set the default value of option.
*
* @param defaultValue Default value
*/
public void defaults(@NotNull V defaultValue) {
this.defaultValue = defaultValue;
}
public boolean isDefault(@NotNull V value) {
return value.equals(defaultValue);
}
}
@@ -0,0 +1,70 @@
package cc.carm.lib.configuration.source.option;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
public class ConfigurationOptionHolder {
public static @NotNull ConfigurationOptionHolder of(@NotNull Map<ConfigurationOption<?>, Object> options) {
return new ConfigurationOptionHolder(new ConcurrentHashMap<>(options));
}
protected final Map<ConfigurationOption<?>, Object> options;
public ConfigurationOptionHolder() {
this(new ConcurrentHashMap<>());
}
public ConfigurationOptionHolder(Map<ConfigurationOption<?>, Object> options) {
this.options = options;
}
public @NotNull Map<ConfigurationOption<?>, Object> values() {
return options;
}
/**
* Get the value of option.
*
* @param type {@link ConfigurationOption}
* @param <V> Value type
* @return Value of option
*/
@SuppressWarnings("unchecked")
public <V> @NotNull V get(@NotNull ConfigurationOption<V> type) {
return Optional.ofNullable(values().get(type)).map(v -> (V) v).orElseGet(type::defaults);
}
/**
* Set the value of option.
*
* @param type {@link ConfigurationOption}
* @param value Value of option
* @param <V> Value type
* @return Previous value of option
*/
@SuppressWarnings("unchecked")
public <V> @Nullable V set(@NotNull ConfigurationOption<V> type, @Nullable V value) {
if (value == null) {
return (V) values().remove(type);
} else {
return (V) values().put(type, value);
}
}
/**
* Set the value of option to option's {@link ConfigurationOption#defaults()}.
*
* @param type {@link ConfigurationOption}
* @param <V> Value type
* @return Previous value of option
*/
public <V> @Nullable V clear(@NotNull ConfigurationOption<V> type) {
return set(type, null);
}
}
@@ -0,0 +1,35 @@
package cc.carm.lib.configuration.source.option;
import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import static cc.carm.lib.configuration.source.option.ConfigurationOption.of;
public interface StandardOptions {
/**
* The configuration path separator.
*/
ConfigurationOption<Character> PATH_SEPARATOR = of('.');
/**
* Whether to set and save default values if offered and not exists in configuration.
*/
ConfigurationOption<Boolean> SET_DEFAULTS = of(true);
/**
* Whether to load subclasses of configuration class.
*/
ConfigurationOption<Boolean> LOAD_SUB_CLASSES = of(true);
/**
* Whether to pre parse the config values,
* may good to set true if you want to keep the config format.
* <br> if true, the values will be parsed when
* {@link ConfigurationHolder#initialize(Configuration)}.
* <br> if false, the values will be parsed when calling
* {@link cc.carm.lib.configuration.value.ConfigValue#get()}
*/
ConfigurationOption<Boolean> PRELOAD = of(true);
}
@@ -0,0 +1,903 @@
package cc.carm.lib.configuration.source.section;
import cc.carm.lib.configuration.function.DataFunction;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnmodifiableView;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
/**
* Represents a section of a configuration.
*
* @author Carm
* @since 4.0.0
*/
public interface ConfigureSection {
/**
* Gets the parent section of this section.
* <p>
* For root sections, this will return null.
*
* @return Parent section, or null if this is a root section.
*/
@Contract(pure = true)
@Nullable ConfigureSection parent();
/**
* Get the current section's path from {@link #parent()} of this section.
*
* @return The current path of this section, if {@link #isRoot()}, return empty string.
*/
@NotNull String path();
/**
* Get the full path of this section.
*
* @return The full path of this section, if {@link #isRoot()}, return empty string.
*/
default @NotNull String fullPath() {
if (parent() == null) return "";
return (parent().isRoot() ? "" : parent().fullPath() + pathSeparator()) + path();
}
/**
* Get the path separator for the section.
*
* @return The path separator
*/
default char pathSeparator() {
return '.';
}
/**
* Gets if this section is a root section.
*
* @return True if this section is a root section, false otherwise.
*/
@Contract(pure = true)
default boolean isRoot() {
return parent() == null;
}
/**
* Gets if this section is empty.
*
* @return True if this section is empty, false otherwise.
*/
default boolean isEmpty() {
return getValues(false).isEmpty();
}
/**
* Gets the number of keys in this section.
*
* @return Number of keys in this section.
*/
default int size(boolean deep) {
return getKeys(deep).size();
}
/**
* Gets a set containing all keys in this section.
* <p>
* If deep is set to true, then this will contain all the keys within any
* child {@link ConfigureSection}s (and their children paths).
* <p>
* If deep is set to false, then this will contain only the keys of any
* direct children, and not their own children.
*
* @param deep Whether to get a deep list.
* @return Set of keys contained within this Section.
*/
@NotNull
@UnmodifiableView
default Set<String> getKeys(boolean deep) {
return getValues(deep).keySet();
}
/**
* Gets a set containing all primary keys in this section.
*
* @return Set of keys contained within this Section.
*/
@NotNull
@UnmodifiableView
default Set<String> keys() {
return getKeys(false);
}
/**
* Gets a set containing all values in this section.
* <p>
* If deep is set to true, then this will contain all the keys within any
* child {@link ConfigureSection}s (and their children paths).
* <p>
* If deep is set to false, then this will contain only the keys of any
* direct children, and not their own children.
*
* @param deep Whether to get a deep list.
* @return Map of data values contained within this Section.
*/
@NotNull
@UnmodifiableView
Map<String, Object> getValues(boolean deep);
/**
* Gets a set containing all key-values in this section.
*
* @return Map of data values contained within this Section.
* @see #getValues(boolean)
*/
@NotNull
@UnmodifiableView
default Map<String, Object> values() {
return getValues(false);
}
/**
* Get this section as a map.
* <p>
* In this map, child {@link ConfigureSection}s will also be represented as {@link Map}s.
*
* @return Map of data values contained within this Section.
*/
@NotNull
@UnmodifiableView
Map<String, Object> asMap();
/**
* Create a stream of all values in this section.
*
* @return Stream of all values in this section.
*/
default Stream<Map.Entry<String, Object>> stream() {
return values().entrySet().stream();
}
/**
* Iterates over all key-values in this section (include child sections)
*
* @param action The action to apply to each key.
*/
default void forEach(@NotNull BiConsumer<String, Object> action) {
values().forEach(action);
}
/**
* Sets the value at the given path.
* <p>
* Null values will be kept, if you want to remove a value use {@link #remove(String)}
* Path separator depends on holder's
* {@link cc.carm.lib.configuration.source.option.StandardOptions#PATH_SEPARATOR}
*
* @param path The path to set the value at.
* @param value The value to set.
*/
void set(@NotNull String path, @Nullable Object value);
/**
* Removes the value at the given path.
* <p>
* Path separator depends on holder's
* {@link cc.carm.lib.configuration.source.option.StandardOptions#PATH_SEPARATOR}
*
* @param path The path to remove the value at.
*/
void remove(@NotNull String path);
/**
* Check if the given path is present.
* <p>
* Path separator depends on holder's
* {@link cc.carm.lib.configuration.source.option.StandardOptions#PATH_SEPARATOR}
*
* @param path The path to check.
* @return True if the value is present, false otherwise.
*/
default boolean contains(@NotNull String path) {
return getKeys(true).contains(path);
}
/**
* Check if the value of given path is present.
* <p>
* Path separator depends on holder's
* {@link cc.carm.lib.configuration.source.option.StandardOptions#PATH_SEPARATOR}
*
* @param path The path to check.
* @return True if the value is present, false otherwise.
*/
default boolean containsValue(@NotNull String path) {
return get(path) != null;
}
/**
* Predicate the value of given path is specific type.
*
* @param path The path to check.
* @param typeClass The type's class
* @param <T> The type to check.
* @return True if the value is present and is the correct type, false otherwise.
*/
default <T> boolean isType(@NotNull String path, @NotNull Class<T> typeClass) {
return typeClass.isInstance(get(path));
}
/**
* Predicate the value of given path is a {@link List}.
*
* @param path The path to check.
* @return True if the value is present and is a list, false otherwise.
*/
default boolean isList(@NotNull String path) {
return isType(path, List.class);
}
/**
* Get the value as a {@link List} from the specified path.
*
* @param path The path to get the {@link List}.
* @return The list if the path exists and is a list, otherwise null.
*/
default @Nullable List<?> getList(@NotNull String path) {
Object val = get(path);
return (val instanceof List<?>) ? (List<?>) val : null;
}
/**
* Predicate the value of given path is a {@link ConfigureSection}.
*
* @param path The path to check.
* @return True if the value is present and is a section, false otherwise.
*/
default boolean isSection(@NotNull String path) {
return isType(path, ConfigureSection.class);
}
/**
* Get the value as a {@link ConfigureSection} from the specified path.
*
* @param path The path to get the section.
* @return The section if the path exists and is a section, otherwise null.
*/
@Nullable
default ConfigureSection getSection(@NotNull String path) {
Object val = get(path);
return (val instanceof ConfigureSection) ? (ConfigureSection) val : null;
}
/**
* Creates a new {@link ConfigureSection} with specified values.
* <p> The {@link #parent()} of the new section will be this section.
* <p> This section will not be saved until {@link #set(String, Object)} is called.
* <p> If you want to create and use a section and set it to this section, use {@link #computeSection(String)}.
*
* @param data The data to be used to create section.
* @return Newly created section
*/
@NotNull ConfigureSection createSection(@NotNull String path, @NotNull Map<?, ?> data);
/**
* Creates a new {@link ConfigureSection} with specified values.
* <p> The {@link #parent()} of the new section will be this section.
*
* @param data The data to be used to create section.
* @return Newly created section
*/
default @NotNull ConfigureSection createSection(@NotNull String path, @NotNull Consumer<Map<String, Object>> data) {
return createSection(path, () -> {
Map<String, Object> map = new LinkedHashMap<>();
data.accept(map);
return map;
});
}
/**
* Creates a new {@link ConfigureSection} with specified values.
* <p> The {@link #parent()} of the new section will be this section.
*
* @param data The data to be used to create section.
* @return Newly created section
*/
default @NotNull ConfigureSection createSection(@NotNull String path, @NotNull Supplier<Map<String, Object>> data) {
return createSection(path, data.get());
}
/**
* Creates a new empty {@link ConfigureSection}.
* <p> The {@link #parent()} of the new section will be this section.
*
* @return Newly created section
*/
default @NotNull ConfigureSection createSection(@NotNull String path) {
return createSection(path, new LinkedHashMap<>());
}
/**
* Get or create a section at the given path.
* <p>
* Any value previously set at this path will be replaced if it is not a section
* or will be returned if it is an exists {@link ConfigureSection}.
*
* @param path The path to get the section from.
* @return The section at the path, or a new section if it does not exist.
* @see #createSection(String, Map)
*/
default @NotNull ConfigureSection computeSection(@NotNull String path) {
return computeSection(path, new LinkedHashMap<>());
}
/**
* Get or create a section at the given path.
* <p>
* Any value previously set at this path will be replaced if it is not a section
* or will be returned if it is an exists {@link ConfigureSection}.
*
* @param path The path to get the section from.
* @return The section at the path, or a new section if it does not exist.
* @see #createSection(String, Map)
*/
default @NotNull ConfigureSection computeSection(@NotNull String path, @NotNull Map<?, ?> data) {
ConfigureSection current = getSection(path);
if (current == null) {
current = createSection(path, data);
set(path, current);
}
return current;
}
/**
* Get or create a section at the given path.
* <p>
* Any value previously set at this path will be replaced if it is not a section
* or will be returned if it is an exists {@link ConfigureSection}.
*
* @param path The path to get the section from.
* @return The section at the path, or a new section if it does not exist.
* @see #createSection(String, Map)
*/
default @NotNull ConfigureSection computeSection(@NotNull String path, @NotNull Consumer<Map<String, Object>> data) {
return computeSection(path, () -> {
Map<String, Object> map = new LinkedHashMap<>();
data.accept(map);
return map;
});
}
/**
* Get or create a section at the given path.
* <p>
* Any value previously set at this path will be replaced if it is not a section
* or will be returned if it is an exists {@link ConfigureSection}.
*
* @param path The path to get the section from.
* @return The section at the path, or a new section if it does not exist.
* @see #createSection(String, Map)
*/
default @NotNull ConfigureSection computeSection(@NotNull String path, @NotNull Supplier<Map<String, Object>> data) {
return computeSection(path, data.get());
}
/**
* Get the origin value of the path.
*
* @param path The path to get the value from.
* @return The value at the path, or null if not found.
*/
@Nullable Object get(@NotNull String path);
/**
* Get the value of the path for specific type,
* if the path does not exist, return null.
*
* @param path The path to get the value from.
* @param type The type class of the value
* @param <T> The type of the value
* @return The value at the path, or the default value if not found.
*/
default @Nullable <T> T get(@NotNull String path, @NotNull Class<T> type) {
return get(path, null, type);
}
/**
* Get the value of the path using a parser function,
* if the path does not exist, return NULL.
*
* @param path The path to get the value from.
* @param parser The function to parse the value
* @param <T> The type of the value
* @return The value at the path, or null if not found.
*/
default @Nullable <T> T get(@NotNull String path, @NotNull DataFunction<@Nullable Object, T> parser) {
return get(path, null, parser);
}
/**
* Get the value of the path for specific type,
* if the path does not exist, return the default value.
*
* @param path The path to get the value from.
* @param defaults The default value to return if the path does not exist.
* @param clazz The type class of the value
* @param <T> The type of the value
* @return The value at the path, or the default value if not found.
*/
@Contract("_,!null,_->!null")
default @Nullable <T> T get(@NotNull String path, @Nullable T defaults, @NotNull Class<T> clazz) {
return get(path, defaults, DataFunction.castObject(clazz));
}
/**
* Get the value of the path using a parser function,
* if the path does not exist, return the default value.
*
* @param path The path to get the value from.
* @param defaultValue The default value to return if the path does not exist.
* @param parser The function to parse the value
* @param <T> The type of the value
* @return The value at the path, or the default value if not found.
*/
@Contract("_,!null,_->!null")
default @Nullable <T> T get(@NotNull String path, @Nullable T defaultValue,
@NotNull DataFunction<Object, T> parser) {
Object value = get(path);
if (value != null) {
try {
return parser.handle(value);
} catch (Exception e) {
e.printStackTrace();
}
}
return defaultValue;
}
/**
* Predicate the value of given path is a {@link Boolean}.
*
* @param path The path to check.
* @return True if the value is present and is a boolean, false otherwise.
*/
default boolean isBoolean(@NotNull String path) {
return isType(path, Boolean.class);
}
/**
* Get the value as a {@link Boolean} from the specified path.
*
* @param path The path to get the boolean.
* @return The boolean if the path exists and is a boolean, otherwise false.
*/
default boolean getBoolean(@NotNull String path) {
return getBoolean(path, false);
}
/**
* Get the value as a {@link Boolean} from the specified path.
*
* @param path The path to get the boolean.
* @param def The default value to return if the path does not exist.
* @return The boolean if the path exists and is a boolean, otherwise the default value.
*/
@Contract("_, !null -> !null")
default @Nullable Boolean getBoolean(@NotNull String path, @Nullable Boolean def) {
return get(path, def, DataFunction.booleanValue());
}
/**
* Predicate the value of given path is a {@link Byte}.
*
* @param path The path to check.
* @return True if the value is present and is a byte, false otherwise.
*/
default @Nullable Boolean isByte(@NotNull String path) {
return isType(path, Byte.class);
}
/**
* Get the value as a {@link Byte} from the specified path.
*
* @param path The path to get the byte.
* @return The byte if the path exists and is a byte, otherwise 0.
*/
default @Nullable Byte getByte(@NotNull String path) {
return getByte(path, (byte) 0);
}
/**
* Get the value as a {@link Byte} from the specified path.
*
* @param path The path to get the byte.
* @param def The default value to return if the path does not exist.
* @return The byte if the path exists and is a byte, otherwise the default value.
*/
@Contract("_, !null -> !null")
default @Nullable Byte getByte(@NotNull String path, @Nullable Byte def) {
return get(path, def, DataFunction.byteValue());
}
/**
* Predicate the value of given path is a {@link Short}.
*
* @param path The path to check.
* @return True if the value is present and is a short, false otherwise.
*/
default boolean isShort(@NotNull String path) {
return isType(path, Short.class);
}
/**
* Get the value as a {@link Short} from the specified path.
*
* @param path The path to get the short.
* @return The short if the path exists and is a short, otherwise 0.
*/
default @Nullable Short getShort(@NotNull String path) {
return getShort(path, (short) 0);
}
/**
* Get the value as a {@link Short} from the specified path.
*
* @param path The path to get the short.
* @param def The default value to return if the path does not exist.
* @return The short if the path exists and is a short, otherwise the default value.
*/
@Contract("_, !null -> !null")
default @Nullable Short getShort(@NotNull String path, @Nullable Short def) {
return get(path, def, DataFunction.shortValue());
}
/**
* Predicate the value of given path is a {@link Integer}.
*
* @param path The path to check.
* @return True if the value is present and is an int, false otherwise.
*/
default boolean isInt(@NotNull String path) {
return isType(path, Integer.class);
}
/**
* Get the value as a {@link Integer} from the specified path.
*
* @param path The path to get the int.
* @return The int if the path exists and is an int, otherwise 0.
*/
default @Nullable Integer getInt(@NotNull String path) {
return getInt(path, 0);
}
/**
* Get the value as a {@link Integer} from the specified path.
*
* @param path The path to get the int.
* @param def The default value to return if the path does not exist.
* @return The int if the path exists and is an int, otherwise the default value.
*/
@Contract("_, !null -> !null")
default @Nullable Integer getInt(@NotNull String path, @Nullable Integer def) {
return get(path, def, DataFunction.intValue());
}
/**
* Predicate the value of given path is a {@link Long}.F
*
* @param path The path to check.
* @return True if the value is present and is a long, false otherwise.
*/
default boolean isLong(@NotNull String path) {
return isType(path, Long.class);
}
/**
* Get the value as a {@link Long} from the specified path.
*
* @param path The path to get the long.
* @return The long if the path exists and is a long, otherwise 0.
*/
default @Nullable Long getLong(@NotNull String path) {
return getLong(path, 0L);
}
/**
* Get the value as a {@link Long} from the specified path.
*
* @param path The path to get the long.
* @param def The default value to return if the path does not exist.
* @return The long if the path exists and is a long, otherwise the default value.
*/
@Contract("_, !null -> !null")
default @Nullable Long getLong(@NotNull String path, @Nullable Long def) {
return get(path, def, DataFunction.longValue());
}
/**
* Predicate the value of given path is a {@link Float}.
*
* @param path The path to check.
* @return True if the value is present and is a float, false otherwise.
*/
default boolean isFloat(@NotNull String path) {
return isType(path, Float.class);
}
/**
* Get the value as a {@link Float} from the specified path.
*
* @param path The path to get the float.
* @return The float if the path exists and is a float, otherwise 0.
*/
default @Nullable Float getFloat(@NotNull String path) {
return getFloat(path, 0.0F);
}
/**
* Get the value as a {@link Float} from the specified path.
*
* @param path The path to get the float.
* @param def The default value to return if the path does not exist.
* @return The float if the path exists and is a float, otherwise the default value.
*/
@Contract("_, !null -> !null")
default @Nullable Float getFloat(@NotNull String path, @Nullable Float def) {
return get(path, def, DataFunction.floatValue());
}
/**
* Predicate the value of given path is a {@link Double}.
*
* @param path The path to check.
* @return True if the value is present and is a double, false otherwise.
*/
default boolean isDouble(@NotNull String path) {
return isType(path, Double.class);
}
/**
* Get the value as a {@link Double} from the specified path.
*
* @param path The path to get the double.
* @return The double if the path exists and is a double, otherwise 0.
*/
default @Nullable Double getDouble(@NotNull String path) {
return getDouble(path, 0.0D);
}
/**
* Get the value as a {@link Double} from the specified path.
*
* @param path The path to get the double.
* @param def The default value to return if the path does not exist.
* @return The double if the path exists and is a double, otherwise the default value.
*/
@Contract("_, !null -> !null")
default @Nullable Double getDouble(@NotNull String path, @Nullable Double def) {
return get(path, def, DataFunction.doubleValue());
}
/**
* Predicate the value of given path is a {@link Character}.
*
* @param path The path to check.
* @return True if the value is present and is a char, false otherwise.
*/
default boolean isChar(@NotNull String path) {
return isType(path, Boolean.class);
}
/**
* Get the value as a {@link Character} from the specified path.
*
* @param path The path to get the char.
* @return The char if the path exists and is a char, otherwise null.
*/
default @Nullable Character getChar(@NotNull String path) {
return getChar(path, null);
}
/**
* Get the value as a {@link Character} from the specified path.
*
* @param path The path to get the char.
* @param def The default value to return if the path does not exist.
* @return The char if the path exists and is a char, otherwise the default value.
*/
@Contract("_, !null -> !null")
default @Nullable Character getChar(@NotNull String path, @Nullable Character def) {
return get(path, def, Character.class);
}
/**
* Predicate the value of given path is a {@link String}.
*
* @param path The path to check.
* @return True if the value is present and is a string, false otherwise.
*/
default boolean isString(@NotNull String path) {
return isType(path, String.class);
}
/**
* Get the value as a {@link String} from the specified path.
*
* @param path The path to get the string.
* @return The string if the path exists and is a string, otherwise null.
*/
default @Nullable String getString(@NotNull String path) {
return getString(path, null);
}
/**
* Get the value as a {@link String} from the specified path.
*
* @param path The path to get the string.
* @param def The default value to return if the path does not exist.
* @return The string if the path exists and is a string, otherwise the default value.
*/
@Contract("_, !null -> !null")
default @Nullable String getString(@NotNull String path, @Nullable String def) {
return get(path, def, String.class);
}
/**
* Get a list of values from the section
* <p>
* If the path does not exist, an empty list will be returned
* <br>Any changes please use {@link #set(String, Object)} after changes
*
* @param path The path to get the list from
* @param parser The function to parse the values
* @param <V> The type of the values
* @return The list of values
*/
default <V> @NotNull List<V> getList(@NotNull String path, @NotNull DataFunction<Object, V> parser) {
return getCollection(path, ArrayList::new, parser);
}
/**
* Get a list of strings from the section
* <p> Limitations see {@link #getList(String, DataFunction)}
*
* @param path The path to get the list from
* @return The list of strings
*/
default @NotNull List<String> getStringList(@NotNull String path) {
return getList(path, DataFunction.castToString());
}
/**
* Get a list of integer from the section
* <p> Limitations see {@link #getList(String, DataFunction)}
*
* @param path The path to get the list from
* @return The list of int values
*/
default @NotNull List<Integer> getIntegerList(@NotNull String path) {
return getList(path, DataFunction.intValue());
}
/**
* Get a list of long from the section
* <p> Limitations see {@link #getList(String, DataFunction)}
*
* @param path The path to get the list from
* @return The list of long values
*/
default @NotNull List<Long> getLongList(@NotNull String path) {
return getList(path, DataFunction.longValue());
}
/**
* Get a list of double from the section
* <p> Limitations see {@link #getList(String, DataFunction)}
*
* @param path The path to get the list from
* @return The list of doubles
*/
default @NotNull List<Double> getDoubleList(@NotNull String path) {
return getList(path, DataFunction.doubleValue());
}
/**
* Get a list of floats from the section
* <p> Limitations see {@link #getList(String, DataFunction)}
*
* @param path The path to get the list from
* @return The list of floats
*/
default @NotNull List<Float> getFloatList(@NotNull String path) {
return getList(path, DataFunction.floatValue());
}
/**
* Get a list of bytes from the section
* <p> Limitations see {@link #getList(String, DataFunction)}
*
* @param path The path to get the list from
* @return The list of bytes
*/
default @NotNull List<Byte> getByteList(@NotNull String path) {
return getList(path, DataFunction.byteValue());
}
/**
* Get a list of char from the section
* <p> Limitations see {@link #getList(String, DataFunction)}
*
* @param path The path to get the list from
* @return The list of char
*/
default @NotNull List<Character> getCharList(@NotNull String path) {
return getList(path, DataFunction.castObject(Character.class));
}
/**
* Get the specific type of collection from the section.
*
* @param path The path to get the collection from
* @param constructor The constructor of the collection
* @param parser The function to parse the values
* @param <T> The type of the values
* @param <C> The type of the collection
* @return The collection of values
*/
default <T, C extends Collection<T>> @NotNull C getCollection(@NotNull String path,
@NotNull Supplier<C> constructor,
@NotNull DataFunction<Object, T> parser) {
return parseCollection(getList(path), constructor, parser);
}
/**
* Get the specific type of steam from the section.
*
* @param path The path to get the stream from
* @return The stream of values
*/
default @NotNull Stream<?> stream(@NotNull String path) {
List<?> values = getList(path);
return values == null ? Stream.empty() : values.stream();
}
/**
* Get the specific type of steam from the section.
*
* @param path The path to get the stream from
* @param parser The function to parse the values
* @param <T> The type of the values
* @return The stream of values
*/
default <T> @NotNull Stream<T> stream(@NotNull String path, @NotNull Function<Object, T> parser) {
return stream(path).map(parser);
}
default String childPath(String path) {
int index = path.indexOf(pathSeparator());
return (index == -1) ? path : path.substring(index + 1);
}
static <T, C extends Collection<T>> @NotNull C parseCollection(
@Nullable List<?> data,
@NotNull Supplier<C> constructor,
@NotNull DataFunction<Object, T> parser
) {
C values = constructor.get();
if (data == null) return values;
for (Object obj : data) {
try {
values.add(parser.handle(obj));
} catch (Exception ignored) {
}
}
return values;
}
}
@@ -0,0 +1,135 @@
package cc.carm.lib.configuration.source.section;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.option.StandardOptions;
import org.jetbrains.annotations.*;
import java.util.Map;
import java.util.Set;
/**
* ConfigureSource represents the source of configuration,
* which can be a file, a database, or any other source.
*
* @param <SECTION> The type of the root section.
* @param <ORIGINAL> The original configuration object.
* @param <SELF> The type of the source itself, for further implement support.
* @see ConfigureSection
*/
public abstract class ConfigureSource<
SECTION extends ConfigureSection, ORIGINAL,
SELF extends ConfigureSource<SECTION, ORIGINAL, SELF>>
implements ConfigureSection {
protected final @NotNull ConfigurationHolder<? extends SELF> holder;
protected long lastUpdateMillis;
protected ConfigureSource(@NotNull ConfigurationHolder<? extends SELF> holder, long lastUpdateMillis) {
this.holder = holder;
this.lastUpdateMillis = lastUpdateMillis;
}
public @NotNull ConfigurationHolder<? extends SELF> holder() {
return holder;
}
public void reload() throws Exception {
onReload(); // 调用重写的Reload方法
this.lastUpdateMillis = System.currentTimeMillis();
}
@Contract(pure = true)
@ApiStatus.Internal
protected abstract @NotNull SELF self();
/**
* @return The original configuration object.
*/
@Contract(pure = true)
public abstract @NotNull ORIGINAL original();
/**
* @return The root {@link ConfigureSection}, which represents the entire configuration.
*/
public abstract @NotNull SECTION section();
/**
* Save the whole configuration.
*
* @throws Exception If any error occurs while saving.
*/
public abstract void save() throws Exception;
/**
* Reload the configuration.
* <br>This used for implementation, for external usage, use {@link #reload()}
*
* @throws Exception If any error occurs while reloading.
*/
@ApiStatus.OverrideOnly
protected abstract void onReload() throws Exception;
public char pathSeparator() {
return holder().options().get(StandardOptions.PATH_SEPARATOR);
}
public long getLastUpdateMillis() {
return this.lastUpdateMillis;
}
public boolean isExpired(long parsedTime) {
return getLastUpdateMillis() > parsedTime;
}
/**
* Source also represents the root section, so it has no parent
*
* @return null
*/
@Override
@Contract(pure = true, value = "->null")
public @Nullable ConfigureSection parent() {
return null;
}
@Override
public @NotNull String path() {
return "";
}
@Override
public @NotNull Map<String, Object> getValues(boolean deep) {
return section().getValues(deep);
}
@Override
public @NotNull @UnmodifiableView Set<String> getKeys(boolean deep) {
return section().getKeys(deep);
}
@Override
public @NotNull @UnmodifiableView Map<String, Object> asMap() {
return section().asMap();
}
@Override
public @NotNull ConfigureSection createSection(@NotNull String path, @NotNull Map<?, ?> data) {
return section().createSection(path, data);
}
@Override
public void set(@NotNull String path, @Nullable Object value) {
section().set(path, value);
}
@Override
public void remove(@NotNull String path) {
section().remove(path);
}
@Override
public @Nullable Object get(@NotNull String path) {
return section().get(path);
}
}
@@ -0,0 +1,141 @@
package cc.carm.lib.configuration.value;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.Optional;
/**
* Represents a configurable value with type safety and null-handling capabilities.
* <p>
* This abstract class provides core functionalities for managing configuration values,
* including value retrieval with fallback defaults, null safety enforcement, and value
* persistence controls. It serves as the foundation for type-specific configuration
* implementations.
* </p>
*
* <h3>Functions:</h3>
* <ul>
* <li>Type-safe value access through {@link #get()} and {@link #optional()}</li>
* <li>Default value fallback via {@link #getOrDefault()}</li>
* <li>Null-safety enforcement with {@link #resolve()} and {@link #getNotNull()}</li>
* <li>Default value initialization through {@link #setDefault()}</li>
* <li>Value comparison with {@link #isDefault()}</li>
* </ul>
*
* <h3>Persistence Behavior:</h3>
* Value modifications via {@link #set(Object)} or {@link #setDefault()} methods
* <b>do NOT automatically persist</b> to configuration sources. Explicit calls to
* {@link ConfigurationHolder#save()} are required for permanent storage.
*
* @see ValueManifest Base class providing metadata and default value handling
* @see ConfigurationHolder Responsible for configuration source persistence
*/
public abstract class ConfigValue<T> extends ValueManifest<T> {
protected ConfigValue(@NotNull ValueManifest<T> manifest) {
super(manifest);
}
/**
* Gets the configured value (i.e., the value read from the source).
* <br> If no default value was written during initialization, you can use
* the {@link #getOrDefault()} method to obtain the default value when this value is empty.
*
* @return Configured value
*/
public abstract @Nullable T get();
/**
* Gets the configured value, or returns the default value if not present.
*
* @return Configured value or default value
*/
public T getOrDefault() {
return optional().orElse(defaults());
}
/**
* Gets the non-null value of this configuration.
*
* @return Non-null value
* @throws NullPointerException Thrown when the corresponding data is null
*/
public @NotNull T resolve() {
return Objects.requireNonNull(getOrDefault(), "Value(" + type() + ") @[" + path() + "] is null.");
}
/**
* Gets the non-null value of this configuration.
*
* @return Non-null value
* @throws NullPointerException Thrown when the corresponding data is null
* @see #resolve() for a more descriptive function
*/
public @NotNull T getNotNull() {
return resolve();
}
/**
* Gets the value of this configuration as an {@link Optional}.
*
* @return {@link Optional} value
*/
public @NotNull Optional<@Nullable T> optional() {
return Optional.ofNullable(get());
}
/**
* Sets the value of this configuration.
* <br> After setting, the configuration file will NOT be saved automatically.
* To save, call {@link ConfigurationHolder#save()}.
*
* @param value The value to set
*/
public abstract void set(@Nullable T value);
/**
* Initializes the default value for this configuration.
* <br> After setting, the configuration file will NOT be saved automatically.
* To save, call {@link ConfigurationHolder#save()}.
*/
public void setDefault() {
setDefault(false);
}
/**
* Sets the configuration value to its default.
* <br> After setting, the configuration file will NOT be saved automatically.
* To save, call {@link ConfigurationHolder#save()}.
*
* @param override Whether to overwrite existing configured value
*/
public void setDefault(boolean override) {
if (config().contains(path()) && !override) return; // Skip if the value is already set
set(defaults()); // Set the default value
}
/**
* Checks if the loaded configuration value matches the default value.
*
* @return Whether the current value is the default value
*/
public boolean isDefault() {
return Objects.equals(defaults(), get());
}
/**
* Try to save the configuration.
* <br>To save multiple modifications,
* it is recommended to call {@link ConfigurationHolder#save()}
* after all modifications are completed instead of this.
*
* @throws Exception Thrown when an error occurs during saving
*/
public void save() throws Exception {
holder().save();
}
}
@@ -0,0 +1,125 @@
package cc.carm.lib.configuration.value;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
import cc.carm.lib.configuration.source.section.ConfigureSource;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
public class ValueManifest<T> {
protected final @NotNull ValueType<T> type;
protected final @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer;
protected @Nullable ConfigurationHolder<?> holder;
protected @Nullable String path; // Section path
protected @NotNull Supplier<@Nullable T> defaultSupplier;
public ValueManifest(@NotNull ValueType<T> type) {
this(type, () -> null, EMPTY_INITIALIZER, null, null);
}
public ValueManifest(@NotNull T defaultValue) {
this(ValueType.of(defaultValue), () -> defaultValue);
}
public ValueManifest(@NotNull ValueType<T> type, @NotNull Supplier<@Nullable T> defaultSupplier) {
this(type, defaultSupplier, EMPTY_INITIALIZER, null, null);
}
public ValueManifest(@NotNull ValueType<T> type, @NotNull Supplier<@Nullable T> defaultSupplier,
@NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer) {
this(type, defaultSupplier, initializer, null, null);
}
public ValueManifest(@NotNull ValueType<T> type, @NotNull Supplier<@Nullable T> defaultSupplier,
@NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer,
@Nullable ConfigurationHolder<?> holder, @Nullable String path) {
this.type = type;
this.initializer = initializer;
this.defaultSupplier = defaultSupplier;
this.holder = holder;
this.path = path;
initialize();
}
protected ValueManifest(@NotNull ValueManifest<T> manifest) {
this(manifest.type, manifest.defaultSupplier, manifest.initializer, manifest.holder, manifest.path);
}
public void initialize(@NotNull ConfigurationHolder<?> holder, @NotNull String path) {
this.holder = holder;
this.path = path;
initialize();
}
protected void initialize() {
if (holder != null && path != null) this.initializer.accept(holder, path);
}
public @NotNull ValueType<T> type() {
return this.type;
}
public void holder(@NotNull ConfigurationHolder<?> holder) {
this.holder = holder;
}
public void path(@NotNull String path) {
this.path = path;
}
public @Nullable T defaults() {
return this.defaultSupplier.get();
}
public void defaults(@Nullable T defaultValue) {
defaults(() -> defaultValue);
}
public void defaults(@NotNull Supplier<@Nullable T> defaultValue) {
this.defaultSupplier = defaultValue;
}
public boolean hasDefaults() {
return this.defaultSupplier.get() != null;
}
public @NotNull String path() {
if (path != null) return path;
else throw new IllegalStateException("No section path provided for Value(" + type() + ").");
}
public @NotNull ConfigurationHolder<?> holder() {
if (this.holder != null) return this.holder;
throw new IllegalStateException("Value(" + type() + ") does not have a provider.");
}
public @NotNull ConfigureSource<?, ?, ?> config() {
return holder().config();
}
public ConfigurationMetaHolder metadata() {
return holder().metadata(path());
}
@ApiStatus.Internal
protected Object getData() {
return config().get(path());
}
@ApiStatus.Internal
protected void setData(@Nullable Object value) {
config().set(path(), value);
}
private static final @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> EMPTY_INITIALIZER = (provider, valuePath) -> {
};
}
@@ -0,0 +1,85 @@
package cc.carm.lib.configuration.value.impl;
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.value.ConfigValue;
import cc.carm.lib.configuration.value.ValueManifest;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class CachedConfigValue<T> extends ConfigValue<T> {
protected @Nullable T cachedValue;
protected long parsedTime = -1;
protected CachedConfigValue(@NotNull ValueManifest<T> manifest) {
super(manifest);
}
protected T updateCache(T value) {
this.parsedTime = System.currentTimeMillis();
this.cachedValue = value;
return getCachedValue();
}
public @Nullable T getCachedValue() {
return cachedValue;
}
public boolean cacheExpired() {
return this.parsedTime <= 0 || config().isExpired(this.parsedTime);
}
protected final T getDefaultFirst(@Nullable T value) {
return updateCache(this.defaults() == null ? value : this.defaults());
}
/**
* Get the cached value or the default value if the cached value is null
*
* @return the cached value or the default value
*/
protected @Nullable T getCachedOrDefault() {
return getCachedOrDefault(null);
}
/**
* Get the cached value or the default value if the cached value is null
*
* @param emptyValue the value to return if the cached value and the default value are null
* @return the cached value or the default value
*/
@Contract("!null->!null")
protected T getCachedOrDefault(@Nullable T emptyValue) {
if (getCachedValue() != null) return getCachedValue();
else if (defaults() != null) return defaults();
else return emptyValue;
}
/**
* @param adapter Value adapter
* @param <O> Base object type
* @return Value's parser, parse base object to value.
*/
protected <O> @Nullable ValueParser<O> parserFor(@NotNull ValueAdapter<O> adapter) {
if (adapter.parser() != null) return adapter.parser();
ValueAdapter<O> registered = holder().adapters().adapterOf(adapter.type());
if (registered == null) return null;
return registered.parser();
}
/**
* @param adapter Value adapter
* @param <O> Base object type
* @return Value's serializer, parse value to base object.
*/
protected <O> @Nullable ValueSerializer<O> serializerFor(@NotNull ValueAdapter<O> adapter) {
if (adapter.serializer() != null) return adapter.serializer();
ValueAdapter<O> registered = holder().adapters().adapterOf(adapter.type());
if (registered == null) return null;
return registered.serializer();
}
}
@@ -0,0 +1,252 @@
package cc.carm.lib.configuration.value.standard;
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.builder.list.ConfigListBuilder;
import cc.carm.lib.configuration.value.ValueManifest;
import cc.carm.lib.configuration.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements List<V> {
public static <T> @NotNull ConfigListBuilder<T> builderOf(@NotNull Class<T> type) {
return builderOf(ValueType.of(type));
}
public static <T> @NotNull ConfigListBuilder<T> builderOf(@NotNull ValueType<T> type) {
return new ConfigListBuilder<>(type);
}
protected final @NotNull Supplier<? extends List<V>> constructor;
protected final @NotNull ValueAdapter<V> paramAdapter;
public ConfiguredList(@NotNull ValueManifest<List<V>> manifest,
@NotNull Supplier<? extends List<V>> constructor,
@NotNull ValueAdapter<V> paramAdapter) {
super(manifest);
this.constructor = constructor;
this.paramAdapter = paramAdapter;
}
/**
* @return Adapter of this value.
*/
public @NotNull ValueAdapter<V> adapter() {
return this.paramAdapter;
}
public @NotNull ValueType<V> paramType() {
return adapter().type();
}
/**
* @return Value's parser, parse base object to value.
*/
public @Nullable ValueParser<V> parser() {
return parserFor(adapter());
}
/**
* @return Value's serializer, parse value to base object.
*/
public @Nullable ValueSerializer<V> serializer() {
return serializerFor(adapter());
}
private @NotNull List<V> createList() {
return constructor.get();
}
@Override
public @NotNull List<V> get() {
if (!cacheExpired()) return getCachedOrDefault(createList());
// Data that is outdated and needs to be parsed again.
List<V> list = createList();
List<?> data = config().contains(path()) ? config().getList(path()) : null;
if (data == null) return getDefaultFirst(list);
ValueParser<V> parser = parser();
if (parser == null) return getDefaultFirst(list);
for (Object dataVal : data) {
if (dataVal == null) continue;
try {
list.add(parser.parse(holder(), paramType(), dataVal));
} catch (Exception e) {
e.printStackTrace();
}
}
return updateCache(list);
}
@Override
public void set(@Nullable List<V> value) {
updateCache(value);
if (value == null) {
setData(null);
return;
}
ValueSerializer<V> serializer = serializer();
if (serializer == null) return;
List<Object> data = new ArrayList<>();
for (V val : value) {
if (val == null) continue;
try {
data.add(serializer.serialize(holder(), paramType(), val));
} catch (Exception ex) {
ex.printStackTrace();
}
}
setData(data);
}
@Override
public V get(int index) {
return resolve().get(index);
}
public @NotNull List<V> copy() {
return new ArrayList<>(resolve());
}
public <T> @NotNull T handle(Function<List<V>, T> function) {
List<V> list = resolve();
T result = function.apply(list);
set(list);
return result;
}
public @NotNull ConfiguredList<V> modify(Consumer<List<V>> consumer) {
List<V> list = resolve();
consumer.accept(list);
set(list);
return this;
}
@Override
public V set(int index, V element) {
return handle(list -> list.set(index, element));
}
@Override
public int size() {
return resolve().size();
}
@Override
public boolean isEmpty() {
return resolve().isEmpty();
}
@Override
public boolean contains(Object o) {
return resolve().contains(o);
}
@NotNull
@Override
public Iterator<V> iterator() {
return resolve().iterator();
}
@NotNull
@Override
public Object @NotNull [] toArray() {
return resolve().toArray();
}
@NotNull
@Override
public <T> T @NotNull [] toArray(@NotNull T[] a) {
return resolve().toArray(a);
}
@Override
public boolean containsAll(@NotNull Collection<?> c) {
return new HashSet<>(resolve()).containsAll(c);
}
@Override
public boolean add(V v) {
handle(list -> list.add(v));
return true;
}
@Override
public void add(int index, V element) {
modify(list -> list.add(index, element));
}
@Override
public boolean addAll(@NotNull Collection<? extends V> c) {
return handle(list -> list.addAll(c));
}
@Override
public boolean addAll(int index, @NotNull Collection<? extends V> c) {
return handle(list -> list.addAll(index, c));
}
@Override
public boolean remove(Object o) {
return handle(list -> list.remove(o));
}
@Override
public V remove(int index) {
return handle(list -> list.remove(index));
}
@Override
public boolean removeAll(@NotNull Collection<?> c) {
return handle(list -> list.removeAll(c));
}
@Override
public boolean retainAll(@NotNull Collection<?> c) {
return handle(list -> list.retainAll(c));
}
@Override
public void clear() {
modify(List::clear);
}
@Override
public int indexOf(Object o) {
return resolve().indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return resolve().lastIndexOf(o);
}
@NotNull
@Override
public ListIterator<V> listIterator() {
return resolve().listIterator();
}
@NotNull
@Override
public ListIterator<V> listIterator(int index) {
return resolve().listIterator(index);
}
@NotNull
@Override
public List<V> subList(int fromIndex, int toIndex) {
return resolve().subList(fromIndex, toIndex);
}
}
@@ -0,0 +1,211 @@
package cc.carm.lib.configuration.value.standard;
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.builder.map.ConfigMapCreator;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import cc.carm.lib.configuration.value.ValueManifest;
import cc.carm.lib.configuration.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements Map<K, V> {
public static <K, V> ConfigMapCreator<K, V> builderOf(@NotNull ValueType<K> keyType, @NotNull ValueType<V> valueType) {
return new ConfigMapCreator<>(keyType, valueType);
}
public static <K, V> ConfigMapCreator<K, V> builderOf(@NotNull Class<K> keyType, @NotNull Class<V> valueType) {
return new ConfigMapCreator<>(ValueType.of(keyType), ValueType.of(valueType));
}
public static <K, V> ConfiguredMap<K, V> of(@NotNull Supplier<? extends Map<K, V>> constructor,
@NotNull ValueAdapter<K> keyAdapter, @NotNull ValueAdapter<V> valueAdapter) {
return new ConfiguredMap<>(new ValueManifest<>(new ValueType<Map<K, V>>() {
}, constructor::get), constructor, keyAdapter, valueAdapter);
}
protected final @NotNull Supplier<? extends Map<K, V>> constructor;
protected final @NotNull ValueAdapter<K> keyAdapter;
protected final @NotNull ValueAdapter<V> valueAdapter;
public ConfiguredMap(@NotNull ValueManifest<Map<K, V>> manifest,
@NotNull Supplier<? extends Map<K, V>> constructor,
@NotNull ValueAdapter<K> keyAdapter, @NotNull ValueAdapter<V> valueAdapter) {
super(manifest);
this.constructor = constructor;
this.keyAdapter = keyAdapter;
this.valueAdapter = valueAdapter;
}
public @NotNull ValueAdapter<K> keyAdapter() {
return keyAdapter;
}
public @NotNull ValueType<K> keyType() {
return keyAdapter().type();
}
public @NotNull ValueAdapter<V> valueAdapter() {
return valueAdapter;
}
public @NotNull ValueType<V> valueType() {
return valueAdapter().type();
}
private Map<K, V> createMap() {
return this.constructor.get();
}
@Override
public @NotNull Map<K, V> get() {
if (!cacheExpired()) return getCachedOrDefault(createMap());
// If the value is expired, we need to update it
Map<K, V> map = createMap();
ConfigureSection section = config().getSection(path());
if (section == null) return getDefaultFirst(map);
Set<String> keys = section.getKeys(false);
if (keys.isEmpty()) return getDefaultFirst(map);
ValueParser<K> keyParser = parserFor(keyAdapter);
ValueParser<V> valueParser = parserFor(valueAdapter);
if (keyParser == null || valueParser == null) return getDefaultFirst(map);
for (String dataKey : keys) {
Object dataVal = section.get(dataKey);
if (dataVal == null) continue;
try {
K key = keyParser.parse(holder(), keyType(), dataKey);
V value = valueParser.parse(holder(), valueType(), dataVal);
map.put(key, value);
} catch (Exception e) {
e.printStackTrace();
}
}
return updateCache(map);
}
@Override
public V get(Object key) {
return get().get(key);
}
public V getNotNull(@Nullable K key) {
return Objects.requireNonNull(get(key));
}
@Override
public void set(@Nullable Map<K, V> value) {
updateCache(value);
if (value == null) {
setData(null);
return;
}
ValueSerializer<K> keySerializer = serializerFor(keyAdapter);
ValueSerializer<V> valueSerializer = serializerFor(valueAdapter);
if (keySerializer == null || valueSerializer == null) return;
Map<Object, Object> data = new LinkedHashMap<>();
for (Map.Entry<K, V> entry : value.entrySet()) {
try {
data.put(
keySerializer.serialize(holder(), keyType(), entry.getKey()),
valueSerializer.serialize(holder(), valueType(), entry.getValue())
);
} catch (Exception e) {
e.printStackTrace();
}
}
setData(data);
}
public <T> @NotNull T handle(Function<Map<K, V>, T> function) {
Map<K, V> m = get();
T result = function.apply(m);
set(m);
return result;
}
public @NotNull ConfiguredMap<K, V> modify(Consumer<Map<K, V>> consumer) {
Map<K, V> m = get();
consumer.accept(m);
set(m);
return this;
}
@Override
public int size() {
return get().size();
}
@Override
public boolean isEmpty() {
return get().isEmpty();
}
@Override
public boolean containsKey(Object key) {
return get().containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return get().containsValue(value);
}
@Nullable
@Override
public V put(K key, V value) {
return handle(m -> m.put(key, value));
}
@Override
public V remove(Object key) {
return handle(m -> m.remove(key));
}
@Override
public void putAll(@NotNull Map<? extends K, ? extends V> m) {
modify(map -> map.putAll(m));
}
@Override
public void clear() {
modify(Map::clear);
}
@NotNull
@Override
public Set<K> keySet() {
return get().keySet();
}
@NotNull
@Override
public Collection<V> values() {
return get().values();
}
@NotNull
@Override
@Unmodifiable
public Set<Entry<K, V>> entrySet() {
return get().entrySet();
}
}
@@ -0,0 +1,143 @@
package cc.carm.lib.configuration.value.standard;
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.builder.value.ConfigValueBuilder;
import cc.carm.lib.configuration.value.ValueManifest;
import cc.carm.lib.configuration.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Supplier;
public class ConfiguredValue<V> extends CachedConfigValue<V> {
public static <V> ConfigValueBuilder<V> builderOf(@NotNull Class<V> type) {
return new ConfigValueBuilder<>(ValueType.of(type));
}
public static <V> ConfigValueBuilder<V> builderOf(@NotNull ValueType<V> type) {
return new ConfigValueBuilder<>(type);
}
public static <V> ConfiguredValue<V> of(@NotNull V defaults) {
return of(ValueType.of(defaults), () -> defaults);
}
public static <V> ConfiguredValue<V> of(@NotNull Class<V> type) {
return of(ValueType.of(type), () -> null);
}
public static <V> ConfiguredValue<V> of(@NotNull Class<V> type, @NotNull V defaults) {
return of(ValueType.of(type), () -> defaults);
}
public static <V> ConfiguredValue<V> of(@NotNull Class<V> type, @NotNull Supplier<@Nullable V> defaultSupplier) {
return of(ValueType.of(type), defaultSupplier);
}
public static <V> ConfiguredValue<V> of(@NotNull ValueType<V> type) {
return of(type, () -> null);
}
public static <V> ConfiguredValue<V> of(@NotNull ValueType<V> type, @NotNull Supplier<@Nullable V> defaultSupplier) {
return of(
new ValueManifest<>(type, defaultSupplier),
(provider, t, data) -> provider.deserialize(type, data),
(provider, t, value) -> provider.serialize(value)
);
}
public static <V> ConfiguredValue<V> of(@NotNull ValueManifest<V> manifest,
@Nullable ValueParser<V> parser,
@Nullable ValueSerializer<V> serializer) {
ValueAdapter<V> adapter = new ValueAdapter<>(manifest.type());
adapter.parser(parser);
adapter.serializer(serializer);
return of(manifest, adapter);
}
public static <V> ConfiguredValue<V> of(@NotNull ValueManifest<V> manifest, @NotNull ValueAdapter<V> adapter) {
return new ConfiguredValue<>(manifest, adapter);
}
protected final @NotNull ValueAdapter<V> adapter;
public ConfiguredValue(@NotNull ValueManifest<V> manifest, @NotNull ValueAdapter<V> adapter) {
super(manifest);
this.adapter = adapter;
}
/**
* @return Adapter of this value.
*/
public @NotNull ValueAdapter<V> adapter() {
return adapter;
}
/**
* @return Value's parser, parse base object to value.
*/
public @Nullable ValueParser<V> parser() {
return parserFor(adapter());
}
/**
* @return Value's serializer, parse value to base object.
*/
public @Nullable ValueSerializer<V> serializer() {
return serializerFor(adapter());
}
@Override
public V get() {
if (!cacheExpired()) return getCachedOrDefault();
// Data that is outdated and needs to be parsed again.
Object data = getData();
if (data == null) return defaults();
ValueParser<V> parser = parser();
if (parser == null) return defaults(); // No parser, return default value.
try {
// If there are no errors, update the cache and return.
return updateCache(parser.parse(holder(), type(), data));
} catch (Exception e) {
// There was a parsing error, prompted and returned the default value.
e.printStackTrace();
return defaults();
}
}
/**
* Set the value of the configuration path.
* Will use {@link #serializer()} to serialize the value.
*
* @param value The value to be set
*/
@Override
public void set(V value) {
updateCache(value); // Update cache
if (value == null) {
setData(null);
return;
}
ValueSerializer<V> serializer = serializer();
if (serializer == null) return; // No serializer, do nothing.
try {
setData(serializer.serialize(holder(), type(), value));
} catch (Exception e) {
e.printStackTrace();
}
}
}
+5 -5
View File
@@ -1,4 +1,4 @@
import cc.carm.lib.configuration.core.ConfigInitializer;
import cc.carm.lib.configuration.source.loader.PathGenerator;
import org.junit.Test;
public class NameTest {
@@ -7,10 +7,10 @@ public class NameTest {
@Test
public void onTest() {
System.out.println(ConfigInitializer.getPathFromName("LoveGames")); // -> love-games
System.out.println(ConfigInitializer.getPathFromName("EASY_GAME")); // -> easy-game
System.out.println(ConfigInitializer.getPathFromName("F")); //-? f
System.out.println(ConfigInitializer.getPathFromName("Test123123")); // -? test123123123
System.out.println(PathGenerator.covertPathName("LoveGames")); // -> love-games
System.out.println(PathGenerator.covertPathName("EASY_GAME")); // -> easy-game
System.out.println(PathGenerator.covertPathName("F")); //-? f
System.out.println(PathGenerator.covertPathName("Test123123")); // -? test123123123
}
+38 -3
View File
@@ -5,12 +5,12 @@
<parent>
<artifactId>easyconfiguration-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>3.3.0</version>
<version>4.0.11</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<properties>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<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>
@@ -26,6 +26,41 @@
<scope>compile</scope>
</dependency>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-commentable</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-versioned</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -1,33 +1,34 @@
package cc.carm.lib.configuration.demo;
import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.ConfigPath;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.annotation.ConfigPath;
import cc.carm.lib.configuration.annotation.HeaderComments;
import cc.carm.lib.configuration.value.ConfigValue;
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
@HeaderComment({"", "数据库配置", " 用于提供数据库连接,进行数据库操作。"})
public class DatabaseConfiguration extends ConfigurationRoot {
@HeaderComments({"", "数据库配置", " 用于提供数据库连接,进行数据库操作。"})
public interface DatabaseConfiguration extends Configuration {
@ConfigPath("driver")
@HeaderComment({
@HeaderComments({
"数据库驱动配置,请根据数据库类型设置。",
"- MySQL(旧): com.mysql.jdbc.Driver",
"- MySQL(新): com.mysql.cj.jdbc.Driver",
"- MariaDB(推荐): org.mariadb.jdbc.Driver",
})
protected static final ConfigValue<String> DRIVER_NAME = ConfiguredValue.of(
ConfigValue<String> DRIVER_NAME = ConfiguredValue.of(
String.class, "com.mysql.cj.jdbc.Driver"
);
protected static final ConfigValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1");
protected static final ConfigValue<Integer> PORT = ConfiguredValue.of(Integer.class, 3306);
protected static final ConfigValue<String> DATABASE = ConfiguredValue.of(String.class, "minecraft");
protected static final ConfigValue<String> USERNAME = ConfiguredValue.of(String.class, "root");
protected static final ConfigValue<String> PASSWORD = ConfiguredValue.of(String.class, "password");
protected static final ConfigValue<String> EXTRA = ConfiguredValue.of(String.class, "?useSSL=false");
ConfigValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1");
ConfigValue<Integer> PORT = ConfiguredValue.of(Integer.class, 3306);
ConfigValue<String> DATABASE = ConfiguredValue.of(String.class, "minecraft");
ConfigValue<String> USERNAME = ConfiguredValue.of(String.class, "root");
ConfigValue<String> PASSWORD = ConfiguredValue.of(String.class, "password");
protected static String buildJDBC() {
ConfigValue<String> EXTRA = ConfiguredValue.of(String.class, "?useSSL=false");
static String buildJDBC() {
return String.format("jdbc:mysql://%s:%s/%s%s", HOST.get(), PORT.get(), DATABASE.get(), EXTRA.get());
}
@@ -1,11 +1,11 @@
package cc.carm.lib.configuration.demo.tests;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.demo.tests.model.TestModel;
import cc.carm.lib.configuration.demo.tests.conf.DemoConfiguration;
import cc.carm.lib.configuration.demo.tests.conf.TestConfiguration;
import cc.carm.lib.configuration.demo.tests.conf.RegistryConfig;
import cc.carm.lib.configuration.demo.tests.model.UserRecord;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.TestOnly;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@@ -13,8 +13,13 @@ import java.util.stream.IntStream;
public class ConfigurationTest {
public static void testDemo(ConfigurationProvider<?> provider) {
provider.initialize(DemoConfiguration.class);
@TestOnly
public static void testDemo(ConfigurationHolder<?> holder) {
try {
holder.initialize(DemoConfiguration.class);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("----------------------------------------------------");
@@ -25,48 +30,57 @@ public class ConfigurationTest {
System.out.println("after: " + DemoConfiguration.TEST_NUMBER.get());
System.out.println("> Test Value:");
System.out.println("before: " + DemoConfiguration.Sub.UUID_CONFIG_VALUE.get());
DemoConfiguration.Sub.UUID_CONFIG_VALUE.set(UUID.randomUUID());
System.out.println("after: " + DemoConfiguration.Sub.UUID_CONFIG_VALUE.get());
System.out.println("before: " + DemoConfiguration.SUB.UUID_CONFIG_VALUE.get());
DemoConfiguration.SUB.UUID_CONFIG_VALUE.set(UUID.randomUUID());
System.out.println("after: " + DemoConfiguration.SUB.UUID_CONFIG_VALUE.get());
System.out.println("> Test List:");
DemoConfiguration.Sub.That.OPERATORS.getNotNull().forEach(System.out::println);
System.out.println(" Before:");
DemoConfiguration.SUB.That.OPERATORS.forEach(System.out::println);
List<UUID> operators = IntStream.range(0, 5).mapToObj(i -> UUID.randomUUID()).collect(Collectors.toList());
DemoConfiguration.Sub.That.OPERATORS.set(operators);
DemoConfiguration.SUB.That.OPERATORS.set(operators);
System.out.println(" After:");
DemoConfiguration.SUB.That.OPERATORS.forEach(System.out::println);
System.out.println("> Clear List:");
System.out.println(" Before: size :" + DemoConfiguration.SUB.That.OPERATORS.size());
DemoConfiguration.SUB.That.OPERATORS.modify(List::clear);
System.out.println(" After size :" + DemoConfiguration.SUB.That.OPERATORS.size());
System.out.println("> Test Section:");
System.out.println(DemoConfiguration.MODEL_TEST.get());
DemoConfiguration.MODEL_TEST.set(TestModel.random());
System.out.println(DemoConfiguration.ALLOWLISTS.get());
DemoConfiguration.ALLOWLISTS.add(UserRecord.random());
System.out.println("> Test Maps:");
DemoConfiguration.USERS.getNotNull().forEach((k, v) -> System.out.println(k + ": " + v));
LinkedHashMap<Integer, UUID> data = new LinkedHashMap<>();
for (int i = 1; i <= 5; i++) {
data.put(i, UUID.randomUUID());
}
DemoConfiguration.USERS.set(data);
// System.out.println("> Test Maps:");
// DemoConfiguration.USERS.forEach((k, v) -> System.out.println(k + ": " + v));
// LinkedHashMap<Integer, UUID> data = new LinkedHashMap<>();
// for (int i = 1; i <= 5; i++) {
// data.put(i, UUID.randomUUID());
// }
// DemoConfiguration.USERS.set(data);
System.out.println("----------------------------------------------------");
}
public static void testInner(ConfigurationProvider<?> provider) {
public static void testInner(ConfigurationHolder<?> provider) {
TestConfiguration TEST = new TestConfiguration();
RegistryConfig TEST = new RegistryConfig();
provider.initialize(TEST, true);
provider.initialize(TEST);
System.out.println("> Test Inner value before:");
System.out.println(TEST.INNER.INNER_VALUE.getNotNull());
System.out.println(TEST.INSTANCE.STATUS.resolve());
double after = Math.random() * 200D;
System.out.println("> Test Inner value -> " + after);
TEST.INNER.INNER_VALUE.set(after);
TEST.INSTANCE.STATUS.set(after);
System.out.println("> Test Inner value after:");
System.out.println(TEST.INNER.INNER_VALUE.getNotNull());
System.out.println(TEST.INSTANCE.STATUS.resolve());
}
public static void save(ConfigurationProvider<?> provider) {
public static void save(ConfigurationHolder<?> provider) {
try {
provider.save();
} catch (Exception e) {
@@ -1,77 +1,89 @@
package cc.carm.lib.configuration.demo.tests.conf;
import cc.carm.lib.configuration.core.ConfigInitializer;
import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.ConfigPath;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.annotation.InlineComment;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.type.ConfiguredList;
import cc.carm.lib.configuration.core.value.type.ConfiguredMap;
import cc.carm.lib.configuration.core.value.type.ConfiguredSection;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
import cc.carm.lib.configuration.demo.tests.model.TestModel;
import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.annotation.*;
import cc.carm.lib.configuration.demo.tests.model.ItemStack;
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.ConfiguredMap;
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
import java.util.List;
import java.util.Map;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Objects;
import java.util.UUID;
@HeaderComment({
"此处内容将显示在配置文件的最上方",
""/*添加一个空行与其他配置的注释分割*/
@ConfigPath(root = true)
@HeaderComments({"此处内容将显示在配置文件的最上方"})
@FooterComments({
"------------------------------------------------",
"此处内容将显示在配置文件的最下方",
"可用于显示版权信息等",
"感谢您使用 https://github.com/CarmJos/EasyConfiguration !"
})
public class DemoConfiguration extends ConfigurationRoot {
public interface DemoConfiguration extends Configuration {
@ConfigPath(root = true)
protected static final ConfigValue<Double> VERSION = ConfiguredValue.of(Double.class, 1.0D);
@ConfigVersion(2)
ConfigValue<Double> VERSION = ConfiguredValue.of(Double.class, 2.0D);
@ConfigPath(root = true)
public static final ConfigValue<Long> TEST_NUMBER = ConfiguredValue.of(Long.class, 1000000L);
@FooterComments({"此处内容将显示在配置条目的下方", "可用于补充说明,但一般不建议使用"})
ConfigValue<Long> TEST_NUMBER = ConfiguredValue.of(1000000L);
// 支持通过 Class<?> 变量标注子配置,一并注册。
// 注意: 若对应类也有注解,则优先使用类的注解。
@ConfigPath("other-class-config") //支持通过注解修改子配置的主路径,若不修改则以变量名自动生成。
@HeaderComment({"", "Something..."}) // 支持给子路径直接打注释
@InlineComment("InlineComments for class path")
public static final Class<?> OTHER = OtherConfiguration.class;
@HeaderComments({"枚举类型测试"})
@FooterComments({"上述的枚举内容本质上是通过STRING解析的"})
ConfigValue<ChronoUnit> TEST_ENUM = ConfiguredValue.of(ChronoUnit.class, ChronoUnit.DAYS);
@ConfigPath("user") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
@HeaderComment({"", "Section类型数据测试"}) // 通过注解给配置添加注释。
@InlineComment("Section数据也支持InlineComment注释")
public static final ConfigValue<TestModel> MODEL_TEST = ConfiguredSection
.builder(TestModel.class)
.defaults(new TestModel("Carm", UUID.randomUUID()))
.parseValue((section, defaultValue) -> TestModel.deserialize(section))
.serializeValue(TestModel::serialize).build();
@HeaderComments({"空值测试"})
@InlineComment("空值Inline注释")
ConfiguredMap<String, String> EMPTY = ConfiguredMap.builderOf(String.class, String.class)
.asLinkedMap().fromString()
.build();
@HeaderComment({"", "[ID - UUID]对照表", "", "用于测试Map类型的解析与序列化保存"})
public static final ConfigValue<Map<Integer, UUID>> USERS = ConfiguredMap
.builder(Integer.class, UUID.class).fromString()
.parseKey(Integer::parseInt)
.parseValue(v -> Objects.requireNonNull(UUID.fromString(v)))
@ConfigPath("registered_users") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
@HeaderComments({"Section类型数据测试"}) // 通过注解给配置添加注释。
@InlineComment("默认地注释会加到Section的首行末尾") // 通过注解给配置添加注释。
ConfiguredList<UserRecord> ALLOWLISTS = ConfiguredList.builderOf(UserRecord.class).fromSection()
.parse(UserRecord::deserialize).serialize(UserRecord::serialize)
.defaults(UserRecord.CARM).build();
@HeaderComments({
"------------------------------------------------",
"[ID - ItemStack]对照表", "", "用于测试Map类型的解析与序列化保存"
})
@FooterComments("------------------------------------------------")
ConfiguredMap<Integer, ItemStack> ITEMS = ConfiguredMap.builderOf(Integer.class, ItemStack.class)
.asLinkedMap().fromSection()
.parseKey(data -> Integer.parseInt(data))
.parse(ItemStack::deserialize).serialize(ItemStack::serialize)
.defaults(m -> {
m.put(1, new ItemStack("stone", 64));
m.put(2, new ItemStack("iron", 64, "铁锭", Arrays.asList("一些铁锭", "可以制造东西")));
})
.build();
/**
* 支持内部类的直接注册。
* 注意,需要使用 {@link ConfigInitializer#initialize(Class, boolean, boolean)} 方法,并设定第三个参数为 true。
* 注意,需要用 {@link cc.carm.lib.configuration.source.option.StandardOptions#LOAD_SUB_CLASSES}
*/
public static class Sub extends ConfigurationRoot {
class SUB implements Configuration {
@ConfigPath(value = "uuid-value", root = true)
@InlineComment("This is an inline comment")
public static final ConfigValue<UUID> UUID_CONFIG_VALUE = ConfiguredValue
.builder(UUID.class).fromString()
.parseValue((data, defaultValue) -> UUID.fromString(data))
.builderOf(UUID.class).fromString()
.parse((holder, data) -> UUID.fromString(data))
.build();
public static class That extends ConfigurationRoot {
@HeaderComments({"内部类的内部类测试", "通过这种方式,您可以轻易实现多层次的配置文件结构"})
@FooterComments({"-------------"})
public interface That extends Configuration {
public static final ConfigValue<List<UUID>> OPERATORS = ConfiguredList
.builder(UUID.class).fromString()
.parseValue(s -> Objects.requireNonNull(UUID.fromString(s)))
ConfiguredList<UUID> OPERATORS = ConfiguredList
.builderOf(UUID.class).fromString()
.parse(s -> Objects.requireNonNull(UUID.fromString(s)))
.build();
}
@@ -0,0 +1,13 @@
package cc.carm.lib.configuration.demo.tests.conf;
import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.annotation.HeaderComments;
import cc.carm.lib.configuration.value.ConfigValue;
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
@HeaderComments("Inner Test")
public class InstanceConfig implements Configuration {
public final ConfigValue<Double> STATUS = ConfiguredValue.of(1.0D);
}
@@ -1,4 +0,0 @@
package cc.carm.lib.configuration.demo.tests.conf;
public class OtherConfiguration {
}
@@ -0,0 +1,29 @@
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.FooterComments;
import cc.carm.lib.configuration.annotation.HeaderComments;
import cc.carm.lib.configuration.annotation.InlineComment;
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 java.util.UUID;
public class RegistryConfig implements Configuration {
@HeaderComments("Support for configurations as instances")
public final InstanceConfig INSTANCE = new InstanceConfig();
@ConfigPath("test.user") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
@FooterComments({"12313213212"})
@InlineComment(value = "用户名(匹配注释)", regex = "name") // 通过注解给配置添加注释。
@InlineComment(value = "信息", regex = {"info.*", "info.game.*"}) // 通过注解给配置添加注释。
public final ConfigValue<UserRecord> OWNER = ConfiguredValue.builderOf(UserRecord.class).fromSection()
.defaults(new UserRecord("Carm", UUID.randomUUID()))
.parse((holder, section) -> UserRecord.deserialize(section))
.serialize((holder, data) -> data.serialize()).build();
}
@@ -1,30 +0,0 @@
package cc.carm.lib.configuration.demo.tests.conf;
import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.ConfigPath;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.annotation.InlineComment;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.type.ConfiguredSection;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
import cc.carm.lib.configuration.demo.tests.model.TestModel;
import java.util.UUID;
public class TestConfiguration extends ConfigurationRoot {
public final TestInnerConfiguration INNER = new TestInnerConfiguration();
public final ConfigValue<Double> CLASS_VALUE = ConfiguredValue.of(Double.class, 1.0D);
@ConfigPath("test.user") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
@HeaderComment({"", "Section类型数据测试"}) // 通过注解给配置添加注释。
@InlineComment("Section数据也支持InlineComment注释")
public final ConfigValue<TestModel> TEST_MODEL = ConfiguredSection
.builder(TestModel.class)
.defaults(new TestModel("Carm", UUID.randomUUID()))
.parseValue((section, defaultValue) -> TestModel.deserialize(section))
.serializeValue(TestModel::serialize).build();
}
@@ -1,13 +0,0 @@
package cc.carm.lib.configuration.demo.tests.conf;
import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
@HeaderComment("Inner Test")
public class TestInnerConfiguration extends ConfigurationRoot {
public final ConfigValue<Double> INNER_VALUE = ConfiguredValue.of(Double.class, 1.0D);
}
@@ -2,11 +2,11 @@ package cc.carm.lib.configuration.demo.tests.model;
import org.jetbrains.annotations.NotNull;
public abstract class AbstractModel {
public abstract class AbstractRecord {
protected final @NotNull String name;
public AbstractModel(@NotNull String name) {
public AbstractRecord(@NotNull String name) {
this.name = name;
}
@@ -0,0 +1,78 @@
package cc.carm.lib.configuration.demo.tests.model;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class ItemStack {
protected String material;
protected int amount;
protected @Nullable String name;
protected @Nullable List<String> lore;
public ItemStack(String material, int amount) {
this(material, amount, null, null);
}
public ItemStack(String material, int amount, @Nullable String name, @Nullable List<String> lore) {
this.material = material;
this.amount = amount;
this.name = name;
this.lore = lore;
}
public String getMaterial() {
return material;
}
public int getAmount() {
return amount;
}
public String getName() {
return name;
}
public List<String> getLore() {
return lore;
}
public void setMaterial(String material) {
this.material = material;
}
public void setAmount(int amount) {
this.amount = amount;
}
public void setName(String name) {
this.name = name;
}
public void setLore(List<String> lore) {
this.lore = lore;
}
public Map<String, Object> serialize() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("material", material);
if (amount != 1) map.put("amount", amount);
if (name != null) map.put("name", name);
if (lore != null) map.put("lore", lore);
return map;
}
public static ItemStack deserialize(ConfigureSection section) {
return new ItemStack(
section.getString("material"),
section.getInt("amount", 1),
section.getString("name"),
section.getStringList("lore")
);
}
}
@@ -1,26 +1,28 @@
package cc.carm.lib.configuration.demo.tests.model;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class TestModel extends AbstractModel {
public class UserRecord extends AbstractRecord {
public UUID uuid;
public static final UserRecord CARM = new UserRecord("Carm", UUID.fromString("f7b3b3b3-3b3b-3b3b-3b3b-3b3b3b3b3b3b"));
public TestModel(String name, UUID uuid) {
protected UUID uuid;
public UserRecord(String name, UUID uuid) {
super(name);
this.uuid = uuid;
}
public void setUuid(UUID uuid) {
public void uuid(UUID uuid) {
this.uuid = uuid;
}
public UUID getUuid() {
public UUID uuid() {
return uuid;
}
@@ -33,16 +35,17 @@ public class TestModel extends AbstractModel {
return map;
}
public static TestModel deserialize(ConfigurationWrapper<?> section) {
public static UserRecord deserialize(ConfigureSection section) {
System.out.println("> Deserializing -> " + section.fullPath());
String name = section.getString("name");
if (name == null) throw new NullPointerException("name is null");
String uuidString = section.getString("info.uuid");
if (uuidString == null) throw new NullPointerException("uuid is null");
return new TestModel(name, UUID.fromString(uuidString));
return new UserRecord(name, UUID.fromString(uuidString));
}
public static TestModel random() {
return new TestModel(UUID.randomUUID().toString().substring(0, 5), UUID.randomUUID());
public static UserRecord random() {
return new UserRecord(UUID.randomUUID().toString().substring(0, 5), UUID.randomUUID());
}
+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>easyconfiguration-parent</artifactId>
<version>4.0.11</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>easyconfiguration-feature-commentable</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>easyconfiguration-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,40 @@
package cc.carm.lib.configuration.annotation;
import org.jetbrains.annotations.NotNull;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Footer Comments.
* Add a comment to the bottom of the corresponding configuration for easy reading and viewing.
* <p>e.g.
* <blockquote><pre>
* foo: "bar"
* # The first line of the comment
* # The second line of the comment
* </pre></blockquote>
*/
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface FooterComments {
/**
* If the content of the note is 0, it will be treated as a blank line.
* <p> e.g. <b>{"foo","","bar"}</b>
* Will be set as
* <blockquote><pre>
* foo: "bar"
* # foo
*
* # bar
* </pre></blockquote>
*
* @return The content of this comment
*/
@NotNull
String[] value() default "";
}

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