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

Compare commits

...

376 Commits

Author SHA1 Message Date
dependabot[bot] 21f0ca8256 build(deps-dev): bump org.jetbrains.dokka:dokka-maven-plugin
Bumps [org.jetbrains.dokka:dokka-maven-plugin](https://github.com/Kotlin/dokka) from 2.1.0 to 2.2.0.
- [Release notes](https://github.com/Kotlin/dokka/releases)
- [Commits](https://github.com/Kotlin/dokka/compare/v2.1.0...v2.2.0)

---
updated-dependencies:
- dependency-name: org.jetbrains.dokka:dokka-maven-plugin
  dependency-version: 2.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-26 14:32:51 +00:00
carm f54ee83938 feat(holder): Add file type multi configuration. #169 2026-03-11 11:24:27 +08:00
carm f5316eb320 feat(holder): Add file type multi configuration. #169 2026-03-11 11:16:19 +08:00
carm 500eebefde feat(holder): Try to support MultiConfiguration. #169 2026-03-11 11:02:11 +08:00
renovate[bot] d9cb95b2e9 chore(deps): update actions/upload-artifact action to v7 2026-03-10 08:05:30 +08:00
renovate[bot] ce6554c3f1 chore(deps): update dependency org.apache.maven.plugins:maven-shade-plugin to v3.6.2 (#221)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-05 14:36:14 +00:00
renovate[bot] 7dcd690a05 fix(deps): update dependency org.yaml:snakeyaml to v2.6 (#219)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-27 01:25:07 +00:00
renovate[bot] f376f22ad0 fix(deps): update dependency com.typesafe:config to v1.4.6 (#218)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-24 19:45:53 +00:00
renovate[bot] ab586c4b00 fix(deps): update dependency org.mongodb:mongodb-driver-sync to v5.6.4 (#216)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-23 12:44:42 +00:00
renovate[bot] 64cbfaa974 chore(deps): update dependency org.apache.maven.plugins:maven-surefire-plugin to v3.5.5 (#215)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-21 17:50:54 +00:00
dependabot[bot] 3cab343919 build(deps): bump kotlin.version from 2.3.0 to 2.3.10
Bumps `kotlin.version` from 2.3.0 to 2.3.10.

Updates `org.jetbrains.kotlin:kotlin-stdlib-jdk8` from 2.3.0 to 2.3.10
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v2.3.0...v2.3.10)

Updates `org.jetbrains.kotlin:kotlin-maven-plugin` from 2.3.0 to 2.3.10

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-21 00:56:59 +08:00
renovate[bot] 1ad8c1f407 chore(deps): update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.15.0 (#207)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-19 00:58:38 +00:00
renovate[bot] 4e6db50049 fix(deps): update dependency org.mongodb:mongodb-driver-sync to v5.6.3 (#209)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-18 22:45:39 +00:00
renovate[bot] e62cef5644 fix(deps): update dependency org.jetbrains:annotations to v26.1.0 (#214)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-18 18:56:13 +00:00
dependabot[bot] d6a56003aa build(deps): bump org.sonatype.central:central-publishing-maven-plugin
Bumps [org.sonatype.central:central-publishing-maven-plugin](https://github.com/sonatype/central-publishing-maven-plugin) from 0.9.0 to 0.10.0.
- [Commits](https://github.com/sonatype/central-publishing-maven-plugin/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-31 02:46:18 +08:00
renovate[bot] 8a5870300d chore(deps): update actions/upload-artifact action to v6 2025-12-29 08:50:26 +08:00
dependabot[bot] 42885b2a12 build(deps): bump kotlin.version from 2.2.21 to 2.3.0
Bumps `kotlin.version` from 2.2.21 to 2.3.0.

Updates `org.jetbrains.kotlin:kotlin-stdlib-jdk8` from 2.2.21 to 2.3.0
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/v2.3.0/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v2.2.21...v2.3.0)

Updates `org.jetbrains.kotlin:kotlin-maven-plugin` from 2.2.21 to 2.3.0

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-29 08:50:04 +08:00
renovate[bot] 96216d5126 chore(deps): update log4j2 monorepo to v2.25.3 (#204)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-16 21:58:48 +00:00
renovate[bot] d890ce1b94 chore(deps): update dependency org.apache.maven.plugins:maven-release-plugin to v3.3.1 (#201)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-13 14:29:02 +00:00
renovate[bot] d1ff4f7014 fix(deps): update dependency org.mongodb:mongodb-driver-sync to v5.6.2 (#199)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-08 21:33:41 +00:00
renovate[bot] 9f3089566c chore(deps): update dependency org.apache.maven.plugins:maven-release-plugin to v3.3.0 (#198)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-03 20:54:54 +00:00
renovate[bot] 79105bf400 chore(deps): update actions/checkout action to v6 2025-12-01 09:31:45 +08:00
renovate[bot] 2b0b74af92 chore(deps): update dependency org.apache.maven.plugins:maven-source-plugin to v3.4.0 (#197)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-29 05:37:12 +00:00
renovate[bot] c65d164167 chore(deps): update dependency org.apache.maven.plugins:maven-jar-plugin to v3.5.0 (#195)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-15 17:30:30 +00:00
renovate[bot] 74bde0c7ea chore(deps): update dependency org.apache.maven.plugins:maven-release-plugin to v3.2.0 (#194)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-09 00:57:07 +00:00
carm 7fba61cb64 docs: Use english version issues templates. 2025-11-06 03:07:02 +08:00
renovate[bot] b609e1d174 chore(deps): update actions/upload-artifact action to v5 2025-10-30 10:54:38 +08:00
renovate[bot] bdbd484690 fix(deps): update kotlin monorepo to v2.2.21 (#191)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-23 14:08:33 +00:00
renovate[bot] cc5383b0f2 chore(deps): update github/codeql-action action to v4 2025-10-23 10:37:05 +08:00
renovate[bot] 35d2653f56 chore(deps): update dependency org.jetbrains.dokka:dokka-maven-plugin to v2.1.0 (#190)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-15 18:54:14 +00:00
carm d6fa7710dc fix: Try to ignore errors when applying replacer 2025-10-09 02:58:21 +08:00
renovate[bot] fdb6d81bf0 fix(deps): update dependency org.mongodb:mongodb-driver-sync to v5.6.1 (#186)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-06 14:26:30 +00:00
huanmeng-qwq 6a03d446a3 fix: https://github.com/CarmJos/configured/pull/185#pullrequestreview-3273500562 2025-09-27 15:56:09 +08:00
huanmeng-qwq 4a0e6b0676 refactor deserialize, add set collection dsl 2025-09-27 15:56:09 +08:00
carm fc4a11bc3e docs: Add more wiki files. 2025-09-27 02:29:58 +08:00
carm e95abd6b37 docs: Add more wiki files. 2025-09-27 02:27:29 +08:00
carm 0b4304474e docs: Add more wiki files. 2025-09-27 02:20:07 +08:00
carm f36fb81249 feat: Add "getOr" function for values. 2025-09-27 02:19:48 +08:00
carm b17c157e18 refactor(collection): Refactor builders of collection types (including List and Set). 2025-09-27 02:09:42 +08:00
carm c86985017f refactor(builder): Refactor builder functions to support custom adapters. 2025-09-27 00:55:38 +08:00
renovate[bot] cb7562cd8c chore(deps): update dependency org.sonatype.central:central-publishing-maven-plugin to v0.9.0 2025-09-24 09:19:25 +08:00
renovate[bot] ae6aaa0461 chore(deps): update log4j2 monorepo to v2.25.2 (#183)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-22 12:25:53 +00:00
renovate[bot] c96a6c7e49 chore(deps): update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.14.1 (#182)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-22 09:14:52 +00:00
renovate[bot] 74b5e80cbc chore(deps): update dependency org.apache.maven.plugins:maven-javadoc-plugin to v3.12.0 (#181)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-21 08:55:00 +00:00
renovate[bot] 51c5c333e9 chore(deps): update dependency org.apache.maven.plugins:maven-surefire-plugin to v3.5.4 (#180)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-14 02:59:18 +00:00
renovate[bot] f09ed5bbc5 chore(deps): update dependency org.apache.maven.plugins:maven-shade-plugin to v3.6.1 (#179)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-13 23:59:11 +00:00
dependabot[bot] f0abdd87e3 build(deps): bump com.typesafe:config from 1.4.4 to 1.4.5
Bumps [com.typesafe:config](https://github.com/lightbend/config) from 1.4.4 to 1.4.5.
- [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.4...v1.4.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-12 08:52:17 +08:00
renovate[bot] 7f091669c7 fix(deps): update dependency org.mongodb:mongodb-driver-sync to v5.6.0 2025-09-12 08:52:10 +08:00
carm 8dbee35757 ci: Update renovate.json 2025-09-12 08:19:16 +08:00
dependabot[bot] 1a2eaff1e6 build(deps): bump kotlin.version from 2.2.10 to 2.2.20
Bumps `kotlin.version` from 2.2.10 to 2.2.20.

Updates `org.jetbrains.kotlin:kotlin-stdlib-jdk8` from 2.2.10 to 2.2.20
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v2.2.10...v2.2.20)

Updates `org.jetbrains.kotlin:kotlin-maven-plugin` from 2.2.10 to 2.2.20

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-11 10:52:07 +08:00
renovate[bot] 36364bc09b fix(deps): update dependency com.google.code.gson:gson to v2.13.2 2025-09-11 10:51:58 +08:00
carm fcb4ced610 feat: Make function interface "serializable" 2025-09-10 08:22:37 +08:00
carm 5df66e59d2 docs: Add Community Standards pages 2025-09-02 18:03:42 +08:00
carm 809cd5b268 docs: Add Community Standards pages 2025-09-02 18:00:38 +08:00
carm 661527a80f docs: Add more pages 2025-09-02 17:40:59 +08:00
carm 9883e75f05 docs: Add more pages 2025-09-02 17:09:40 +08:00
carm c3297d168f docs: Add donation link. 2025-09-02 16:56:46 +08:00
renovate[bot] 627e0ba391 fix(deps): update dependency org.yaml:snakeyaml to v2.5 2025-09-02 16:44:23 +08:00
renovate[bot] b29935ae47 fix(deps): update dependency org.jetbrains:annotations to v26.0.2-1 2025-09-02 16:44:15 +08:00
carm e1a907203e docs: Add wiki module. 2025-09-02 16:43:20 +08:00
carm 3cd1ddb3ad docs: Add wiki module. 2025-09-02 16:42:36 +08:00
renovate[bot] b46e116712 chore(deps): update actions/setup-java action to v5 2025-08-21 23:41:56 +08:00
dependabot[bot] 44194d6055 build(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.11.2 to 3.11.3.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.11.2...maven-javadoc-plugin-3.11.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-21 23:15:49 +08:00
renovate[bot] 47fd058f44 chore(deps): update actions/checkout action to v5 2025-08-15 19:29:18 +08:00
renovate[bot] c73fcafb15 fix(deps): update kotlin monorepo to v2.2.10 2025-08-15 19:28:11 +08:00
carm beb6d93f7b build: Fixed wrong scm connection. 2025-07-28 15:50:46 +08:00
dependabot[bot] d62aa14ca7 build(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.7 to 3.2.8.
- [Release notes](https://github.com/apache/maven-gpg-plugin/releases)
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.7...maven-gpg-plugin-3.2.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-21 03:32:51 +08:00
dependabot[bot] a439ca5cde build(deps): bump com.typesafe:config from 1.4.3 to 1.4.4
Bumps [com.typesafe:config](https://github.com/lightbend/config) from 1.4.3 to 1.4.4.
- [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.3...v1.4.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-21 03:32:45 +08:00
renovate[bot] 0736153fd6 chore(deps): update log4j2 monorepo to v2.25.1 2025-07-21 03:32:27 +08:00
carm 0bce5f1a22 build: Add project module names 2025-07-21 02:31:27 +08:00
carm feb43bb382 fix(list): Fixed error when getting the section list 2025-07-09 15:41:31 +08:00
carm 0bfd15aaad feat(record): Support record type values adapter. 2025-07-02 11:04:27 +08:00
carm 15f395a8e0 test(record): Add testcase for nullable values. 2025-06-26 03:04:21 +08:00
carm a61040a0e2 ci(jdk): Using JDK 21. 2025-06-26 02:28:32 +08:00
carm 8766b4d77b feat(adapter): Support complex ParameterizedType's serialize & deserialize. 2025-06-26 02:24:42 +08:00
carm 8c1214612a feat(adapter): Support complex ParameterizedType's serialize & deserialize. 2025-06-25 09:31:07 +08:00
carm 608d92f834 feat(record): Support record type values adapter. 2025-06-25 07:10:26 +08:00
carm ad6ab9eb36 feat(temp): Add a "temporary source" for Testing/FastDev cases. (Use default config in codes first.) 2025-06-25 07:10:04 +08:00
dependabot[bot] 0eda8d8a0f build(deps-dev): bump log4j.version from 2.24.3 to 2.25.0
Bumps `log4j.version` from 2.24.3 to 2.25.0.

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

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

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

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

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

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-25 06:29:28 +08:00
renovate[bot] c7331aa556 fix(deps): update kotlin monorepo to v2.2.0 2025-06-25 06:29:18 +08:00
carm a440c050e5 feat(type): Add ofMap(K,V) method for ValueType 2025-06-23 15:27:52 +08:00
renovate[bot] b9d45a9bb9 fix(deps): update dependency org.mongodb:mongodb-driver-sync to v5.5.1 2025-06-10 22:45:19 +08:00
carm 67482de7a9 docs: drop visitors counter 2025-05-14 04:25:23 +08:00
carm 04bedbef07 style: Reformatted code with .editorconfig 2025-05-14 04:24:56 +08:00
carm a4abfb733a style: Reformatted code with .editorconfig 2025-05-14 04:22:48 +08:00
carm 76d276436b ci(deploy): Skip deployment for demo project. 2025-05-14 03:55:54 +08:00
carm e7198f22d5 ci(deploy): Skip deployment for demo project. 2025-05-14 03:48:54 +08:00
carm 5bd20e173f ci(deploy): Skip deployment for demo project. 2025-05-14 03:41:15 +08:00
carm 15c4bb13e8 build(repo): Use official repositories. 2025-05-14 03:33:45 +08:00
dependabot[bot] b74eb5c035 build(deps): bump com.google.code.gson:gson from 2.13.0 to 2.13.1
Bumps [com.google.code.gson:gson](https://github.com/google/gson) from 2.13.0 to 2.13.1.
- [Release notes](https://github.com/google/gson/releases)
- [Changelog](https://github.com/google/gson/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google/gson/compare/gson-parent-2.13.0...gson-parent-2.13.1)

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

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

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

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

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

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

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

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

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

link #132
2025-03-16 23:56:36 +08:00
carm 854e3df49f feat: Upgrade configured to v4.1.0 2025-03-15 01:52:52 +08:00
carm f6167c3b5e docs: Update license [skip ci] 2025-03-15 01:51:07 +08:00
carm ffe3e88b3b docs: Translated to English 2025-03-14 19:34:06 +08:00
carm caa3077f48 chore: Add missing @Nullable 2025-03-14 19:33:30 +08:00
carm 05dbf0b504 docs: Redesign readme 2025-03-14 19:20:31 +08:00
carm 810e95198e docs: Redesign readme 2025-03-14 19:17:26 +08:00
carm 10004f16b4 docs(logo): Add project banner & logo 2025-03-14 19:09:43 +08:00
carm 8e19748c7c feat(map): Add more builder functions 2025-03-12 04:04:00 +08:00
carm 17762a2e70 refactor(proj): Change project name to "configured" 2025-03-12 03:27:35 +08:00
carm 7dbd607a3f refactor(proj): Change project name to "configured" 2025-03-12 03:22:40 +08:00
carm 035e8a227e test(parse): Add more tests 2025-03-06 20:12:33 +08:00
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
245 changed files with 14849 additions and 3934 deletions
+6
View File
@@ -0,0 +1,6 @@
# configured Javadoc
Based
on [Github Pages](https://pages.github.com/),
please
see [JavaDoc](https://carmjos.github.io/configured) 。
+3
View File
@@ -0,0 +1,3 @@
# Documentation
See [wiki](https://github.com/CarmJos/configured/wiki).
Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

-9
View File
@@ -1,9 +0,0 @@
# EasyConfiguration Javadoc
基于 [Github Pages](https://pages.github.com/) 搭建,请访问 [JavaDoc](https://carmjos.github.io/EasyConfiguration) 。
## 如何实现?
若您也想通过 [Github Actions](https://docs.github.com/en/actions/learn-github-actions)
自动部署项目的Javadoc到 [Github Pages](https://pages.github.com/)
可以参考我的文章 [《自动部署Javadoc到Github Pages》](https://pages.carm.cc/doc/javadoc-in-github.html) 。
-3
View File
@@ -1,3 +0,0 @@
# 欢迎使用 EasyConfiguration
这个项目刚刚创建,详细的Javadoc与开发指南还在补充,请给我一点时间~
+346
View File
@@ -0,0 +1,346 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
tab_width = 4
[*.java]
indent_size = 4
max_line_length = 120
ij_java_align_consecutive_assignments = false
ij_java_align_consecutive_variable_declarations = false
ij_java_align_group_field_declarations = false
ij_java_align_multiline_annotation_parameters = false
ij_java_align_multiline_array_initializer_expression = false
ij_java_align_multiline_assignment = false
ij_java_align_multiline_binary_operation = false
ij_java_align_multiline_chained_methods = false
ij_java_align_multiline_deconstruction_list_components = true
ij_java_align_multiline_extends_list = false
ij_java_align_multiline_for = true
ij_java_align_multiline_method_parentheses = false
ij_java_align_multiline_parameters = true
ij_java_align_multiline_parameters_in_calls = false
ij_java_align_multiline_parenthesized_expression = false
ij_java_align_multiline_records = true
ij_java_align_multiline_resources = true
ij_java_align_multiline_ternary_operation = false
ij_java_align_multiline_text_blocks = false
ij_java_align_multiline_throws_list = false
ij_java_align_subsequent_simple_methods = false
ij_java_align_throws_keyword = false
ij_java_align_types_in_multi_catch = true
ij_java_annotation_new_line_in_record_component = false
ij_java_annotation_parameter_wrap = off
ij_java_array_initializer_new_line_after_left_brace = false
ij_java_array_initializer_right_brace_on_new_line = false
ij_java_array_initializer_wrap = off
ij_java_assert_statement_colon_on_next_line = false
ij_java_assert_statement_wrap = off
ij_java_assignment_wrap = off
ij_java_binary_operation_sign_on_next_line = false
ij_java_binary_operation_wrap = off
ij_java_blank_lines_after_anonymous_class_header = 0
ij_java_blank_lines_after_class_header = 0
ij_java_blank_lines_after_imports = 1
ij_java_blank_lines_after_package = 1
ij_java_blank_lines_around_class = 1
ij_java_blank_lines_around_field = 0
ij_java_blank_lines_around_field_in_interface = 0
ij_java_blank_lines_around_field_with_annotations = 0
ij_java_blank_lines_around_initializer = 1
ij_java_blank_lines_around_method = 1
ij_java_blank_lines_around_method_in_interface = 1
ij_java_blank_lines_before_class_end = 0
ij_java_blank_lines_before_imports = 1
ij_java_blank_lines_before_method_body = 0
ij_java_blank_lines_before_package = 0
ij_java_blank_lines_between_record_components = 0
ij_java_block_brace_style = end_of_line
ij_java_block_comment_add_space = false
ij_java_block_comment_at_first_column = true
ij_java_builder_methods =
ij_java_call_parameters_new_line_after_left_paren = false
ij_java_call_parameters_right_paren_on_new_line = false
ij_java_call_parameters_wrap = off
ij_java_case_statement_on_separate_line = true
ij_java_catch_on_new_line = false
ij_java_class_annotation_wrap = split_into_lines
ij_java_class_brace_style = end_of_line
ij_java_class_count_to_use_import_on_demand = 5
ij_java_class_names_in_javadoc = 1
ij_java_deconstruction_list_wrap = normal
ij_java_do_not_indent_top_level_class_members = false
ij_java_do_not_wrap_after_single_annotation = false
ij_java_do_not_wrap_after_single_annotation_in_parameter = false
ij_java_do_while_brace_force = never
ij_java_doc_add_blank_line_after_description = true
ij_java_doc_add_blank_line_after_param_comments = false
ij_java_doc_add_blank_line_after_return = false
ij_java_doc_add_p_tag_on_empty_lines = true
ij_java_doc_align_exception_comments = true
ij_java_doc_align_param_comments = true
ij_java_doc_do_not_wrap_if_one_line = false
ij_java_doc_enable_formatting = true
ij_java_doc_enable_leading_asterisks = true
ij_java_doc_indent_on_continuation = false
ij_java_doc_keep_empty_lines = true
ij_java_doc_keep_empty_parameter_tag = true
ij_java_doc_keep_empty_return_tag = true
ij_java_doc_keep_empty_throws_tag = true
ij_java_doc_keep_invalid_tags = true
ij_java_doc_param_description_on_new_line = false
ij_java_doc_preserve_line_breaks = false
ij_java_doc_use_throws_not_exception_tag = true
ij_java_else_on_new_line = false
ij_java_entity_dd_prefix =
ij_java_entity_dd_suffix = EJB
ij_java_entity_eb_prefix =
ij_java_entity_eb_suffix = Bean
ij_java_entity_hi_prefix =
ij_java_entity_hi_suffix = Home
ij_java_entity_lhi_prefix = Local
ij_java_entity_lhi_suffix = Home
ij_java_entity_li_prefix = Local
ij_java_entity_li_suffix =
ij_java_entity_pk_class = java.lang.String
ij_java_entity_ri_prefix =
ij_java_entity_ri_suffix =
ij_java_entity_vo_prefix =
ij_java_entity_vo_suffix = VO
ij_java_enum_constants_wrap = off
ij_java_enum_field_annotation_wrap = off
ij_java_extends_keyword_wrap = off
ij_java_extends_list_wrap = off
ij_java_field_annotation_wrap = split_into_lines
ij_java_field_name_prefix =
ij_java_field_name_suffix =
ij_java_filter_class_prefix =
ij_java_filter_class_suffix =
ij_java_filter_dd_prefix =
ij_java_filter_dd_suffix =
ij_java_finally_on_new_line = false
ij_java_for_brace_force = never
ij_java_for_statement_new_line_after_left_paren = false
ij_java_for_statement_right_paren_on_new_line = false
ij_java_for_statement_wrap = off
ij_java_generate_final_locals = false
ij_java_generate_final_parameters = false
ij_java_generate_use_type_annotation_before_type = true
ij_java_if_brace_force = never
ij_java_imports_layout = @*, *, |, javax.**, java.**, |, $*
ij_java_indent_case_from_switch = true
ij_java_insert_inner_class_imports = false
ij_java_insert_override_annotation = true
ij_java_keep_blank_lines_before_right_brace = 2
ij_java_keep_blank_lines_between_package_declaration_and_header = 2
ij_java_keep_blank_lines_in_code = 2
ij_java_keep_blank_lines_in_declarations = 2
ij_java_keep_builder_methods_indents = false
ij_java_keep_control_statement_in_one_line = true
ij_java_keep_first_column_comment = true
ij_java_keep_indents_on_empty_lines = false
ij_java_keep_line_breaks = true
ij_java_keep_multiple_expressions_in_one_line = false
ij_java_keep_simple_blocks_in_one_line = false
ij_java_keep_simple_classes_in_one_line = false
ij_java_keep_simple_lambdas_in_one_line = false
ij_java_keep_simple_methods_in_one_line = false
ij_java_label_indent_absolute = false
ij_java_label_indent_size = 0
ij_java_lambda_brace_style = end_of_line
ij_java_layout_on_demand_import_from_same_package_first = true
ij_java_layout_static_imports_separately = true
ij_java_line_comment_add_space = false
ij_java_line_comment_add_space_on_reformat = false
ij_java_line_comment_at_first_column = true
ij_java_listener_class_prefix =
ij_java_listener_class_suffix =
ij_java_local_variable_name_prefix =
ij_java_local_variable_name_suffix =
ij_java_message_dd_prefix =
ij_java_message_dd_suffix = EJB
ij_java_message_eb_prefix =
ij_java_message_eb_suffix = Bean
ij_java_method_annotation_wrap = split_into_lines
ij_java_method_brace_style = end_of_line
ij_java_method_call_chain_wrap = off
ij_java_method_parameters_new_line_after_left_paren = false
ij_java_method_parameters_right_paren_on_new_line = false
ij_java_method_parameters_wrap = off
ij_java_modifier_list_wrap = false
ij_java_multi_catch_types_wrap = normal
ij_java_names_count_to_use_import_on_demand = 3
ij_java_new_line_after_lparen_in_annotation = false
ij_java_new_line_after_lparen_in_deconstruction_pattern = true
ij_java_new_line_after_lparen_in_record_header = false
ij_java_new_line_when_body_is_presented = false
ij_java_packages_to_use_import_on_demand = java.awt.*, javax.swing.*
ij_java_parameter_annotation_wrap = off
ij_java_parameter_name_prefix =
ij_java_parameter_name_suffix =
ij_java_parentheses_expression_new_line_after_left_paren = false
ij_java_parentheses_expression_right_paren_on_new_line = false
ij_java_place_assignment_sign_on_next_line = false
ij_java_prefer_longer_names = true
ij_java_prefer_parameters_wrap = false
ij_java_preserve_module_imports = true
ij_java_record_components_wrap = normal
ij_java_repeat_annotations =
ij_java_repeat_synchronized = true
ij_java_replace_instanceof_and_cast = false
ij_java_replace_null_check = true
ij_java_replace_sum_lambda_with_method_ref = true
ij_java_resource_list_new_line_after_left_paren = false
ij_java_resource_list_right_paren_on_new_line = false
ij_java_resource_list_wrap = off
ij_java_rparen_on_new_line_in_annotation = false
ij_java_rparen_on_new_line_in_deconstruction_pattern = true
ij_java_rparen_on_new_line_in_record_header = false
ij_java_servlet_class_prefix =
ij_java_servlet_class_suffix =
ij_java_servlet_dd_prefix =
ij_java_servlet_dd_suffix =
ij_java_session_dd_prefix =
ij_java_session_dd_suffix = EJB
ij_java_session_eb_prefix =
ij_java_session_eb_suffix = Bean
ij_java_session_hi_prefix =
ij_java_session_hi_suffix = Home
ij_java_session_lhi_prefix = Local
ij_java_session_lhi_suffix = Home
ij_java_session_li_prefix = Local
ij_java_session_li_suffix =
ij_java_session_ri_prefix =
ij_java_session_ri_suffix =
ij_java_session_si_prefix =
ij_java_session_si_suffix = Service
ij_java_space_after_closing_angle_bracket_in_type_argument = false
ij_java_space_after_colon = true
ij_java_space_after_comma = true
ij_java_space_after_comma_in_type_arguments = true
ij_java_space_after_for_semicolon = true
ij_java_space_after_quest = true
ij_java_space_after_type_cast = true
ij_java_space_before_annotation_array_initializer_left_brace = false
ij_java_space_before_annotation_parameter_list = false
ij_java_space_before_array_initializer_left_brace = false
ij_java_space_before_catch_keyword = true
ij_java_space_before_catch_left_brace = true
ij_java_space_before_catch_parentheses = true
ij_java_space_before_class_left_brace = true
ij_java_space_before_colon = true
ij_java_space_before_colon_in_foreach = true
ij_java_space_before_comma = false
ij_java_space_before_deconstruction_list = false
ij_java_space_before_do_left_brace = true
ij_java_space_before_else_keyword = true
ij_java_space_before_else_left_brace = true
ij_java_space_before_finally_keyword = true
ij_java_space_before_finally_left_brace = true
ij_java_space_before_for_left_brace = true
ij_java_space_before_for_parentheses = true
ij_java_space_before_for_semicolon = false
ij_java_space_before_if_left_brace = true
ij_java_space_before_if_parentheses = true
ij_java_space_before_method_call_parentheses = false
ij_java_space_before_method_left_brace = true
ij_java_space_before_method_parentheses = false
ij_java_space_before_opening_angle_bracket_in_type_parameter = false
ij_java_space_before_quest = true
ij_java_space_before_switch_left_brace = true
ij_java_space_before_switch_parentheses = true
ij_java_space_before_synchronized_left_brace = true
ij_java_space_before_synchronized_parentheses = true
ij_java_space_before_try_left_brace = true
ij_java_space_before_try_parentheses = true
ij_java_space_before_type_parameter_list = false
ij_java_space_before_while_keyword = true
ij_java_space_before_while_left_brace = true
ij_java_space_before_while_parentheses = true
ij_java_space_inside_one_line_enum_braces = false
ij_java_space_within_empty_array_initializer_braces = false
ij_java_space_within_empty_method_call_parentheses = false
ij_java_space_within_empty_method_parentheses = false
ij_java_spaces_around_additive_operators = true
ij_java_spaces_around_annotation_eq = true
ij_java_spaces_around_assignment_operators = true
ij_java_spaces_around_bitwise_operators = true
ij_java_spaces_around_equality_operators = true
ij_java_spaces_around_lambda_arrow = true
ij_java_spaces_around_logical_operators = true
ij_java_spaces_around_method_ref_dbl_colon = false
ij_java_spaces_around_multiplicative_operators = true
ij_java_spaces_around_relational_operators = true
ij_java_spaces_around_shift_operators = true
ij_java_spaces_around_type_bounds_in_type_parameters = true
ij_java_spaces_around_unary_operator = false
ij_java_spaces_inside_block_braces_when_body_is_present = false
ij_java_spaces_within_angle_brackets = false
ij_java_spaces_within_annotation_parentheses = false
ij_java_spaces_within_array_initializer_braces = false
ij_java_spaces_within_braces = false
ij_java_spaces_within_brackets = false
ij_java_spaces_within_cast_parentheses = false
ij_java_spaces_within_catch_parentheses = false
ij_java_spaces_within_deconstruction_list = false
ij_java_spaces_within_for_parentheses = false
ij_java_spaces_within_if_parentheses = false
ij_java_spaces_within_method_call_parentheses = false
ij_java_spaces_within_method_parentheses = false
ij_java_spaces_within_parentheses = false
ij_java_spaces_within_record_header = false
ij_java_spaces_within_switch_parentheses = false
ij_java_spaces_within_synchronized_parentheses = false
ij_java_spaces_within_try_parentheses = false
ij_java_spaces_within_while_parentheses = false
ij_java_special_else_if_treatment = true
ij_java_static_field_name_prefix =
ij_java_static_field_name_suffix =
ij_java_subclass_name_prefix =
ij_java_subclass_name_suffix = Impl
ij_java_switch_expressions_wrap = normal
ij_java_ternary_operation_signs_on_next_line = false
ij_java_ternary_operation_wrap = off
ij_java_test_name_prefix =
ij_java_test_name_suffix = Test
ij_java_throws_keyword_wrap = off
ij_java_throws_list_wrap = off
ij_java_use_external_annotations = false
ij_java_use_fq_class_names = false
ij_java_use_relative_indents = false
ij_java_use_single_class_imports = true
ij_java_variable_annotation_wrap = off
ij_java_visibility = public
ij_java_while_brace_force = never
ij_java_while_on_new_line = false
ij_java_wrap_comments = false
ij_java_wrap_first_method_in_call_chain = false
ij_java_wrap_long_lines = false
ij_java_wrap_semicolon_after_call_chain = false
[*.xml]
indent_style = space
indent_size = 4
tab_width = 4
max_line_length = 120
[*.json]
indent_style = space
indent_size = 2
tab_width = 2
max_line_length = 120
[*.{yml,yaml}]
indent_style = space
indent_size = 2
tab_width = 2
max_line_length = 120
[*.md]
max_line_length = 500
trim_trailing_whitespace = false
-1
View File
@@ -1,2 +1 @@
github: [ CarmJos ]
custom: [ 'https://donate.carm.cc' ]
+19 -22
View File
@@ -1,37 +1,34 @@
---
name: 问题提交
about: 描述问题并提交,帮助我们对其进行检查与修复。
title: ''
name: Submit bugs&issues
about: Describe the problem and submit it to help us review and fix it.
title: 'fix: '
labels: bug
assignees: ''
---
### **问题简述**
### **Description**
用简短的话语描述一下大概问题。
<!-- Describe the general problem in short words.-->
### **问题来源**
### **Operations**
描述一下通过哪些操作才发现的问题,如:
<!--
Describe the problem discovered through what operations, such as:
1. 使用了 '...'
2. 输入了 '....'
3. 出现了报错 '....'
1. Clicked '...'
2. Typed '....'
3. Error says '....'
-->
### **预期结果** (可选)
### **Expected result** _(Optional)_
如果问题不发生,应该是什么情况
### **Screenshots & Error Logs**
### **问题截图/问题报错**
### **Environment**
如果有报错或输出,请提供截图。
- System: `Windows 10` / `Ubuntu` / `...`
- Java version: `JDK11` / `OPENJDK8` / `JRE8` / `...`
### **操作环境**
### **Anything else...**
- 系统环境: `Windows 10` / `Ubuntu` / `...`
- Java版本: `JDK11` / `OPENJDK8` / `JRE8` / `...`
### **其他补充**
如有其他补充,可以在这里描述。
<!-- If there are other supplements, they can be described here. -->
+11 -11
View File
@@ -1,23 +1,23 @@
---
name: 功能需求
about: 希望我们提供更多的功能。
title: ''
name: Features
about: Ask for new features.
title: 'feat: '
labels: enhancement
assignees: ''
---
### **功能简述**
### **Description**
简单的描述一下你想要的功能
<!-- Describe the features in short words.-->
### **需求来源**
### **Source**
简单的描述一下为什么需要这个功能。
<!-- Describe the reason that you need this feature in short words.-->
### **功能参考**(可选)
### **Examples** _(Optional)_
如果有相关功能的参考,如文本、截图,请提供给我们。
<!--Any screenshots or example codes please.-->
### **附加内容**
### **Additional details**
如果有什么小细节需要重点注意,请在这里告诉我们。
<!--If there are any small details that need to be highlighted, please let us know here.-->
-54
View File
@@ -1,54 +0,0 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow checks out code, performs a Codacy security scan
# and integrates the results with the
# GitHub Advanced Security code scanning feature. For more information on
# the Codacy security scan action usage and parameters, see
# https://github.com/codacy/codacy-analysis-cli-action.
# For more information on Codacy Analysis CLI in general, see
# https://github.com/codacy/codacy-analysis-cli.
name: "Codacy Security Scan"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '27 16 * * 5'
jobs:
codacy-security-scan:
name: Codacy Security Scan
runs-on: ubuntu-latest
steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout code
uses: actions/checkout@v2
# 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
with:
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
# You can also omit the token and run the tools that support default configurations
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
verbose: true
output: results.sarif
format: sarif
# Adjust severity of non-security issues
gh-code-scanning-compat: true
# Force 0 exit code to allow SARIF file generation
# This will handover control about PR rejection to the GitHub side
max-allowed-issues: 2147483647
# Upload the SARIF file generated in the previous step
- name: Upload SARIF results file
uses: github/codeql-action/upload-sarif@v1
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@v6
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v4
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@v4
# ️ 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@v4
+12 -12
View File
@@ -16,11 +16,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v6
- name: "Set up JDK"
uses: actions/setup-java@v2
uses: actions/setup-java@v5
with:
java-version: '11'
java-version: '21'
distribution: 'adopt'
cache: maven
server-id: github
@@ -40,14 +40,14 @@ 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
uses: cicirello/generate-sitemap@v1
with:
base-url-path: https://CarmJos.github.io/EasyConfiguration
base-url-path: https://CarmJos.github.io/configured
path-to-root: docs
- name: "Output stats"
@@ -72,7 +72,7 @@ jobs:
run: |
cd docs
git init
git remote add origin git@github.com:CarmJos/EasyConfiguration.git
git remote add origin git@github.com:CarmJos/configured.git
git checkout -b gh-pages
git add -A
git commit -m "API Document generated."
@@ -87,21 +87,21 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v6
- name: "Set up JDK"
uses: actions/setup-java@v2
uses: actions/setup-java@v5
with:
java-version: '11'
java-version: '21'
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 }}
+4 -4
View File
@@ -15,18 +15,18 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v6
- name: "Set up JDK"
uses: actions/setup-java@v2
uses: actions/setup-java@v5
with:
java-version: '11'
java-version: '21'
distribution: 'adopt'
- name: "Package"
run: mvn -B package --file pom.xml -Dgpg.skip
- name: "Target Stage"
run: mkdir staging && cp */target/*.jar staging
- name: "Upload artifact"
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v7
with:
name: Artifact
path: staging
+2 -1
View File
@@ -1,3 +1,4 @@
/.idea/
.idea/*
!.idea/icon.svg
**/target/
**.iml
+3
View File
@@ -0,0 +1,3 @@
[submodule ".wiki"]
path = .wiki
url = https://github.com/CarmJos/configured.wiki.git
+36
View File
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

Submodule
+1
Submodule .wiki added at c79c6f4a43
+75
View File
@@ -0,0 +1,75 @@
# Code of Conduct
(English primary version a brief Chinese note may follow. 中文提示:本文件英文为主,若理解存在困难可联系维护者。)
This project adopts the principles of the Contributor Covenant v2.1 (https://www.contributor-covenant.org/version/2/1/code_of_conduct/) with projectspecific clarifications below. By participating you agree to uphold this Code.
## Our Pledge
We strive to provide a harassmentfree, inclusive, friendly, and productive environment for everyone, regardless of age, body, disability, ethnicity, sex characteristics, gender identity or expression, level of experience, education, socioeconomic status, nationality, personal appearance, race, caste, religion (or lack thereof), sexual identity or orientation, or technical choices.
## Our Standards
Examples of behavior that contributes to a positive environment:
- Showing empathy and respect to all participants
- Giving and gracefully accepting constructive feedback
- Focusing on what is best for the project and community
- Being honest about mistakes and seeking improvement
- Using welcoming and inclusive language
Examples of unacceptable behavior include:
- Harassment, discrimination, or derogatory comments
- Trolling, insulting or antagonistic remarks, personal or political attacks
- Public or private harassment or sustained disruption of activities
- Publishing others private information without explicit permission
- Sexualized language, imagery, or unwelcome advances
- Any other conduct reasonably deemed inappropriate or unsafe
## Scope
This Code applies within all project spaces (repository code, issues, pull requests, discussions, wiki, CI logs) and in public spaces whenever an individual is representing the project or community.
## Responsibilities & Enforcement
Project maintainers ("maintainers") are responsible for clarifying standards and taking appropriate, fair, and consistent corrective action.
Maintainers may remove or edit contributions that violate this Code (comments, commits, code, wiki edits, issues, discussions) and may temporarily or permanently ban any contributor for abusive, harassing, or otherwise harmful behavior.
## Reporting
Report violations privately via:
- Email: carm@carm.cc
Please include (if possible):
- Links, timestamps, or message IDs
- Description of what happened and why it is a concern
- Screenshots or logs (if relevant)
- Preferred or suggested resolution
We aim to acknowledge reports within 72 hours and provide an initial assessment within 7 days. All goodfaith reports will be treated confidentially and only shared with individuals who need the information to resolve the issue.
## Enforcement Guidelines
Maintainers will use these guidelines to determine the impact of an incident and consequences:
1. Correction
- Impact: Use of inappropriate language or other unprofessional conduct.
- Consequence: Private or public warning, request for change.
2. Warning
- Impact: A single severe incident or repeated inappropriate behavior.
- Consequence: Official warning; continued misconduct leads to escalation.
3. Temporary Suspension
- Impact: Persistent violations despite previous warnings.
- Consequence: Temporary participation suspension (issues/PRs/discussions). Conditions for reinstatement communicated.
4. Permanent Ban
- Impact: Demonstrated pattern of harassment, hate, or threats; refusal to reform.
- Consequence: Permanent removal from community spaces.
## Conflicts of Interest
Maintainers will recuse themselves from enforcement decisions where they have a personal conflict. A neutral maintainer or external trusted community member may be asked to assist when appropriate.
## Appeals
If you believe an enforcement action was made in error or was unfair, you may appeal by emailing the same reporting address within 14 days, providing context and justification.
## Attribution
Portions adapted from Contributor Covenant v2.1 and other open source community best practices.
## Changes & Versioning
Substantive changes to this Code will be announced in the repository (Release Notes / CHANGELOG / Discussions). Historical versions will remain accessible via Git history.
---
If unsure whether something is acceptable: choose respect, transparency, and ask a maintainer before acting.
+210
View File
@@ -0,0 +1,210 @@
# Contributing Guide
> English is the primary language. A brief Chinese hint: 若需中文协助可在 Issue 中说明。
Thank you for investing time in contributing! This document describes how to propose changes and how we maintain quality and consistency across the project.
## Quick Links
- Code of Conduct: ./CODE_OF_CONDUCT.md
- Security Policy: ./SECURITY.md
- Issues: https://github.com/CarmJos/configured/issues
- Discussions / Q&A: (open an Issue if Discussions are disabled)
## Table of Contents
1. Principles
2. Scope of Contributions
3. Getting Started (Environment & Build)
4. Project Structure
5. Branching & Workflow
6. Issue Workflow
7. Pull Request Guidelines
8. Commit Message Convention
9. Coding Standards
10. Testing Guidelines
11. Documentation & JavaDoc
12. Dependency Policy
13. Versioning & Releases
14. Performance Expectations
15. Internationalization / Language
16. FAQ for Contributors
17. Attribution
---
## 1. Principles
We value: correctness, clarity, minimalism, maintainability, security-by-default, and performance without premature complexity. Every contribution should move at least one of these forward while not regressing the others.
## 2. Scope of Contributions
Acceptable contributions include (but are not limited to):
- Bug fixes & test coverage improvements
- Performance optimizations with measurable benefit
- New configuration providers (storage backends) with generic value
- Validation or serialization helpers
- Documentation, examples, or tutorials
- Tooling that improves developer productivity or release robustness
Out-of-scope (likely to be declined):
- Vendor lockin features narrowly targeting one proprietary platform (unless optional & isolated)
- Large feature branches without prior design discussion
- Unbounded abstraction that increases complexity with unclear user value
## 3. Getting Started (Environment & Build)
Requirements:
- JDK 8 (minimum). Later JDKs may work but target bytecode is 1.8.
- Maven 3.8+ (Wrapper optional; project assumes standard mvn).
Build all modules:
```bash
mvn -q clean verify
```
Skip tests (NOT recommended for PR validation):
```bash
mvn -q clean install -DskipTests
```
Run a single module:
```bash
mvn -q -pl core -am test
```
Generate JavaDoc (already bound in build):
```bash
mvn -q javadoc:javadoc
```
## 4. Project Structure (High-level)
- core/ : Fundamental abstractions (Configuration, Value types, factories)
- features/ : Optional, orthogonal enhancements (validators, section, text, etc.)
- providers/ : Concrete persistence / parsing backends (yaml, gson, hocon, sql, mongodb, temp)
- demo/ : Usage demonstrations & sample scenarios
Rules:
- Core must not depend on feature or provider modules.
- Features must not form cycles; prefer depending only on core.
- Providers should keep external dependencies minimal and shaded/isolated only if necessary.
## 5. Branching & Workflow
- main (or master): Stable; only fastforward / squash from reviewed PRs.
- feature/<short-name>: New feature work. Open draft PR early for feedback.
- fix/<issue-id>-<slug>: Bug fix referencing an Issue.
- chore/<topic>: Build, infra, docs improvements.
Never force push to main. Force pushes allowed only to your own feature branches.
## 6. Issue Workflow
1. Search existing issues first to avoid duplication.
2. Provide reproduction steps (minimal code or config) for bugs.
3. Label suggestions as enhancement; performance items as perf.
4. For larger features, open a design issue summarizing: Problem, Motivation, Proposed API, Alternatives.
## 7. Pull Request Guidelines
Checklist before opening a PR:
- Linked to at least one Issue (unless trivial doc fix)
- Passes `mvn verify`
- Adds or updates tests covering new behavior / bug
- Includes JavaDoc / README / CHANGELOG fragment if user-facing
- No unrelated refactors or formatting churn
- Minimal diff: avoid reordering imports unless enforced by style
Review expectations:
- Maintainers strive to respond within 5 business days.
- Use constructive, actionoriented comments.
- Resolve conversations or explain why not.
- Squash commits if they are noisy; retain meaningful logical grouping.
## 8. Commit Message Convention
Use Conventional Commits (https://www.conventionalcommits.org/) with optional scope:
```
<type>(<scope>): <short imperative summary>
<body>(optional)
<footer>(breaking changes, issue references)
```
Types used:
- feat: New feature (user visible)
- fix: Bug fix
- perf: Performance improvement
- refactor: Internal restructuring without behavior change
- docs: Documentation only
- test: Add or fix tests
- build: Build system or dependency changes
- ci: Continuous integration changes
- chore: Maintenance tasks
- style: Formatting (rare; avoid large styleonly changes)
Breaking changes: add `!` after type/scope or include `BREAKING CHANGE:` footer.
## 9. Coding Standards
- Java: Follow effective Java principles; prefer explicit types over inference for public APIs.
- Nullability: Use JetBrains annotations (`@NotNull`, `@Nullable`) where helpful.
- Immutability: Favor immutable value objects; avoid exposing mutable internal state.
- Exceptions: Use specific exception types; no swallowing silently. Validate inputs early.
- Logging: Keep core logging minimal; let consumers decide verbosity. Avoid println.
- APIs: Minimize surface; avoid exposing prematurely general interfaces.
- Annotations: Provide meaningful config path / comments metadata clearly.
### Style
- Indentation: 4 spaces.
- Line length guideline: ≤ 140 chars (soft limit).
- Avoid wildcard imports.
## 10. Testing Guidelines
- Use JUnit (current: JUnit 4). Prefer deterministic, isolated tests.
- Each bug fix must include a regression test failing before the fix.
- Avoid timesensitive sleeps; prefer deterministic constructs.
- Keep provider-specific integration tests under provider module.
- Use random data cautiously; if used, log seed for reproduction.
Command:
```bash
mvn -q test
```
## 11. Documentation & JavaDoc
- Public classes & methods: brief JavaDoc describing contract, thread-safety, nullability.
- Add code examples when clarifying complex usage.
- Update README or module README for new feature flags or environment variables.
- Keep demo module aligned with latest recommended usage.
## 12. Dependency Policy
- Keep transitive dependency footprint lean.
- No large frameworks for simple utilities.
- Justify each new dependency in PR description (purpose, size, maintenance risk).
- Prefer stable, well-adopted libraries with permissive licenses compatible with LGPL.
- Security-sensitive libs (parsers, DB drivers) should be periodically updated.
## 13. Versioning & Releases
- Follows Semantic Versioning (MAJOR.MINOR.PATCH).
- Public API additions => MINOR bump.
- Backwards-compatible bug fix => PATCH.
- Backwards-incompatible change => MAJOR (document rationale & migration).
- Release steps (maintainers):
1. Ensure main is green (CI all passing)
2. Update CHANGELOG (if present) or Release Notes draft
3. Bump versions via maven-release-plugin (ensure GPG & staging configured)
4. Tag + push; verify publication (Central / GitHub Packages)
5. Publish GitHub Release with highlights + migration notes
## 14. Performance Expectations
- Avoid unnecessary object churn in hot paths.
- Profile before large rewrites. Provide benchmark or allocation stats if claiming improvement.
- Defer I/O and heavy parsing until needed (lazy loading pattern).
## 15. Internationalization / Language
- Primary language: English for code, comments, issues, PRs.
- Chinese clarifications acceptable if accompanied by English.
## 16. FAQ for Contributors
Q: Can I add a new provider?
A: Yes—open a design Issue first summarizing data model, external dependencies, and test strategy.
Q: How do I mark experimental APIs?
A: Add JavaDoc: `@apiNote Experimental: subject to change without notice.` and avoid wide promotion.
Q: Why Java 8 target?
A: Maximizes compatibility across server & embedded environments.
## 17. Attribution
Portions inspired by widely adopted open-source guidelines (Kotlin, Spring, Apache projects) and Conventional Commits.
---
Thank you for helping build a robust configuration ecosystem!
+1
View File
@@ -1,6 +1,7 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
+166 -71
View File
@@ -1,43 +1,139 @@
```text
____ _____ ____ __ _
/ __/__ ____ __ __ / ___/__ ___ / _(_)__ ___ _________ _/ /_(_)__ ___
/ _// _ `(_-</ // / / /__/ _ \/ _ \/ _/ / _ `/ // / __/ _ `/ __/ / _ \/ _ \
/___/\_,_/___/\_, / \___/\___/_//_/_//_/\_, /\_,_/_/ \_,_/\__/_/\___/_//_/
/___/ /___/
<div align=center>
<img src=".doc/images/banner.png" alt="Banner"/>
[![version](https://img.shields.io/github/v/release/CarmJos/configured)](https://github.com/CarmJos/configured/releases)
[![License](https://img.shields.io/github/license/CarmJos/configured)](https://www.gnu.org/licenses/lgpl-3.0.html)
[![workflow](https://github.com/CarmJos/configured/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/configured/actions/workflows/maven.yml)
[![CodeFactor](https://www.codefactor.io/repository/github/carmjos/configured/badge)](https://www.codefactor.io/repository/github/carmjos/configured)
![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/configured)
README LANGUAGES [ [**English**](README.md) | [中文](README_CN.md) ]
</div>
# configured _(config framework)_
<img src=".doc/images/logo-bg.svg" width="150px" alt="logo" align="right" style="float: right"/>
_**"Once set, Simple get."**_
A simple, easy-to-use and universal solution for managing, loading, reading,
and updating configuration files.
Supported **JSON**, **YAML**, **Hocon**, **TOML**, **SQL**, **MongoDB**... and much more!
## Features & Advantages
Supported [YAML](providers/yaml), [JSON](providers/json), [HOCON](providers/hocon) and [SQL](providers/sql)
based configuration files format.
- Class-based mechanism for initializing, loading, retrieving, and updating configuration files, ensuring convenience
and efficiency.
- 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
For the latest JavaDoc release, [CLICK HERE](https://CarmJos.github.io/configured).
For a detailed development guide, see [wiki](https://github.com/CarmJos/configured/wiki).
### Preview
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 configurations instance classes.](demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java)
Check out all code demonstrations [HERE](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java).
For more examples, see the [Development Guide](.doc/README.md).
```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);
}
}
```
# EasyConfiguration
```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();
[![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)
// 2. Initialize the configuration classes or instances.
holder.initialize(SampleConfig.class);
// 3. Enjoy using the configuration!
System.out.println("Enabled? -> " + SampleConfig.ENABLED.resolve()); // true
SampleConfig.ENABLED.set(false);
System.out.println("And now? -> " + SampleConfig.ENABLED.resolve()); // false
// p.s. Changes not save so enable value will still be true in the next run.
轻松(做)配置,简单便捷的通用配置文件加载、读取与更新工具,可自定义配置格式。
System.out.println("Your name is " + SampleConfig.INFO.NAME.resolve() + " (age=" + SampleConfig.INFO.AGE.resolve() + ")!");
}
}
## 优势
```
- 基于类的配置文件初始化、加载、获取与更新机制,方便快捷。
- 支持复杂配置的手动序列化、反序列化。
- 提供多种builder形式,快速构建 `ConfigValue<?>` 对象。
- 支持通过注解规定配置对应的路径、注释等信息。
```yaml
# Configurations for sample
## 开发
enabled: true #Enabled?
详细开发介绍请 [点击这里](.documentation/README.md) , JavaDoc(最新Release) 请 [点击这里](https://CarmJos.github.io/EasyConfiguration) 。
# Server configurations
port:
### 示例代码
# [ UUID >-----------------------------------
# A lot of UUIDs
uuids:
- 00000000-0000-0000-0000-000000000000
- 00000000-0000-0000-0000-000000000001
# [ UUID >-----------------------------------
您可以 [点击这里](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java) 查看部分代码演示,更多演示详见 [开发介绍](.documentation/README.md) 。
info:
# Configure your name!
name: Joker
how-old-are-you: 24
```
### 依赖方式
### Dependencies
#### Maven 依赖
#### Maven Dependency
<details>
<summary>远程库配置</summary>
<summary>Remote Repository Configuration</summary>
```xml
@@ -45,24 +141,17 @@
<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依赖库,实时更新,但需要配置 (推荐) -->
<id>EasyConfiguration</id>
<!-- Using GitHub dependencies for real-time updates, configuration required (recommended). -->
<id>configured</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>
<url>https://maven.pkg.github.com/CarmJos/configured</url>
</repository>
</repositories>
@@ -72,33 +161,32 @@
</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>
<artifactId>configured-core</artifactId>
<version>[LATEST RELEASE]</version>
<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>
<artifactId>configured-yaml</artifactId>
<version>[LATEST RELEASE]</version>
<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>configured-gson</artifactId>
<version>[LATEST RELEASE]</version>
<scope>compile</scope>
</dependency>
@@ -109,66 +197,73 @@
</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依赖库,实时更新,但需要配置 (推荐)
maven { url 'https://maven.pkg.github.com/CarmJos/EasyConfiguration' }
// Using GitHub dependencies for real-time updates, configuration required (recommended).
maven { url 'https://maven.pkg.github.com/CarmJos/configured' }
// 采用我的私人依赖库,简单方便,但可能因为变故而无法使用
maven { url 'https://repo.carm.cc/repository/maven-public/' }
}
```
</details>
<details>
<summary>通用原生依赖</summary>
<summary>Generic Native Dependency</summary>
```groovy
dependencies {
//基础实现部分,需要自行实现“Provider”“Wrapper”
api "cc.carm.lib:easyconfiguration-core:[LATEST RELEASE]"
// Basic implementation part, requiring custom implementation of “Provider” and “Wrapper”.
api "cc.carm.lib:configured-core:[LATEST RELEASE]"
//基于YAML文件的实现版本,可用于全部Java环境。
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]"
// YAML file-based implementation, compatible with all Java environments.
api "cc.carm.lib:configured-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:configured-gson:[LATEST RELEASE]"
}
```
</details>
## 衍生项目
## Derived Projects
### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos )
### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos)
EasyConfiguration for MineCraft!
开始在 MineCraft 相关服务器平台上轻松(做)配置吧!
configured for 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](https://github.com/sponsors/CarmJos)!
感谢您对开源项目的支持!
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/configured)
Many thanks to [ArtformGames](https://github.com/ArtformGames) for their
strong support and active contribution to this project!
<img src="https://raw.githubusercontent.com/ArtformGames/.github/master/logo/logo_full.svg" width="317px" height="117px" alt="ArtformGames">
## Open Source License
This project's source code is licensed under
the [GNU LESSER GENERAL PUBLIC LICENSE](https://www.gnu.org/licenses/lgpl-3.0.html).
本项目源码采用 [GNU LESSER GENERAL PUBLIC LICENSE](https://www.gnu.org/licenses/lgpl-3.0.html) 开源协议。
+285
View File
@@ -0,0 +1,285 @@
<div align=center>
<img src=".doc/images/banner.png" alt="Banner"/>
[![version](https://img.shields.io/github/v/release/CarmJos/configured)](https://github.com/CarmJos/configured/releases)
[![License](https://img.shields.io/github/license/CarmJos/configured)](https://www.gnu.org/licenses/lgpl-3.0.html)
[![workflow](https://github.com/CarmJos/configured/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/configured/actions/workflows/maven.yml)
[![CodeFactor](https://www.codefactor.io/repository/github/carmjos/configured/badge)](https://www.codefactor.io/repository/github/carmjos/configured)
![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/configured)
README LANGUAGES [ [English](README.md) | [**中文**](README_CN.md) ]
</div>
# configured _(配置文件框架)_
<img src=".doc/images/logo-bg.svg" width="150px" alt="logo" align="right" style="float: right"/>
**一次配置,轻松读取!**
一款简单便捷的通用配置文件加载、读取与更新工具,可自定义配置的格式。
## 特性 & 优势
支持 [YAML](providers/yaml), [JSON](providers/gson), [HOCON](providers/hocon) 和 [SQL](providers/sql) 等多种配置文件格式。
- 基于类的配置文件初始化、加载、获取与更新机制,方便快捷。
- 支持复杂配置的手动序列化、反序列化。
- 提供多种builder形式,快速构建 `ConfigValue<?>` 对象。
- 支持通过注解规定配置对应的路径、注释等信息。
## 开发
详细开发介绍请 [点击这里](.doc/README.md) , JavaDoc(最新Release)
请 [点击这里](https://CarmJos.github.io/configured) 。
### 示例代码
为快速的展示该项目的适用性,这里有几个实际演示:
- [数据库配置文件实例](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java)
- [全种类配置实例类演示](demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java)
您可以 [点击这里](demo/src/main/java/cc/carm/lib/configuration/demo)
直接查看现有的代码演示,更多复杂情况演示详见 [开发介绍](https://github.com/CarmJos/configured/wiki) 。
```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>configured</id>
<name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/configured</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>configured-core</artifactId>
<version>[LATEST RELEASE]</version>
<scope>compile</scope>
</dependency>
<!--基于YAML文件的实现版本,可用于全部Java环境。-->
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-yaml</artifactId>
<version>[LATEST RELEASE]</version>
<scope>compile</scope>
</dependency>
<!--基于JSON文件的实现版本,可用于全部Java环境。-->
<!--需要注意的是,JSON不支持文件注释。-->
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-gson</artifactId>
<version>[LATEST RELEASE]</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-hocon</artifactId>
<version>[LATEST RELEASE]</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-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/configured' }
// 采用我的私人依赖库,简单方便,但可能因为变故而无法使用
maven { url 'https://repo.carm.cc/repository/maven-public/' }
}
```
</details>
<details>
<summary>通用原生依赖</summary>
```groovy
dependencies {
//基础实现部分,需要自行实现“Provider”与“Wrapper”。
api "cc.carm.lib:configured-core:[LATEST RELEASE]"
//基于YAML文件的实现版本,可用于全部Java环境。
api "cc.carm.lib:configured-yaml:[LATEST RELEASE]"
//基于JSON文件的实现版本,可用于全部Java环境。
//需要注意的是,JSON不支持文件注释。
api "cc.carm.lib:configured-gson:[LATEST RELEASE]"
api "cc.carm.lib:configured-hocon:[LATEST RELEASE]"
api "cc.carm.lib:configured-sql:[LATEST RELEASE]"
}
```
</details>
## 衍生项目
### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos )
configured for MineCraft!
开始在 MineCraft 相关服务器平台上轻松(做)配置吧!
目前支持 BungeeCord, Bukkit(Spigot) 服务端,后续将支持更多平台。
## 支持与捐赠
若您觉得本插件做的不错,您可以通过[捐赠](https://github.com/sponsors/CarmJos)支持我!
感谢您对开源项目的支持!
万分感谢 Jetbrains 为我们提供了从事此项目和其他开源项目的许可!
[![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/CarmJos/configured)
万分感谢来自 [ArtformGames](https://github.com/ArtformGames) 对本项目的大力支持与积极贡献!
<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) 开源协议。
+102
View File
@@ -0,0 +1,102 @@
# Security Policy
English is the authoritative language of this document.
## Supported Versions
We generally provide security fixes only for the latest released MINOR version (most recent tag on the default branch). Older versions may receive fixes only if the vulnerability is critical and a patch is low risk.
| Version | Status |
|----------|-------------------------|
| Latest | Security fixes |
| < Latest | Not routinely supported |
If you rely on an older version you are strongly encouraged to upgrade promptly after each release.
## Reporting a Vulnerability
Please DO NOT open a public Issue for suspected security problems.
Instead, email: carm@carm.cc with:
- A clear description of the issue and potential impact
- Steps to reproduce (minimal code / configuration)
- Affected version(s) and environment (JDK, OS)
- Any known workarounds
- Preferred public credit name (optional)
You will receive an acknowledgement within 72 hours (workdays) confirming receipt.
## Assessment & Disclosure Process
1. Triage & validation (attempt reproduction, scope impact)
2. Determine severity (CVSS or qualitative: Low / Moderate / High / Critical)
3. Prepare a private fix / patch + regression tests
4. Coordinate an embargoed release window (typically ≤14 days after validation for High/Critical)
5. Release a new version (and possibly backport if warranted)
6. Publish security advisory (GitHub Security Advisory + Release Notes) including mitigation steps
We may reject reports that are clearly nonsecurity bugs (e.g., feature requests, performance tuning) or issues requiring unreasonable preconditions (e.g., attacker already has full local code execution).
## Non-Qualifying Issues (Examples)
- Missing rate limits on non-authenticated, non-state-changing operations
- Denial-of-service requiring unrealistic resource constraints or already solved via JVM flags
- Vulnerabilities only exploitable on unsupported / EOL Java versions
- Social engineering, SPF/DMARC issues beyond this codebases control
## Coordinated Disclosure
If you plan to blog or speak publicly about the vulnerability prior to patch availability, please coordinate timing so users can upgrade safely.
## Dependency Security
We periodically review dependency versions for CVEs. You can help by:
- Submitting PRs that upgrade vulnerable libraries with changelog & compatibility notes
- Avoiding unnecessary new dependencies
## Cryptographic Material
This project does not bundle custom cryptographic primitives. If you discover misuse of crypto APIs or insecure random number use in security-sensitive areas, treat it as a security report.
## Reporting Format Template (Recommended)
```
Subject: [Security Report] <short title>
Affected Component: (module / class)
Version(s) Tested: x.y.z (and earlier if known)
Environment: JDK x, OS
Summary:
Describe the vulnerability and impact.
Reproduction Steps:
1. ...
2. ...
3. ...
Expected vs Actual:
Potential Impact:
Workarounds / Mitigations (if any):
Credit: (name / handle / anonymous)
```
## Credit & Acknowledgement
We will list (with permission) reporters who submit valid, first responsibly disclosed security issues in the release notes / advisory.
## GPG / Integrity
Release artifacts are signed (see project docs). Always verify signatures and checksums when consuming artifacts from Maven Central or GitHub Packages.
## Questions
For general (non-sensitive) questions, open an Issue labeled `question` rather than using the security email.
Thank you for helping keep the ecosystem safe.
+12 -5
View File
@@ -3,21 +3,28 @@
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">
<parent>
<artifactId>easyconfiguration-parent</artifactId>
<artifactId>configured-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>3.3.1</version>
<version>4.2.1</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>
<artifactId>easyconfiguration-core</artifactId>
<artifactId>configured-core</artifactId>
<packaging>jar</packaging>
<name>Configured - Core</name>
<url>https://github.com/CarmJos/configured</url>
<description>
The core module of Configured framework,
providing essential configuration management functionality.
</description>
<build>
<plugins>
<plugin>
@@ -0,0 +1,8 @@
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,88 @@
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 @Nullable Object serialize(
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type,
@NotNull TYPE value
) throws Exception {
if (serializer == null) throw new UnsupportedOperationException("Serializer is not supported");
return serializer.serialize(holder, type, value);
}
@Override
public @Nullable TYPE parse(
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type,
@NotNull Object value
) throws Exception {
if (deserializer == null) throw new UnsupportedOperationException("Deserializer is not supported");
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,308 @@
package cc.carm.lib.configuration.adapter;
import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
public class ValueAdapterRegistry {
protected final Set<ValueAdapter<?>> adapters = new HashSet<>();
protected final Map<ValueType<?>, ValueAdapter<?>> adapterCache = new HashMap<>();
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));
adapterCache.clear();
}
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));
adapterCache.clear();
}
@SuppressWarnings("unchecked")
public <T> @Nullable ValueAdapter<T> adapterOf(@NotNull ValueType<T> type) {
if (adapterCache.containsKey(type)) {
return (ValueAdapter<T>) adapterCache.get(type);
}
for (ValueAdapter<?> adapter : adapters) {
if (adapter.type().equals(type)) {
adapterCache.put(type, adapter);
return (ValueAdapter<T>) adapter;
}
}
for (ValueAdapter<?> adapter : adapters) {
if (adapter.type().isSubtypeOf(type)) {
adapterCache.put(type, adapter);
return (ValueAdapter<T>) adapter;
}
}
adapterCache.put(type, null);
return 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));
}
public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull Class<T> type, @Nullable Object source) throws Exception {
return deserialize(holder, ValueType.of(type), source);
}
public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> type, @Nullable Object source) throws Exception {
if (source == null) return null;
Type typeInstance = type.getType();
if (!(typeInstance instanceof ParameterizedType) && type.isInstance(source)) {
return type.cast(source);
}
ValueAdapter<T> adapter = adapterOf(type);
if (adapter != null) {
return adapter.parse(holder, type, source);
}
return deserializeWithoutAdapter(holder, type, source, typeInstance);
}
private <T> T deserializeWithoutAdapter(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> type,
@NotNull Object source, @NotNull Type typeInstance) throws Exception {
Class<?> rawType = type.getRawType();
if (rawType.isArray()) {
return deserializeArray(holder, type, source, rawType);
}
if (typeInstance instanceof ParameterizedType) {
return deserializeParameterized(holder, type, source, (ParameterizedType) typeInstance);
}
throw new RuntimeException("No adapter for type " + type);
}
private <T> T deserializeArray(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> type,
@NotNull Object source, @NotNull Class<?> rawType) throws Exception {
List<?> list;
if (source instanceof List<?>) {
list = (List<?>) source;
} else {
// For non-list sources, treat as single element array
list = Collections.singletonList(source);
}
int size = list.size();
if (size == 0) {
return type.cast(Array.newInstance(rawType.getComponentType(), 0));
}
Class<?> componentType = rawType.getComponentType();
Object[] array = (Object[]) Array.newInstance(componentType, size);
for (int i = 0; i < size; i++) {
array[i] = deserialize(holder, componentType, list.get(i));
}
return type.cast(array);
}
@SuppressWarnings("unchecked")
private <T> T deserializeParameterized(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> type,
@NotNull Object source, @NotNull ParameterizedType pt) throws Exception {
Type rawType = pt.getRawType();
Type[] typeArgs = pt.getActualTypeArguments();
if (rawType == List.class || rawType == Collection.class || rawType == ArrayList.class) {
return (T) deserializeCollection(holder, source, typeArgs[0], ArrayList::new);
}
if (rawType == Set.class || rawType == HashSet.class) {
return (T) deserializeCollection(holder, source, typeArgs[0], HashSet::new);
}
if (rawType == Map.class || rawType == LinkedHashMap.class) {
return (T) deserializeMap(holder, source, typeArgs[0], typeArgs[1]);
}
throw new RuntimeException("No adapter for parameterized type " + type);
}
private Collection<?> deserializeCollection(@NotNull ConfigurationHolder<?> holder, @NotNull Object source,
@NotNull Type elementType, @NotNull java.util.function.Supplier<Collection<Object>> collectionFactory) throws Exception {
ValueType<?> elementValueType = ValueType.of(elementType);
List<?> sourceList = deserializeList(holder, elementValueType, source);
if (sourceList.isEmpty()) {
return collectionFactory.get();
}
Collection<Object> result = collectionFactory.get();
if (result instanceof ArrayList) {
((ArrayList<Object>) result).ensureCapacity(sourceList.size());
}
for (Object item : sourceList) {
Object deserializedItem = deserialize(holder, elementValueType, item);
if (deserializedItem != null) {
result.add(deserializedItem);
}
}
return result;
}
private Map<Object, Object> deserializeMap(@NotNull ConfigurationHolder<?> holder, @NotNull Object source,
@NotNull Type keyType, @NotNull Type valueType) throws Exception {
Map<?, ?> sourceMap;
if (source instanceof Map<?, ?>) {
sourceMap = (Map<?, ?>) source;
} else if (source instanceof ConfigureSection) {
sourceMap = ((ConfigureSection) source).asMap();
} else {
throw new IllegalArgumentException("Cannot deserialize to Map from " + source.getClass());
}
int mapSize = sourceMap.size();
if (mapSize == 0) {
return new LinkedHashMap<>();
}
ValueType<?> keyValueType = ValueType.of(keyType);
ValueType<?> valueValueType = ValueType.of(valueType);
Map<Object, Object> resultMap = new LinkedHashMap<>(mapSize);
for (Map.Entry<?, ?> entry : sourceMap.entrySet()) {
Object key = deserialize(holder, keyValueType, entry.getKey());
Object value = deserialize(holder, valueValueType, entry.getValue());
resultMap.put(key, value);
}
return resultMap;
}
@Nullable
public <T> Object serialize(@NotNull ConfigurationHolder<?> holder, @Nullable T value) throws Exception {
if (value == null) return null; // Null check
ValueType<T> type = ValueType.of(value);
ValueAdapter<T> adapter = adapterOf(type);
if (adapter != null) return adapter.serialize(holder, type, value);
if (value.getClass().isArray()) {
Object[] array = (Object[]) value;
List<Object> serializedList = new ArrayList<>(array.length);
for (Object item : array) {
serializedList.add(serialize(holder, item));
}
return serializedList;
} else if (value instanceof Collection<?>) {
Collection<?> collection = (Collection<?>) value;
List<Object> serializedList = new ArrayList<>(collection.size());
for (Object item : collection) {
serializedList.add(serialize(holder, item));
}
return serializedList;
} else if (value instanceof Map<?, ?>) {
Map<?, ?> map = (Map<?, ?>) value;
Map<Object, Object> serializedMap = new LinkedHashMap<>(map.size());
for (Map.Entry<?, ?> entry : map.entrySet()) {
Object key = serialize(holder, entry.getKey());
Object val = serialize(holder, entry.getValue());
serializedMap.put(key, val);
}
return serializedMap;
}
return value; // No adapters, and cannot handle, try to return the original value
}
protected <T> List<T> deserializeList(@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<T> type, @Nullable Object source) throws Exception {
if (source == null) return Collections.emptyList(); // Null check
if (source instanceof List<?>) {
List<?> list = (List<?>) source;
List<T> result = new ArrayList<>(list.size());
for (Object item : list) {
T deserializedItem = deserialize(holder, type, item);
if (deserializedItem != null) {
result.add(deserializedItem);
}
}
return result;
} else { // Maybe singleton? Let's try to deserialize it as a single element list
T deserializedItem = deserialize(holder, type, source);
if (deserializedItem != null) {
return Collections.singletonList(deserializedItem);
} else return Collections.emptyList();
}
}
}
@@ -0,0 +1,20 @@
package cc.carm.lib.configuration.adapter;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Value deserializer, convert base data to target value.
*
* @param <TYPE> The type of target value
*/
@FunctionalInterface
public interface ValueParser<TYPE> {
@Nullable TYPE parse(
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type, @NotNull Object data
) throws Exception;
}
@@ -0,0 +1,20 @@
package cc.carm.lib.configuration.adapter;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Value serializer, convert target value to base data.
*
* @param <TYPE> The type of value
*/
@FunctionalInterface
public interface ValueSerializer<TYPE> {
@Nullable Object serialize(
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type, @NotNull TYPE value
) throws Exception;
}
@@ -0,0 +1,249 @@
package cc.carm.lib.configuration.adapter;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* {@link ValueType} used to get the generic type of the value,
* It can be used to check if an object is an instance of a specific type,
* and to cast objects to the correct type.
* <p>
* Java's type system is not capable of retaining generic type information at runtime.
* This class is used to represent a type with its generic parameters.
* </p>
*/
public abstract class ValueType<T> {
public static final ValueType<Object> OBJECT = ofPrimitiveType(Object.class);
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 to fast 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 @NotNull Class<T> clazz) {
return of((Type) clazz);
}
public static <T> ValueType<List<T>> ofList(final @NotNull Class<T> paramType) {
return of(List.class, paramType);
}
public static <T> ValueType<List<T>> ofList(final @NotNull ValueType<T> paramType) {
return of(List.class, paramType.getType());
}
public static <K, V> ValueType<Map<K, V>> ofMap(final @NotNull Class<K> keyType, final @NotNull Class<V> valueType) {
return of(Map.class, keyType, valueType);
}
public static <K, V> ValueType<Map<K, V>> ofMap(final @NotNull ValueType<K> keyType, final @NotNull ValueType<V> valueType) {
return of(Map.class, keyType.getType(), valueType.getType());
}
/**
* Get the generic type of the complex type.
*
* @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);
}
@ApiStatus.Internal
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;
}
/**
* Checks if this ValueType is a subtype of the given Class.
*
* @param target The target Class to check against
* @return true if this ValueType is a subtype of the target Class, false otherwise
*/
public boolean isSubtypeOf(Class<?> target) {
Class<?> rawType = getRawType();
return target.isAssignableFrom(rawType);
}
/**
* Checks if this ValueType is a subtype of the given ValueType.
*
* @param target The target ValueType to check against
* @return true if this ValueType is a subtype of the target, false otherwise
*/
public boolean isSubtypeOf(ValueType<?> target) {
return target.isSubtypeOf(getRawType());
}
/**
* Checks if the given object is an instance of the type represented by this ValueType.
*
* @param obj The object to check
* @return true if the object is an instance of the type, false otherwise
*/
public boolean isInstance(Object obj) {
return obj != null && getRawType().isInstance(obj);
}
/**
* Extracts the raw type from the generic type.
*
* @return The raw type of the generic type
* @throws IllegalStateException if the type is not a Class or ParameterizedType
*/
@SuppressWarnings("unchecked")
public Class<T> getRawType() {
if (type instanceof Class<?>) {
return (Class<T>) type;
}
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
Type raw = pt.getRawType();
if (raw instanceof Class<?>) {
return (Class<T>) raw;
}
}
throw new IllegalStateException("Unsupported type: " + type);
}
/**
* Casts the object to the type represented by this ValueType.
*
* @param obj The object to cast
* @return The object cast to the type represented by this ValueType
*/
@SuppressWarnings("unchecked")
public T cast(Object obj) {
if (!isInstance(obj)) {
throw new ClassCastException("Cannot cast object " + obj + " to type " + this);
}
return (T) obj;
}
/**
* Returns a string representation of the type.
* Like "{@code java.util.List<java.lang.String>}" or "java.lang.Integer".
*
* @return String representation of the type
*/
@Override
public String toString() {
if (type instanceof Class<?>) {
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,38 @@
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 java.util.UUID;
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<UUID> UUID = new ValueAdapter<>(
ValueType.of(UUID.class),
(provider, type, value) -> value.toString(),
(provider, type, value) -> java.util.UUID.fromString(value.toString())
);
@NotNull ValueAdapter<ConfigureSection> SECTIONS = new ValueAdapter<>(
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,162 @@
package cc.carm.lib.configuration.builder;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.function.DataValidator;
import cc.carm.lib.configuration.function.ValueValidator;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.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.Predicate;
import java.util.function.Supplier;
public abstract class AbstractConfigBuilder<
TYPE, UNIT, RESULT extends ConfigValue<TYPE, UNIT>, HOLDER extends ConfigurationHolder<?>,
SELF extends AbstractConfigBuilder<TYPE, UNIT, RESULT, HOLDER, SELF>
> {
protected final Class<? super HOLDER> providerClass;
protected final ValueType<TYPE> type;
protected @Nullable HOLDER holder;
protected @Nullable String path;
protected @NotNull ValueValidator<UNIT> valueValidator = ValueValidator.none();
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 SELF self();
public abstract @NotNull RESULT build();
public SELF holder(@Nullable HOLDER holder) {
this.holder = holder;
return self();
}
public SELF path(@Nullable String path) {
this.path = path;
return self();
}
/**
* Set the {@link ValueValidator} for the value.
*
* @param validator The validator to set.
* @return this builder
*/
public SELF validator(@NotNull ValueValidator<UNIT> validator) {
this.valueValidator = validator;
return self();
}
/**
* Set the {@link DataValidator} for the value.
*
* @param validator The validator to set.
* @return this builder
*/
public SELF validator(@NotNull DataValidator<? super UNIT> validator) {
return validator((h, value) -> validator.validate(value));
}
/**
* Validate the value with the specified condition.
*
* @param validator The validator to append.
* @return this builder
*/
public SELF validate(@NotNull ValueValidator<? super UNIT> validator) {
return validator(this.valueValidator.and(validator));
}
/**
* Validate the value with the specified condition.
*
* @param validator The validator to append.
* @return this builder
*/
public SELF validate(@NotNull DataValidator<? super UNIT> validator) {
return validate((h, value) -> validator.validate(value));
}
/**
* Validate the value with the specified condition.
*
* @param condition The condition to check, if the condition is false, an exception will be thrown.
* @param exception The exception to throw if the condition is false.
* @return this builder
*/
public SELF validate(@NotNull Predicate<? super UNIT> condition, @NotNull Exception exception) {
return validate((h, value) -> {
if (!condition.test(value)) throw exception;
});
}
/**
* Validate the value with the specified condition.
*
* @param condition The condition to check, if the condition is false, an exception will be thrown.
* @param msg The message to throw if the condition is false.
* @return this builder
*/
public SELF validate(@NotNull Predicate<? super UNIT> condition, @NotNull String msg) {
return validate((h, value) -> {
if (!condition.test(value)) throw new IllegalArgumentException(msg);
});
}
public SELF initializer(@NotNull BiConsumer<ConfigurationHolder<?>, String> initializer) {
this.initializer = initializer;
return self();
}
public SELF append(@NotNull BiConsumer<ConfigurationHolder<?>, String> initializer) {
return initializer(initializer.andThen(initializer));
}
public SELF append(@NotNull Consumer<ConfigurationHolder<?>> initializer) {
return append((provider, valuePath) -> initializer.accept(provider));
}
public SELF defaults(@Nullable TYPE defaultValue) {
return defaults(() -> defaultValue);
}
public SELF defaults(@NotNull Supplier<@Nullable TYPE> supplier) {
this.defaultValueSupplier = supplier;
return self();
}
public SELF meta(@NotNull Consumer<@NotNull ConfigurationMetaHolder> metaConsumer) {
return append((h, p) -> metaConsumer.accept(h.metadata(p)));
}
public <M> SELF meta(@NotNull ConfigurationMetadata<M> type, @Nullable M value) {
return meta(h -> h.set(type, value));
}
protected @NotNull ValueManifest<TYPE, UNIT> buildManifest() {
return new ValueManifest<>(
type(), this.defaultValueSupplier, this.valueValidator,
this.initializer, this.holder, this.path
);
}
}
@@ -0,0 +1,17 @@
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, UNIT,
RESULT extends ConfigValue<TYPE, UNIT>,
SELF extends CommonConfigBuilder<TYPE, UNIT, RESULT, SELF>
> extends AbstractConfigBuilder<TYPE, UNIT, RESULT, ConfigurationHolder<?>, SELF> {
protected CommonConfigBuilder(ValueType<TYPE> type) {
super(ConfigurationHolder.class, type);
}
}
@@ -0,0 +1,55 @@
package cc.carm.lib.configuration.builder.collection;
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.impl.CollectionConfigValue;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
public abstract class SectionCollectionBuilder<
V, C extends Collection<V>,
RESULT extends CollectionConfigValue<V, C, ?>,
SELF extends SectionCollectionBuilder<V, C, RESULT, SELF>
> extends AbstractSectionBuilder<C, V, RESULT, SELF> {
protected @NotNull Supplier<? extends C> constructor;
public SectionCollectionBuilder(@NotNull Supplier<? extends C> constructor,
@NotNull ValueType<V> paramType,
@NotNull ValueHandler<ConfigureSection, V> parser,
@NotNull ValueHandler<V, ? extends Map<String, Object>> serializer) {
super(new ValueType<C>() {
}, paramType, parser, serializer);
this.constructor = constructor;
}
@SafeVarargs
public final @NotNull SELF defaults(@NotNull V... values) {
return defaults(c -> c.addAll(Arrays.asList(values)));
}
public final @NotNull SELF defaults(@NotNull Consumer<C> constructor) {
return defaults(() -> {
C collection = this.constructor.get();
constructor.accept(collection);
return collection;
});
}
public SELF constructor(@NotNull Supplier<? extends C> constructor) {
this.constructor = constructor;
return self();
}
public SELF construct(@NotNull C collection) {
return constructor(() -> collection);
}
}
@@ -0,0 +1,138 @@
package cc.carm.lib.configuration.builder.collection;
import cc.carm.lib.configuration.adapter.ValueAdapter;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import cc.carm.lib.configuration.value.ValueManifest;
import cc.carm.lib.configuration.value.impl.CollectionConfigValue;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Map;
import java.util.function.Supplier;
public class SimpleCollectionCreator<V, C extends Collection<V>, RESULT extends CollectionConfigValue<V, C, ?>> {
public static <V, C extends Collection<V>, RESULT extends CollectionConfigValue<V, C, ?>>
@NotNull SimpleCollectionCreator<V, C, RESULT> create(
@NotNull ValueType<V> type,
@NotNull Supplier<? extends C> defaultConstructor,
@NotNull CollectionValueFactory<V, C, RESULT> factory) {
return new SimpleCollectionCreator<>(type, defaultConstructor, factory);
}
protected final @NotNull Supplier<? extends C> defaultConstructor;
protected final @NotNull ValueType<V> type;
protected final @NotNull CollectionValueFactory<V, C, RESULT> factory;
public SimpleCollectionCreator(@NotNull ValueType<V> type,
@NotNull Supplier<? extends C> defaultConstructor,
@NotNull CollectionValueFactory<V, C, RESULT> factory) {
this.defaultConstructor = defaultConstructor;
this.type = type;
this.factory = factory;
}
public <S> @NotNull Source<S, V, C, RESULT> from(@NotNull Class<S> sourceType) {
return from(ValueType.of(sourceType));
}
public <S> @NotNull Source<S, V, C, RESULT> from(@NotNull ValueType<S> sourceType) {
return new Source<S, V, C, RESULT>(
defaultConstructor, sourceType, type,
ValueHandler.required(type),
ValueHandler.required(sourceType),
factory
);
}
public @NotNull SimpleCollectionCreator.Source<Object, V, C, RESULT> fromObject() {
return new Source<Object, V, C, RESULT>(
defaultConstructor, ValueType.OBJECT, type,
ValueHandler.deserialize(type), ValueHandler.toObject(),
factory
);
}
public @NotNull SimpleCollectionCreator.Source<String, V, C, RESULT> fromString() {
return new Source<String, V, C, RESULT>(
defaultConstructor, ValueType.STRING, type,
ValueHandler.required(type), ValueHandler.stringValue(),
factory
);
}
public @NotNull SimpleCollectionCreator.Section<V, C, RESULT> fromSection() {
return new Section<V, C, RESULT>(
defaultConstructor, type,
ValueHandler.required(type), ValueHandler.required(),
factory
);
}
@FunctionalInterface
public interface CollectionValueFactory<V, C, RESULT> {
@NotNull RESULT build(
@NotNull ValueManifest<C, V> manifest,
@NotNull Supplier<? extends C> constructor,
@NotNull ValueAdapter<V> paramAdapter
);
}
public static class Source<SOURCE, V, C extends Collection<V>, RESULT extends CollectionConfigValue<V, C, ?>>
extends SourceCollectionBuilder<SOURCE, V, C, RESULT, Source<SOURCE, V, C, RESULT>> {
protected final @NotNull CollectionValueFactory<V, C, RESULT> factory;
public Source(
@NotNull Supplier<? extends C> constructor,
@NotNull ValueType<SOURCE> sourceType,
@NotNull ValueType<V> paramType,
@NotNull ValueHandler<SOURCE, V> parser,
@NotNull ValueHandler<V, SOURCE> serializer,
@NotNull CollectionValueFactory<V, C, RESULT> factory) {
super(constructor, sourceType, paramType, parser, serializer);
this.factory = factory;
}
@Override
protected @NotNull SimpleCollectionCreator.Source<SOURCE, V, C, RESULT> self() {
return this;
}
@Override
public @NotNull RESULT build() {
return factory.build(buildManifest(), constructor, buildAdapter());
}
}
public static class Section<V, C extends Collection<V>, RESULT extends CollectionConfigValue<V, C, ?>>
extends SectionCollectionBuilder<V, C, RESULT, Section<V, C, RESULT>> {
protected final @NotNull CollectionValueFactory<V, C, RESULT> factory;
public Section(
@NotNull Supplier<? extends C> constructor,
@NotNull ValueType<V> paramType,
@NotNull ValueHandler<ConfigureSection, V> parser,
@NotNull ValueHandler<V, ? extends Map<String, Object>> serializer,
@NotNull CollectionValueFactory<V, C, RESULT> factory) {
super(constructor, paramType, parser, serializer);
this.factory = factory;
}
@Override
protected @NotNull SimpleCollectionCreator.Section<V, C, RESULT> self() {
return this;
}
@Override
public @NotNull RESULT build() {
return factory.build(buildManifest(), constructor, buildAdapter());
}
}
}
@@ -0,0 +1,53 @@
package cc.carm.lib.configuration.builder.collection;
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.impl.CollectionConfigValue;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Collection;
import java.util.function.Consumer;
import java.util.function.Supplier;
public abstract class SourceCollectionBuilder<
SOURCE, V, C extends Collection<V>,
RESULT extends CollectionConfigValue<V, C, ?>,
SELF extends SourceCollectionBuilder<SOURCE, V, C, RESULT, SELF>
>
extends AbstractSourceBuilder<C, SOURCE, V, RESULT, SELF> {
protected @NotNull Supplier<? extends C> constructor;
public SourceCollectionBuilder(@NotNull Supplier<? extends C> constructor,
@NotNull ValueType<SOURCE> sourceType, @NotNull ValueType<V> paramType,
@NotNull ValueHandler<SOURCE, V> parser, @NotNull ValueHandler<V, SOURCE> serializer) {
super(new ValueType<C>() {
}, sourceType, paramType, parser, serializer);
this.constructor = constructor;
}
@SafeVarargs
public final @NotNull SELF defaults(@NotNull V... values) {
return defaults(c -> c.addAll(Arrays.asList(values)));
}
public final @NotNull SELF defaults(@NotNull Consumer<C> constructor) {
return defaults(() -> {
C collection = this.constructor.get();
constructor.accept(collection);
return collection;
});
}
public SELF constructor(@NotNull Supplier<? extends C> constructor) {
this.constructor = constructor;
return self();
}
public SELF construct(@NotNull C collection) {
return constructor(() -> collection);
}
}
@@ -0,0 +1,76 @@
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.ValueComposer;
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, UNIT,
RESULT extends ConfigValue<TYPE, UNIT>,
SELF extends AbstractSectionBuilder<TYPE, UNIT, RESULT, SELF>
> extends CommonConfigBuilder<TYPE, UNIT, RESULT, SELF> {
protected final @NotNull ValueType<UNIT> paramType;
protected @NotNull ValueHandler<ConfigureSection, UNIT> parser;
protected @NotNull ValueHandler<UNIT, ? extends Map<String, Object>> serializer;
protected AbstractSectionBuilder(@NotNull ValueType<TYPE> type, @NotNull ValueType<UNIT> paramType,
@NotNull ValueHandler<ConfigureSection, UNIT> parser,
@NotNull ValueHandler<UNIT, ? extends Map<String, Object>> serializer) {
super(type);
this.paramType = paramType;
this.parser = parser;
this.serializer = serializer;
}
public @NotNull SELF parse(@NotNull DataFunction<ConfigureSection, UNIT> valueParser) {
return parse((p, section) -> valueParser.handle(section));
}
public @NotNull SELF parse(@NotNull ValueHandler<ConfigureSection, UNIT> valueParser) {
this.parser = valueParser;
return self();
}
public @NotNull SELF serialize(@NotNull ValueHandler<UNIT, ? extends Map<String, Object>> serializer) {
this.serializer = serializer;
return self();
}
public @NotNull SELF serialize(@NotNull DataFunction<UNIT, ? extends Map<String, Object>> serializer) {
return serialize((p, value) -> serializer.handle(value));
}
public @NotNull SELF serialize(@NotNull ValueComposer<Map<String, Object>, UNIT> serializer) {
return serialize((h, value) -> {
Map<String, Object> map = new LinkedHashMap<>();
serializer.accept(h, map, value);
return map;
});
}
protected ValueAdapter<UNIT> buildAdapter() {
return new ValueAdapter<>(this.paramType)
.parser((p, type, data) -> {
ConfigureSection section = p.deserialize(ConfigureSection.class, data);
if (section == null) return null;
return this.parser.handle(p, section);
})
.serializer((p, type, data) -> {
Map<String, Object> map = this.serializer.handle(p, data);
return map == null || map.isEmpty() ? null : map;
});
}
}
@@ -0,0 +1,74 @@
package cc.carm.lib.configuration.builder.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.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, UNIT, RESULT extends ConfigValue<V, UNIT>,
SELF extends AbstractSourceBuilder<V, SOURCE, UNIT, RESULT, SELF>
> extends CommonConfigBuilder<V, UNIT, RESULT, SELF> {
protected final @NotNull ValueType<SOURCE> sourceType;
protected final @NotNull ValueType<UNIT> paramType;
@SuppressWarnings("NotNullFieldNotInitialized") // Already initialized in constructor
protected @NotNull ValueParser<UNIT> valueParser;
@SuppressWarnings("NotNullFieldNotInitialized") // Already initialized in constructor
protected @NotNull ValueSerializer<UNIT> valueSerializer;
protected AbstractSourceBuilder(@NotNull ValueType<V> type,
@NotNull ValueType<SOURCE> sourceType, @NotNull ValueType<UNIT> paramType,
@NotNull ValueHandler<SOURCE, UNIT> parser,
@NotNull ValueHandler<UNIT, SOURCE> serializer) {
super(type);
this.sourceType = sourceType;
this.paramType = paramType;
parse(parser);
serialize(serializer);
}
public @NotNull SELF parse(@NotNull DataFunction<SOURCE, UNIT> parser) {
return parse((p, source) -> parser.handle(source));
}
public @NotNull SELF parse(@NotNull ValueHandler<SOURCE, UNIT> parser) {
return parser((holder, type, data) -> {
SOURCE source = holder.deserialize(this.sourceType, data);
return parser.handle(holder, source);
});
}
public @NotNull SELF parser(@NotNull ValueParser<UNIT> parser) {
this.valueParser = parser;
return self();
}
public @NotNull SELF serialize(@NotNull ValueHandler<UNIT, SOURCE> serializer) {
return serializer((holder, type, data) -> {
SOURCE source = serializer.handle(holder, data);
return holder.serialize(source);
});
}
public @NotNull SELF serialize(@NotNull DataFunction<UNIT, SOURCE> serializer) {
return serialize((p, value) -> serializer.handle(value));
}
public @NotNull SELF serializer(@NotNull ValueSerializer<UNIT> serializer) {
this.valueSerializer = serializer;
return self();
}
protected ValueAdapter<UNIT> buildAdapter() {
return new ValueAdapter<>(this.paramType, this.valueSerializer, this.valueParser);
}
}
@@ -0,0 +1,17 @@
package cc.carm.lib.configuration.builder.list;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.collection.SimpleCollectionCreator;
import cc.carm.lib.configuration.value.standard.ConfiguredList;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class ConfigListCreator<V> extends SimpleCollectionCreator<V, List<V>, ConfiguredList<V>> {
public ConfigListCreator(@NotNull ValueType<V> type) {
super(type, ArrayList::new, ConfiguredList::new);
}
}
@@ -0,0 +1,89 @@
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 <S> SourceMapBuilder<M, Object, K, V> fromObject() {
return from(
ValueType.OBJECT,
ValueHandler.deserialize(keyType), ValueHandler.stringValue(),
ValueHandler.deserialize(valueType), ValueHandler.toObject()
);
}
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,49 @@
package cc.carm.lib.configuration.builder.map;
import cc.carm.lib.configuration.adapter.ValueType;
import org.jetbrains.annotations.NotNull;
import java.util.*;
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);
}
public @NotNull ConfigMapBuilder<TreeMap<K, V>, K, V> asTreeMap(@NotNull Comparator<? super K> comparator) {
return constructor(() -> new TreeMap<>(comparator));
}
}
@@ -0,0 +1,96 @@
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 SectionMapBuilder<MAP, K, V> defaults(@NotNull K key, @NotNull V value) {
return defaults(map -> map.put(key, value));
}
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,92 @@
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> defaults(@NotNull K key, @NotNull V value) {
return defaults(map -> map.put(key, value));
}
public @NotNull SourceMapBuilder<MAP, SOURCE, K, V> parseKey(@NotNull DataFunction<String, K> keyParser) {
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,47 @@
package cc.carm.lib.configuration.builder.value;
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;
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,28 @@
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,22 @@
package cc.carm.lib.configuration.function;
import org.jetbrains.annotations.NotNull;
@FunctionalInterface
public interface ConfigExceptionHandler {
void handle(@NotNull String path, @NotNull Throwable throwable);
static @NotNull ConfigExceptionHandler silence() {
return (path, throwable) -> {
};
}
static @NotNull ConfigExceptionHandler print() {
return (path, throwable) -> {
System.err.println("Error occurred at path: " + path);
throwable.printStackTrace();
};
}
}
@@ -0,0 +1,20 @@
package cc.carm.lib.configuration.function;
import org.jetbrains.annotations.NotNull;
import java.io.Serializable;
@FunctionalInterface
public interface DataConsumer<T> extends Serializable {
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,158 @@
package cc.carm.lib.configuration.function;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.io.Serializable;
import java.util.Objects;
@FunctionalInterface
public interface DataFunction<T, R> extends Serializable {
@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,19 @@
package cc.carm.lib.configuration.function;
import org.jetbrains.annotations.Nullable;
import java.io.Serializable;
@FunctionalInterface
public interface DataValidator<T> extends Serializable {
void validate(@Nullable T value) throws Exception;
default DataValidator<T> compose(DataValidator<? super T> other) {
return value -> {
validate(value);
other.validate(value);
};
}
}
@@ -0,0 +1,31 @@
package cc.carm.lib.configuration.function;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
import java.io.Serializable;
@FunctionalInterface
public interface ValueComposer<T, U> extends Serializable {
/**
* Accept the value and the data, and then compose the value.
*
* @param holder The configuration holder
* @param type The value type, e.g. {@link java.util.List}, {@link java.util.Map}, etc.
* @param data The unit data
* @throws Exception If an error occurs
*/
void accept(@NotNull ConfigurationHolder<?> holder, @NotNull T type, @NotNull U data) throws Exception;
default ValueComposer<T, U> andThen(ValueComposer<? super T, ? super U> after) {
return (holder, unit, data) -> {
accept(holder, unit, data);
after.accept(holder, unit, data);
};
}
}
@@ -0,0 +1,80 @@
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.io.Serializable;
import java.util.Objects;
@FunctionalInterface
public interface ValueHandler<T, R> extends Serializable {
@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,49 @@
package cc.carm.lib.configuration.function;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.Serializable;
@FunctionalInterface
public interface ValueValidator<T> extends Serializable {
void validate(@NotNull ConfigurationHolder<?> holder, @Nullable T value) throws Exception;
default ValueValidator<T> and(ValueValidator<? super T> other) {
return (holder, value) -> {
validate(holder, value);
other.validate(holder, value);
};
}
static <V> ValueValidator<V> none() {
return (holder, data) -> {
};
}
static <V> ValueValidator<V> nonnull() {
return nonnull("Value cannot be null");
}
static <V> ValueValidator<V> nonnull(String message) {
return (holder, data) -> {
if (data == null) throw new IllegalArgumentException(message);
};
}
static <V extends Number> ValueValidator<V> range(V min, V max) {
return range(min, max, "Value must be in range [" + min + ", " + max + "]");
}
static <V extends Number> ValueValidator<V> range(V min, V max, String message) {
return (holder, data) -> {
if (data.doubleValue() < min.doubleValue() || data.doubleValue() > max.doubleValue()) {
throw new IllegalArgumentException(message);
}
};
}
}
@@ -0,0 +1,204 @@
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.ConfigExceptionHandler;
import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.function.ValueValidator;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
import cc.carm.lib.configuration.source.loader.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 @NotNull ValueAdapterRegistry adapters = new ValueAdapterRegistry();
protected @NotNull ConfigurationOptionHolder options = new ConfigurationOptionHolder();
protected @NotNull Map<String, ConfigurationMetaHolder> metadata = new HashMap<>();
protected @NotNull ConfigurationInitializer initializer = new ConfigurationInitializer();
protected @NotNull ConfigExceptionHandler exceptionHandler = ConfigExceptionHandler.print();
protected ConfigurationFactory() {
this.adapters.register(StandardAdapters.PRIMITIVES);
this.adapters.register(StandardAdapters.SECTIONS);
this.adapters.register(StandardAdapters.ENUMS);
this.adapters.register(StandardAdapters.UUID);
}
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();
}
public SELF exceptionally(@NotNull ConfigExceptionHandler handler) {
this.exceptionHandler = handler;
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));
}
/**
* Register a new annotation for {@link ValueValidator} to the configuration loader
*
* @param annotation The {@link Annotation}
* @param builder The {@link Function} to build the {@link ValueValidator} from the annotation
* @param <A> The annotation type
* @return this
*/
public <A extends Annotation> SELF validAnnotation(@NotNull Class<A> annotation,
@NotNull Function<A, ValueValidator<Object>> builder) {
return initializer(loader -> loader.registerValidAnnotation(annotation, builder));
}
/**
* Build the configuration holder.
*
* @return The configuration holder
*/
public abstract @NotNull HOLDER build();
}
@@ -0,0 +1,155 @@
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.function.ConfigExceptionHandler;
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.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;
protected @NotNull ConfigExceptionHandler exceptionHandler;
public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters,
@NotNull ConfigurationOptionHolder options,
@NotNull Map<String, ConfigurationMetaHolder> metadata,
@NotNull ConfigurationInitializer initializer) {
this(adapters, options, metadata, initializer, ConfigExceptionHandler.print());
}
public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters,
@NotNull ConfigurationOptionHolder options,
@NotNull Map<String, ConfigurationMetaHolder> metadata,
@NotNull ConfigurationInitializer initializer,
@NotNull ConfigExceptionHandler exceptionHandler) {
this.initializer = initializer;
this.adapters = adapters;
this.options = options;
this.metadata = metadata;
this.exceptionHandler = exceptionHandler;
}
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<@Nullable 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;
}
@Nullable
public <T> T deserialize(@NotNull Class<T> type, @Nullable Object source) throws Exception {
return adapters().deserialize(this, type, source);
}
@Nullable
public <T> T deserialize(@NotNull ValueType<T> type, @Nullable Object source) throws Exception {
return adapters().deserialize(this, type, source);
}
@Nullable
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) {
throwing(configClass.getName(), e);
}
}
public void initialize(@NotNull Configuration config) {
try {
initializer.initialize(this, config);
} catch (Exception e) {
throwing(config.getClass().getName(), e);
}
}
public void initialize(@NotNull ValueManifest<?, ?> value) {
value.holder(this);
}
public void throwing(@NotNull String path, @NotNull Throwable e) {
this.exceptionHandler.handle(path, e);
}
public void exceptionally(@NotNull ConfigExceptionHandler handler) {
this.exceptionHandler = handler;
}
}
@@ -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, instance) -> {
};
}
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,209 @@
package cc.carm.lib.configuration.source.loader;
import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.function.ValueValidator;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.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 <A extends Annotation> void registerValidAnnotation(@NotNull Class<A> annotation,
@NotNull Function<A, ValueValidator<Object>> builder) {
appendFieldInitializer((holder, path, field, instance) -> {
A data = field.getAnnotation(annotation);
if (data == null) return;
instance.validate((h, t) -> builder.apply(data).validate(h, t));
});
}
public @Nullable String getFieldPath(@NotNull ConfigurationHolder<?> holder, @Nullable String parentPath, @NotNull Field field) {
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) {
holder.throwing(path, e);
}
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) {
holder.throwing(path, e);
}
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) {
holder.throwing(path, e);
}
if (holder.option(StandardOptions.PRELOAD)) {
value.get(); // Preload the value by calling #get method.
}
} else if (source instanceof Configuration && object instanceof Configuration) {
// 当且仅当 源字段与字段 均为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,920 @@
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, null);
}
/**
* Get the value as a {@link Boolean} from the specified path.
*
* @param path The path to get the boolean.
* @param def The default value to return if the path does not exist.
* @return The boolean if the path exists and is a boolean, otherwise the default value.
*/
@Contract("_, !null -> !null")
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, null);
}
/**
* Get the value as a {@link Byte} from the specified path.
*
* @param path The path to get the byte.
* @param def The default value to return if the path does not exist.
* @return The byte if the path exists and is a byte, otherwise the default value.
*/
@Contract("_, !null -> !null")
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, null);
}
/**
* Get the value as a {@link Short} from the specified path.
*
* @param path The path to get the short.
* @param def The default value to return if the path does not exist.
* @return The short if the path exists and is a short, otherwise the default value.
*/
@Contract("_, !null -> !null")
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, null);
}
/**
* Get the value as a {@link Integer} from the specified path.
*
* @param path The path to get the int.
* @param def The default value to return if the path does not exist.
* @return The int if the path exists and is an int, otherwise the default value.
*/
@Contract("_, !null -> !null")
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, null);
}
/**
* Get the value as a {@link Long} from the specified path.
*
* @param path The path to get the long.
* @param def The default value to return if the path does not exist.
* @return The long if the path exists and is a long, otherwise the default value.
*/
@Contract("_, !null -> !null")
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, null);
}
/**
* Get the value as a {@link Float} from the specified path.
*
* @param path The path to get the float.
* @param def The default value to return if the path does not exist.
* @return The float if the path exists and is a float, otherwise the default value.
*/
@Contract("_, !null -> !null")
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, null);
}
/**
* Get the value as a {@link Double} from the specified path.
*
* @param path The path to get the double.
* @param def The default value to return if the path does not exist.
* @return The double if the path exists and is a double, otherwise the default value.
*/
@Contract("_, !null -> !null")
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, Character.class);
}
/**
* Get the value as a {@link Character} from the specified path.
*
* @param path The path to get the char.
* @return The char if the path exists and is a char, otherwise null.
*/
default @Nullable Character getChar(@NotNull String path) {
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 current 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 current 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 current 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 current 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 current 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 current 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 current 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 current 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 a list of {@link ConfigureSection} from current section
*
* @param path The path to get the list from
* @return The list of {@link ConfigureSection}
*/
default @NotNull List<ConfigureSection> getSectionList(@NotNull String path) {
return getList(path, obj -> {
if (obj instanceof ConfigureSection) {
return (ConfigureSection) obj;
} else if (obj instanceof Map) {
return createSection(childPath(path), (Map<?, ?>) obj);
}
return null;
});
}
/**
* Get the specific type of collection from current section.
*
* @param path The path to get the collection from
* @param constructor The constructor of the collection
* @param parser The function to parse the values
* @param <T> The type of the values
* @param <C> The type of the collection
* @return The collection of values
*/
default <T, C extends Collection<T>> @NotNull C getCollection(@NotNull String path,
@NotNull Supplier<C> constructor,
@NotNull DataFunction<Object, T> parser) {
return parseCollection(getList(path), constructor, parser);
}
/**
* Get the specific type of steam from current section.
*
* @param path The path to get the stream from
* @return The stream of values
*/
default @NotNull Stream<?> stream(@NotNull String path) {
List<?> values = getList(path);
return values == null ? Stream.empty() : values.stream();
}
/**
* Get the specific type of steam from current section.
*
* @param path The path to get the stream from
* @param parser The function to parse the values
* @param <T> The type of the values
* @return The stream of values
*/
default <T> @NotNull Stream<T> stream(@NotNull String path, @NotNull Function<Object, T> parser) {
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,153 @@
package cc.carm.lib.configuration.value;
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;
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, U> extends ValueManifest<T, U> {
protected ConfigValue(@NotNull ValueManifest<T, U> 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 getOr(defaults());
}
/**
* Gets the configured value, or returns the specified default value if not present.
*
* @param defaults The default value to return if the configured value is not present
* @return Configured value or specified default value
*/
@Contract("!null -> !null")
public T getOr(T defaults) {
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();
}
}

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