1
mirror of https://github.com/CarmJos/EasyConfiguration.git synced 2026-06-04 18:48:20 +08:00

Compare commits

..

100 Commits

Author SHA1 Message Date
carm 505b86ec9c feat(sql): Support sql based configuration provider. 2023-12-24 04:52:56 +08:00
carm 374f646f9e feat(sql): Support sql based configuration provider. 2023-12-24 04:52:28 +08:00
carm aa50345329 feat(interface): Support interface root configurations. 2023-12-23 22:25:16 +08:00
carm db8b227317 feat(interface): Support interface root configurations. 2023-12-23 22:24:34 +08:00
carm 60eed8a14d docs(readme): Add English version of README files. 2023-12-23 21:24:45 +08:00
carm d41630be72 docs(readme): Add English version of README files. 2023-12-23 21:24:15 +08:00
carm 1c3a2b01ea docs(readme): Add English version of README files. 2023-12-23 21:18:50 +08:00
carm 1ede74c692 docs(readme): Add English version of README files. 2023-12-23 21:18:20 +08:00
carm 67456a8aac docs(readme): Add English version of README files. 2023-12-23 21:17:43 +08:00
carm f422900fb5 docs(readme): Add English version of README files. 2023-12-23 21:16:00 +08:00
carm b3e0007eba docs(readme): Add English version of README files. 2023-12-23 21:15:15 +08:00
carm 89c8ec8adf fix(type): 修复部分原生类型无法转换的问题。#54 2023-12-21 20:47:13 +08:00
huanmeng_qwq e8f49bf8bc fix(core): 解决 #54 的问题 (#55) 2023-12-21 20:43:15 +08:00
dependabot[bot] 8ac980fdbb chore(deps): Bump org.apache.maven.plugins:maven-compiler-plugin (#53)
Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.11.0 to 3.12.0.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.11.0...maven-compiler-plugin-3.12.0)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-12 22:49:54 +08:00
carm 96e90dd71b chore 2022-12-11 19:10:50 +08:00
carm a9f3d829bd build(javadoc): 修复Demo项目缺失的javadoc 2022-12-11 02:30:47 +08:00
carm 8eefba5159 feat(init): 支持针对于实体类的初始化 #9 2022-12-11 02:17:30 +08:00
carm 01e20df559 feat(init): 支持针对于实体类的初始化 #9 2022-12-11 02:04:23 +08:00
carm 35398ab741 feat(init): 支持针对于实体类的初始化 #9 2022-12-11 02:02:16 +08:00
carm 6f97166192 fix(parse): 修复Number基础类型转型丢失的问题。 fix #17 2022-12-06 21:53:05 +08:00
dependabot[bot] ccd239ad6b chore(deps): Bump yamlconfiguration from 1.2.2 to 1.3.0 (#16)
Bumps [yamlconfiguration](https://github.com/bspfsystems/YamlConfiguration) from 1.2.2 to 1.3.0.
- [Release notes](https://github.com/bspfsystems/YamlConfiguration/releases)
- [Commits](https://github.com/bspfsystems/YamlConfiguration/compare/v1.2.2...v1.3.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>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-03 19:50:13 +08:00
dependabot[bot] 69b27476bc chore(deps): Bump maven-shade-plugin from 3.4.0 to 3.4.1 (#15)
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.4.0 to 3.4.1.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.4.0...maven-shade-plugin-3.4.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>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-02 18:31:07 +08:00
dependabot[bot] 0651cac6b0 chore(deps): Bump gson from 2.9.1 to 2.10 (#14)
Bumps [gson](https://github.com/google/gson) from 2.9.1 to 2.10.
- [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.9.1...gson-parent-2.10)

---
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>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-27 00:00:49 +08:00
dependabot[bot] 1a1efad283 Bump maven-shade-plugin from 3.3.0 to 3.4.0 (#11)
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.3.0...maven-shade-plugin-3.4.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>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-20 00:12:03 +08:00
dependabot[bot] 3c1ba61b61 Bump yamlconfiguration from 1.2.1 to 1.2.2 (#10)
Bumps [yamlconfiguration](https://github.com/bspfsystems/YamlConfiguration) from 1.2.1 to 1.2.2.
- [Release notes](https://github.com/bspfsystems/YamlConfiguration/releases)
- [Commits](https://github.com/bspfsystems/YamlConfiguration/compare/v1.2.1...v1.2.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>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-20 00:11:44 +08:00
dependabot[bot] 1a3e84a787 Bump maven-jar-plugin from 3.2.2 to 3.3.0 (#12)
Bumps [maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.2.2 to 3.3.0.
- [Release notes](https://github.com/apache/maven-jar-plugin/releases)
- [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.2.2...maven-jar-plugin-3.3.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>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-20 00:11:31 +08:00
carm 00228db2c4 chore(dev): 取消开发中模块的部署 2022-09-10 01:11:04 +08:00
carm 0fddfe28af feat(source): 为 ConfigurationWrapper 添加 getSource() 方法以获取源实现内容。
BREAKING-CHANGE: ConfigurationWrapper 更改为泛型类,并新增 “getSource” 方法需要实现。
2022-09-10 00:36:46 +08:00
dependabot[bot] 4a17089da0 Bump gson from 2.9.0 to 2.9.1 (#6)
Bumps [gson](https://github.com/google/gson) from 2.9.0 to 2.9.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.9.0...gson-parent-2.9.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>
2022-09-09 21:54:36 +08:00
dependabot[bot] 8faa7b1c24 Bump yamlconfiguration from 1.2.0 to 1.2.1 (#7)
Bumps [yamlconfiguration](https://github.com/bspfsystems/YamlConfiguration) from 1.2.0 to 1.2.1.
- [Release notes](https://github.com/bspfsystems/YamlConfiguration/releases)
- [Commits](https://github.com/bspfsystems/YamlConfiguration/compare/v1.2.0...v1.2.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-09-09 21:54:25 +08:00
dependabot[bot] 5e525428fe Bump maven-javadoc-plugin from 3.4.0 to 3.4.1 (#8)
Bumps [maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.4.0 to 3.4.1.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.4.0...maven-javadoc-plugin-3.4.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>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-09 21:54:16 +08:00
carm bc0dfd5698 feat(source): 为 ConfigurationWrapper 添加 getSource() 方法以获取源实现内容。
BREAKING-CHANGE: ConfigurationWrapper 更改为泛型类,并新增 “getSource” 方法需要实现。
2022-09-09 21:54:05 +08:00
carm dc28d743db feat(source): 为 ConfigurationWrapper 添加 getSource() 方法以获取源实现内容。
BREAKING-CHANGE: ConfigurationWrapper 更改为泛型类,并新增 “getSource” 方法需要实现。
2022-09-09 21:52:26 +08:00
carm f61294c5f3 feat(sql): 优化数据表结构 2022-08-11 17:43:42 +08:00
carm 6883a464db feat(sql): 添加数据库存储支持 2022-08-11 16:02:12 +08:00
carm bcdf0d9bd1 refactor(comments): 优化注释的存储方式 2022-08-11 16:01:27 +08:00
carm 5f89ff4db7 Merge remote-tracking branch 'origin/master' 2022-05-20 18:18:47 +08:00
carm d6f4970277 [3.1.0] fix(api): configuration reload problem
BREAKING CHANGES: Now we override "onReload()" method to define ConfigurationProvider how to reload the configs.

Fix the problem that when the configuration file is read, the "reload()" method not working.
2022-05-20 18:16:44 +08:00
carm c045ca1489 Merge pull request #5 from CarmJos/dependabot/maven/org.bspfsystems-yamlconfiguration-1.2.0
Bump yamlconfiguration from 1.1.0 to 1.2.0
2022-05-20 10:10:38 +08:00
dependabot[bot] ceea900b08 Bump yamlconfiguration from 1.1.0 to 1.2.0
Bumps [yamlconfiguration](https://github.com/bspfsystems/YamlConfiguration) from 1.1.0 to 1.2.0.
- [Release notes](https://github.com/bspfsystems/YamlConfiguration/releases)
- [Commits](https://github.com/bspfsystems/YamlConfiguration/compare/v1.1.0...v1.2.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>
2022-05-19 14:41:47 +00:00
carm 85bacb24f3 Merge remote-tracking branch 'origin/master' 2022-05-18 23:23:25 +08:00
carm 6b3a353fcc [3.0.0] (breaking-update) update comments usage. 2022-05-18 23:23:11 +08:00
carm 2c026fc0b0 Merge pull request #4 from CarmJos/dependabot/maven/org.bspfsystems-yamlconfiguration-1.1.0
Bump yamlconfiguration from 1.0.11 to 1.1.0
2022-04-25 22:59:37 +08:00
dependabot[bot] f8b4bbd3a9 Bump yamlconfiguration from 1.0.11 to 1.1.0
Bumps [yamlconfiguration](https://github.com/bspfsystems/YamlConfiguration) from 1.0.11 to 1.1.0.
- [Release notes](https://github.com/bspfsystems/YamlConfiguration/releases)
- [Commits](https://github.com/bspfsystems/YamlConfiguration/compare/v1.0.11...v1.1.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>
2022-04-25 14:45:52 +00:00
carm e9a0f0ff30 [ci skip] 补充README介绍 2022-04-23 21:37:25 +08:00
carm e3fe6e7c80 [ci skip] 补充README介绍 2022-04-23 21:37:18 +08:00
carm c179fa2ccd 添加部分注释 2022-04-23 20:52:08 +08:00
99 changed files with 3487 additions and 1380 deletions
+16
View File
@@ -0,0 +1,16 @@
# 欢迎使用 EasyConfiguration
这个项目刚刚创建,详细的Javadoc与开发指南还在补充,请给我一点时间~
## 基本定义
Value: 实际配置的单例值。
Manifest: 用于描述值基本配置的对象。
Provider: 用于提供配置文件的接口。
Wrapper: 用于包装配置文件的接口。
Initializer: 用于初始化的接口
-3
View File
@@ -1,3 +0,0 @@
# 欢迎使用 EasyConfiguration
这个项目刚刚创建,详细的Javadoc与开发指南还在补充,请给我一点时间~
+1 -1
View File
@@ -41,7 +41,7 @@ jobs:
rm -rf docs
mkdir -vp docs
cp -vrf core/target/apidocs/* docs/
cp -vrf .documentation/JAVADOC-README.md docs/README.md
cp -vrf .doc/JAVADOC-README.md docs/README.md
- name: "Generate the Javadoc sitemap"
id: sitemap
+58 -50
View File
@@ -1,10 +1,5 @@
```text
____ _____ ____ __ _
/ __/__ ____ __ __ / ___/__ ___ / _(_)__ ___ _________ _/ /_(_)__ ___
/ _// _ `(_-</ // / / /__/ _ \/ _ \/ _/ / _ `/ // / __/ _ `/ __/ / _ \/ _ \
/___/\_,_/___/\_, / \___/\___/_//_/_//_/\_, /\_,_/_/ \_,_/\__/_/\___/_//_/
/___/ /___/
```
README LANGUAGES [ [**English**](README.md) | [中文](README_CN.md) ]
# EasyConfiguration
@@ -15,53 +10,55 @@
![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/EasyConfiguration)
![](https://visitor-badge.glitch.me/badge?page_id=EasyConfiguration.readme)
轻松(做)配置,简单便捷的通用配置文件加载、读取与更新工具,可自定义配置格式。
**Easy _(to make)_ Configurations!**
## 优势
A simple, easy-to-use and universal solution for managing configuration files.
Enjoy the ease of use with customizable formats for loading, reading, and updating your configuration files.
- 基于类的配置文件初始化、加载、获取与更新机制,方便快捷。
## Features & Advantages
## 开发
- 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.
详细开发介绍请 [点击这里](.documentation/README.md) , JavaDoc(最新Release) 请 [点击这里](https://CarmJos.github.io/EasyConfiguration) 。
## Development
### 示例代码
For a detailed development guide, [CLICK HERE](.doc/README.md).
您可以 [点击这里](impl/yaml/src/test/java/config/source/DemoConfiguration.java) 查看部分代码演示,更多演示详见 [开发介绍](.documentation/README.md) 。
For the latest JavaDoc release, [CLICK HERE](https://CarmJos.github.io/EasyConfiguration).
### 依赖方式
### Code Samples
#### Maven 依赖
Check out some code demonstrations [HERE](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java).
For more examples, see the [Development Guide](.doc/README.md).
### Dependencies
#### Maven Dependency
<details>
<summary>远程库配置</summary>
<summary>Remote Repository Configuration</summary>
```xml
<project>
<repositories>
<repository>
<!--采用Maven中心库,安全稳定,但版本更新需要等待同步-->
<!-- Using Maven Central Repository for secure and stable updates, though synchronization might be needed. -->
<id>maven</id>
<name>Maven Central</name>
<url>https://repo1.maven.org/maven2</url>
</repository>
<repository>
<!--采用github依赖库,实时更新,但需要配置 (推荐) -->
<!-- Using GitHub dependencies for real-time updates, configuration required (recommended). -->
<id>EasyConfiguration</id>
<name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url>
</repository>
<repository>
<!--采用我的私人依赖库,简单方便,但可能因为变故而无法使用-->
<id>carm-repo</id>
<name>Carm's Repo</name>
<url>https://repo.carm.cc/repository/maven-public/</url>
</repository>
</repositories>
</project>
```
@@ -69,13 +66,12 @@
</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>
@@ -83,7 +79,7 @@
<scope>compile</scope>
</dependency>
<!--基于YAML文件的实现版本,可用于全部Java环境。-->
<!-- YAML file-based implementation, compatible with all Java environments. -->
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-yaml</artifactId>
@@ -91,68 +87,80 @@
<scope>compile</scope>
</dependency>
<!-- JSON file-based implementation, compatible with all Java environments. Note: JSON does not support file comments. -->
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-json</artifactId>
<version>[LATEST RELEASE]</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
```
</details>
#### Gradle 依赖
#### Gradle Dependency
<details>
<summary>远程库配置</summary>
<summary>Remote Repository Configuration</summary>
```groovy
repositories {
// 采用Maven中心库,安全稳定,但版本更新需要等待同步
// Using Maven Central Repository for secure and stable updates, though synchronization might be needed.
mavenCentral()
// 采用github依赖库,实时更新,但需要配置 (推荐)
// Using GitHub dependencies for real-time updates, configuration required (recommended).
maven { url 'https://maven.pkg.github.com/CarmJos/EasyConfiguration' }
// 采用我的私人依赖库,简单方便,但可能因为变故而无法使用
maven { url 'https://repo.carm.cc/repository/maven-public/' }
}
```
</details>
<details>
<summary>通用原生依赖</summary>
<summary>Generic Native Dependency</summary>
```groovy
dependencies {
//基础实现部分,需要自行实现“Provider”“Wrapper”
// Basic implementation part, requiring custom implementation of “Provider” and “Wrapper”.
api "cc.carm.lib:easyconfiguration-core:[LATEST RELEASE]"
//基于YAML文件的实现版本,可用于全部Java环境。
// YAML file-based implementation, compatible with all Java environments.
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]"
// JSON file-based implementation, compatible with all Java environments. Note: JSON does not support file comments.
api "cc.carm.lib:easyconfiguration-json:[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 相关服务器平台上轻松(做)配置吧!
Easily manage configurations on MineCraft-related server platforms.
目前支持 BungeeCord, Bukkit(Spigot) 服务端,后续将支持更多平台。
Currently supports BungeeCord, Bukkit (Spigot) servers, with more platforms to be supported soon.
## 支持与捐赠
## Support and Donation
若您觉得本插件做的不错,您可以通过捐赠支持我!
If you appreciate this plugin, consider supporting me with a donation!
感谢您对开源项目的支持!
Thank you for supporting open-source projects!
<img height=25% width=25% src="https://raw.githubusercontent.com/CarmJos/CarmJos/main/img/donate-code.jpg" alt=""/>
Many thanks to Jetbrains for kindly providing a license for us to work on this and other open-source projects.
## 开源协议
[![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/ArtformGames/ResidenceList)
本项目源码采用 [GNU LESSER GENERAL PUBLIC LICENSE](https://www.gnu.org/licenses/lgpl-3.0.html) 开源协议。
## 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).
+180
View File
@@ -0,0 +1,180 @@
```text
____ _____ ____ __ _
/ __/__ ____ __ __ / ___/__ ___ / _(_)__ ___ _________ _/ /_(_)__ ___
/ _// _ `(_-</ // / / /__/ _ \/ _ \/ _/ / _ `/ // / __/ _ `/ __/ / _ \/ _ \
/___/\_,_/___/\_, / \___/\___/_//_/_//_/\_, /\_,_/_/ \_,_/\__/_/\___/_//_/
/___/ /___/
```
README LANGUAGES [ [English](README.md) | [**中文**](README_CN.md) ]
# EasyConfiguration
[![version](https://img.shields.io/github/v/release/CarmJos/EasyConfiguration)](https://github.com/CarmJos/EasyConfiguration/releases)
[![License](https://img.shields.io/github/license/CarmJos/EasyConfiguration)](https://www.gnu.org/licenses/lgpl-3.0.html)
[![workflow](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml)
[![CodeFactor](https://www.codefactor.io/repository/github/carmjos/easyconfiguration/badge)](https://www.codefactor.io/repository/github/carmjos/easyconfiguration)
![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/EasyConfiguration)
![](https://visitor-badge.glitch.me/badge?page_id=EasyConfiguration.readme)
**轻松(做)配置!**
一款简单便捷的通用配置文件加载、读取与更新工具,可自定义配置的格式。
## 特性 & 优势
- 基于类的配置文件初始化、加载、获取与更新机制,方便快捷。
- 支持复杂配置的手动序列化、反序列化。
- 提供多种builder形式,快速构建 `ConfigValue<?>` 对象。
- 支持通过注解规定配置对应的路径、注释等信息。
## 开发
详细开发介绍请 [点击这里](.doc/README.md) , JavaDoc(最新Release) 请 [点击这里](https://CarmJos.github.io/EasyConfiguration) 。
### 示例代码
您可以 [点击这里](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java) 查看部分代码演示,更多演示详见 [开发介绍](.doc/README.md) 。
### 依赖方式
#### Maven 依赖
<details>
<summary>远程库配置</summary>
```xml
<project>
<repositories>
<repository>
<!--采用Maven中心库,安全稳定,但版本更新需要等待同步-->
<id>maven</id>
<name>Maven Central</name>
<url>https://repo1.maven.org/maven2</url>
</repository>
<repository>
<!--采用github依赖库,实时更新,但需要配置 (推荐) -->
<id>EasyConfiguration</id>
<name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url>
</repository>
<repository>
<!--采用我的私人依赖库,简单方便,但可能因为变故而无法使用-->
<id>carm-repo</id>
<name>Carm's Repo</name>
<url>https://repo.carm.cc/repository/maven-public/</url>
</repository>
</repositories>
</project>
```
</details>
<details>
<summary>通用原生依赖</summary>
```xml
<project>
<dependencies>
<!--基础实现部分,需要自行实现“Provider”与“Wrapper”。-->
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-core</artifactId>
<version>[LATEST RELEASE]</version>
<scope>compile</scope>
</dependency>
<!--基于YAML文件的实现版本,可用于全部Java环境。-->
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-yaml</artifactId>
<version>[LATEST RELEASE]</version>
<scope>compile</scope>
</dependency>
<!--基于JSON文件的实现版本,可用于全部Java环境。-->
<!--需要注意的是,JSON不支持文件注释。-->
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-json</artifactId>
<version>[LATEST RELEASE]</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
```
</details>
#### Gradle 依赖
<details>
<summary>远程库配置</summary>
```groovy
repositories {
// 采用Maven中心库,安全稳定,但版本更新需要等待同步
mavenCentral()
// 采用github依赖库,实时更新,但需要配置 (推荐)
maven { url 'https://maven.pkg.github.com/CarmJos/EasyConfiguration' }
// 采用我的私人依赖库,简单方便,但可能因为变故而无法使用
maven { url 'https://repo.carm.cc/repository/maven-public/' }
}
```
</details>
<details>
<summary>通用原生依赖</summary>
```groovy
dependencies {
//基础实现部分,需要自行实现“Provider”与“Wrapper”。
api "cc.carm.lib:easyconfiguration-core:[LATEST RELEASE]"
//基于YAML文件的实现版本,可用于全部Java环境。
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]"
//基于JSON文件的实现版本,可用于全部Java环境。
//需要注意的是,JSON不支持文件注释。
api "cc.carm.lib:easyconfiguration-json:[LATEST RELEASE]"
}
```
</details>
## 衍生项目
### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos )
EasyConfiguration for MineCraft!
开始在 MineCraft 相关服务器平台上轻松(做)配置吧!
目前支持 BungeeCord, Bukkit(Spigot) 服务端,后续将支持更多平台。
## 支持与捐赠
若您觉得本插件做的不错,您可以通过捐赠支持我!
感谢您对开源项目的支持!
万分感谢 Jetbrains 为我们提供了从事此项目和其他开源项目的许可!
[![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/ArtformGames/ResidenceList)
## 开源协议
本项目源码采用 [GNU LESSER GENERAL PUBLIC LICENSE](https://www.gnu.org/licenses/lgpl-3.0.html) 开源协议。
+5 -3
View File
@@ -5,12 +5,14 @@
<parent>
<artifactId>easyconfiguration-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>2.3.0</version>
<version>3.9.0</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>
@@ -1,18 +1,20 @@
package cc.carm.lib.configuration.core;
import cc.carm.lib.configuration.core.annotation.ConfigComment;
import cc.carm.lib.configuration.core.annotation.ConfigPath;
import cc.carm.lib.configuration.core.source.ConfigCommentInfo;
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} 对象
* 用于初始化 {@link Configuration} 中的每个 {@link ConfigValue} 对象
*
* @param <T> {@link ConfigurationProvider} 配置文件的数据来源
* @author CarmJos
@@ -28,24 +30,24 @@ public class ConfigInitializer<T extends ConfigurationProvider<?>> {
/**
* 初始化指定类以及其子类的所有 {@link ConfigValue} 对象。
*
* @param clazz 配置文件类,须继承于 {@link ConfigurationRoot} 。
* @param clazz 配置文件类,须继承于 {@link Configuration} 。
* @param saveDefaults 是否写入默认值(默认为 true)。
*/
public void initialize(@NotNull Class<? extends ConfigurationRoot> clazz, boolean saveDefaults) {
public void initialize(@NotNull Class<? extends Configuration> clazz, boolean saveDefaults) {
initialize(clazz, saveDefaults, true);
}
/**
* 初始化指定类的所有 {@link ConfigValue} 对象。
*
* @param clazz 配置文件类,须继承于 {@link ConfigurationRoot} 。
* @param clazz 配置文件类,须继承于 {@link Configuration} 。
* @param saveDefaults 是否写入默认值(默认为 true)。
* @param loadSubClasses 是否加载内部子类(默认为 true)。
*/
public void initialize(@NotNull Class<? extends ConfigurationRoot> clazz,
public void initialize(@NotNull Class<? extends Configuration> clazz,
boolean saveDefaults, boolean loadSubClasses) {
initializeClass(
clazz, null,
initializeStaticClass(
clazz, null, null,
null, null, null,
saveDefaults, loadSubClasses
);
@@ -58,70 +60,154 @@ public class ConfigInitializer<T extends ConfigurationProvider<?>> {
}
}
protected void initializeClass(@NotNull Class<?> clazz,
/**
* 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link Configuration} 对象。
*
* @param config 配置文件实例类,须实现 {@link Configuration} 。
*/
public void initialize(@NotNull Configuration config) {
initialize(config, true);
}
/**
* 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link Configuration} 对象。
*
* @param config 配置文件实例类,须实现 {@link Configuration} 。
* @param saveDefaults 是否写入默认值(默认为 true)。
*/
public void initialize(@NotNull Configuration 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 Configuration root,
@Nullable String parentPath, @Nullable String fieldName,
@Nullable ConfigPath fieldPath, @Nullable ConfigComment filedComments,
@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 (!Configuration.class.isAssignableFrom(clazz)) return; // 只解析继承了 ConfigurationRoot 的类
String path = getClassPath(clazz, parentPath, fieldName, fieldPath);
this.provider.setComment(path, getClassComments(clazz, filedComments));
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();
if (loadSubClasses && classes.length > 0) {
// 逆向加载,保持顺序。
for (int i = classes.length - 1; i >= 0; i--) {
initializeClass(
for (int i = classes.length - 1; i >= 0; i--) { // 逆向加载,保持顺序。
initializeStaticClass(
classes[i], path, classes[i].getSimpleName(),
null, null,
null, null, null,
saveDefaults, true
);
}
}
}
protected void initializeValue(@NotNull ConfigValue<?> value, @NotNull String path,
@Nullable ConfigCommentInfo comments, boolean saveDefaults) {
value.initialize(provider, saveDefaults, path, comments);
}
private void initializeField(@NotNull Class<?> source, @NotNull Field field, @Nullable String parent,
boolean saveDefaults, boolean loadSubClasses) {
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),
ConfigCommentInfo.fromAnnotation(field.getAnnotation(ConfigComment.class)),
field.getAnnotation(HeaderComment.class),
field.getAnnotation(InlineComment.class),
saveDefaults
);
} else if (object instanceof Class<?>) {
initializeClass(
} else if (source instanceof Configuration && object instanceof Configuration) {
// 当且仅当 源字段与字段 均为ConfigurationRoot实例时,才对目标字段进行下一步初始化加载。
initializeInstance(
(Configuration) 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(ConfigComment.class),
field.getAnnotation(HeaderComment.class),
field.getAnnotation(InlineComment.class),
saveDefaults, loadSubClasses
);
}
// 以上判断实现以下规范:
// - 实例类中仅加载 ConfigValue实例 与 ConfigurationRoot实例
// - 静态类中仅加载 静态ConfigValue实例 与 静态ConfigurationRoot类
} catch (IllegalAccessException ignored) {
}
}
protected void setComments(@Nullable String path, @Nullable ConfigCommentInfo comments) {
if (comments != null) this.provider.setComment(path, comments);
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 ConfigCommentInfo getClassComments(@NotNull Class<?> clazz,
@Nullable ConfigComment fieldAnnotation) {
ConfigCommentInfo classComments = ConfigCommentInfo.fromAnnotation(clazz.getAnnotation(ConfigComment.class));
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;
return ConfigCommentInfo.fromAnnotation(fieldAnnotation);
else return readHeaderComments(fieldAnnotation);
}
protected static @Nullable String getClassPath(@NotNull Class<?> clazz,
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) {
@@ -129,6 +215,7 @@ public class ConfigInitializer<T extends ConfigurationProvider<?>> {
boolean fromRoot = false;
// 先获取 Class 对应的路径注解 其优先度最高。
if (clazz != null) {
ConfigPath clazzAnnotation = clazz.getAnnotation(ConfigPath.class);
if (clazzAnnotation != null) {
fromRoot = clazzAnnotation.root();
@@ -136,6 +223,7 @@ public class ConfigInitializer<T extends ConfigurationProvider<?>> {
return (fromRoot ? "" : parent) + clazzAnnotation.value();
}
}
}
if (fieldAnnotation != null) {
fromRoot = fromRoot || fieldAnnotation.root();
@@ -0,0 +1,8 @@
package cc.carm.lib.configuration.core;
/**
* The root interface of the configuration file interfaces,
* which is used to label and record the configuration information.
*/
public interface Configuration {
}
@@ -1,7 +1,8 @@
package cc.carm.lib.configuration.core;
/**
* 配置文件类的根节点,用于标注该类用于记录配置文件中的配置信息。
* The root node of the configuration file class,
* which is used to label and record the configuration information.
*/
public abstract class ConfigurationRoot {
public abstract class ConfigurationRoot implements Configuration {
}
@@ -1,45 +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;
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ConfigComment {
@NotNull
String[] value() default "";
/**
* 首行换行,即会在注释开始前进行一次换行,与上方配置分离,优化观感。
* 如:
* <blockquote><pre>
* some-key: "SomeValue"
*
* # 注释第一行
* # 注释第二行
* startWrap: true
* </pre></blockquote>
*
* @return 是否在结尾添加换行符
*/
boolean startWrap() default true;
/**
* 末尾换行,即会在注释结束后进行一次换行,如:
* <blockquote><pre>
* # 注释第一行
* # 注释第二行
*
* endWrap: true
* </pre></blockquote>
* <p> 该功能可用于编写配置文件的顶部注释。
*
* @return 是否在结尾添加换行符
*/
boolean endWrap() default false;
}
@@ -0,0 +1,39 @@
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;
/**
* 顶部注释,用于给对应配置的顶部添加注释,便于使用者阅读查看。
* <p>如:
* <blockquote><pre>
* # 注释第一行
* # 注释第二行
* foo: "bar"
* </pre></blockquote>
*/
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface HeaderComment {
/**
* 注释内容,若内容长度为0则会视为一个空行。
* <p> 如 <b>{"foo","","bar"}</b>
* 会被添加为
* <blockquote><pre>
* # foo
*
* # bar
* foo: "bar"
* </pre></blockquote>
*
* @return 注释内容
*/
@NotNull
String[] value() default "";
}
@@ -0,0 +1,33 @@
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,11 +1,15 @@
package cc.carm.lib.configuration.core.builder;
import cc.carm.lib.configuration.core.source.ConfigCommentInfo;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.value.ValueManifest;
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;
import java.util.function.Supplier;
public abstract class AbstractConfigBuilder<T, B extends AbstractConfigBuilder<T, B, P>, P extends ConfigurationProvider<?>> {
protected final Class<? super P> providerClass;
@@ -13,9 +17,8 @@ public abstract class AbstractConfigBuilder<T, B extends AbstractConfigBuilder<T
protected @Nullable P provider;
protected @Nullable String path;
protected @NotNull String[] comments = new String[0];
protected boolean startWrap = true;
protected boolean endWrap = false;
protected @Nullable List<String> headerComments;
protected @Nullable String inlineComment;
protected @Nullable T defaultValue;
@@ -38,38 +41,37 @@ public abstract class AbstractConfigBuilder<T, B extends AbstractConfigBuilder<T
}
public @NotNull B comments(@NotNull String... comments) {
this.comments = 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 setStartWarp(boolean enable) {
this.startWrap = enable;
public @NotNull B inlineComment(@NotNull String comment) {
this.inlineComment = comment;
return getThis();
}
public @NotNull B startWarp() {
return setStartWarp(true);
}
public @NotNull B setEndWarp(boolean enable) {
this.endWrap = enable;
return getThis();
}
public @NotNull B endWarp() {
return setEndWarp(true);
}
public @NotNull B defaults(@Nullable T defaultValue) {
this.defaultValue = defaultValue;
return getThis();
}
protected @Nullable ConfigCommentInfo buildComments() {
ConfigCommentInfo info = ConfigCommentInfo.of(this.comments, this.startWrap, this.endWrap);
if (info.equals(ConfigCommentInfo.defaults())) return null;
else return info;
public @NotNull B defaults(@NotNull Supplier<@Nullable T> defaultValueSupplier) {
return defaults(defaultValueSupplier.get());
}
protected @NotNull ValueManifest<T> buildManifest() {
return ValueManifest.of(
this.provider, this.path,
this.headerComments, this.inlineComment, this.defaultValue
);
}
}
@@ -2,6 +2,7 @@ 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.map.ConfigMapCreator;
import cc.carm.lib.configuration.core.builder.value.ConfigValueBuilder;
import org.jetbrains.annotations.NotNull;
@@ -19,24 +20,24 @@ public class ConfigBuilder {
return new ConfigListBuilder<>(valueClass);
}
public <K, V> @NotNull ConfigMapBuilder<LinkedHashMap<K, V>, K, V> asMap(@NotNull Class<K> keyClass,
public <K, V> @NotNull ConfigMapCreator<K, V> asMap(@NotNull Class<K> keyClass,
@NotNull Class<V> valueClass) {
return new ConfigMapBuilder<>(LinkedHashMap::new, keyClass, valueClass);
return new ConfigMapCreator<>(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);
return asMap(keyClass, valueClass).asHashMap();
}
public <K, V> @NotNull ConfigMapBuilder<LinkedHashMap<K, V>, K, V> asLinkedMap(@NotNull Class<K> keyClass,
@NotNull Class<V> valueClass) {
return asMap(keyClass, valueClass);
return asMap(keyClass, valueClass).asLinkedMap();
}
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);
return asMap(keyClass, valueClass).asTreeMap();
}
}
@@ -3,6 +3,9 @@ package cc.carm.lib.configuration.core.builder.list;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public class ConfigListBuilder<V> {
protected final @NotNull Class<V> valueClass;
@@ -11,7 +14,7 @@ public class ConfigListBuilder<V> {
this.valueClass = valueClass;
}
public @NotNull <S> SourceListBuilder<S, V> from(@NotNull Class<S> sourceClass,
public @NotNull <S> SourceListBuilder<S, V> from(@NotNull Class<? super S> sourceClass,
@NotNull ConfigDataFunction<Object, S> sourceParser,
@NotNull ConfigDataFunction<S, V> valueParser,
@NotNull ConfigDataFunction<V, S> valueSerializer,
@@ -43,4 +46,13 @@ public class ConfigListBuilder<V> {
);
}
public @NotNull SourceListBuilder<Map<String, Object>, V> fromMap() {
return from(
Map.class, obj -> (Map<String, Object>) obj,
ConfigDataFunction.required(),
ConfigDataFunction.required(),
ConfigDataFunction.toObject()
);
}
}
@@ -7,11 +7,12 @@ import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
public class SourceListBuilder<S, V> extends CommonConfigBuilder<List<V>, SourceListBuilder<S, V>> {
protected final @NotNull Class<S> sourceClass;
protected final @NotNull Class<? super S> sourceClass;
protected @NotNull ConfigDataFunction<Object, S> sourceParser;
protected final @NotNull Class<V> valueClass;
@@ -20,7 +21,7 @@ public class SourceListBuilder<S, V> extends CommonConfigBuilder<List<V>, Source
protected @NotNull ConfigDataFunction<V, S> valueSerializer;
protected @NotNull ConfigDataFunction<S, Object> sourceSerializer;
public SourceListBuilder(@NotNull Class<S> sourceClass, @NotNull ConfigDataFunction<Object, S> sourceParser,
public SourceListBuilder(@NotNull Class<? super 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) {
@@ -37,6 +38,10 @@ public class SourceListBuilder<S, V> extends CommonConfigBuilder<List<V>, Source
return defaults(new ArrayList<>(Arrays.asList(values)));
}
public final @NotNull SourceListBuilder<S, V> defaults(@NotNull Collection<V> values) {
return defaults(new ArrayList<>(values));
}
public @NotNull SourceListBuilder<S, V> parseSource(ConfigDataFunction<Object, S> sourceParser) {
this.sourceParser = sourceParser;
return this;
@@ -65,8 +70,7 @@ public class SourceListBuilder<S, V> extends CommonConfigBuilder<List<V>, Source
@Override
public @NotNull ConfiguredList<V> build() {
return new ConfiguredList<>(
this.provider, this.path, this.buildComments(),
this.valueClass, this.defaultValue,
buildManifest(), this.valueClass,
this.sourceParser.andThen(this.valueParser),
this.valueSerializer.andThen(sourceSerializer)
);
@@ -48,6 +48,14 @@ public class ConfigMapBuilder<M extends Map<K, V>, K, V> {
return fromString(ConfigDataFunction.castFromString(this.valueClass));
}
public SectionMapBuilder<M, K, V> fromSection() {
return new SectionMapBuilder<>(
supplier,
keyClass, ConfigDataFunction.castFromString(keyClass),
valueClass, ConfigDataFunction.required(),
ConfigDataFunction.castToString(), ConfigDataFunction.required());
}
public SourceMapBuilder<M, Object, K, V> fromObject(@NotNull ConfigDataFunction<Object, V> valueParser) {
return from(Object.class, valueParser, ConfigDataFunction.toObject());
}
@@ -0,0 +1,37 @@
package cc.carm.lib.configuration.core.builder.map;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Supplier;
public class ConfigMapCreator<K, V> {
protected final @NotNull Class<K> keyClass;
protected final @NotNull Class<V> valueClass;
public ConfigMapCreator(@NotNull Class<K> keyClass, @NotNull Class<V> valueClass) {
this.keyClass = keyClass;
this.valueClass = valueClass;
}
public <M extends Map<K, V>> @NotNull ConfigMapBuilder<M, K, V> asMap(Supplier<M> mapSuppler) {
return new ConfigMapBuilder<>(mapSuppler, keyClass, valueClass);
}
public @NotNull ConfigMapBuilder<HashMap<K, V>, K, V> asHashMap() {
return asMap(HashMap::new);
}
public @NotNull ConfigMapBuilder<LinkedHashMap<K, V>, K, V> asLinkedMap() {
return asMap(LinkedHashMap::new);
}
public @NotNull ConfigMapBuilder<TreeMap<K, V>, K, V> asTreeMap() {
return asMap(TreeMap::new);
}
}
@@ -0,0 +1,99 @@
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.source.ConfigurationWrapper;
import cc.carm.lib.configuration.core.value.ValueManifest;
import cc.carm.lib.configuration.core.value.type.ConfiguredSectionMap;
import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class SectionMapBuilder<M extends Map<K, V>, K, V> extends CommonConfigBuilder<M, SectionMapBuilder<M, 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<V> valueClass;
protected @NotNull ConfigDataFunction<ConfigurationWrapper<?>, V> valueParser;
protected @NotNull ConfigDataFunction<K, String> keySerializer;
protected @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> valueSerializer;
public SectionMapBuilder(@NotNull Supplier<@NotNull M> supplier,
@NotNull Class<K> keyClass, @NotNull ConfigDataFunction<String, K> keyParser,
@NotNull Class<V> valueClass, @NotNull ConfigDataFunction<ConfigurationWrapper<?>, V> valueParser,
@NotNull ConfigDataFunction<K, String> keySerializer,
@NotNull ConfigDataFunction<V, ? extends Map<String, Object>> valueSerializer) {
this.supplier = supplier;
this.keyClass = keyClass;
this.keyParser = keyParser;
this.valueClass = valueClass;
this.valueParser = valueParser;
this.keySerializer = keySerializer;
this.valueSerializer = valueSerializer;
}
public <MAP extends Map<K, V>> SectionMapBuilder<MAP, K, V> supplier(@NotNull Supplier<MAP> supplier) {
return new SectionMapBuilder<>(supplier,
keyClass, keyParser, valueClass, valueParser, keySerializer, valueSerializer
);
}
public @NotNull SectionMapBuilder<M, K, V> defaults(@NotNull Consumer<M> factory) {
M map = supplier.get();
factory.accept(map);
return defaults(map);
}
public @NotNull SectionMapBuilder<M, K, V> parseKey(@NotNull ConfigDataFunction<String, K> parser) {
this.keyParser = parser;
return this;
}
public @NotNull SectionMapBuilder<M, K, V> parseValue(@NotNull ConfigDataFunction<ConfigurationWrapper<?>, V> parser) {
this.valueParser = parser;
return this;
}
public @NotNull SectionMapBuilder<M, K, V> serializeKey(@NotNull ConfigDataFunction<K, String> serializer) {
this.keySerializer = serializer;
return this;
}
public @NotNull SectionMapBuilder<M, K, V> serializeValue(@NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer) {
this.valueSerializer = serializer;
return this;
}
public @NotNull SectionMapBuilder<M, K, V> serializeValue(@NotNull BiConsumer<V, Map<String, Object>> serializer) {
return serializeValue(v -> {
Map<String, Object> map = new LinkedHashMap<>();
serializer.accept(v, map);
return map;
});
}
@Override
protected @NotNull SectionMapBuilder<M, K, V> getThis() {
return this;
}
@Override
public @NotNull ConfiguredSectionMap<K, V> build() {
return new ConfiguredSectionMap<>(
new ValueManifest<>(provider, path, headerComments, inlineComment, defaultValue),
this.supplier, this.keyClass, this.keyParser,
this.valueClass, this.valueParser,
this.keySerializer, this.valueSerializer
);
}
}
@@ -2,10 +2,12 @@ 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.ValueManifest;
import cc.carm.lib.configuration.core.value.type.ConfiguredMap;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class SourceMapBuilder<M extends Map<K, V>, S, K, V> extends CommonConfigBuilder<M, SourceMapBuilder<M, S, K, V>> {
@@ -51,6 +53,12 @@ public class SourceMapBuilder<M extends Map<K, V>, S, K, V> extends CommonConfig
);
}
public @NotNull SourceMapBuilder<M, S, K, V> defaults(@NotNull Consumer<M> factory) {
M map = supplier.get();
factory.accept(map);
return defaults(map);
}
public @NotNull SourceMapBuilder<M, S, K, V> parseKey(@NotNull ConfigDataFunction<String, K> parser) {
this.keyParser = parser;
return this;
@@ -89,9 +97,8 @@ public class SourceMapBuilder<M extends Map<K, V>, S, K, V> extends CommonConfig
@Override
public @NotNull ConfiguredMap<K, V> build() {
return new ConfiguredMap<>(
this.provider, this.path,this.buildComments(),
this.defaultValue, this.supplier,
this.keyClass, this.keyParser,
new ValueManifest<>(provider, path, headerComments, inlineComment, defaultValue),
this.supplier, this.keyClass, this.keyParser,
this.valueClass, this.sourceParser.andThen(this.valueParser),
this.keySerializer, this.valueSerializer.andThen(this.sourceSerializer)
);
@@ -19,7 +19,7 @@ public class ConfigValueBuilder<V> {
return fromSection(ConfigValueParser.required(), ConfigDataFunction.required());
}
public @NotNull SectionValueBuilder<V> fromSection(@NotNull ConfigValueParser<ConfigurationWrapper, V> valueParser,
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);
}
@@ -46,7 +46,10 @@ public class ConfigValueBuilder<V> {
return from(
Object.class, ConfigDataFunction.identity(),
ConfigValueParser.castObject(valueClass),
ConfigDataFunction.toObject(), ConfigDataFunction.toObject()
s -> {
if (s instanceof Enum<?>) return ((Enum<?>) s).name();
else return s;
}, ConfigDataFunction.toObject()
);
}
@@ -15,11 +15,11 @@ public class SectionValueBuilder<V>
protected final @NotNull Class<V> valueClass;
protected @NotNull ConfigValueParser<ConfigurationWrapper, V> parser;
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 ConfigValueParser<ConfigurationWrapper<?>, V> parser,
@NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer) {
this.valueClass = valueClass;
this.parser = parser;
@@ -32,7 +32,11 @@ public class SectionValueBuilder<V>
return this;
}
public @NotNull SectionValueBuilder<V> parseValue(ConfigValueParser<ConfigurationWrapper, V> valueParser) {
public @NotNull SectionValueBuilder<V> parseValue(ConfigDataFunction<ConfigurationWrapper<?>, V> valueParser) {
return parseValue((section, path) -> valueParser.parse(section));
}
public @NotNull SectionValueBuilder<V> parseValue(ConfigValueParser<ConfigurationWrapper<?>, V> valueParser) {
this.parser = valueParser;
return this;
}
@@ -44,11 +48,7 @@ public class SectionValueBuilder<V>
@Override
public @NotNull ConfiguredSection<V> build() {
return new ConfiguredSection<>(
this.provider, this.path,this.buildComments(),
this.valueClass, this.defaultValue,
this.parser, this.serializer
);
return new ConfiguredSection<>(buildManifest(), this.valueClass, this.parser, this.serializer);
}
}
@@ -3,7 +3,6 @@ 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.ConfigCommentInfo;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
import org.jetbrains.annotations.NotNull;
@@ -40,6 +39,10 @@ public class SourceValueBuilder<S, V> extends CommonConfigBuilder<V, SourceValue
return this;
}
public @NotNull SourceValueBuilder<S, V> parseValue(ConfigDataFunction<S, V> valueParser) {
return parseValue((section, path) -> valueParser.parse(section));
}
public @NotNull SourceValueBuilder<S, V> parseValue(@NotNull ConfigValueParser<S, V> valueParser) {
this.valueParser = valueParser;
return this;
@@ -58,8 +61,7 @@ public class SourceValueBuilder<S, V> extends CommonConfigBuilder<V, SourceValue
@Override
public @NotNull ConfiguredValue<V> build() {
return new ConfiguredValue<>(
this.provider, this.path, this.buildComments(),
this.valueClass, this.defaultValue,
buildManifest(), this.valueClass,
this.valueParser.compose(this.sourceParser),
this.valueSerializer.andThen(sourceSerializer)
);
@@ -13,34 +13,34 @@ public interface ConfigDataFunction<T, R> {
default <V> @NotNull ConfigDataFunction<T, V> andThen(@NotNull ConfigDataFunction<? super R, V> after) {
Objects.requireNonNull(after);
return ((data) -> after.parse(parse(data)));
return data -> after.parse(parse(data));
}
@Contract(pure = true)
static <T> @NotNull ConfigDataFunction<T, T> identity() {
return (input) -> input;
return input -> input;
}
@Contract(pure = true)
static <T> @NotNull ConfigDataFunction<T, T> identity(Class<T> type) {
return (input) -> input;
return input -> input;
}
@Contract(pure = true)
static <T, V> @NotNull ConfigDataFunction<T, V> required() {
return (input) -> {
return input -> {
throw new IllegalArgumentException("Please specify the value parser.");
};
}
@Contract(pure = true)
static <T> @NotNull ConfigDataFunction<T, Object> toObject() {
return (input) -> input;
return input -> input;
}
@Contract(pure = true)
static <V> @NotNull ConfigDataFunction<Object, V> castObject(Class<V> valueClass) {
return (input) -> {
return input -> {
if (valueClass.isInstance(input)) return valueClass.cast(input);
else throw new IllegalArgumentException("Cannot cast value to " + valueClass.getName());
};
@@ -48,7 +48,7 @@ public interface ConfigDataFunction<T, R> {
@Contract(pure = true)
static <V> @NotNull ConfigDataFunction<String, V> castFromString(Class<V> valueClass) {
return (input) -> {
return input -> {
if (valueClass.isInstance(input)) return valueClass.cast(input);
else throw new IllegalArgumentException("Cannot cast string to " + valueClass.getName());
};
@@ -56,12 +56,101 @@ public interface ConfigDataFunction<T, R> {
@Contract(pure = true)
static <T> @NotNull ConfigDataFunction<T, String> castToString() {
return (input) -> {
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 ConfigDataFunction<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 ConfigDataFunction<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 ConfigDataFunction<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 ConfigDataFunction<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 ConfigDataFunction<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 ConfigDataFunction<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 ConfigDataFunction<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 ConfigDataFunction<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());
};
}
}
@@ -50,6 +50,27 @@ public interface ConfigValueParser<T, R> {
@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) || long.class.isAssignableFrom(valueClass)) {
input = longValue().parse(input, (Long) defaultValue);
} else if (Integer.class.isAssignableFrom(valueClass) || int.class.isAssignableFrom(valueClass)) {
input = intValue().parse(input, (Integer) defaultValue);
} else if (Float.class.isAssignableFrom(valueClass) || float.class.isAssignableFrom(valueClass)) {
input = floatValue().parse(input, (Float) defaultValue);
} else if (Double.class.isAssignableFrom(valueClass) || double.class.isAssignableFrom(valueClass)) {
input = doubleValue().parse(input, (Double) defaultValue);
} else if (Byte.class.isAssignableFrom(valueClass) || byte.class.isAssignableFrom(valueClass)) {
input = byteValue().parse(input, (Byte) defaultValue);
} else if (Short.class.isAssignableFrom(valueClass) || short.class.isAssignableFrom(valueClass)) {
input = shortValue().parse(input, (Short) defaultValue);
}
} else if (Boolean.class.isAssignableFrom(valueClass) || boolean.class.isAssignableFrom(valueClass)) {
input = booleanValue().parse(input, (Boolean) defaultValue);
} else if (Enum.class.isAssignableFrom(valueClass) && input instanceof String) {
String enumName = (String) input;
input = valueClass.getDeclaredMethod("valueOf", String.class).invoke(null, enumName);
}
if (valueClass.isInstance(input)) return valueClass.cast(input);
else throw new IllegalArgumentException("Cannot cast value to " + valueClass.getName());
};
@@ -71,91 +92,53 @@ public interface ConfigValueParser<T, R> {
};
}
@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());
};
return (input, defaultValue) -> ConfigDataFunction.intValue().parse(input);
}
@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());
};
return (input, defaultValue) -> ConfigDataFunction.shortValue().parse(input);
}
@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());
};
return (input, defaultValue) -> ConfigDataFunction.doubleValue().parse(input);
}
@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());
};
return (input, defaultValue) -> ConfigDataFunction.byteValue().parse(input);
}
@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());
};
return (input, defaultValue) -> ConfigDataFunction.floatValue().parse(input);
}
@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());
};
return (input, defaultValue) -> ConfigDataFunction.longValue().parse(input);
}
@Contract(pure = true)
static @NotNull ConfigValueParser<Object, Boolean> booleanValue() {
return (input, defaultValue) -> ConfigDataFunction.booleanValue().parse(input);
}
@Contract(pure = true)
static @NotNull <E extends Enum<E>> ConfigValueParser<Object, E> enumValue(Class<E> enumClass) {
return (input, defaultValue) -> {
if (input instanceof Boolean) {
return (Boolean) input;
if (input instanceof Enum) {
return enumClass.cast(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());
return Enum.valueOf(enumClass, (String) input);
} else if (input instanceof Number) {
return enumClass.getEnumConstants()[((Number) input).intValue()];
} else {
throw new IllegalArgumentException("Cannot cast value to " + enumClass.getName());
}
};
}
@@ -1,80 +0,0 @@
package cc.carm.lib.configuration.core.source;
import cc.carm.lib.configuration.core.annotation.ConfigComment;
import cc.carm.lib.configuration.core.value.ConfigValue;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;
public class ConfigCommentInfo {
public static @NotNull ConfigCommentInfo DEFAULT_INFO = of(new String[0], true, false);
protected final @NotNull String[] comments;
protected final boolean startWrap;
protected final boolean endWrap;
public ConfigCommentInfo(@NotNull String[] comments, boolean startWrap, boolean endWrap) {
this.comments = comments;
this.startWrap = startWrap;
this.endWrap = endWrap;
}
public @NotNull String[] getComments() {
return comments;
}
public boolean endWrap() {
return endWrap;
}
public boolean startWrap() {
return startWrap;
}
public static @NotNull ConfigCommentInfo of(@NotNull String[] comments, boolean startWrap, boolean endWrap) {
return new ConfigCommentInfo(comments, startWrap, endWrap);
}
public static @NotNull ConfigCommentInfo defaults() {
return DEFAULT_INFO;
}
@Contract("!null->!null")
public static @Nullable ConfigCommentInfo fromAnnotation(@Nullable ConfigComment comment) {
if (comment == null) return null;
else return new ConfigCommentInfo(comment.value(), comment.startWrap(), comment.endWrap());
}
public static @NotNull ConfigCommentInfo fromValue(@NotNull ConfigValue<?> value) {
return Optional.ofNullable(value.getComments()).orElse(defaults());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ConfigCommentInfo that = (ConfigCommentInfo) o;
return startWrap == that.startWrap && endWrap == that.endWrap && Arrays.equals(getComments(), that.getComments());
}
@Override
public int hashCode() {
int result = Objects.hash(startWrap, endWrap);
result = 31 * result + Arrays.hashCode(getComments());
return result;
}
@Override
public String toString() {
return "ConfigCommentInfo{" +
"comments=" + Arrays.toString(comments) +
", startWrap=" + startWrap +
", endWrap=" + endWrap +
'}';
}
}
@@ -0,0 +1,51 @@
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 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,48 +1,151 @@
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.Configuration;
import cc.carm.lib.configuration.core.Configuration;
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;
public abstract class ConfigurationProvider<W extends ConfigurationWrapper> {
import java.util.List;
import java.util.Optional;
/**
* 配置文件提供者,用于为 {@link ConfigValue} 提供配置文件的源,以便实现读取、保存等操作。
*
* @param <W> 配置文件的原生功能类
*/
public abstract class ConfigurationProvider<W extends ConfigurationWrapper<?>> {
protected long updateTime;
public ConfigurationProvider() {
protected ConfigurationProvider() {
this.updateTime = System.currentTimeMillis();
}
/**
* 得到配置文件的更新(最后加载)时间。
*
* @return 更新时间
*/
public long getUpdateTime() {
return updateTime;
}
/**
* 用于 {@link CachedConfigValue} 判断缓存值是否过期(即缓存的时间早于配置文件的最后加载时间)。
*
* @param time 缓存值时的时间戳
* @return 缓存值是否过期
*/
public boolean isExpired(long time) {
return this.updateTime > time;
return getUpdateTime() > time;
}
/**
* 得到配置文件的原生功能类。
*
* @return 原生类
*/
public abstract @NotNull W getConfiguration();
public abstract void reload() throws Exception;
/**
* 重载当前配置文件。(将不会保存已修改的内容)
*
* @throws Exception 当重载出现错误时抛出
*/
public void reload() throws Exception {
onReload(); // 调用重写的Reload方法
this.updateTime = System.currentTimeMillis();
}
/**
* 将当前对配置文件的更改进行保存。
*
* @throws Exception 当保存出现错误时抛出
*/
public abstract void save() throws Exception;
public abstract void setComment(@Nullable String path, @Nullable ConfigCommentInfo comment);
/**
* 针对于不同配置文件类型所执行的重载操作。
*
* @throws Exception 当操作出现错误时抛出。
*/
protected abstract void onReload() throws Exception;
public abstract @Nullable ConfigCommentInfo getComment(@Nullable String path);
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();
public void initialize(Class<? extends ConfigurationRoot> configClazz) {
/**
* 初始化指定类以及其子类的所有 {@link ConfigValue} 对象。
*
* @param configClazz 配置文件类,须继承于 {@link Configuration} 。
*/
public void initialize(Class<? extends Configuration> configClazz) {
initialize(configClazz, true);
}
public void initialize(Class<? extends ConfigurationRoot> configClazz, boolean saveDefaults) {
getInitializer().initialize(configClazz, saveDefaults);
/**
* 初始化指定类以及其子类的所有 {@link ConfigValue} 对象。
*
* @param configClazz 配置文件类,须继承于 {@link Configuration} 。
* @param saveDefaults 是否写入默认值(默认为 true)。
*/
public void initialize(Class<? extends Configuration> configClazz, boolean saveDefaults) {
this.getInitializer().initialize(configClazz, saveDefaults);
}
public void initialize(Class<? extends ConfigurationRoot> configClazz, boolean saveDefaults, boolean loadSubClasses) {
getInitializer().initialize(configClazz, saveDefaults, loadSubClasses);
/**
* 初始化指定类的所有 {@link ConfigValue} 对象。
*
* @param configClazz 配置文件类,须继承于 {@link Configuration} 。
* @param saveDefaults 是否写入默认值(默认为 true)。
* @param loadSubClasses 是否加载内部子类(默认为 true)。
*/
public void initialize(Class<? extends Configuration> configClazz, boolean saveDefaults, boolean loadSubClasses) {
this.getInitializer().initialize(configClazz, saveDefaults, loadSubClasses);
}
/**
* 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link Configuration} 对象。
*
* @param config 配置文件实例类,须实现 {@link Configuration} 。
*/
public void initialize(@NotNull Configuration config) {
this.getInitializer().initialize(config, true);
}
/**
* 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link Configuration} 对象。
*
* @param config 配置文件实例类,须实现 {@link Configuration} 。
* @param saveDefaults 是否写入默认值(默认为 true)。
*/
public void initialize(@NotNull Configuration config, boolean saveDefaults) {
this.getInitializer().initialize(config, saveDefaults);
}
}
@@ -4,10 +4,15 @@ 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();
ConfigurationWrapper<?> getWrapper();
default boolean isBoolean(@NotNull String path) {
return getWrapper().isType(path, Boolean.class);
@@ -26,7 +31,6 @@ interface ConfigurationReader {
return getWrapper().isType(path, Byte.class);
}
default @Nullable Byte getByte(@NotNull String path) {
return getByte(path, (byte) 0);
}
@@ -36,12 +40,10 @@ interface ConfigurationReader {
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);
}
@@ -56,7 +58,6 @@ interface ConfigurationReader {
return getWrapper().isType(path, Integer.class);
}
default @Nullable Integer getInt(@NotNull String path) {
return getInt(path, 0);
}
@@ -71,7 +72,6 @@ interface ConfigurationReader {
return getWrapper().isType(path, Long.class);
}
default @Nullable Long getLong(@NotNull String path) {
return getLong(path, 0L);
}
@@ -86,7 +86,6 @@ interface ConfigurationReader {
return getWrapper().isType(path, Float.class);
}
default @Nullable Float getFloat(@NotNull String path) {
return getFloat(path, 0.0F);
}
@@ -101,7 +100,6 @@ interface ConfigurationReader {
return getWrapper().isType(path, Double.class);
}
default @Nullable Double getDouble(@NotNull String path) {
return getDouble(path, 0.0D);
}
@@ -116,7 +114,6 @@ interface ConfigurationReader {
return getWrapper().isType(path, Boolean.class);
}
default @Nullable Character getChar(@NotNull String path) {
return getChar(path, null);
}
@@ -140,5 +137,58 @@ interface ConfigurationReader {
return getWrapper().get(path, def, String.class);
}
default <V> @NotNull List<V> getList(@NotNull String path, @NotNull ConfigValueParser<Object, V> parser) {
return parseList(getWrapper().getList(path), parser);
}
@Unmodifiable
default @NotNull List<String> getStringList(@NotNull String path) {
return getList(path, ConfigValueParser.castToString());
}
@Unmodifiable
default @NotNull List<Integer> getIntegerList(@NotNull String path) {
return getList(path, ConfigValueParser.intValue());
}
@Unmodifiable
default @NotNull List<Long> getLongList(@NotNull String path) {
return getList(path, ConfigValueParser.longValue());
}
@Unmodifiable
default @NotNull List<Double> getDoubleList(@NotNull String path) {
return getList(path, ConfigValueParser.doubleValue());
}
@Unmodifiable
default @NotNull List<Float> getFloatList(@NotNull String path) {
return getList(path, ConfigValueParser.floatValue());
}
@Unmodifiable
default @NotNull List<Byte> getByteList(@NotNull String path) {
return getList(path, ConfigValueParser.byteValue());
}
@Unmodifiable
default @NotNull List<Character> getCharList(@NotNull String path) {
return 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;
}
}
@@ -9,13 +9,15 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
public interface ConfigurationWrapper extends ConfigurationReader {
public interface ConfigurationWrapper<S> extends ConfigurationReader {
@Override
default ConfigurationWrapper getWrapper() {
default ConfigurationWrapper<S> getWrapper() {
return this;
}
@NotNull S getSource();
@NotNull
Set<String> getKeys(boolean deep);
@@ -66,6 +68,6 @@ public interface ConfigurationWrapper extends ConfigurationReader {
boolean isConfigurationSection(@NotNull String path);
@Nullable
ConfigurationWrapper getConfigurationSection(@NotNull String path);
ConfigurationWrapper<S> getConfigurationSection(@NotNull String path);
}
@@ -5,16 +5,20 @@ import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.util.Objects;
public abstract class FileConfigProvider<W extends ConfigurationWrapper> extends ConfigurationProvider<W> {
public abstract class FileConfigProvider<W extends ConfigurationWrapper<?>> extends ConfigurationProvider<W> {
protected final @NotNull File file;
public FileConfigProvider(@NotNull File file) {
protected FileConfigProvider(@NotNull File file) {
this.file = file;
}
@@ -37,39 +41,35 @@ public abstract class FileConfigProvider<W extends ConfigurationWrapper> extends
if (sourcePath != null) {
try {
saveResource(sourcePath, true);
} catch (Exception ignored) {
} catch (IllegalArgumentException ignored) {
}
}
}
public void saveResource(@NotNull String resourcePath, boolean replace)
throws NullPointerException, IOException, IllegalArgumentException {
throws IOException, IllegalArgumentException {
Objects.requireNonNull(resourcePath, "ResourcePath cannot be null");
if (resourcePath.equals("")) throw new IllegalArgumentException("ResourcePath cannot be empty");
if (resourcePath.isEmpty()) 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");
URL url = this.getClass().getClassLoader().getResource(resourcePath);
if (url == 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)));
File outDir = file.getParentFile();
if (!outDir.exists() && !outDir.mkdirs()) throw new IOException("Failed to create directory " + outDir);
if (!file.exists() || replace) {
try {
OutputStream out = new FileOutputStream(file);
try (OutputStream out = Files.newOutputStream(file.toPath())) {
URLConnection connection = url.openConnection();
connection.setUseCaches(false);
try (InputStream in = connection.getInputStream()) {
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();
}
}
}
}
@@ -1,51 +1,43 @@
package cc.carm.lib.configuration.core.value;
import cc.carm.lib.configuration.core.builder.ConfigBuilder;
import cc.carm.lib.configuration.core.source.ConfigCommentInfo;
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.util.List;
import java.util.Objects;
import java.util.Optional;
public abstract class ConfigValue<T> {
public abstract class ConfigValue<T> extends ValueManifest<T> {
public static @NotNull ConfigBuilder builder() {
return new ConfigBuilder();
}
protected @Nullable ConfigurationProvider<?> provider;
protected @Nullable String configPath;
protected @Nullable ConfigCommentInfo comments;
protected ConfigValue(@NotNull ValueManifest<T> manifest) {
super(manifest.provider, manifest.configPath, manifest.headerComments, manifest.inlineComment, manifest.defaultValue);
}
protected @Nullable T defaultValue;
public ConfigValue(@Nullable ConfigurationProvider<?> provider,
@Nullable String configPath, @Nullable ConfigCommentInfo comments,
/**
* @param provider 配置文件提供者
* @param configPath 配置路径
* @param headerComments 头部注释内容
* @param inlineComments 行内注释内容
* @param defaultValue 默认参数值
* @deprecated 请使用 {@link #ConfigValue(ValueManifest)} 构造器。
*/
@Deprecated
protected ConfigValue(@Nullable ConfigurationProvider<?> provider, @Nullable String configPath,
@Nullable List<String> headerComments, @Nullable String inlineComments,
@Nullable T defaultValue) {
this.provider = provider;
this.configPath = configPath;
this.comments = comments;
this.defaultValue = defaultValue;
super(provider, configPath, headerComments, inlineComments, defaultValue);
}
public void initialize(@NotNull ConfigurationProvider<?> provider, boolean saveDefault,
@NotNull String configPath, @Nullable ConfigCommentInfo comments) {
if (this.provider == null) this.provider = provider;
if (this.configPath == null) this.configPath = configPath;
if (this.comments == null) this.comments = comments;
public void initialize(@NotNull ConfigurationProvider<?> provider, boolean saveDefault, @NotNull String configPath,
@Nullable List<String> headerComments, @Nullable String inlineComments) {
this.initialize(provider, configPath, headerComments, inlineComments);
if (saveDefault) setDefault();
if (getComments() != null) this.provider.setComment(getConfigPath(), getComments());
}
public @Nullable T getDefaultValue() {
return defaultValue;
}
public void setDefaultValue(@Nullable T defaultValue) {
this.defaultValue = defaultValue;
}
/**
@@ -119,34 +111,4 @@ public abstract class ConfigValue<T> {
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 ConfigCommentInfo getComments() {
return comments;
}
}
@@ -0,0 +1,125 @@
package cc.carm.lib.configuration.core.value;
import cc.carm.lib.configuration.core.ConfigInitializer;
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.Optional;
/**
* 配置值描述清单。用于描述一个配置值的相关基础信息。
*
* @param <T> 配置值类型
* @author CarmJos
*/
public class ValueManifest<T> {
public static <V> ValueManifest<V> of(@Nullable ConfigurationProvider<?> provider, @Nullable String configPath,
@Nullable List<String> headerComments, @Nullable String inlineComments) {
return new ValueManifest<>(provider, configPath, headerComments, inlineComments, null);
}
public static <V> ValueManifest<V> of(@Nullable ConfigurationProvider<?> provider, @Nullable String configPath,
@Nullable List<String> headerComments, @Nullable String inlineComments,
@Nullable V defaultValue) {
return new ValueManifest<>(provider, configPath, headerComments, inlineComments, defaultValue);
}
protected @Nullable ConfigurationProvider<?> provider;
protected @Nullable String configPath;
protected @Nullable List<String> headerComments;
protected @Nullable String inlineComment;
protected @Nullable T defaultValue;
/**
* @param provider 配置文件提供者
* @param configPath 配置路径
* @param headerComments 头部注释内容
* @param inlineComment 行内注释内容
* @param defaultValue 默认参数值
*/
public ValueManifest(@Nullable ConfigurationProvider<?> provider, @Nullable String configPath,
@Nullable List<String> headerComments, @Nullable String inlineComment,
@Nullable T defaultValue) {
this.provider = provider;
this.configPath = configPath;
this.headerComments = headerComments;
this.inlineComment = inlineComment;
this.defaultValue = defaultValue;
}
/**
* 此方法提供给 {@link ConfigInitializer},以便对配置值的相关信息进行统一初始化操作。
*
* @param provider 配置文件提供者
* @param configPath 配置路径
* @param headerComments 头部注释内容
* @param inlineComment 行内注释内容
*/
protected void initialize(@NotNull ConfigurationProvider<?> provider, @NotNull String configPath,
@Nullable List<String> headerComments, @Nullable String inlineComment) {
if (this.provider == null) this.provider = provider;
if (this.configPath == null) this.configPath = configPath;
if (this.headerComments == null) this.headerComments = headerComments;
if (this.inlineComment == null) this.inlineComment = inlineComment;
if (getHeaderComments() != null) {
this.provider.setHeaderComment(getConfigPath(), getHeaderComments());
}
if (getInlineComment() != null) {
this.provider.setInlineComment(getConfigPath(), getInlineComment());
}
}
public @Nullable T getDefaultValue() {
return this.defaultValue;
}
public void setDefaultValue(@Nullable T defaultValue) {
this.defaultValue = defaultValue;
}
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() {
String path = getConfigPath(); // 当未指定路径时,优先抛出异常
return getConfiguration().get(path);
}
protected void setValue(@Nullable Object value) {
getConfiguration().set(getConfigPath(), value);
}
public @Nullable String getInlineComment() {
return inlineComment;
}
@Unmodifiable
public @Nullable List<String> getHeaderComments() {
return headerComments;
}
}
@@ -1,8 +1,8 @@
package cc.carm.lib.configuration.core.value.impl;
import cc.carm.lib.configuration.core.source.ConfigCommentInfo;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.ValueManifest;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -12,9 +12,8 @@ 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 ConfigCommentInfo comments, @Nullable T defaultValue) {
super(provider, sectionPath, comments, defaultValue);
protected CachedConfigValue(@NotNull ValueManifest<T> manifest) {
super(manifest);
}
protected T updateCache(T value) {
@@ -31,12 +30,19 @@ public abstract class CachedConfigValue<T> extends ConfigValue<T> {
return this.parsedTime <= 0 || getProvider().isExpired(this.parsedTime);
}
protected final T useDefault() {
return useOrDefault(null);
}
protected final T useOrDefault(@Nullable T value) {
protected final T getDefaultFirst(@Nullable T value) {
return updateCache(this.defaultValue == null ? value : this.defaultValue);
}
protected @Nullable T getCachedOrDefault() {
return getCachedOrDefault(null);
}
@Contract("!null->!null")
protected T getCachedOrDefault(@Nullable T emptyValue) {
if (getCachedValue() != null) return getCachedValue();
else if (getDefaultValue() != null) return getDefaultValue();
else return emptyValue;
}
}
@@ -0,0 +1,214 @@
package cc.carm.lib.configuration.core.value.impl;
import cc.carm.lib.configuration.core.builder.map.ConfigMapCreator;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import cc.carm.lib.configuration.core.value.ValueManifest;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
public abstract class ConfigValueMap<K, V, S> extends CachedConfigValue<Map<K, V>> implements Map<K, V> {
public static <K, V> @NotNull ConfigMapCreator<K, V> builderOf(@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<? super S> sourceClass;
protected final @NotNull Class<K> keyClass;
protected final @NotNull Class<V> valueClass;
protected final @NotNull ConfigDataFunction<String, K> keyParser;
protected final @NotNull ConfigDataFunction<S, V> valueParser;
protected final @NotNull ConfigDataFunction<K, String> keySerializer;
protected final @NotNull ConfigDataFunction<V, Object> valueSerializer;
protected ConfigValueMap(@NotNull ValueManifest<Map<K, V>> manifest, @NotNull Class<? super S> sourceClass,
@NotNull Supplier<? extends Map<K, V>> mapObjSupplier,
@NotNull Class<K> keyClass, @NotNull ConfigDataFunction<String, K> keyParser,
@NotNull Class<V> valueClass, @NotNull ConfigDataFunction<S, V> valueParser,
@NotNull ConfigDataFunction<K, String> keySerializer,
@NotNull ConfigDataFunction<V, Object> valueSerializer) {
super(manifest);
this.supplier = mapObjSupplier;
this.sourceClass = sourceClass;
this.keyClass = keyClass;
this.valueClass = valueClass;
this.keyParser = keyParser;
this.valueParser = valueParser;
this.keySerializer = keySerializer;
this.valueSerializer = valueSerializer;
}
public @NotNull Class<? super S> getSourceClass() {
return sourceClass;
}
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<S, V> getValueParser() {
return valueParser;
}
public @NotNull ConfigDataFunction<K, String> getKeySerializer() {
return keySerializer;
}
public @NotNull ConfigDataFunction<V, Object> getValueSerializer() {
return valueSerializer;
}
public abstract S getSource(ConfigurationWrapper<?> section, String dataKey);
@Override
public @NotNull Map<K, V> get() {
if (!isExpired()) return getCachedOrDefault(supplier.get());
// 已过时的数据,需要重新解析一次。
Map<K, V> map = supplier.get();
ConfigurationWrapper<?> section = getConfiguration().getConfigurationSection(getConfigPath());
if (section == null) return getDefaultFirst(map);
Set<String> keys = section.getKeys(false);
if (keys.isEmpty()) return getDefaultFirst(map);
for (String dataKey : keys) {
S dataVal = getSource(section, 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);
}
@Override
public V get(Object key) {
return get().get(key);
}
public V getNotNull(Object key) {
return Objects.requireNonNull(get(key));
}
@Override
public void set(@Nullable 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);
}
}
public <T> @NotNull T modifyValue(Function<Map<K, V>, T> function) {
Map<K, V> m = get();
T result = function.apply(m);
set(m);
return result;
}
public @NotNull Map<K, V> modifyMap(Consumer<Map<K, V>> consumer) {
Map<K, V> m = get();
consumer.accept(m);
set(m);
return m;
}
@Override
public int size() {
return get().size();
}
@Override
public boolean isEmpty() {
return get().isEmpty();
}
@Override
public boolean containsKey(Object key) {
return get().containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return get().containsValue(value);
}
@Nullable
@Override
public V put(K key, V value) {
return modifyValue(m -> m.put(key, value));
}
@Override
public V remove(Object key) {
return modifyValue(m -> m.remove(key));
}
@Override
public void putAll(@NotNull Map<? extends K, ? extends V> m) {
modifyMap(map -> map.putAll(m));
}
@Override
public void clear() {
modifyMap(Map::clear);
}
@NotNull
@Override
public Set<K> keySet() {
return get().keySet();
}
@NotNull
@Override
public Collection<V> values() {
return get().values();
}
@NotNull
@Override
@Unmodifiable
public Set<Entry<K, V>> entrySet() {
return get().entrySet();
}
}
@@ -2,32 +2,39 @@ package cc.carm.lib.configuration.core.value.type;
import cc.carm.lib.configuration.core.builder.list.ConfigListBuilder;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.core.source.ConfigCommentInfo;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.value.ValueManifest;
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;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
public class ConfiguredList<V> extends CachedConfigValue<List<V>> {
public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements List<V> {
public static <V> @NotNull ConfigListBuilder<V> builder(@NotNull Class<V> valueClass) {
public static <V> @NotNull ConfigListBuilder<V> builderOf(@NotNull Class<V> valueClass) {
return builder().asList(valueClass);
}
public static <V> @NotNull ConfiguredList<V> of(@NotNull Class<V> valueClass, @NotNull Collection<V> defaults) {
return builderOf(valueClass).fromObject().defaults(defaults).build();
}
@SafeVarargs
public static <V> @NotNull ConfiguredList<V> of(@NotNull Class<V> valueClass, @NotNull V... defaults) {
return builderOf(valueClass).fromObject().defaults(defaults).build();
}
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 ConfigCommentInfo comments,
@NotNull Class<V> valueClass, @Nullable List<V> defaultValue,
public ConfiguredList(@NotNull ValueManifest<List<V>> manifest, @NotNull Class<V> valueClass,
@NotNull ConfigDataFunction<Object, V> parser,
@NotNull ConfigDataFunction<V, Object> serializer) {
super(provider, sectionPath, comments, defaultValue);
super(manifest);
this.valueClass = valueClass;
this.parser = parser;
this.serializer = serializer;
@@ -35,10 +42,12 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>> {
@Override
public @NotNull List<V> get() {
if (isExpired()) { // 已过时的数据,需要重新解析一次。
if (!isExpired()) return getCachedOrDefault(new ArrayList<>());
// Data that is outdated and needs to be parsed again.
List<V> list = new ArrayList<>();
List<?> data = getConfiguration().getList(getConfigPath());
if (data == null || data.isEmpty()) return useOrDefault(list);
List<?> data = getConfiguration().contains(getConfigPath()) ?
getConfiguration().getList(getConfigPath()) : null;
if (data == null) return getDefaultFirst(list);
for (Object dataVal : data) {
if (dataVal == null) continue;
try {
@@ -48,9 +57,29 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>> {
}
}
return updateCache(list);
} else if (getCachedValue() != null) return getCachedValue();
else if (getDefaultValue() != null) return getDefaultValue();
else return new ArrayList<>();
}
@Override
public V get(int index) {
return get().get(index);
}
public @NotNull List<V> copy() {
return new ArrayList<>(get());
}
public <T> @NotNull T handle(Function<List<V>, T> function) {
List<V> list = get();
T result = function.apply(list);
set(list);
return result;
}
public @NotNull List<V> modify(Consumer<List<V>> consumer) {
List<V> list = get();
consumer.accept(list);
set(list);
return list;
}
@Override
@@ -71,5 +100,121 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>> {
}
}
@Override
public V set(int index, V element) {
return handle(list -> list.set(index, element));
}
@Override
public int size() {
return get().size();
}
@Override
public boolean isEmpty() {
return get().isEmpty();
}
@Override
public boolean contains(Object o) {
return get().contains(o);
}
@NotNull
@Override
public Iterator<V> iterator() {
return get().iterator();
}
@NotNull
@Override
public Object @NotNull [] toArray() {
return get().toArray();
}
@NotNull
@Override
public <T> T @NotNull [] toArray(@NotNull T[] a) {
return get().toArray(a);
}
@Override
public boolean containsAll(@NotNull Collection<?> c) {
return new HashSet<>(get()).containsAll(c);
}
@Override
public boolean add(V v) {
handle(list -> list.add(v));
return true;
}
@Override
public void add(int index, V element) {
modify(list -> list.add(index, element));
}
@Override
public boolean addAll(@NotNull Collection<? extends V> c) {
return handle(list -> list.addAll(c));
}
@Override
public boolean addAll(int index, @NotNull Collection<? extends V> c) {
return handle(list -> list.addAll(index, c));
}
@Override
public boolean remove(Object o) {
return handle(list -> list.remove(o));
}
@Override
public V remove(int index) {
return handle(list -> list.remove(index));
}
@Override
public boolean removeAll(@NotNull Collection<?> c) {
return handle(list -> list.removeAll(c));
}
@Override
public boolean retainAll(@NotNull Collection<?> c) {
return handle(list -> list.retainAll(c));
}
@Override
public void clear() {
modify(List::clear);
}
@Override
public int indexOf(Object o) {
return get().indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return get().lastIndexOf(o);
}
@NotNull
@Override
public ListIterator<V> listIterator() {
return get().listIterator();
}
@NotNull
@Override
public ListIterator<V> listIterator(int index) {
return get().listIterator(index);
}
@NotNull
@Override
public List<V> subList(int fromIndex, int toIndex) {
return get().subList(fromIndex, toIndex);
}
}
@@ -1,126 +1,28 @@
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.ConfigCommentInfo;
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 cc.carm.lib.configuration.core.value.ValueManifest;
import cc.carm.lib.configuration.core.value.impl.ConfigValueMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> {
public class ConfiguredMap<K, V> extends ConfigValueMap<K, V, Object> {
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 ConfigCommentInfo comments,
@Nullable Map<K, V> defaultValue, @NotNull Supplier<? extends Map<K, V>> supplier,
public ConfiguredMap(@NotNull ValueManifest<Map<K, V>> manifest,
@NotNull Supplier<? extends Map<K, V>> mapObjSupplier,
@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, comments, 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;
super(manifest, Object.class, mapObjSupplier, keyClass, keyParser, valueClass, valueParser, keySerializer, 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();
public Object getSource(ConfigurationWrapper<?> section, String dataKey) {
return section.get(dataKey);
}
}
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);
}
}
}
@@ -3,66 +3,83 @@ 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.ConfigCommentInfo;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import cc.carm.lib.configuration.core.value.ValueManifest;
import cc.carm.lib.configuration.core.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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) {
public static <V> @NotNull SectionValueBuilder<V> builderOf(@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 ConfigValueParser<ConfigurationWrapper<?>, V> parser;
protected final @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer;
public ConfiguredSection(@Nullable ConfigurationProvider<?> provider,
@Nullable String sectionPath, @Nullable ConfigCommentInfo comments,
@NotNull Class<V> valueClass, @Nullable V defaultValue,
@NotNull ConfigValueParser<ConfigurationWrapper, V> parser,
public ConfiguredSection(@NotNull ValueManifest<V> manifest, @NotNull Class<V> valueClass,
@NotNull ConfigValueParser<ConfigurationWrapper<?>, V> parser,
@NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer) {
super(provider, sectionPath, comments, defaultValue);
super(manifest);
this.valueClass = valueClass;
this.parser = parser;
this.serializer = serializer;
}
/**
* @return Value's type class
*/
public @NotNull Class<V> getValueClass() {
return valueClass;
}
public @NotNull ConfigValueParser<ConfigurationWrapper, V> getParser() {
/**
* @return Value's parser, cast value from section.
*/
public @NotNull ConfigValueParser<ConfigurationWrapper<?>, V> getParser() {
return parser;
}
/**
* @return Value's serializer, serialize value to section.
*/
public @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> getSerializer() {
return serializer;
}
/**
* @return Get the value that parsed from the configuration section.
*/
@Override
public @Nullable V get() {
if (isExpired()) { // 已过时的数据,需要重新解析一次。
ConfigurationWrapper section = getConfiguration().getConfigurationSection(getConfigPath());
if (section == null) return useDefault();
if (!isExpired()) return getCachedOrDefault();
// Data that is outdated and needs to be parsed again.
ConfigurationWrapper<?> section = getConfiguration().getConfigurationSection(getConfigPath());
if (section == null) return getDefaultValue();
try {
// 若未出现错误,则直接更新缓存并返回。
// If there are no errors, update the cache and return.
return updateCache(this.parser.parse(section, this.defaultValue));
} catch (Exception e) {
// 出现了解析错误,提示并返回默认值。
// There was a parsing error, prompted and returned the default value.
e.printStackTrace();
return useDefault();
}
} else return Optional.ofNullable(getCachedValue()).orElse(defaultValue);
return getDefaultValue();
}
}
/**
* Use the specified value to update the configuration section.
* Will use {@link #getSerializer()} to serialize the value to section.
*
* @param value The value that needs to be set in the configuration.
*/
@Override
public void set(V value) {
updateCache(value);
@@ -0,0 +1,32 @@
package cc.carm.lib.configuration.core.value.type;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import cc.carm.lib.configuration.core.value.ValueManifest;
import cc.carm.lib.configuration.core.value.impl.ConfigValueMap;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.function.Supplier;
public class ConfiguredSectionMap<K, V> extends ConfigValueMap<K, V, ConfigurationWrapper<?>> {
public ConfiguredSectionMap(@NotNull ValueManifest<Map<K, V>> manifest,
@NotNull Supplier<? extends Map<K, V>> mapObjSupplier,
@NotNull Class<K> keyClass, @NotNull ConfigDataFunction<String, K> keyParser,
@NotNull Class<V> valueClass, @NotNull ConfigDataFunction<ConfigurationWrapper<?>, V> valueParser,
@NotNull ConfigDataFunction<K, String> keySerializer,
@NotNull ConfigDataFunction<V, ? extends Map<String, Object>> valueSerializer) {
super(
manifest, ConfigurationWrapper.class, mapObjSupplier,
keyClass, keyParser, valueClass, valueParser,
keySerializer, valueSerializer.andThen(s -> (Object) s)
);
}
@Override
public ConfigurationWrapper<?> getSource(ConfigurationWrapper<?> section, String dataKey) {
return section.getConfigurationSection(dataKey);
}
}
@@ -3,26 +3,28 @@ 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.ConfigCommentInfo;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.value.ValueManifest;
import cc.carm.lib.configuration.core.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
public class ConfiguredValue<V> extends CachedConfigValue<V> {
public static <V> ConfigValueBuilder<V> builder(Class<V> valueClass) {
public static <V> ConfigValueBuilder<V> builderOf(Class<V> valueClass) {
return builder().asValue(valueClass);
}
@SuppressWarnings("unchecked")
public static <V> ConfiguredValue<V> of(@NotNull V defaultValue) {
return of((Class<V>) defaultValue.getClass(), defaultValue);
}
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();
return builderOf(valueClass).fromObject().defaults(defaultValue).build();
}
protected final @NotNull Class<V> valueClass;
@@ -30,42 +32,60 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
protected final @NotNull ConfigValueParser<Object, V> parser;
protected final @NotNull ConfigDataFunction<V, Object> serializer;
public ConfiguredValue(@Nullable ConfigurationProvider<?> provider,
@Nullable String sectionPath, @Nullable ConfigCommentInfo comments,
@NotNull Class<V> valueClass, @Nullable V defaultValue,
public ConfiguredValue(@NotNull ValueManifest<V> manifest, @NotNull Class<V> valueClass,
@NotNull ConfigValueParser<Object, V> parser,
@NotNull ConfigDataFunction<V, Object> serializer) {
super(provider, sectionPath, comments, defaultValue);
super(manifest);
this.valueClass = valueClass;
this.parser = parser;
this.serializer = serializer;
}
/**
* @return Value's type class
*/
public @NotNull Class<V> getValueClass() {
return valueClass;
}
/**
* @return Value's parser, cast value from base object.
*/
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);
/**
* @return Value's serializer, serialize value to base object.
*/
public @NotNull ConfigDataFunction<V, Object> getSerializer() {
return serializer;
}
@Override
public V get() {
if (!isExpired()) return getCachedOrDefault();
// Data that is outdated and needs to be parsed again.
Object value = getValue();
if (value == null) return getDefaultValue(); // 获取的值不存在,直接使用默认值。
try {
// If there are no errors, update the cache and return.
return updateCache(this.parser.parse(value, this.defaultValue));
} catch (Exception e) {
// There was a parsing error, prompted and returned the default value.
e.printStackTrace();
return getDefaultValue();
}
}
/**
* Set the value of the configuration path.
* Will use {@link #getSerializer()} to serialize the value.
*
* @param value The value to be set
*/
@Override
public void set(V value) {
updateCache(value);
@@ -1,4 +1,4 @@
package config.offset;
package cc.carm.test.config.offset;
import org.jetbrains.annotations.NotNull;
@@ -0,0 +1,63 @@
//package config.offset;
//
//
//import sun.misc.Unsafe;
//
//import java.lang.reflect.Field;
//import java.lang.reflect.Modifier;
//import java.util.Collections;
//import java.util.LinkedList;
//import java.util.List;
//
///**
// * @author Chris2018998
// */
//public class OffsetUtil {
// private static Unsafe unsafe;
//
// static {
// try {
// // 获取 Unsafe 内部的私有的实例化单例对象
// Field field = Unsafe.class.getDeclaredField("theUnsafe");
// // 无视权限
// field.setAccessible(true);
// unsafe = (Unsafe) field.get(null);
// } catch (NoSuchFieldException | IllegalAccessException e) {
// e.printStackTrace();
// }
//// try {
//// unsafe = AccessController.doPrivileged((PrivilegedExceptionAction<Unsafe>) () -> {
//// Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
//// theUnsafe.setAccessible(true);
//// return (Unsafe) theUnsafe.get(null);
//// });
//// } catch (Throwable e) {
//// System.err.println("Unable to load unsafe");
//// }
// }
//
// public static List<FieldOffset> getClassMemberOffset(Class<?> beanClass) {
// List<FieldOffset> offsetsList = new LinkedList<>();
// for (Field field : beanClass.getDeclaredFields()) {
// FieldOffset fieldOffset = new FieldOffset(field);
// offsetsList.add(fieldOffset);
// if (Modifier.isStatic(field.getModifiers()))
// fieldOffset.setOffsetValue(unsafe.staticFieldOffset(field));
// else
// fieldOffset.setOffsetValue(unsafe.objectFieldOffset(field));
// Class<?> fieldType = field.getType();
// if (!fieldType.getName().startsWith("java")) {
// Field[] subfields = fieldType.getDeclaredFields();
// if (subfields.length > 0) {
// fieldOffset.setSubFieldOffsetList(getClassMemberOffset(fieldType));
// }
// }
// }
//
// Collections.sort(offsetsList);
// return offsetsList;
// }
//
//
//}
//
+52
View File
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>easyconfiguration-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>3.9.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<properties>
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties>
<artifactId>easyconfiguration-demo</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -1,35 +1,30 @@
package config.source;
package cc.carm.lib.configuration.demo;
import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.ConfigComment;
import cc.carm.lib.configuration.core.annotation.ConfigPath;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
@ConfigComment({"数据库配置", " 用于提供数据库连接,进行数据库操作。"})
@HeaderComment({"", "数据库配置", " 用于提供数据库连接,进行数据库操作。"})
public class DatabaseConfiguration extends ConfigurationRoot {
@ConfigPath("driver")
@ConfigComment(value = {
@HeaderComment({
"数据库驱动配置,请根据数据库类型设置。",
"- MySQL: com.mysql.cj.jdbc.Driver",
"- MySQL(旧): com.mysql.jdbc.Driver",
"- MySQL(新): com.mysql.cj.jdbc.Driver",
"- MariaDB(推荐): org.mariadb.jdbc.Driver",
}, startWrap = false)
})
protected static final ConfigValue<String> DRIVER_NAME = ConfiguredValue.of(
String.class, "com.mysql.cj.jdbc.Driver"
);
@ConfigComment(startWrap = false)
protected static final ConfigValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1");
@ConfigComment(startWrap = false)
protected static final ConfigValue<Integer> PORT = ConfiguredValue.of(Integer.class, 3306);
@ConfigComment(startWrap = false)
protected static final ConfigValue<String> DATABASE = ConfiguredValue.of(String.class, "minecraft");
@ConfigComment(startWrap = false)
protected static final ConfigValue<String> USERNAME = ConfiguredValue.of(String.class, "root");
@ConfigComment(startWrap = false)
protected static final ConfigValue<String> PASSWORD = ConfiguredValue.of(String.class, "password");
@ConfigComment(startWrap = false)
protected static final ConfigValue<String> EXTRA = ConfiguredValue.of(String.class, "?useSSL=false");
protected static String buildJDBC() {
@@ -0,0 +1,89 @@
package cc.carm.lib.configuration.demo.tests;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.demo.tests.conf.DemoConfiguration;
import cc.carm.lib.configuration.demo.tests.conf.TestConfiguration;
import cc.carm.lib.configuration.demo.tests.model.TestModel;
import org.jetbrains.annotations.TestOnly;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class ConfigurationTest {
@TestOnly
public static void testDemo(ConfigurationProvider<?> provider) {
provider.initialize(DemoConfiguration.class);
System.out.println("----------------------------------------------------");
System.out.println("Test Number: ");
System.out.println("before: " + DemoConfiguration.TEST_NUMBER.get());
DemoConfiguration.TEST_NUMBER.set((long) (Long.MAX_VALUE * Math.random()));
System.out.println("after: " + DemoConfiguration.TEST_NUMBER.get());
System.out.println("> Test Value:");
System.out.println("before: " + DemoConfiguration.Sub.UUID_CONFIG_VALUE.get());
DemoConfiguration.Sub.UUID_CONFIG_VALUE.set(UUID.randomUUID());
System.out.println("after: " + DemoConfiguration.Sub.UUID_CONFIG_VALUE.get());
System.out.println("> Test List:");
System.out.println(" Before:");
DemoConfiguration.Sub.That.OPERATORS.forEach(System.out::println);
List<UUID> operators = IntStream.range(0, 5).mapToObj(i -> UUID.randomUUID()).collect(Collectors.toList());
DemoConfiguration.Sub.That.OPERATORS.set(operators);
System.out.println(" After:");
DemoConfiguration.Sub.That.OPERATORS.forEach(System.out::println);
System.out.println("> Clear List:");
System.out.println(" Before: size :" + DemoConfiguration.Sub.That.OPERATORS.size());
DemoConfiguration.Sub.That.OPERATORS.modify(List::clear);
System.out.println(" After size :" + DemoConfiguration.Sub.That.OPERATORS.size());
System.out.println("> Test Section:");
System.out.println(DemoConfiguration.MODEL_TEST.get());
DemoConfiguration.MODEL_TEST.set(TestModel.random());
System.out.println("> Test Maps:");
DemoConfiguration.USERS.forEach((k, v) -> System.out.println(k + ": " + v));
LinkedHashMap<Integer, UUID> data = new LinkedHashMap<>();
for (int i = 1; i <= 5; i++) {
data.put(i, UUID.randomUUID());
}
DemoConfiguration.USERS.set(data);
System.out.println("----------------------------------------------------");
}
public static void testInner(ConfigurationProvider<?> provider) {
TestConfiguration TEST = new TestConfiguration();
provider.initialize(TEST, true);
System.out.println("> Test Inner value before:");
System.out.println(TEST.INNER.INNER_VALUE.getNotNull());
double after = Math.random() * 200D;
System.out.println("> Test Inner value -> " + after);
TEST.INNER.INNER_VALUE.set(after);
System.out.println("> Test Inner value after:");
System.out.println(TEST.INNER.INNER_VALUE.getNotNull());
}
public static void save(ConfigurationProvider<?> provider) {
try {
provider.save();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -1,55 +1,52 @@
package config.source;
package cc.carm.lib.configuration.demo.tests.conf;
import cc.carm.lib.configuration.core.ConfigInitializer;
import cc.carm.lib.configuration.core.Configuration;
import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.ConfigComment;
import cc.carm.lib.configuration.core.annotation.ConfigPath;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.annotation.InlineComment;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.type.ConfiguredList;
import cc.carm.lib.configuration.core.value.type.ConfiguredMap;
import cc.carm.lib.configuration.core.value.type.ConfiguredSection;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
import config.model.TestModel;
import cc.carm.lib.configuration.demo.tests.model.TestModel;
import java.util.List;
import java.util.Map;
import java.time.temporal.ChronoUnit;
import java.util.Objects;
import java.util.UUID;
@ConfigComment({"给根类添加的注释将显示在文件的末尾。"})
public class DemoConfiguration extends ConfigurationRoot {
@HeaderComment({"此处内容将显示在配置文件的最上方"})
public interface DemoConfiguration extends Configuration {
@ConfigPath(root = true)
@ConfigComment(value = {
"有时候,需要在配置文件最上面显示点东西,",
"此时就推荐添加一个可以用到但并不重要的参数到最上面",
"并给他添加对应的注释。"
}, startWrap = false, endWrap = true)
protected static final ConfigValue<Double> VERSION = ConfiguredValue.of(Double.class, 1.0D);
ConfigValue<Double> VERSION = ConfiguredValue.of(Double.class, 1.0D);
@ConfigPath(root = true)
ConfigValue<Long> TEST_NUMBER = ConfiguredValue.of(1000000L);
ConfigValue<ChronoUnit> TEST_ENUM = ConfiguredValue.of(ChronoUnit.class, ChronoUnit.DAYS);
// 支持通过 Class<?> 变量标注子配置一并注册
// 注意 若对应类也有注解则优先使用类的注解
@ConfigPath("impl-test") //支持通过注解修改子配置的主路径若不修改则以变量名自动生成
@ConfigComment("Something...") // 支持给子路径直接打注释
public static final Class<?> IMPL = ImplConfiguration.class;
// 子配置文件
@ConfigPath("database")
public static final Class<?> DB_CONFIG = DatabaseConfiguration.class;
@ConfigPath("other-class-config") //支持通过注解修改子配置的主路径若不修改则以变量名自动生成
@HeaderComment({"", "Something..."}) // 支持给子路径直接打注释
@InlineComment("InlineComments for class path")
Class<?> OTHER = OtherConfiguration.class;
@ConfigPath("user") // 通过注解规定配置文件中的路径若不进行注解则以变量名自动生成
@ConfigComment({"Section类型数据测试"}) // 通过注解给配置添加注释
public static final ConfigValue<TestModel> MODEL_TEST = ConfiguredSection
.builder(TestModel.class)
@HeaderComment({"Section类型数据测试"}) // 通过注解给配置添加注释
@InlineComment("Section数据也支持InlineComment注释")
ConfigValue<TestModel> MODEL_TEST = ConfiguredSection.builderOf(TestModel.class)
.defaults(new TestModel("Carm", UUID.randomUUID()))
.parseValue((section, defaultValue) -> TestModel.deserialize(section))
.serializeValue(TestModel::serialize).build();
@ConfigComment({"[ID-UUID] 对照表", "", "用于测试Map类型的解析与序列化保存"})
public static final ConfigValue<Map<Integer, UUID>> USERS = ConfiguredMap
.builder(Integer.class, UUID.class).fromString()
@HeaderComment({"[ID - UUID]对照表", "", "用于测试Map类型的解析与序列化保存"})
ConfiguredMap<Integer, UUID> USERS = ConfiguredMap.builderOf(Integer.class, UUID.class)
.asLinkedMap().fromString()
.parseKey(Integer::parseInt)
.parseValue(v -> Objects.requireNonNull(UUID.fromString(v)))
.build();
@@ -59,23 +56,23 @@ public class DemoConfiguration extends ConfigurationRoot {
* 支持内部类的直接注册
* 注意需要使用 {@link ConfigInitializer#initialize(Class, boolean, boolean)} 方法并设定第三个参数为 true
*/
public static class Sub extends ConfigurationRoot {
class Sub extends ConfigurationRoot {
@ConfigPath(value = "uuid-value", root = true)
@InlineComment("This is an inline comment")
public static final ConfigValue<UUID> UUID_CONFIG_VALUE = ConfiguredValue
.builder(UUID.class).fromString()
.builderOf(UUID.class).fromString()
.parseValue((data, defaultValue) -> UUID.fromString(data))
.build();
public static class That extends ConfigurationRoot {
public static final ConfigValue<List<UUID>> OPERATORS = ConfiguredList
.builder(UUID.class).fromString()
public static final ConfiguredList<UUID> OPERATORS = ConfiguredList
.builderOf(UUID.class).fromString()
.parseValue(s -> Objects.requireNonNull(UUID.fromString(s)))
.build();
}
}
@@ -0,0 +1,4 @@
package cc.carm.lib.configuration.demo.tests.conf;
public class OtherConfiguration {
}
@@ -0,0 +1,30 @@
package cc.carm.lib.configuration.demo.tests.conf;
import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.ConfigPath;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.annotation.InlineComment;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.type.ConfiguredSection;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
import cc.carm.lib.configuration.demo.tests.model.TestModel;
import java.util.UUID;
public class TestConfiguration extends ConfigurationRoot {
public final TestInnerConfiguration INNER = new TestInnerConfiguration();
public final ConfigValue<Double> CLASS_VALUE = ConfiguredValue.of(Double.class, 1.0D);
@ConfigPath("test.user") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
@HeaderComment({"Section类型数据测试"}) // 通过注解给配置添加注释。
@InlineComment("Section数据也支持InlineComment注释")
public final ConfigValue<TestModel> TEST_MODEL = ConfiguredSection
.builderOf(TestModel.class)
.defaults(new TestModel("Carm", UUID.randomUUID()))
.parseValue((section, defaultValue) -> TestModel.deserialize(section))
.serializeValue(TestModel::serialize).build();
}
@@ -0,0 +1,13 @@
package cc.carm.lib.configuration.demo.tests.conf;
import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
@HeaderComment("Inner Test")
public class TestInnerConfiguration extends ConfigurationRoot {
public final ConfigValue<Double> INNER_VALUE = ConfiguredValue.of(Double.class, 1.0D);
}
@@ -1,4 +1,4 @@
package config.model;
package cc.carm.lib.configuration.demo.tests.model;
import org.jetbrains.annotations.NotNull;
@@ -1,4 +1,4 @@
package config.model;
package cc.carm.lib.configuration.demo.tests.model;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import org.jetbrains.annotations.NotNull;
@@ -33,7 +33,7 @@ public class TestModel extends AbstractModel {
return map;
}
public static TestModel deserialize(ConfigurationWrapper section) {
public static TestModel deserialize(ConfigurationWrapper<?> section) {
String name = section.getString("name");
if (name == null) throw new NullPointerException("name is null");
String uuidString = section.getString("info.uuid");
+66
View File
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId>
<version>3.9.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties>
<artifactId>easyconfiguration-hocon</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-demo</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.typesafe</groupId>
<artifactId>config</artifactId>
<version>1.4.3</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,36 @@
package cc.carm.lib.configuration;
import cc.carm.lib.configuration.hocon.HOCONFileConfigProvider;
import java.io.File;
import java.io.IOException;
public class EasyConfiguration {
private EasyConfiguration() {
}
public static HOCONFileConfigProvider from(File file, String source) {
HOCONFileConfigProvider provider = new HOCONFileConfigProvider(file);
try {
provider.initializeFile(source);
provider.initializeConfig();
} catch (IOException e) {
e.printStackTrace();
}
return provider;
}
public static HOCONFileConfigProvider from(File file) {
return from(file, file.getName());
}
public static HOCONFileConfigProvider from(String fileName) {
return from(fileName, fileName);
}
public static HOCONFileConfigProvider from(String fileName, String source) {
return from(new File(fileName), source);
}
}
@@ -0,0 +1,117 @@
package cc.carm.lib.configuration.hocon;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import cc.carm.lib.configuration.hocon.util.HOCONUtils;
import com.typesafe.config.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class HOCONConfigWrapper implements ConfigurationWrapper<Map<String, Object>> {
private static final char SEPARATOR = '.';
protected final Map<String, Object> data;
public HOCONConfigWrapper(ConfigObject config) {
this.data = new LinkedHashMap<>();
config.forEach((key, value) -> {
Config cfg = config.toConfig();
ConfigValue cv = cfg.getValue(key);
if (cv.valueType() == ConfigValueType.OBJECT) {
HOCONConfigWrapper.this.data.put(key, new HOCONConfigWrapper((ConfigObject) cv));
} else {
HOCONConfigWrapper.this.data.put(key, value.unwrapped());
}
});
}
@Override
public @NotNull Map<String, Object> getSource() {
return this.data;
}
@Override
public @NotNull Set<String> getKeys(boolean deep) {
return this.getValues(deep).keySet();
}
@Override
public @NotNull Map<String, Object> getValues(boolean deep) {
return HOCONUtils.getKeysFromObject(this, deep, "").stream().collect(
LinkedHashMap::new,
(map, key) -> map.put(key, get(key)),
LinkedHashMap::putAll
);
}
@Override
public void set(@NotNull String path, @Nullable Object value) {
if (value instanceof Map) {
//noinspection unchecked
value = new HOCONConfigWrapper(ConfigFactory.parseMap((Map<String, ?>) value).root());
}
HOCONConfigWrapper section = HOCONUtils.getObjectOn(this, path, SEPARATOR);
String simplePath = HOCONUtils.getSimplePath(path, SEPARATOR);
if (value == null) {
section.data.remove(simplePath);
} else {
section.setDirect(simplePath, value);
}
}
/**
* 只能设置当前路径下的内容
* 避免环回
*
* @param path 路径
*/
public void setDirect(@NotNull String path, @Nullable Object value) {
this.data.put(path, value);
}
@Override
public boolean contains(@NotNull String path) {
return this.get(path) != null;
}
@Override
public @Nullable Object get(@NotNull String path) {
HOCONConfigWrapper section = HOCONUtils.getObjectOn(this, path, SEPARATOR);
return section.getDirect(HOCONUtils.getSimplePath(path, SEPARATOR));
}
/**
* 只能获取当前路径下的内容
* 避免环回
*
* @param path 路径
*/
public Object getDirect(@NotNull String path) {
return this.data.get(path);
}
@Override
public boolean isList(@NotNull String path) {
return this.get(path) instanceof List<?>;
}
@Override
public @Nullable List<?> getList(@NotNull String path) {
Object val = this.get(path);
return (val instanceof List<?>) ? (List<?>) val : null;
}
@Override
public boolean isConfigurationSection(@NotNull String path) {
return this.get(path) instanceof HOCONConfigWrapper;
}
@Override
public @Nullable ConfigurationWrapper<Map<String, Object>> getConfigurationSection(@NotNull String path) {
Object val = get(path);
return (val instanceof HOCONConfigWrapper) ? (HOCONConfigWrapper) val : null;
}
}
@@ -0,0 +1,106 @@
package cc.carm.lib.configuration.hocon;
import cc.carm.lib.configuration.core.ConfigInitializer;
import cc.carm.lib.configuration.core.source.ConfigurationComments;
import cc.carm.lib.configuration.core.source.impl.FileConfigProvider;
import cc.carm.lib.configuration.hocon.exception.HOCONGetValueException;
import cc.carm.lib.configuration.hocon.util.HOCONUtils;
import com.typesafe.config.*;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.List;
import java.util.Set;
public class HOCONFileConfigProvider extends FileConfigProvider<HOCONConfigWrapper> {
protected final @NotNull ConfigurationComments comments = new ConfigurationComments();
protected HOCONConfigWrapper configuration;
protected ConfigInitializer<HOCONFileConfigProvider> initializer;
public HOCONFileConfigProvider(@NotNull File file) {
super(file);
this.initializer = new ConfigInitializer<>(this);
}
public void initializeConfig() {
try {
this.configuration = new HOCONConfigWrapper(ConfigFactory.parseFile(this.file, ConfigParseOptions.defaults()
.setSyntax(ConfigSyntax.CONF)
.setAllowMissing(false)).root());
} catch (ConfigException e) {
e.printStackTrace();
}
}
@Override
public @NotNull HOCONConfigWrapper getConfiguration() {
return this.configuration;
}
@Override
public void save() throws IOException {
Files.write(this.file.toPath(), HOCONUtils.renderWithComment(configuration, comments::getHeaderComment).getBytes(StandardCharsets.UTF_8));
}
@Override
protected void onReload() throws ConfigException {
ConfigObject conf = ConfigFactory.parseFile(this.file, ConfigParseOptions.defaults()
.setSyntax(ConfigSyntax.CONF)
.setAllowMissing(false)).root();
this.configuration = new HOCONConfigWrapper(conf);
}
@Override
public @NotNull ConfigurationComments getComments() {
return this.comments;
}
@Override
public @NotNull ConfigInitializer<HOCONFileConfigProvider> getInitializer() {
return this.initializer;
}
public String serializeValue(@NotNull String key, @NotNull Object value) {
// 带有 key=value 的新空对象
return ConfigFactory.empty()
.withValue(key, ConfigValueFactory.fromAnyRef(value))
.root().render();
}
public @NotNull Set<String> getKeys() {
return getKeys(null, true);
}
@Contract("null,_->!null")
public @Nullable Set<String> getKeys(@Nullable String sectionKey, boolean deep) {
if (sectionKey == null) { // 当前路径
return HOCONUtils.getKeysFromObject(this.configuration, deep, "");
}
HOCONConfigWrapper section;
try {
// 获取目标字段所在路径
section = (HOCONConfigWrapper) this.configuration.get(sectionKey);
} catch (ClassCastException e) {
// 值和类型不匹配
throw new HOCONGetValueException(e);
}
if (section == null) {
return null;
}
return HOCONUtils.getKeysFromObject(section, deep, "");
}
public @Nullable Object getValue(@NotNull String key) {
return this.configuration.get(key);
}
public @Nullable List<String> getHeaderComments(@Nullable String key) {
return this.comments.getHeaderComment(key);
}
}
@@ -0,0 +1,19 @@
package cc.carm.lib.configuration.hocon.exception;
public class HOCONGetValueException extends RuntimeException {
public HOCONGetValueException() {
super();
}
public HOCONGetValueException(String message) {
super(message);
}
public HOCONGetValueException(String message, Throwable cause) {
super(message, cause);
}
public HOCONGetValueException(Throwable cause) {
super(cause);
}
}
@@ -0,0 +1,110 @@
package cc.carm.lib.configuration.hocon.util;
import cc.carm.lib.configuration.hocon.HOCONConfigWrapper;
import cc.carm.lib.configuration.hocon.exception.HOCONGetValueException;
import com.typesafe.config.*;
import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
public class HOCONUtils {
private HOCONUtils() {
}
public static String getSimplePath(String path, char separator) {
int index = path.lastIndexOf(separator);
return (index == -1) ? path : path.substring(index + 1);
}
public static HOCONConfigWrapper getObjectOn(@NotNull HOCONConfigWrapper parent, @NotNull String path, char separator) {
String currentPath = path;
HOCONConfigWrapper currentObject = parent;
int index;
while ((index = currentPath.indexOf(separator)) != -1) {
HOCONConfigWrapper previousObject = currentObject;
String pathName = currentPath.substring(0, index);
try {
currentObject = (HOCONConfigWrapper) previousObject.getDirect(pathName);
} catch (ClassCastException e) {
throw new HOCONGetValueException(e);
}
if (currentObject == null) {
currentObject = new HOCONConfigWrapper(ConfigFactory.empty().root());
previousObject.setDirect(pathName, currentObject);
}
currentPath = currentPath.substring(index + 1);
}
return currentObject;
}
/**
* 在 Object 中获取所有键
* 思路:在第一次执行时 prefix 应该是 ""
* 后续找到了更深层的键,将会变为 "deep."
* 下一次键名就是 "deep.key"
*
* @param parent Object
* @param deep 是否更深层获取
* @param prefix 当前 Object 键名前缀
* @return Object 中的所有键
*/
public static Set<String> getKeysFromObject(HOCONConfigWrapper parent, boolean deep, String prefix) {
return parent.getSource().entrySet().stream().collect(
LinkedHashSet::new,
(set, entry) -> {
Object value = entry.getValue();
if (value instanceof HOCONConfigWrapper && deep) {
set.addAll(HOCONUtils.getKeysFromObject((HOCONConfigWrapper) value, true, prefix + entry.getKey() + "."));
} else {
set.add(prefix + entry.getKey());
}
},
LinkedHashSet::addAll
);
}
/**
* 将 Object 保存为字符串
* 并使用注释器打上注释
*
* @param object Object
* @param commenter 注释器
* @return 保存的字符串
*/
public static @NotNull String renderWithComment(@NotNull HOCONConfigWrapper object, @NotNull Function<String, List<String>> commenter) {
return HOCONUtils.makeConfigWithComment(object, "", commenter).root().render(
ConfigRenderOptions.defaults()
.setJson(false)
.setOriginComments(false)
);
}
public static @NotNull Config makeConfigWithComment(@NotNull HOCONConfigWrapper object, @NotNull String prefix, @NotNull Function<String, List<String>> commenter) {
Config config = ConfigFactory.empty();
for (Map.Entry<String, Object> entry : object.getSource().entrySet()) {
String key = entry.getKey();
String fullKey = prefix + key;
Object value = entry.getValue();
ConfigValue result;
if (value instanceof Iterable) {
result = ConfigValueFactory.fromIterable((Iterable<?>) value);
} else if (value instanceof HOCONConfigWrapper) {
result = makeConfigWithComment((HOCONConfigWrapper) value, fullKey + ".", commenter).root();
} else {
result = ConfigValueFactory.fromAnyRef(value);
}
result = result.withOrigin(
ConfigOriginFactory.newSimple()
.withComments(commenter.apply(fullKey))
);
config = config.withValue(key, result);
}
return config;
}
}
@@ -0,0 +1,28 @@
package online.flowerinsnow.test.easyconfiguration;
import cc.carm.lib.configuration.EasyConfiguration;
import cc.carm.lib.configuration.hocon.HOCONFileConfigProvider;
import online.flowerinsnow.test.easyconfiguration.config.SimpleConfig;
import org.junit.Test;
import java.io.File;
public class HOCONTest {
@Test
public void onTest() {
HOCONFileConfigProvider provider = EasyConfiguration.from(new File("target/hocon.conf"));
provider.initialize(SimpleConfig.class);
// provider.initialize(DatabaseConfiguration.class);
System.out.println(SimpleConfig.TEST_INT.getNotNull());
SimpleConfig.TEST_INT.set((int) (Math.random() * 100 * 5));
System.out.println(SimpleConfig.TEST_INT.getNotNull());
try {
provider.save();
provider.reload();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,28 @@
package online.flowerinsnow.test.easyconfiguration.config;
import cc.carm.lib.configuration.core.Configuration;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.value.type.ConfiguredList;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
public interface SimpleConfig extends Configuration {
@HeaderComment("测试字段 int")
ConfiguredValue<Integer> TEST_INT = ConfiguredValue.of(Integer.class, 15);
@HeaderComment("测试字段 List<String>")
ConfiguredList<String> TEST_LIST_STRING = ConfiguredList.of(String.class, "li", "li", "li1");
@HeaderComment("测试对象")
interface TestObject extends Configuration {
@HeaderComment("测试字段 Boolean")
ConfiguredValue<Boolean> TEST_BOOLEAN = ConfiguredValue.of(Boolean.class, true);
@HeaderComment("inner")
interface InnerObject extends Configuration {
@HeaderComment("测试字段")
public static final ConfiguredValue<Boolean> TEST_BOOLEAN_1 = ConfiguredValue.of(Boolean.class, true);
}
}
}
+13 -4
View File
@@ -5,13 +5,15 @@
<parent>
<artifactId>easyconfiguration-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>2.3.0</version>
<version>3.9.0</version>
<relativePath>../../pom.xml</relativePath>
</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-json</artifactId>
<packaging>jar</packaging>
@@ -25,10 +27,17 @@
<scope>compile</scope>
</dependency>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-demo</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.0</version>
<version>2.10.1</version>
<scope>compile</scope>
</dependency>
@@ -7,6 +7,9 @@ import java.io.IOException;
public class EasyConfiguration {
private EasyConfiguration() {
}
public static JSONConfigProvider from(File file, String source) {
JSONConfigProvider provider = new JSONConfigProvider(file);
try {
@@ -1,7 +1,7 @@
package cc.carm.lib.configuration.json;
import cc.carm.lib.configuration.core.ConfigInitializer;
import cc.carm.lib.configuration.core.source.ConfigCommentInfo;
import cc.carm.lib.configuration.core.source.ConfigurationComments;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.source.impl.FileConfigProvider;
import com.google.gson.Gson;
@@ -12,6 +12,7 @@ import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.LinkedHashMap;
/**
@@ -37,6 +38,16 @@ public class JSONConfigProvider extends FileConfigProvider<JSONConfigWrapper> {
}
public void initializeConfig() {
onReload();
}
@Override
public @NotNull JSONConfigWrapper getConfiguration() {
return this.configuration;
}
@Override
protected void onReload() {
LinkedHashMap<?, ?> map = null;
try (FileInputStream is = new FileInputStream(file)) {
@@ -48,37 +59,20 @@ public class JSONConfigProvider extends FileConfigProvider<JSONConfigWrapper> {
if (map == null) map = new LinkedHashMap<>();
this.configuration = new JSONConfigWrapper(map);
this.initializer = new ConfigInitializer<>(this);
}
@Override
public @NotNull JSONConfigWrapper getConfiguration() {
return this.configuration;
}
@Override
public void reload() {
initializeConfig();
public @Nullable ConfigurationComments getComments() {
return null;
}
@Override
public void save() throws Exception {
try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
try (Writer writer = new OutputStreamWriter(Files.newOutputStream(file.toPath()), StandardCharsets.UTF_8)) {
gson.toJson(configuration.data, writer);
}
}
@Override
public void setComment(@Nullable String path, @Nullable ConfigCommentInfo comment) {
// JSON doesn't support comments;
}
@Override
public @Nullable ConfigCommentInfo getComment(@Nullable String path) {
return null;
}
@Override
public @NotNull ConfigInitializer<? extends ConfigurationProvider<JSONConfigWrapper>> getInitializer() {
return this.initializer;
@@ -14,7 +14,7 @@ import java.util.Set;
*
* @author md_5, CarmJos
*/
public class JSONConfigWrapper implements ConfigurationWrapper {
public class JSONConfigWrapper implements ConfigurationWrapper<Map<String, Object>> {
private static final char SEPARATOR = '.';
protected final Map<String, Object> data;
@@ -33,6 +33,10 @@ public class JSONConfigWrapper implements ConfigurationWrapper {
}
}
@Override
public @NotNull Map<String, Object> getSource() {
return this.data;
}
@Override
public @NotNull Set<String> getKeys(boolean deep) {
@@ -94,7 +98,7 @@ public class JSONConfigWrapper implements ConfigurationWrapper {
}
@Override
public @Nullable ConfigurationWrapper getConfigurationSection(@NotNull String path) {
public @Nullable JSONConfigWrapper getConfigurationSection(@NotNull String path) {
Object val = get(path);
return (val instanceof JSONConfigWrapper) ? (JSONConfigWrapper) val : null;
}
@@ -1,4 +0,0 @@
package cc.carm.lib.configuration.json;
public abstract class JSONValue {
}
@@ -1,67 +1,28 @@
package config;
import cc.carm.lib.configuration.EasyConfiguration;
import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
import cc.carm.lib.configuration.json.JSONConfigProvider;
import config.model.TestModel;
import config.source.DemoConfiguration;
import org.junit.Test;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class JSONConfigTest {
protected final JSONConfigProvider provider = EasyConfiguration.from("target/config.yml", "config.yml");
protected final JSONConfigProvider provider = EasyConfiguration.from("target/config.json", "config.json");
@Test
public void onTest() {
provider.initialize(DemoConfiguration.class);
ConfigurationTest.testDemo(this.provider);
ConfigurationTest.testInner(this.provider);
testDemo();
System.out.println("----------------------------------------------------");
provider.getConfiguration().getValues(true).forEach((k, v) -> System.out.println(k + ": " + v));
System.out.println("----------------------------------------------------");
provider.getConfiguration().getValues(false).forEach((k, v) -> System.out.println(k + ": " + v));
System.out.println("----------------------------------------------------");
try {
provider.save();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void testDemo() {
System.out.println("----------------------------------------------------");
System.out.println("> Test Value:");
System.out.println("before: " + DemoConfiguration.Sub.UUID_CONFIG_VALUE.get());
DemoConfiguration.Sub.UUID_CONFIG_VALUE.set(UUID.randomUUID());
System.out.println("after: " + DemoConfiguration.Sub.UUID_CONFIG_VALUE.get());
System.out.println("> Test List:");
DemoConfiguration.Sub.That.OPERATORS.getNotNull().forEach(System.out::println);
List<UUID> operators = IntStream.range(0, 5).mapToObj(i -> UUID.randomUUID()).collect(Collectors.toList());
DemoConfiguration.Sub.That.OPERATORS.set(operators);
System.out.println("> Test Section:");
System.out.println(DemoConfiguration.MODEL_TEST.get());
DemoConfiguration.MODEL_TEST.set(TestModel.random());
System.out.println("> Test Maps:");
DemoConfiguration.USERS.getNotNull().forEach((k, v) -> System.out.println(k + ": " + v));
LinkedHashMap<Integer, UUID> data = new LinkedHashMap<>();
for (int i = 1; i <= 5; i++) {
data.put(i, UUID.randomUUID());
}
DemoConfiguration.USERS.set(data);
System.out.println("----------------------------------------------------");
ConfigurationTest.save(this.provider);
}
@@ -1,39 +0,0 @@
package config.model;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
import java.util.HashMap;
import java.util.Map;
public class SomeModel extends AbstractModel {
int num;
public SomeModel(@NotNull String name, int num) {
super(name);
this.num = num;
}
@Override
public String toString() {
return "SomeModel{" +
"name='" + name + '\'' +
", num=" + num +
'}';
}
public @NotNull Map<String, Object> serialize() {
Map<String, Object> map = new HashMap<>();
map.put("name", name);
map.put("num", num);
return map;
}
@TestOnly
public static SomeModel deserialize(Map<String, ?> args) {
return new SomeModel((String) args.get("name"), (Integer) args.get("num"));
}
}
@@ -1,30 +0,0 @@
package config.source;
import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.ConfigComment;
import cc.carm.lib.configuration.core.annotation.ConfigPath;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
@ConfigComment({"数据库配置", " 用于提供数据库连接,进行数据库操作。"})
public class DatabaseConfiguration extends ConfigurationRoot {
@ConfigPath("driver")
protected static final ConfigValue<String> DRIVER_NAME = ConfiguredValue.of(
String.class, "com.mysql.cj.jdbc.Driver"
);
protected static final ConfigValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1");
protected static final ConfigValue<Integer> PORT = ConfiguredValue.of(Integer.class, 3306);
protected static final ConfigValue<String> DATABASE = ConfiguredValue.of(String.class, "minecraft");
protected static final ConfigValue<String> USERNAME = ConfiguredValue.of(String.class, "root");
protected static final ConfigValue<String> PASSWORD = ConfiguredValue.of(String.class, "password");
protected static final ConfigValue<String> EXTRA = ConfiguredValue.of(String.class, "?useSSL=false");
protected static String buildJDBC() {
return String.format("jdbc:mysql://%s:%s/%s%s", HOST.get(), PORT.get(), DATABASE.get(), EXTRA.get());
}
}
@@ -1,65 +0,0 @@
package config.source;
import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.ConfigPath;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.type.ConfiguredList;
import cc.carm.lib.configuration.core.value.type.ConfiguredMap;
import cc.carm.lib.configuration.core.value.type.ConfiguredSection;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
import config.model.TestModel;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
public class DemoConfiguration extends ConfigurationRoot {
@ConfigPath(root = true)
protected static final ConfigValue<Double> VERSION = ConfiguredValue.of(Double.class, 1.0D);
// 可以直接写静态内部类,并通过 Class<?> 声明。
public static final Class<?> SUB_TEST = Sub.class;
@ConfigPath("user") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
public static final ConfigValue<TestModel> MODEL_TEST = ConfiguredSection
.builder(TestModel.class)
.defaults(new TestModel("Carm", UUID.randomUUID()))
.parseValue((section, defaultValue) -> TestModel.deserialize(section))
.serializeValue(TestModel::serialize).build();
// 子配置文件
@ConfigPath("database")
public static final Class<?> DB_CONFIG = DatabaseConfiguration.class;
public static final ConfigValue<Map<Integer, UUID>> USERS = ConfiguredMap
.builder(Integer.class, UUID.class).fromString()
.parseKey(Integer::parseInt)
.parseValue(v -> Objects.requireNonNull(UUID.fromString(v)))
.build();
public static class Sub extends ConfigurationRoot {
@ConfigPath(value = "uuid-value", root = true)
public static final ConfigValue<UUID> UUID_CONFIG_VALUE = ConfiguredValue
.builder(UUID.class).fromString()
.parseValue((data, defaultValue) -> UUID.fromString(data))
.build();
public static final Class<?> NOTHING = That.class;
public static class That extends ConfigurationRoot {
public static final ConfigValue<List<UUID>> OPERATORS = ConfiguredList
.builder(UUID.class).fromString()
.parseValue(s -> Objects.requireNonNull(UUID.fromString(s)))
.build();
}
}
}
+81
View File
@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>easyconfiguration-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>3.9.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<properties>
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<log4j.version>2.22.0</log4j.version>
</properties>
<artifactId>easyconfiguration-sql</artifactId>
<dependencies>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>easysql-beecp</artifactId>
<version>0.4.7</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.1.210</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-demo</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,26 @@
package cc.carm.lib.configuration;
import cc.carm.lib.configuration.sql.SQLConfigProvider;
import cc.carm.lib.easysql.api.SQLManager;
import org.jetbrains.annotations.NotNull;
public class EasyConfiguration {
private EasyConfiguration() {
}
public static SQLConfigProvider from(@NotNull SQLManager sqlManager, @NotNull String tableName, @NotNull String namespace) {
SQLConfigProvider provider = new SQLConfigProvider(sqlManager, tableName, namespace);
try {
provider.initializeConfig();
} catch (Exception e) {
e.printStackTrace();
}
return provider;
}
public static SQLConfigProvider from(@NotNull SQLManager sqlManager, @NotNull String tableName) {
return from(sqlManager, tableName, "base");
}
}
@@ -0,0 +1,186 @@
package cc.carm.lib.configuration.sql;
import cc.carm.lib.configuration.core.ConfigInitializer;
import cc.carm.lib.configuration.core.source.ConfigurationComments;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.api.SQLQuery;
import cc.carm.lib.easysql.api.SQLTable;
import cc.carm.lib.easysql.api.enums.IndexType;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import org.jetbrains.annotations.NotNull;
import java.sql.ResultSet;
import java.util.*;
public class SQLConfigProvider extends ConfigurationProvider<SQLConfigWrapper> {
public static Gson GSON = new GsonBuilder().serializeNulls().disableHtmlEscaping().setPrettyPrinting().create();
protected final @NotNull SQLManager sqlManager;
protected final @NotNull SQLTable table;
protected final @NotNull String namespace;
protected ConfigInitializer<SQLConfigProvider> initializer;
protected ConfigurationComments comments = new ConfigurationComments();
protected SQLConfigWrapper rootConfiguration;
protected final @NotNull Set<String> updated = new HashSet<>();
public SQLConfigProvider(@NotNull SQLManager sqlManager, @NotNull String tableName, @NotNull String namespace) {
this.sqlManager = sqlManager;
this.table = SQLTable.of(tableName, builder -> {
builder.addColumn("namespace", "VARCHAR(32) NOT NULL");
builder.addColumn("path", "VARCHAR(96) NOT NULL");
builder.addColumn("type", "TINYINT NOT NULL DEFAULT 0");
builder.addColumn("value", "TEXT");
builder.addColumn("inline_comment", "TEXT");
builder.addColumn("header_comments", "MEDIUMTEXT");
builder.addColumn("create_time", "TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP");
builder.addColumn("update_time", "TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP");
builder.setIndex(
IndexType.PRIMARY_KEY, "pk_" + tableName.toLowerCase(),
"namespace", "path"
);
builder.setTableSettings("ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
});
this.namespace = namespace;
}
@Override
public @NotNull SQLConfigWrapper getConfiguration() {
return rootConfiguration;
}
public void initializeConfig() throws Exception {
this.table.create(this.sqlManager);
this.initializer = new ConfigInitializer<>(this);
onReload();
}
@Override
protected void onReload() throws Exception {
this.comments = new ConfigurationComments();
LinkedHashMap<String, Object> values = new LinkedHashMap<>();
try (SQLQuery query = this.table.createQuery()
.addCondition("namespace", namespace)
.build().execute()) {
ResultSet rs = query.getResultSet();
while (rs.next()) {
String path = rs.getString("path");
int type = rs.getInt("type");
try {
SQLValueResolver<?> resolver = SQLValueTypes.get(type);
if (resolver == null) throw new IllegalStateException("No resolver for type #" + type);
String value = rs.getString("value");
values.put(path, resolver.resolve(value));
loadInlineComment(path, rs.getString("inline_comment"));
loadHeaderComment(path, rs.getString("header_comments"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
this.rootConfiguration = new SQLConfigWrapper(this, values);
}
@Override
public void save() throws Exception {
if (this.updated.isEmpty()) return;
Date date = new Date();
List<Object[]> values = new ArrayList<>();
List<String> deletes = new ArrayList<>();
for (String path : this.updated) {
Object value = this.rootConfiguration.get(path);
if (value == null) {
deletes.add(path);
continue;
}
if (value instanceof SQLConfigWrapper) {
value = getSourceMap(((SQLConfigWrapper) value).getSource());
}
SQLValueResolver<?> type = SQLValueTypes.get(value.getClass());
if (type != null) {
values.add(new Object[]{
this.namespace, path, date,
type.getID(), type.serializeObject(value),
getComments().getInlineComment(path),
GSON.toJson(getComments().getHeaderComment(path))
});
}
}
this.updated.clear();
this.table.createReplaceBatch()
.setColumnNames("namespace", "path", "update_time", "type", "value", "inline_comment", "header_comments")
.setAllParams(values)
.execute();
for (String path : deletes) {
this.table.createDelete()
.addCondition("namespace", this.namespace)
.addCondition("path", path)
.build().execute();
}
}
@Override
public @NotNull ConfigurationComments getComments() {
return this.comments;
}
@Override
public @NotNull ConfigInitializer<? extends ConfigurationProvider<SQLConfigWrapper>> getInitializer() {
return this.initializer;
}
protected void loadInlineComment(String path, String comment) {
if (comment == null) return;
comment = comment.trim();
if (comment.isEmpty()) return;
this.comments.setInlineComment(path, comment);
}
protected void loadHeaderComment(String path, String commentJson) {
if (commentJson == null) return;
commentJson = commentJson.trim();
if (commentJson.isEmpty()) return;
List<String> headerComments = GSON.fromJson(commentJson, new TypeToken<List<String>>() {
}.getType());
if (headerComments == null || headerComments.isEmpty()) return;
this.comments.setHeaderComments(path, headerComments);
}
protected static Map<String, Object> getSourceMap(Map<String, Object> map) {
Map<String, Object> source = new LinkedHashMap<>();
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getValue() instanceof SQLConfigWrapper) {
source.put(entry.getKey(), getSourceMap(((SQLConfigWrapper) entry.getValue()).getSource()));
} else {
source.put(entry.getKey(), entry.getValue());
}
}
return source;
}
}
@@ -0,0 +1,122 @@
package cc.carm.lib.configuration.sql;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
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;
/**
* For SQL configs, that primary path will be directly mapped to the value.
*
* @author CarmJos
*/
public class SQLConfigWrapper implements ConfigurationWrapper<Map<String, Object>> {
private static final char SEPARATOR = '.';
protected final @NotNull SQLConfigProvider provider;
protected final @NotNull Map<String, Object> data;
SQLConfigWrapper(@NotNull SQLConfigProvider provider, @NotNull Map<?, ?> map) {
this.provider = provider;
this.data = new LinkedHashMap<>();
for (Map.Entry<?, ?> entry : map.entrySet()) {
String key = (entry.getKey() == null) ? "null" : entry.getKey().toString();
if (entry.getValue() instanceof Map) {
this.data.put(key, new SQLConfigWrapper(provider, (Map<?, ?>) entry.getValue()));
} else {
this.data.put(key, entry.getValue());
}
}
}
@Override
public @NotNull Map<String, Object> getSource() {
return this.data;
}
@Override
public @NotNull Set<String> getKeys(boolean deep) {
return getValues(deep).keySet();
}
@Override
public @NotNull Map<String, Object> getValues(boolean deep) {
// Deep is not supported for SQL configs.
return new LinkedHashMap<>(this.data);
}
@Override
public void set(@NotNull String path, @Nullable Object value) {
if (value instanceof Map) {
value = new SQLConfigWrapper(this.provider, (Map<?, ?>) value);
}
SQLConfigWrapper section = getSectionFor(path);
if (section == this) {
if (value == null) {
this.data.remove(path);
} else {
this.data.put(path, value);
}
} else {
section.set(getChild(path), value);
}
this.provider.updated.add(path);
}
@Override
public boolean contains(@NotNull String path) {
return get(path) != null;
}
@Override
public @Nullable Object get(@NotNull String path) {
SQLConfigWrapper section = getSectionFor(path);
return section == this ? data.get(path) : section.get(getChild(path));
}
@Override
public boolean isList(@NotNull String path) {
return get(path) instanceof List<?>;
}
@Override
public @Nullable List<?> getList(@NotNull String path) {
Object val = get(path);
return (val instanceof List<?>) ? (List<?>) val : null;
}
@Override
public boolean isConfigurationSection(@NotNull String path) {
return get(path) instanceof SQLConfigWrapper;
}
@Override
public @Nullable SQLConfigWrapper getConfigurationSection(@NotNull String path) {
Object val = get(path);
return (val instanceof SQLConfigWrapper) ? (SQLConfigWrapper) val : null;
}
private SQLConfigWrapper getSectionFor(String path) {
int index = path.indexOf(SEPARATOR);
if (index == -1) return this;
String root = path.substring(0, index);
Object section = this.data.computeIfAbsent(root, k -> new SQLConfigWrapper(this.provider, new LinkedHashMap<>()));
return (SQLConfigWrapper) section;
}
private String getChild(String path) {
int index = path.indexOf(SEPARATOR);
return (index == -1) ? path : path.substring(index + 1);
}
}
@@ -0,0 +1,60 @@
package cc.carm.lib.configuration.sql;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
public class SQLValueResolver<T> {
public static <V> SQLValueResolver<V> of(int id, @NotNull Class<V> clazz,
@NotNull ConfigDataFunction<String, V> resolver) {
return of(id, clazz, resolver, String::valueOf);
}
public static <V> SQLValueResolver<V> of(int id, @NotNull Class<V> clazz,
@NotNull ConfigDataFunction<String, V> resolver,
@NotNull Function<V, String> serializer) {
return new SQLValueResolver<>(id, clazz, resolver, serializer);
}
protected final int id;
protected final @NotNull Class<T> clazz;
protected final @NotNull ConfigDataFunction<String, T> resolver;
protected final @NotNull Function<T, String> serializer;
protected SQLValueResolver(int id, @NotNull Class<T> clazz,
@NotNull ConfigDataFunction<String, T> resolver,
@NotNull Function<T, String> serializer) {
this.id = id;
this.clazz = clazz;
this.resolver = resolver;
this.serializer = serializer;
}
public int getID() {
return id;
}
public @NotNull Class<T> getClazz() {
return clazz;
}
public boolean isTypeOf(@NotNull Class<?> clazz) {
return this.clazz.isAssignableFrom(clazz);
}
public @NotNull T resolve(String data) throws Exception {
return resolver.parse(data);
}
public @Nullable String serialize(T value) {
return String.valueOf(value);
}
public @Nullable String serializeObject(Object value) {
return isTypeOf(value.getClass()) ? serialize(clazz.cast(value)) : null;
}
}
@@ -0,0 +1,54 @@
package cc.carm.lib.configuration.sql;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
interface SQLValueTypes {
SQLValueResolver<String> STRING = SQLValueResolver.of(0, String.class, ConfigDataFunction.identity());
SQLValueResolver<Byte> BYTE = SQLValueResolver.of(1, Byte.class, Byte::parseByte);
SQLValueResolver<Short> SHORT = SQLValueResolver.of(2, Short.class, Short::parseShort);
SQLValueResolver<Integer> INTEGER = SQLValueResolver.of(3, Integer.class, Integer::parseInt);
SQLValueResolver<Long> LONG = SQLValueResolver.of(4, Long.class, Long::parseLong);
SQLValueResolver<Float> FLOAT = SQLValueResolver.of(5, Float.class, Float::parseFloat);
SQLValueResolver<Double> DOUBLE = SQLValueResolver.of(6, Double.class, Double::parseDouble);
SQLValueResolver<Boolean> BOOLEAN = SQLValueResolver.of(7, Boolean.class, Boolean::parseBoolean);
SQLValueResolver<Character> CHAR = SQLValueResolver.of(8, Character.class, s -> s.charAt(0));
@SuppressWarnings("rawtypes")
SQLValueResolver<List> LIST = SQLValueResolver.of(10, List.class,
array -> SQLConfigProvider.GSON.fromJson(array, List.class),
list -> SQLConfigProvider.GSON.toJson(list)
);
@SuppressWarnings("rawtypes")
SQLValueResolver<Map> SECTION = SQLValueResolver.of(20, Map.class,
section -> SQLConfigProvider.GSON.fromJson(section, LinkedHashMap.class),
section -> SQLConfigProvider.GSON.toJson(section)
);
static @NotNull SQLValueResolver<?>[] values() {
return new SQLValueResolver<?>[]{
STRING, BYTE, SHORT, INTEGER, LONG, FLOAT, DOUBLE, BOOLEAN, CHAR, LIST, SECTION
};
}
static SQLValueResolver<?> valueOf(int index) {
return values()[index];
}
static @Nullable SQLValueResolver<?> get(int id) {
return Arrays.stream(values()).filter(v -> v.id == id).findFirst().orElse(null);
}
static @Nullable SQLValueResolver<?> get(Class<?> typeClazz) {
return Arrays.stream(values()).filter(v -> v.isTypeOf(typeClazz)).findFirst().orElse(null);
}
}
@@ -0,0 +1,40 @@
package config;
import cc.carm.lib.configuration.EasyConfiguration;
import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
import cc.carm.lib.configuration.sql.SQLConfigProvider;
import cc.carm.lib.easysql.EasySQL;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.beecp.BeeDataSourceConfig;
import org.junit.Test;
public class SQLConfigTest {
@Test
public void onTest() {
// test();
}
public void test() {
BeeDataSourceConfig config = new BeeDataSourceConfig();
config.setDriverClassName("org.h2.Driver");
config.setJdbcUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;MODE=MySQL;");
SQLManager manager = EasySQL.createManager(config);
manager.setDebugMode(true);
SQLConfigProvider provider = EasyConfiguration.from(manager, "conf_test", "TESTING");
ConfigurationTest.testDemo(provider);
ConfigurationTest.testInner(provider);
System.out.println("----------------------------------------------------");
provider.getConfiguration().getValues(true).forEach((k, v) -> System.out.println(k + ": " + v));
System.out.println("----------------------------------------------------");
provider.getConfiguration().getValues(false).forEach((k, v) -> System.out.println(k + ": " + v));
System.out.println("----------------------------------------------------");
ConfigurationTest.save(provider);
}
}
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="config.SQLConfigTest">
<Appenders>
<console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg%n"/>
</console>
</Appenders>
<Loggers>
<Root level="info">
<filters>
<MarkerFilter marker="NETWORK_PACKETS" onMatch="DENY" onMismatch="NEUTRAL"/>
<RegexFilter regex=".*\$\{[^}]*\}.*" onMatch="DENY" onMismatch="NEUTRAL"/>
</filters>
<AppenderRef ref="File"/>
<appender-ref ref="Console"/>
</Root>
</Loggers>
</Configuration>
+14
View File
@@ -0,0 +1,14 @@
CREATE TABLE IF NOT EXISTS conf
(
`namespace` VARCHAR(32) NOT NULL, # ()
`path` VARCHAR(96) NOT NULL, # (ConfigPath)
`type` TINYINT UNSIGNED NOT NULL DEFAULT 0, # (Integer/Byte/List/Map/...)
`value` MEDIUMTEXT, # (JSON格式)
`inline_comments` TEXT, #
`header_comments` MEDIUMTEXT, #
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, #
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`namespace`, `path`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
+20 -4
View File
@@ -5,13 +5,15 @@
<parent>
<artifactId>easyconfiguration-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>2.3.0</version>
<version>3.9.0</version>
<relativePath>../../pom.xml</relativePath>
</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-yaml</artifactId>
@@ -26,10 +28,24 @@
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>yamlcommentwriter</artifactId>
<version>1.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-demo</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.bspfsystems</groupId>
<artifactId>yamlconfiguration</artifactId>
<version>1.0.11</version>
<version>2.0.0</version>
<scope>compile</scope>
</dependency>
@@ -7,6 +7,9 @@ import java.io.IOException;
public class EasyConfiguration {
private EasyConfiguration() {
}
public static YAMLConfigProvider from(File file, String source) {
YAMLConfigProvider provider = new YAMLConfigProvider(file);
try {
@@ -30,5 +33,4 @@ public class EasyConfiguration {
return from(new File(fileName), source);
}
}
@@ -1,114 +0,0 @@
package cc.carm.lib.configuration.yaml;
import cc.carm.lib.configuration.core.source.ConfigCommentInfo;
import org.bspfsystems.yamlconfiguration.configuration.ConfigurationSection;
import org.bspfsystems.yamlconfiguration.file.FileConfiguration;
import org.bspfsystems.yamlconfiguration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.StringJoiner;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static cc.carm.lib.configuration.yaml.YAMLConfigProvider.SEPARATOR;
public class YAMLComments {
Map<String, ConfigCommentInfo> comments = new HashMap<>();
protected Map<String, ConfigCommentInfo> getComments() {
return comments;
}
public void set(@Nullable String path, @Nullable ConfigCommentInfo comments) {
if (comments == null) {
getComments().remove(path);
} else {
getComments().put(path, comments);
}
}
public @NotNull ConfigCommentInfo get(@Nullable String path) {
return getComments().getOrDefault(path, ConfigCommentInfo.defaults());
}
public @Nullable String buildComments(@NotNull String indents, @Nullable String path) {
ConfigCommentInfo comments = get(path);
if (!String.join("", comments.getComments()).isEmpty()) {
String prefix = comments.startWrap() ? "\n" : "";
String suffix = comments.endWrap() ? "\n" : "";
StringJoiner joiner = new StringJoiner("\n", prefix, suffix);
for (String comment : comments.getComments()) {
if (comment.length() == 0) joiner.add(" ");
else joiner.add(indents + "# " + comment);
}
return joiner + "\n";
} else {
return comments.startWrap() || comments.endWrap() ? "\n" : null;
}
}
/**
* 从一个文件读取配置并写入注释到某个写入器中。
* 该方法的源代码来自 tchristofferson/ConfigUpdater 项目。
*
* @param source 源配置文件
* @param writer 配置写入器
* @throws IOException 当写入发生错误时抛出
*/
public void writeComments(@NotNull YamlConfiguration source, @NotNull BufferedWriter writer) throws IOException {
FileConfiguration parserConfig = new YamlConfiguration();
for (String fullKey : source.getKeys(true)) {
String indents = getIndents(fullKey);
String comment = buildComments(indents, fullKey);
if (comment != null) writer.write(comment);
Object currentValue = source.get(fullKey);
String[] splitFullKey = fullKey.split("[" + SEPARATOR + "]");
String trailingKey = splitFullKey[splitFullKey.length - 1];
if (currentValue instanceof ConfigurationSection) {
writer.write(indents + trailingKey + ":");
if (!((ConfigurationSection) currentValue).getKeys(false).isEmpty())
writer.write("\n");
else
writer.write(" {}\n");
continue;
}
parserConfig.set(trailingKey, currentValue);
String yaml = parserConfig.saveToString();
yaml = yaml.substring(0, yaml.length() - 1).replace("\n", "\n" + indents);
String toWrite = indents + yaml + "\n";
parserConfig.set(trailingKey, null);
writer.write(toWrite);
}
String endComment = buildComments("", null);
if (endComment != null) writer.write(endComment);
writer.close();
}
/**
* 得到一个键的缩进。
* 该方法的源代码来自 tchristofferson/ConfigUpdater 项目。
*
* @param key 键
* @return 该键的缩进文本
*/
protected static String getIndents(String key) {
String[] splitKey = key.split("[" + YAMLConfigProvider.SEPARATOR + "]");
return IntStream.range(1, splitKey.length).mapToObj(i -> " ").collect(Collectors.joining());
}
}
@@ -1,24 +1,23 @@
package cc.carm.lib.configuration.yaml;
import cc.carm.lib.configuration.core.ConfigInitializer;
import cc.carm.lib.configuration.core.source.ConfigCommentInfo;
import cc.carm.lib.configuration.core.source.ConfigurationComments;
import cc.carm.lib.configuration.core.source.impl.FileConfigProvider;
import cc.carm.lib.yamlcommentupdater.CommentedYAML;
import cc.carm.lib.yamlcommentupdater.CommentedYAMLWriter;
import org.bspfsystems.yamlconfiguration.configuration.ConfigurationSection;
import org.bspfsystems.yamlconfiguration.file.FileConfiguration;
import org.bspfsystems.yamlconfiguration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.BufferedWriter;
import java.io.File;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Set;
public class YAMLConfigProvider extends FileConfigProvider<YAMLSectionWrapper> {
public class YAMLConfigProvider extends FileConfigProvider<YAMLSectionWrapper> implements CommentedYAML {
protected static final char SEPARATOR = '.';
protected final @NotNull YAMLComments comments = new YAMLComments();
protected final @NotNull ConfigurationComments comments = new ConfigurationComments();
protected YamlConfiguration configuration;
protected ConfigInitializer<YAMLConfigProvider> initializer;
@@ -37,37 +36,23 @@ public class YAMLConfigProvider extends FileConfigProvider<YAMLSectionWrapper> {
}
@Override
public void reload() throws Exception {
protected void onReload() throws Exception {
configuration.load(getFile());
}
@Override
public @NotNull ConfigurationComments getComments() {
return this.comments;
}
@Override
public void save() throws Exception {
configuration.save(getFile());
// tchristofferson/ConfigUpdater start
StringWriter writer = new StringWriter();
this.comments.writeComments(configuration, new BufferedWriter(writer));
String value = writer.toString(); // config contents
Path toUpdatePath = getFile().toPath();
if (!value.equals(new String(Files.readAllBytes(toUpdatePath), StandardCharsets.UTF_8))) {
// if updated contents are not the same as current file contents, update
Files.write(toUpdatePath, value.getBytes(StandardCharsets.UTF_8));
try {
CommentedYAMLWriter.writeWithComments(this, this.file);
} catch (Exception ex) {
configuration.save(file);
throw ex;
}
// tchristofferson/ConfigUpdater end
}
@Override
public void setComment(@Nullable String path, @Nullable ConfigCommentInfo comments) {
this.comments.set(path, comments);
}
@Override
public @Nullable ConfigCommentInfo getComment(@Nullable String path) {
return this.comments.get(path);
}
@Override
@@ -75,4 +60,31 @@ public class YAMLConfigProvider extends FileConfigProvider<YAMLSectionWrapper> {
return this.initializer;
}
@Override
public String serializeValue(@NotNull String key, @NotNull Object value) {
FileConfiguration temp = new YamlConfiguration();
temp.set(key, value);
return temp.saveToString();
}
@Override
public Set<String> getKeys(@Nullable String sectionKey, boolean deep) {
if (sectionKey == null) return configuration.getKeys(deep);
ConfigurationSection section = configuration.getConfigurationSection(sectionKey);
if (section == null) return null;
return section.getKeys(deep);
}
@Override
public @Nullable Object getValue(@NotNull String key) {
return configuration.get(key);
}
@Override
public @Nullable List<String> getHeaderComments(@Nullable String key) {
return comments.getHeaderComment(key);
}
}
@@ -12,7 +12,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
public class YAMLSectionWrapper implements ConfigurationWrapper {
public class YAMLSectionWrapper implements ConfigurationWrapper<ConfigurationSection> {
private final ConfigurationSection section;
@@ -25,6 +25,11 @@ public class YAMLSectionWrapper implements ConfigurationWrapper {
return section == null ? null : new YAMLSectionWrapper(section);
}
@Override
public @NotNull ConfigurationSection getSource() {
return this.section;
}
@Override
public @NotNull Set<String> getKeys(boolean deep) {
return new LinkedHashSet<>(section.getKeys(deep));
@@ -66,7 +71,7 @@ public class YAMLSectionWrapper implements ConfigurationWrapper {
}
@Override
public @Nullable ConfigurationWrapper getConfigurationSection(@NotNull String path) {
public @Nullable YAMLSectionWrapper getConfigurationSection(@NotNull String path) {
return of(this.section.getConfigurationSection(path));
}
@@ -1,11 +1,10 @@
package cc.carm.lib.configuration.yaml;
import cc.carm.lib.configuration.core.source.ConfigCommentInfo;
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.value.ValueManifest;
import cc.carm.lib.configuration.core.value.impl.CachedConfigValue;
import cc.carm.lib.configuration.yaml.builder.YAMLConfigBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class YAMLValue<T> extends CachedConfigValue<T> {
@@ -13,10 +12,8 @@ public abstract class YAMLValue<T> extends CachedConfigValue<T> {
return new YAMLConfigBuilder();
}
public YAMLValue(@Nullable YAMLConfigProvider provider,
@Nullable String configPath, @Nullable ConfigCommentInfo comments,
@Nullable T defaultValue) {
super(provider, configPath, comments, defaultValue);
public YAMLValue(@NotNull ValueManifest<T> manifest) {
super(manifest);
}
public YAMLConfigProvider getYAMLProvider() {
@@ -21,7 +21,7 @@ public class SerializableBuilder<T extends ConfigurationSerializable>
@Override
public @NotNull ConfiguredSerializable<T> build() {
return new ConfiguredSerializable<>(this.provider, this.path, buildComments(), this.valueClass, this.defaultValue);
return new ConfiguredSerializable<>(buildManifest(), this.valueClass);
}
@@ -1,14 +1,11 @@
package cc.carm.lib.configuration.yaml.value;
import cc.carm.lib.configuration.core.source.ConfigCommentInfo;
import cc.carm.lib.configuration.yaml.YAMLConfigProvider;
import cc.carm.lib.configuration.core.value.ValueManifest;
import cc.carm.lib.configuration.yaml.YAMLValue;
import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
public class ConfiguredSerializable<T extends ConfigurationSerializable> extends YAMLValue<T> {
public static <V extends ConfigurationSerializable> ConfiguredSerializable<V> of(@NotNull Class<V> valueClass) {
@@ -22,25 +19,24 @@ public class ConfiguredSerializable<T extends ConfigurationSerializable> extends
protected final @NotNull Class<T> valueClass;
public ConfiguredSerializable(@Nullable YAMLConfigProvider provider,
@Nullable String configPath, @Nullable ConfigCommentInfo comments,
@NotNull Class<T> valueClass, @Nullable T defaultValue) {
super(provider, configPath, comments, defaultValue);
public ConfiguredSerializable(@NotNull ValueManifest<T> manifest, @NotNull Class<T> valueClass) {
super(manifest);
this.valueClass = valueClass;
}
@Override
public @Nullable T get() {
if (isExpired()) { // 已过时的数据,需要重新解析一次。
if (!isExpired()) return getCachedOrDefault();
try {
// 若未出现错误,则直接更新缓存并返回。
return updateCache(getYAMLConfig().getSerializable(getConfigPath(), valueClass, getDefaultValue()));
} catch (Exception e) {
// 出现了解析错误,提示并返回默认值。
e.printStackTrace();
return useDefault();
return getDefaultValue();
}
} else return Optional.ofNullable(getCachedValue()).orElse(defaultValue);
}
@Override
@@ -1,81 +0,0 @@
package config;
import cc.carm.lib.configuration.EasyConfiguration;
import cc.carm.lib.configuration.yaml.YAMLConfigProvider;
import config.model.AbstractModel;
import config.model.SomeModel;
import config.model.TestModel;
import config.source.DemoConfiguration;
import config.source.ImplConfiguration;
import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerialization;
import org.junit.Test;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class ConfigTester {
static {
ConfigurationSerialization.registerClass(TestModel.class);
ConfigurationSerialization.registerClass(SomeModel.class);
}
protected final YAMLConfigProvider provider = EasyConfiguration.from("target/config.yml", "config.yml");
@Test
public void onTest() {
provider.initialize(DemoConfiguration.class);
testDemo();
testSerialization();
try {
provider.save();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void testDemo() {
System.out.println("----------------------------------------------------");
System.out.println("> Test Value:");
System.out.println("before: " + DemoConfiguration.Sub.UUID_CONFIG_VALUE.get());
DemoConfiguration.Sub.UUID_CONFIG_VALUE.set(UUID.randomUUID());
System.out.println("after: " + DemoConfiguration.Sub.UUID_CONFIG_VALUE.get());
System.out.println("> Test List:");
DemoConfiguration.Sub.That.OPERATORS.getNotNull().forEach(System.out::println);
List<UUID> operators = IntStream.range(0, 5).mapToObj(i -> UUID.randomUUID()).collect(Collectors.toList());
DemoConfiguration.Sub.That.OPERATORS.set(operators);
System.out.println("> Test Section:");
System.out.println(DemoConfiguration.MODEL_TEST.get());
DemoConfiguration.MODEL_TEST.set(TestModel.random());
System.out.println("> Test Maps:");
DemoConfiguration.USERS.getNotNull().forEach((k, v) -> System.out.println(k + ": " + v));
LinkedHashMap<Integer, UUID> data = new LinkedHashMap<>();
for (int i = 1; i <= 5; i++) {
data.put(i, UUID.randomUUID());
}
DemoConfiguration.USERS.set(data);
System.out.println("----------------------------------------------------");
}
public static void testSerialization() {
System.out.println("----------------------------------------------------");
AbstractModel model = ImplConfiguration.TEST.get();
if (model != null) {
System.out.println(model.getName());
}
System.out.println("----------------------------------------------------");
}
}
@@ -0,0 +1,54 @@
package config;
import cc.carm.lib.configuration.EasyConfiguration;
import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
import cc.carm.lib.configuration.demo.tests.model.AbstractModel;
import cc.carm.lib.configuration.yaml.YAMLConfigProvider;
import config.model.AnyModel;
import config.model.SomeModel;
import config.source.ModelConfiguration;
import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerialization;
import org.junit.Test;
import java.io.IOException;
public class DemoConfigTest {
static {
ConfigurationSerialization.registerClass(SomeModel.class);
ConfigurationSerialization.registerClass(AnyModel.class);
}
protected final YAMLConfigProvider provider = EasyConfiguration.from("target/config.yml", "test/test2/config.yml");
@Test
public void onTest() {
ConfigurationTest.testDemo(this.provider);
ConfigurationTest.testInner(this.provider);
testSerialization(this.provider);
ConfigurationTest.save(this.provider);
}
public static void testSerialization(YAMLConfigProvider provider) {
provider.initialize(ModelConfiguration.class);
System.out.println("----------------------------------------------------");
AbstractModel someModel = ModelConfiguration.SOME_MODEL.get();
if (someModel != null) System.out.println(someModel.getName());
AbstractModel anyModel = ModelConfiguration.ANY_MODEL.get();
if (anyModel != null) System.out.println(anyModel.getName());
ModelConfiguration.MODELS.forEach(System.out::println);
ModelConfiguration.MODEL_MAP.forEach((v, anyModel1) -> System.out.println(v + " -> " + anyModel1.toString()));
System.out.println("----------------------------------------------------");
}
}
@@ -1,26 +0,0 @@
package config;
import config.offset.FieldOffset;
import config.offset.OffsetUtil;
import config.source.DemoConfiguration;
import org.junit.Test;
import java.util.List;
public class OffsetTest {
@Test
public void test() {
//
// output(OffsetUtil.getClassMemberOffset(DemoConfiguration.class));
// output(OffsetUtil.getClassMemberOffset(DemoConfiguration.Sub.class));
}
protected static void output(List<FieldOffset> fieldOffsets) {
for (FieldOffset fieldOffset : fieldOffsets) {
System.out.println(fieldOffset.getOffsetValue() + " -> " + fieldOffset);
}
}
}
@@ -1,17 +0,0 @@
package config.model;
import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable;
import org.jetbrains.annotations.NotNull;
public abstract class AbstractModel implements ConfigurationSerializable {
protected final @NotNull String name;
public AbstractModel(@NotNull String name) {
this.name = name;
}
public @NotNull String getName() {
return name;
}
}
@@ -0,0 +1,50 @@
package config.model;
import cc.carm.lib.configuration.demo.tests.model.AbstractModel;
import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable;
import org.bspfsystems.yamlconfiguration.serialization.SerializableAs;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@SerializableAs("AnyModel")
public class AnyModel extends AbstractModel implements ConfigurationSerializable {
public final boolean bool;
public AnyModel(@NotNull String name, boolean bool) {
super(name);
this.bool = bool;
}
@Override
public String toString() {
return "AnyModel{" +
"name='" + name + '\'' +
", bool=" + bool +
'}';
}
@Override
public @NotNull Map<String, Object> serialize() {
Map<String, Object> map = new HashMap<>();
map.put("name", name);
map.put("state", bool);
return map;
}
public static AnyModel random() {
return new AnyModel(UUID.randomUUID().toString().substring(0, 5), Math.random() > 0.5);
}
@TestOnly
public static AnyModel deserialize(Map<String, ?> args) {
return new AnyModel((String) args.get("name"), (Boolean) args.get("state"));
}
}
@@ -1,5 +1,6 @@
package config.model;
import cc.carm.lib.configuration.demo.tests.model.AbstractModel;
import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable;
import org.bspfsystems.yamlconfiguration.serialization.SerializableAs;
import org.jetbrains.annotations.NotNull;
@@ -7,11 +8,12 @@ import org.jetbrains.annotations.TestOnly;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@SerializableAs("SomeModel")
public class SomeModel extends AbstractModel implements ConfigurationSerializable {
int num;
public final int num;
public SomeModel(@NotNull String name, int num) {
super(name);
@@ -34,6 +36,11 @@ public class SomeModel extends AbstractModel implements ConfigurationSerializabl
return map;
}
public static SomeModel random() {
return new SomeModel(UUID.randomUUID().toString().substring(0, 5), (int) (Math.random() * 1000));
}
@TestOnly
public static SomeModel deserialize(Map<String, ?> args) {
return new SomeModel((String) args.get("name"), (Integer) args.get("num"));
@@ -1,72 +0,0 @@
package config.model;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable;
import org.bspfsystems.yamlconfiguration.serialization.SerializableAs;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@SerializableAs("TestModel")
public class TestModel extends AbstractModel implements ConfigurationSerializable {
public UUID uuid;
public TestModel(String name, UUID uuid) {
super(name);
this.uuid = uuid;
}
public void setUuid(UUID uuid) {
this.uuid = uuid;
}
public UUID getUuid() {
return uuid;
}
@Override
public @NotNull Map<String, Object> serialize() {
Map<String, Object> map = new HashMap<>();
map.put("name", name);
Map<String, Object> map2 = new HashMap<>();
map2.put("uuid", uuid.toString());
map.put("info", map2);
return map;
}
public static TestModel deserialize(ConfigurationWrapper section) {
String name = section.getString("name");
if (name == null) throw new NullPointerException("name is null");
String uuidString = section.getString("info.uuid");
if (uuidString == null) throw new NullPointerException("uuid is null");
return new TestModel(name, UUID.fromString(uuidString));
}
@TestOnly
@SuppressWarnings("unchecked")
public static TestModel deserialize(Map<String, ?> args) {
String name = (String) args.get("name");
if (name == null) throw new NullPointerException("name is null");
Map<String, ?> map = (Map<String, ?>) args.get("info");
String uuidString = (String) map.get("uuid");
if (uuidString == null) throw new NullPointerException("uuid is null");
return new TestModel(name, UUID.fromString(uuidString));
}
public static TestModel random() {
return new TestModel(UUID.randomUUID().toString().substring(0, 5), UUID.randomUUID());
}
@Override
public String toString() {
return "TestUser{" +
"name='" + name + '\'' +
", uuid=" + uuid +
'}';
}
}
@@ -1,63 +0,0 @@
package config.offset;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* @author Chris2018998
*/
public class OffsetUtil {
private static Unsafe unsafe;
static {
try {
// 获取 Unsafe 内部的私有的实例化单例对象
Field field = Unsafe.class.getDeclaredField("theUnsafe");
// 无视权限
field.setAccessible(true);
unsafe = (Unsafe) field.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
// try {
// unsafe = AccessController.doPrivileged((PrivilegedExceptionAction<Unsafe>) () -> {
// Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
// theUnsafe.setAccessible(true);
// return (Unsafe) theUnsafe.get(null);
// });
// } catch (Throwable e) {
// System.err.println("Unable to load unsafe");
// }
}
public static List<FieldOffset> getClassMemberOffset(Class<?> beanClass) {
List<FieldOffset> offsetsList = new LinkedList<>();
for (Field field : beanClass.getDeclaredFields()) {
FieldOffset fieldOffset = new FieldOffset(field);
offsetsList.add(fieldOffset);
if (Modifier.isStatic(field.getModifiers()))
fieldOffset.setOffsetValue(unsafe.staticFieldOffset(field));
else
fieldOffset.setOffsetValue(unsafe.objectFieldOffset(field));
Class<?> fieldType = field.getType();
if (!fieldType.getName().startsWith("java")) {
Field[] subfields = fieldType.getDeclaredFields();
if (subfields.length > 0) {
fieldOffset.setSubFieldOffsetList(getClassMemberOffset(fieldType));
}
}
}
Collections.sort(offsetsList);
return offsetsList;
}
}
@@ -1,16 +0,0 @@
package config.source;
import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.ConfigPath;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.yaml.value.ConfiguredSerializable;
import config.model.AbstractModel;
import config.model.TestModel;
@ConfigPath(root = true)
public class ImplConfiguration extends ConfigurationRoot {
public static final ConfigValue<? extends AbstractModel> TEST = ConfiguredSerializable.of(TestModel.class, TestModel.random());
}
@@ -0,0 +1,43 @@
package config.source;
import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.ConfigPath;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.type.ConfiguredList;
import cc.carm.lib.configuration.core.value.type.ConfiguredMap;
import cc.carm.lib.configuration.core.value.type.ConfiguredSectionMap;
import cc.carm.lib.configuration.demo.tests.model.AbstractModel;
import cc.carm.lib.configuration.yaml.value.ConfiguredSerializable;
import config.model.AnyModel;
import config.model.SomeModel;
@HeaderComment("以下内容用于测试序列化")
@ConfigPath("model-test")
public class ModelConfiguration extends ConfigurationRoot {
public static final ConfigValue<? extends AbstractModel> SOME_MODEL = ConfiguredSerializable.of(
SomeModel.class, SomeModel.random()
);
public static final ConfigValue<? extends AbstractModel> ANY_MODEL = ConfiguredSerializable.of(
AnyModel.class, AnyModel.random()
);
public static final ConfiguredList<AnyModel> MODELS = ConfiguredList.builderOf(AnyModel.class)
.fromMap()
.parseValue(AnyModel::deserialize).serializeValue(AnyModel::serialize)
.defaults(AnyModel.random(), AnyModel.random(), AnyModel.random())
.build();
public static final ConfiguredSectionMap<String, AnyModel> MODEL_MAP = ConfiguredMap.builderOf(String.class, AnyModel.class)
.asLinkedMap().fromSection()
.parseValue(v -> new AnyModel(v.getString("name", "EMPTY"), v.getBoolean("state", false)))
.serializeValue(AnyModel::serialize)
.defaults(m -> {
m.put("a", AnyModel.random());
m.put("b", AnyModel.random());
})
.build();
}
-2
View File
@@ -1,2 +0,0 @@
# Test Header
version: 1.0
@@ -0,0 +1,2 @@
version: 1.0
test-save: false
+19 -16
View File
@@ -5,9 +5,9 @@
<modelVersion>4.0.0</modelVersion>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<project.jdk.version>1.8</project.jdk.version>
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties>
@@ -15,11 +15,14 @@
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId>
<packaging>pom</packaging>
<version>2.3.0</version>
<version>3.9.0</version>
<modules>
<module>core</module>
<module>demo</module>
<module>impl/yaml</module>
<module>impl/json</module>
<module>impl/sql</module>
<module>impl/hocon</module>
</modules>
<name>EasyConfiguration</name>
@@ -90,7 +93,7 @@
<downloadUrl>https://github.com/CarmJos/EasyConfiguration/releases</downloadUrl>
<site>
<id>javadoc</id>
<name>EasyConfiguration JavaDoc (on Github Pages)</name>
<name>EasyConfiguration JavaDoc (on GitHub Pages)</name>
<url>https://CarmJos.github.io/EasyConfiguration</url>
</site>
</distributionManagement>
@@ -107,7 +110,7 @@
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>23.0.0</version>
<version>24.1.0</version>
<scope>provided</scope>
</dependency>
@@ -120,7 +123,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<version>3.2.3</version>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
@@ -128,7 +131,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.0.1</version>
<version>3.1.0</version>
<executions>
<execution>
<id>sign-artifacts</id>
@@ -148,7 +151,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
<version>3.0.1</version>
<configuration>
<autoVersionSubmodules>true</autoVersionSubmodules>
<useReleaseProfile>false</useReleaseProfile>
@@ -164,7 +167,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.4.0</version>
<version>3.6.3</version>
<configuration>
<classifier>javadoc</classifier>
<detectJavaApiLink>false</detectJavaApiLink>
@@ -191,10 +194,10 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<version>3.12.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<source>${project.jdk.version}</source>
<target>${project.jdk.version}</target>
<encoding>UTF-8</encoding>
<compilerArgument>-parameters</compilerArgument>
</configuration>
@@ -203,13 +206,13 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.2</version>
<version>3.3.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<version>3.3.0</version>
<executions>
<execution>
<phase>package</phase>
@@ -223,7 +226,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version>
<version>3.5.1</version>
<executions>
<execution>
<phase>package</phase>