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

Compare commits

...

24 Commits

Author SHA1 Message Date
carm dbec551c84 chore: Fixed the param errors. 2025-03-17 01:39:08 +08:00
carm 82cca5eca2 feat(exception): Supported ConfigExceptionHandler for holders. 2025-03-17 01:06:57 +08:00
carm 65f3cc1b3d feat(validator): Support validators for config values.
BREAKING CHANGE: `ValueManifest` and `ConfigValue` added a new type "UNIT" to mark the minimal unit value of this instance.

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

link #132
2025-03-16 23:56:36 +08:00
carm 854e3df49f feat: Upgrade configured to v4.1.0 2025-03-15 01:52:52 +08:00
carm f6167c3b5e docs: Update license [skip ci] 2025-03-15 01:51:07 +08:00
carm ffe3e88b3b docs: Translated to English 2025-03-14 19:34:06 +08:00
carm caa3077f48 chore: Add missing @Nullable 2025-03-14 19:33:30 +08:00
carm 05dbf0b504 docs: Redesign readme 2025-03-14 19:20:31 +08:00
carm 810e95198e docs: Redesign readme 2025-03-14 19:17:26 +08:00
carm 10004f16b4 docs(logo): Add project banner & logo 2025-03-14 19:09:43 +08:00
carm 8e19748c7c feat(map): Add more builder functions 2025-03-12 04:04:00 +08:00
carm 17762a2e70 refactor(proj): Change project name to "configured" 2025-03-12 03:27:35 +08:00
carm 7dbd607a3f refactor(proj): Change project name to "configured" 2025-03-12 03:22:40 +08:00
carm 035e8a227e test(parse): Add more tests 2025-03-06 20:12:33 +08:00
carm 04eaf6606d feat: Jump to 4.0.11 2025-03-06 18:19:25 +08:00
carm e558e93410 feat(sql): Support custom sql table schema 2025-03-06 18:19:06 +08:00
flowerinsnow e55fe3a8d5 feat: hocon supported 2025-03-06 18:03:27 +08:00
carm 8f075b99b5 chore(deps): use parent dependencies' version 2025-03-04 11:58:01 +08:00
carm 09a0b3c373 chore(deps): use parent dependencies' version 2025-03-04 11:34:16 +08:00
carm 4df4977733 feat(msg): add enhanced text support 2025-03-04 04:21:58 +08:00
carm 6434feb980 fix(sql): Fixed sql table format 2025-03-04 01:57:04 +08:00
carm bc3e4b3e6f fix(comment): Fixed yaml comments 2025-03-04 01:24:12 +08:00
carm c2a9e2254c feat(section): Add ConfigureSection#asMap function 2025-03-04 01:06:21 +08:00
94 changed files with 1406 additions and 1106 deletions
+2 -8
View File
@@ -1,9 +1,3 @@
# EasyConfiguration Javadoc # configured Javadoc
基于 [Github Pages](https://pages.github.com/) 搭建,请访问 [JavaDoc](https://carmjos.github.io/EasyConfiguration) 。 Based on [Github Pages](https://pages.github.com/), please see [JavaDoc](https://carmjos.github.io/configured) 。
## 如何实现?
若您也想通过 [Github Actions](https://docs.github.com/en/actions/learn-github-actions)
自动部署项目的Javadoc到 [Github Pages](https://pages.github.com/)
可以参考我的文章 [《自动部署Javadoc到Github Pages》](https://pages.carm.cc/doc/javadoc-in-github.html) 。
+1 -16
View File
@@ -1,16 +1 @@
# 欢迎使用 EasyConfiguration # Documentation
这个项目刚刚创建,详细的Javadoc与开发指南还在补充,请给我一点时间~
## 基本定义
Value: 实际配置的单例值。
Manifest: 用于描述值基本配置的对象。
Provider: 用于提供配置文件的接口。
Wrapper: 用于包装配置文件的接口。
Initializer: 用于初始化的接口
Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

+2 -2
View File
@@ -47,7 +47,7 @@ jobs:
id: sitemap id: sitemap
uses: cicirello/generate-sitemap@v1 uses: cicirello/generate-sitemap@v1
with: with:
base-url-path: https://CarmJos.github.io/EasyConfiguration base-url-path: https://CarmJos.github.io/configured
path-to-root: docs path-to-root: docs
- name: "Output stats" - name: "Output stats"
@@ -72,7 +72,7 @@ jobs:
run: | run: |
cd docs cd docs
git init git init
git remote add origin git@github.com:CarmJos/EasyConfiguration.git git remote add origin git@github.com:CarmJos/configured.git
git checkout -b gh-pages git checkout -b gh-pages
git add -A git add -A
git commit -m "API Document generated." git commit -m "API Document generated."
+1
View File
@@ -1,6 +1,7 @@
GNU LESSER GENERAL PUBLIC LICENSE GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007 Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.
+31 -31
View File
@@ -1,26 +1,24 @@
```text <div align=center>
____ _____ ____ __ _ <img src=".doc/images/banner.png" alt="Banner"/>
/ __/__ ____ __ __ / ___/__ ___ / _(_)__ ___ _________ _/ /_(_)__ ___
/ _// _ `(_-</ // / / /__/ _ \/ _ \/ _/ / _ `/ // / __/ _ `/ __/ / _ \/ _ \ [![version](https://img.shields.io/github/v/release/CarmJos/configured)](https://github.com/CarmJos/configured/releases)
/___/\_,_/___/\_, / \___/\___/_//_/_//_/\_, /\_,_/_/ \_,_/\__/_/\___/_//_/ [![License](https://img.shields.io/github/license/CarmJos/configured)](https://www.gnu.org/licenses/lgpl-3.0.html)
/___/ /___/ [![workflow](https://github.com/CarmJos/configured/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/configured/actions/workflows/maven.yml)
``` [![CodeFactor](https://www.codefactor.io/repository/github/carmjos/configured/badge)](https://www.codefactor.io/repository/github/carmjos/configured)
![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/configured)
![](https://visitor-badge.glitch.me/badge?page_id=configured.readme)
README LANGUAGES [ [**English**](README.md) | [中文](README_CN.md) ] README LANGUAGES [ [**English**](README.md) | [中文](README_CN.md) ]
</div>
# EasyConfiguration # configured (config-framework)
[![version](https://img.shields.io/github/v/release/CarmJos/EasyConfiguration)](https://github.com/CarmJos/EasyConfiguration/releases) _**"Once set, Simple get."**_
[![License](https://img.shields.io/github/license/CarmJos/EasyConfiguration)](https://www.gnu.org/licenses/lgpl-3.0.html)
[![workflow](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml)
[![CodeFactor](https://www.codefactor.io/repository/github/carmjos/easyconfiguration/badge)](https://www.codefactor.io/repository/github/carmjos/easyconfiguration)
![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/EasyConfiguration)
![](https://visitor-badge.glitch.me/badge?page_id=EasyConfiguration.readme)
**Easy _(to make)_ Configurations!** A simple, easy-to-use and universal solution for managing, loading, reading,
and updating configuration files.
A simple, easy-to-use and universal solution for managing configuration files. Supported **JSON**, **YAML**, **Hocon**, **TOML**, **SQL**, **MongoDB**... and much more!
Enjoy the ease of use with customizable formats for loading, reading, and updating your configuration files.
## Features & Advantages ## Features & Advantages
@@ -35,13 +33,14 @@ format.
## Development ## Development
For the latest JavaDoc release, [CLICK HERE](https://CarmJos.github.io/EasyConfiguration). For the latest JavaDoc release, [CLICK HERE](https://CarmJos.github.io/configured).
For a detailed development guide, [CLICK HERE](.doc/README.md). For a detailed development guide, [CLICK HERE](.doc/README.md).
### Code Samples ### Code Samples
To quickly demonstrate the applicability of the project, here are a few practical demonstrations: To quickly demonstrate the applicability of the project, here are a few practical demonstrations:
- [Database configuration.](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java) - [Database configuration.](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java)
- [Demonstration of all types of configuration instance classes.](demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java) - [Demonstration of all types of configuration instance classes.](demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java)
@@ -49,6 +48,7 @@ Check out all code demonstrations [HERE](demo/src/main/java/cc/carm/lib/configur
For more examples, see the [Development Guide](.doc/README.md). For more examples, see the [Development Guide](.doc/README.md).
```java ```java
@ConfigPath(root = true) @ConfigPath(root = true)
@HeaderComments("Configurations for sample") @HeaderComments("Configurations for sample")
public interface SampleConfig extends Configuration { public interface SampleConfig extends Configuration {
@@ -95,9 +95,9 @@ public class Sample {
// 2. Initialize the configuration classes or instances. // 2. Initialize the configuration classes or instances.
holder.initialize(SampleConfig.class); holder.initialize(SampleConfig.class);
// 3. Enjoy using the configuration! // 3. Enjoy using the configuration!
System.out.println("Enabled? -> " + SampleConfig.ENABLED.resolve()); System.out.println("Enabled? -> " + SampleConfig.ENABLED.resolve()); // true
SampleConfig.ENABLED.set(false); SampleConfig.ENABLED.set(false);
System.out.println("And now? -> " + SampleConfig.ENABLED.resolve()); System.out.println("And now? -> " + SampleConfig.ENABLED.resolve()); // false
// p.s. Changes not save so enable value will still be true in the next run. // p.s. Changes not save so enable value will still be true in the next run.
System.out.println("Your name is " + SampleConfig.INFO.NAME.resolve() + " (age=" + SampleConfig.INFO.AGE.resolve() + ")!"); System.out.println("Your name is " + SampleConfig.INFO.NAME.resolve() + " (age=" + SampleConfig.INFO.AGE.resolve() + ")!");
@@ -148,9 +148,9 @@ info:
<repository> <repository>
<!-- Using GitHub dependencies for real-time updates, configuration required (recommended). --> <!-- Using GitHub dependencies for real-time updates, configuration required (recommended). -->
<id>EasyConfiguration</id> <id>configured</id>
<name>GitHub Packages</name> <name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url> <url>https://maven.pkg.github.com/CarmJos/configured</url>
</repository> </repository>
</repositories> </repositories>
@@ -169,7 +169,7 @@ info:
<!-- Basic implementation part, requiring custom implementation of “Provider” and “Wrapper”. --> <!-- Basic implementation part, requiring custom implementation of “Provider” and “Wrapper”. -->
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -177,7 +177,7 @@ info:
<!-- YAML file-based implementation, compatible with all Java environments. --> <!-- YAML file-based implementation, compatible with all Java environments. -->
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-yaml</artifactId> <artifactId>configured-yaml</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -185,7 +185,7 @@ info:
<!-- JSON file-based implementation, compatible with all Java environments. --> <!-- JSON file-based implementation, compatible with all Java environments. -->
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-gson</artifactId> <artifactId>configured-gson</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -208,7 +208,7 @@ repositories {
mavenCentral() mavenCentral()
// Using GitHub dependencies for real-time updates, configuration required (recommended). // Using GitHub dependencies for real-time updates, configuration required (recommended).
maven { url 'https://maven.pkg.github.com/CarmJos/EasyConfiguration' } maven { url 'https://maven.pkg.github.com/CarmJos/configured' }
} }
``` ```
@@ -223,13 +223,13 @@ repositories {
dependencies { dependencies {
// Basic implementation part, requiring custom implementation of “Provider” and “Wrapper”. // Basic implementation part, requiring custom implementation of “Provider” and “Wrapper”.
api "cc.carm.lib:easyconfiguration-core:[LATEST RELEASE]" api "cc.carm.lib:configured-core:[LATEST RELEASE]"
// YAML file-based implementation, compatible with all Java environments. // YAML file-based implementation, compatible with all Java environments.
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]" api "cc.carm.lib:configured-yaml:[LATEST RELEASE]"
// JSON file-based implementation, compatible with all Java environments. // JSON file-based implementation, compatible with all Java environments.
api "cc.carm.lib:easyconfiguration-gson:[LATEST RELEASE]" api "cc.carm.lib:configured-gson:[LATEST RELEASE]"
} }
``` ```
@@ -240,7 +240,7 @@ dependencies {
### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos) ### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos)
EasyConfiguration for MineCraft! configured for MineCraft!
Easily manage configurations on MineCraft-related server platforms. Easily manage configurations on MineCraft-related server platforms.
Currently, it supports BungeeCord, Velocity, Bukkit (Spigot) servers, Currently, it supports BungeeCord, Velocity, Bukkit (Spigot) servers,
@@ -254,7 +254,7 @@ Thank you for supporting open-source projects!
Many thanks to Jetbrains for kindly providing a license for us to work on this and other open-source projects. Many thanks to Jetbrains for kindly providing a license for us to work on this and other open-source projects.
[![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/CarmJos/EasyConfiguration) [![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/CarmJos/configured)
Many thanks to [ArtformGames](https://github.com/ArtformGames) for their Many thanks to [ArtformGames](https://github.com/ArtformGames) for their
strong support and active contribution to this project! strong support and active contribution to this project!
+29 -32
View File
@@ -1,29 +1,26 @@
```text <div align=center>
____ _____ ____ __ _ <img src=".doc/images/banner.png" alt="Banner"/>
/ __/__ ____ __ __ / ___/__ ___ / _(_)__ ___ _________ _/ /_(_)__ ___
/ _// _ `(_-</ // / / /__/ _ \/ _ \/ _/ / _ `/ // / __/ _ `/ __/ / _ \/ _ \ [![version](https://img.shields.io/github/v/release/CarmJos/configured)](https://github.com/CarmJos/configured/releases)
/___/\_,_/___/\_, / \___/\___/_//_/_//_/\_, /\_,_/_/ \_,_/\__/_/\___/_//_/ [![License](https://img.shields.io/github/license/CarmJos/configured)](https://www.gnu.org/licenses/lgpl-3.0.html)
/___/ /___/ [![workflow](https://github.com/CarmJos/configured/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/configured/actions/workflows/maven.yml)
``` [![CodeFactor](https://www.codefactor.io/repository/github/carmjos/configured/badge)](https://www.codefactor.io/repository/github/carmjos/configured)
![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/configured)
![](https://visitor-badge.glitch.me/badge?page_id=configured.readme)
README LANGUAGES [ [English](README.md) | [**中文**](README_CN.md) ] README LANGUAGES [ [English](README.md) | [**中文**](README_CN.md) ]
# EasyConfiguration </div>
[![version](https://img.shields.io/github/v/release/CarmJos/EasyConfiguration)](https://github.com/CarmJos/EasyConfiguration/releases) # configured (config-framework)
[![License](https://img.shields.io/github/license/CarmJos/EasyConfiguration)](https://www.gnu.org/licenses/lgpl-3.0.html)
[![workflow](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml)
[![CodeFactor](https://www.codefactor.io/repository/github/carmjos/easyconfiguration/badge)](https://www.codefactor.io/repository/github/carmjos/easyconfiguration)
![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/EasyConfiguration)
![](https://visitor-badge.glitch.me/badge?page_id=EasyConfiguration.readme)
**轻松(做)配置** **一次配置,轻松读取**
一款简单便捷的通用配置文件加载、读取与更新工具,可自定义配置的格式。 一款简单便捷的通用配置文件加载、读取与更新工具,可自定义配置的格式。
## 特性 & 优势 ## 特性 & 优势
支持 [YAML](impl/yaml), [JSON](impl/json), [HOCON](impl/hocon) 和 [SQL](impl/sql) 等多种配置文件格式。 支持 [YAML](providers/yaml), [JSON](providers/gson), [HOCON](providers/hocon) 和 [SQL](providers/sql) 等多种配置文件格式。
- 基于类的配置文件初始化、加载、获取与更新机制,方便快捷。 - 基于类的配置文件初始化、加载、获取与更新机制,方便快捷。
- 支持复杂配置的手动序列化、反序列化。 - 支持复杂配置的手动序列化、反序列化。
@@ -33,7 +30,7 @@ README LANGUAGES [ [English](README.md) | [**中文**](README_CN.md) ]
## 开发 ## 开发
详细开发介绍请 [点击这里](.doc/README.md) , JavaDoc(最新Release) 详细开发介绍请 [点击这里](.doc/README.md) , JavaDoc(最新Release)
请 [点击这里](https://CarmJos.github.io/EasyConfiguration) 。 请 [点击这里](https://CarmJos.github.io/configured) 。
### 示例代码 ### 示例代码
@@ -142,9 +139,9 @@ info:
<repository> <repository>
<!--采用github依赖库,实时更新,但需要配置 (推荐) --> <!--采用github依赖库,实时更新,但需要配置 (推荐) -->
<id>EasyConfiguration</id> <id>configured</id>
<name>GitHub Packages</name> <name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url> <url>https://maven.pkg.github.com/CarmJos/configured</url>
</repository> </repository>
<repository> <repository>
@@ -170,7 +167,7 @@ info:
<!--基础实现部分,需要自行实现“Provider”与“Wrapper”。--> <!--基础实现部分,需要自行实现“Provider”与“Wrapper”。-->
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -178,7 +175,7 @@ info:
<!--基于YAML文件的实现版本,可用于全部Java环境。--> <!--基于YAML文件的实现版本,可用于全部Java环境。-->
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-yaml</artifactId> <artifactId>configured-yaml</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -187,21 +184,21 @@ info:
<!--需要注意的是,JSON不支持文件注释。--> <!--需要注意的是,JSON不支持文件注释。-->
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-gson</artifactId> <artifactId>configured-gson</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-hocon</artifactId> <artifactId>configured-hocon</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-sql</artifactId> <artifactId>configured-sql</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -224,7 +221,7 @@ repositories {
mavenCentral() mavenCentral()
// 采用github依赖库,实时更新,但需要配置 (推荐) // 采用github依赖库,实时更新,但需要配置 (推荐)
maven { url 'https://maven.pkg.github.com/CarmJos/EasyConfiguration' } maven { url 'https://maven.pkg.github.com/CarmJos/configured' }
// 采用我的私人依赖库,简单方便,但可能因为变故而无法使用 // 采用我的私人依赖库,简单方便,但可能因为变故而无法使用
maven { url 'https://repo.carm.cc/repository/maven-public/' } maven { url 'https://repo.carm.cc/repository/maven-public/' }
@@ -241,18 +238,18 @@ repositories {
dependencies { dependencies {
//基础实现部分,需要自行实现“Provider”与“Wrapper”。 //基础实现部分,需要自行实现“Provider”与“Wrapper”。
api "cc.carm.lib:easyconfiguration-core:[LATEST RELEASE]" api "cc.carm.lib:configured-core:[LATEST RELEASE]"
//基于YAML文件的实现版本,可用于全部Java环境。 //基于YAML文件的实现版本,可用于全部Java环境。
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]" api "cc.carm.lib:configured-yaml:[LATEST RELEASE]"
//基于JSON文件的实现版本,可用于全部Java环境。 //基于JSON文件的实现版本,可用于全部Java环境。
//需要注意的是,JSON不支持文件注释。 //需要注意的是,JSON不支持文件注释。
api "cc.carm.lib:easyconfiguration-gson:[LATEST RELEASE]" api "cc.carm.lib:configured-gson:[LATEST RELEASE]"
api "cc.carm.lib:easyconfiguration-hocon:[LATEST RELEASE]" api "cc.carm.lib:configured-hocon:[LATEST RELEASE]"
api "cc.carm.lib:easyconfiguration-sql:[LATEST RELEASE]" api "cc.carm.lib:configured-sql:[LATEST RELEASE]"
} }
``` ```
@@ -263,7 +260,7 @@ dependencies {
### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos ) ### [**MineConfiguration**](https://github.com/CarmJos/MineConfiguration) (by @CarmJos )
EasyConfiguration for MineCraft! configured for MineCraft!
开始在 MineCraft 相关服务器平台上轻松(做)配置吧! 开始在 MineCraft 相关服务器平台上轻松(做)配置吧!
目前支持 BungeeCord, Bukkit(Spigot) 服务端,后续将支持更多平台。 目前支持 BungeeCord, Bukkit(Spigot) 服务端,后续将支持更多平台。
@@ -276,7 +273,7 @@ EasyConfiguration for MineCraft!
万分感谢 Jetbrains 为我们提供了从事此项目和其他开源项目的许可! 万分感谢 Jetbrains 为我们提供了从事此项目和其他开源项目的许可!
[![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/CarmJos/EasyConfiguration) [![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/CarmJos/configured)
万分感谢来自 [ArtformGames](https://github.com/ArtformGames) 对本项目的大力支持与积极贡献! 万分感谢来自 [ArtformGames](https://github.com/ArtformGames) 对本项目的大力支持与积极贡献!
+3 -3
View File
@@ -3,9 +3,9 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>4.0.8</version> <version>4.1.1</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<properties> <properties>
@@ -15,7 +15,7 @@
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties> </properties>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<build> <build>
@@ -15,6 +15,7 @@ public class ValueAdapter<TYPE>
implements ValueSerializer<TYPE>, ValueParser<TYPE> { implements ValueSerializer<TYPE>, ValueParser<TYPE> {
protected final @NotNull ValueType<TYPE> type; protected final @NotNull ValueType<TYPE> type;
protected @Nullable ValueSerializer<TYPE> serializer; protected @Nullable ValueSerializer<TYPE> serializer;
protected @Nullable ValueParser<TYPE> deserializer; protected @Nullable ValueParser<TYPE> deserializer;
@@ -53,13 +54,17 @@ public class ValueAdapter<TYPE>
} }
@Override @Override
public Object serialize(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<? super TYPE> type, @NotNull TYPE value) throws Exception { public @Nullable Object serialize(
@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<? super TYPE> type,
@NotNull TYPE value) throws Exception {
if (serializer == null) throw new UnsupportedOperationException("Serializer is not supported"); if (serializer == null) throw new UnsupportedOperationException("Serializer is not supported");
return serializer.serialize(holder, type, value); return serializer.serialize(holder, type, value);
} }
@Override @Override
public TYPE parse(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<? super TYPE> type, @NotNull Object value) throws Exception { public @Nullable TYPE parse(
@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<? super TYPE> type,
@NotNull Object value) throws Exception {
if (deserializer == null) throw new UnsupportedOperationException("Deserializer is not supported"); if (deserializer == null) throw new UnsupportedOperationException("Deserializer is not supported");
return deserializer.parse(holder, type, value); return deserializer.parse(holder, type, value);
} }
@@ -61,7 +61,9 @@ public class ValueAdapterRegistry {
} }
} }
public <T> void register(@NotNull ValueType<T> type, @Nullable ValueSerializer<T> serializer, @Nullable ValueParser<T> deserializer) { public <T> void register(@NotNull ValueType<T> type,
@Nullable ValueSerializer<T> serializer,
@Nullable ValueParser<T> deserializer) {
if (serializer == null && deserializer == null) return; if (serializer == null && deserializer == null) return;
ValueAdapter<T> existing = adapterOf(type); ValueAdapter<T> existing = adapterOf(type);
if (existing != null) { if (existing != null) {
@@ -2,6 +2,7 @@ package cc.carm.lib.configuration.adapter;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* Value deserializer, convert base data to target value. * Value deserializer, convert base data to target value.
@@ -11,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
@FunctionalInterface @FunctionalInterface
public interface ValueParser<TYPE> { public interface ValueParser<TYPE> {
TYPE parse( @Nullable TYPE parse(
@NotNull ConfigurationHolder<?> holder, @NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type, @NotNull Object data @NotNull ValueType<? super TYPE> type, @NotNull Object data
) throws Exception; ) throws Exception;
@@ -2,6 +2,7 @@ package cc.carm.lib.configuration.adapter;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* Value serializer, convert target value to base data. * Value serializer, convert target value to base data.
@@ -11,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
@FunctionalInterface @FunctionalInterface
public interface ValueSerializer<TYPE> { public interface ValueSerializer<TYPE> {
Object serialize( @Nullable Object serialize(
@NotNull ConfigurationHolder<?> holder, @NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type, @NotNull TYPE value @NotNull ValueType<? super TYPE> type, @NotNull TYPE value
) throws Exception; ) throws Exception;
@@ -5,6 +5,8 @@ import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.source.section.ConfigureSection; import cc.carm.lib.configuration.source.section.ConfigureSection;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.UUID;
import static cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapter.*; import static cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapter.*;
public interface StandardAdapters { public interface StandardAdapters {
@@ -17,6 +19,12 @@ public interface StandardAdapters {
@NotNull ValueAdapter<Enum<?>> ENUMS = PrimitiveAdapter.ofEnum(); @NotNull ValueAdapter<Enum<?>> ENUMS = PrimitiveAdapter.ofEnum();
@NotNull ValueAdapter<UUID> UUID = new ValueAdapter<>(
ValueType.of(UUID.class),
(provider, type, value) -> value.toString(),
(provider, type, value) -> java.util.UUID.fromString(value.toString())
);
@NotNull ValueAdapter<ConfigureSection> SECTIONS = new ValueAdapter<>( @NotNull ValueAdapter<ConfigureSection> SECTIONS = new ValueAdapter<>(
ValueType.of(ConfigureSection.class), ValueType.of(ConfigureSection.class),
(provider, type, value) -> value, (provider, type, value) -> value,
@@ -1,21 +1,26 @@
package cc.carm.lib.configuration.builder; package cc.carm.lib.configuration.builder;
import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.function.DataValidator;
import cc.carm.lib.configuration.function.ValueValidator;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder; import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.ConfigValue;
import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.ValueManifest;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.NotNullByDefault;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier; import java.util.function.Supplier;
@NotNullByDefault
public abstract class AbstractConfigBuilder< public abstract class AbstractConfigBuilder<
TYPE, RESULT extends ConfigValue<TYPE>, HOLDER extends ConfigurationHolder<?>, TYPE, UNIT, RESULT extends ConfigValue<TYPE, UNIT>, HOLDER extends ConfigurationHolder<?>,
SELF extends AbstractConfigBuilder<TYPE, RESULT, HOLDER, SELF> SELF extends AbstractConfigBuilder<TYPE, UNIT, RESULT, HOLDER, SELF>
> { > {
protected final Class<? super HOLDER> providerClass; protected final Class<? super HOLDER> providerClass;
@@ -24,6 +29,7 @@ public abstract class AbstractConfigBuilder<
protected @Nullable HOLDER holder; protected @Nullable HOLDER holder;
protected @Nullable String path; protected @Nullable String path;
protected @NotNull ValueValidator<UNIT> valueValidator = ValueValidator.none();
protected @NotNull Supplier<@Nullable TYPE> defaultValueSupplier = () -> null; protected @NotNull Supplier<@Nullable TYPE> defaultValueSupplier = () -> null;
protected @NotNull BiConsumer<ConfigurationHolder<?>, String> initializer = (h, p) -> { protected @NotNull BiConsumer<ConfigurationHolder<?>, String> initializer = (h, p) -> {
}; };
@@ -37,54 +43,121 @@ public abstract class AbstractConfigBuilder<
return type; return type;
} }
protected abstract @NotNull SELF self(); protected abstract SELF self();
public abstract @NotNull RESULT build(); public abstract @NotNull RESULT build();
public @NotNull SELF holder(@Nullable HOLDER holder) { public SELF holder(@Nullable HOLDER holder) {
this.holder = holder; this.holder = holder;
return self(); return self();
} }
public @NotNull SELF path(@Nullable String path) { public SELF path(@Nullable String path) {
this.path = path; this.path = path;
return self(); return self();
} }
public @NotNull SELF initializer(@NotNull BiConsumer<ConfigurationHolder<?>, String> initializer) { /**
* Set the {@link ValueValidator} for the value.
*
* @param validator The validator to set.
* @return this builder
*/
public SELF validator(@NotNull ValueValidator<UNIT> validator) {
this.valueValidator = validator;
return self();
}
/**
* Set the {@link DataValidator} for the value.
*
* @param validator The validator to set.
* @return this builder
*/
public SELF validator(@NotNull DataValidator<? super UNIT> validator) {
return validator((h, value) -> validator.validate(value));
}
/**
* Validate the value with the specified condition.
*
* @param validator The validator to append.
* @return this builder
*/
public SELF validate(@NotNull ValueValidator<? super UNIT> validator) {
return validator(this.valueValidator.and(validator));
}
/**
* Validate the value with the specified condition.
*
* @param validator The validator to append.
* @return this builder
*/
public SELF validate(@NotNull DataValidator<? super UNIT> validator) {
return validate((h, value) -> validator.validate(value));
}
/**
* Validate the value with the specified condition.
*
* @param condition The condition to check, if the condition is false, an exception will be thrown.
* @param exception The exception to throw if the condition is false.
* @return this builder
*/
public SELF validate(@NotNull Predicate<? super UNIT> condition, @NotNull Exception exception) {
return validate((h, value) -> {
if (!condition.test(value)) throw exception;
});
}
/**
* Validate the value with the specified condition.
*
* @param condition The condition to check, if the condition is false, an exception will be thrown.
* @param msg The message to throw if the condition is false.
* @return this builder
*/
public SELF validate(@NotNull Predicate<? super UNIT> condition, @NotNull String msg) {
return validate((h, value) -> {
if (!condition.test(value)) throw new IllegalArgumentException(msg);
});
}
public SELF initializer(@NotNull BiConsumer<ConfigurationHolder<?>, String> initializer) {
this.initializer = initializer; this.initializer = initializer;
return self(); return self();
} }
public @NotNull SELF append(@NotNull BiConsumer<ConfigurationHolder<?>, String> initializer) { public SELF append(@NotNull BiConsumer<ConfigurationHolder<?>, String> initializer) {
return initializer(initializer.andThen(initializer)); return initializer(initializer.andThen(initializer));
} }
public @NotNull SELF append(@NotNull Consumer<ConfigurationHolder<?>> initializer) { public SELF append(@NotNull Consumer<ConfigurationHolder<?>> initializer) {
return append((provider, valuePath) -> initializer.accept(provider)); return append((provider, valuePath) -> initializer.accept(provider));
} }
public @NotNull SELF defaults(@Nullable TYPE defaultValue) { public SELF defaults(@Nullable TYPE defaultValue) {
return defaults(() -> defaultValue); return defaults(() -> defaultValue);
} }
public @NotNull SELF defaults(@NotNull Supplier<@Nullable TYPE> supplier) { public SELF defaults(@NotNull Supplier<@Nullable TYPE> supplier) {
this.defaultValueSupplier = supplier; this.defaultValueSupplier = supplier;
return self(); return self();
} }
public <M> @NotNull SELF meta(@NotNull Consumer<@NotNull ConfigurationMetaHolder> metaConsumer) { public SELF meta(@NotNull Consumer<@NotNull ConfigurationMetaHolder> metaConsumer) {
return append((h, p) -> metaConsumer.accept(h.metadata(p))); return append((h, p) -> metaConsumer.accept(h.metadata(p)));
} }
public <M> @NotNull SELF meta(@NotNull ConfigurationMetadata<M> type, @Nullable M value) { public <M> SELF meta(@NotNull ConfigurationMetadata<M> type, @Nullable M value) {
return meta(h -> h.set(type, value)); return meta(h -> h.set(type, value));
} }
protected @NotNull ValueManifest<TYPE> buildManifest() { protected @NotNull ValueManifest<TYPE, UNIT> buildManifest() {
return new ValueManifest<>( return new ValueManifest<>(
type(), this.defaultValueSupplier, this.initializer, type(), this.defaultValueSupplier, this.valueValidator,
this.holder, this.path this.initializer, this.holder, this.path
); );
} }
@@ -4,8 +4,11 @@ import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.ConfigValue;
public abstract class CommonConfigBuilder<TYPE, RESULT extends ConfigValue<TYPE>, SELF extends CommonConfigBuilder<TYPE, RESULT, SELF>> public abstract class CommonConfigBuilder<
extends AbstractConfigBuilder<TYPE, RESULT, ConfigurationHolder<?>, SELF> { TYPE, UNIT,
RESULT extends ConfigValue<TYPE, UNIT>,
SELF extends CommonConfigBuilder<TYPE, UNIT, RESULT, SELF>
> extends AbstractConfigBuilder<TYPE, UNIT, RESULT, ConfigurationHolder<?>, SELF> {
protected CommonConfigBuilder(ValueType<TYPE> type) { protected CommonConfigBuilder(ValueType<TYPE> type) {
super(ConfigurationHolder.class, type); super(ConfigurationHolder.class, type);
@@ -4,7 +4,7 @@ import cc.carm.lib.configuration.adapter.ValueAdapter;
import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.CommonConfigBuilder; import cc.carm.lib.configuration.builder.CommonConfigBuilder;
import cc.carm.lib.configuration.function.DataFunction; import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.function.ValueConsumer; import cc.carm.lib.configuration.function.ValueComposer;
import cc.carm.lib.configuration.function.ValueHandler; import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.source.section.ConfigureSection; import cc.carm.lib.configuration.source.section.ConfigureSection;
import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.ConfigValue;
@@ -14,47 +14,45 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
public abstract class AbstractSectionBuilder< public abstract class AbstractSectionBuilder<
TYPE, PARAM, TYPE, UNIT,
RESULT extends ConfigValue<TYPE>, RESULT extends ConfigValue<TYPE, UNIT>,
SELF extends AbstractSectionBuilder<TYPE, PARAM, RESULT, SELF> SELF extends AbstractSectionBuilder<TYPE, UNIT, RESULT, SELF>
> extends CommonConfigBuilder<TYPE, RESULT, SELF> { > extends CommonConfigBuilder<TYPE, UNIT, RESULT, SELF> {
protected final @NotNull ValueType<PARAM> paramType; protected final @NotNull ValueType<UNIT> paramType;
protected @NotNull ValueHandler<ConfigureSection, PARAM> parser; protected @NotNull ValueHandler<ConfigureSection, UNIT> parser;
protected @NotNull ValueHandler<PARAM, ? extends Map<String, Object>> serializer; protected @NotNull ValueHandler<UNIT, ? extends Map<String, Object>> serializer;
protected AbstractSectionBuilder(@NotNull ValueType<TYPE> type, @NotNull ValueType<PARAM> paramType, protected AbstractSectionBuilder(@NotNull ValueType<TYPE> type, @NotNull ValueType<UNIT> paramType,
@NotNull ValueHandler<ConfigureSection, PARAM> parser, @NotNull ValueHandler<ConfigureSection, UNIT> parser,
@NotNull ValueHandler<PARAM, ? extends Map<String, Object>> serializer) { @NotNull ValueHandler<UNIT, ? extends Map<String, Object>> serializer) {
super(type); super(type);
this.paramType = paramType; this.paramType = paramType;
this.parser = parser; this.parser = parser;
this.serializer = serializer; this.serializer = serializer;
} }
public @NotNull SELF parse(@NotNull DataFunction<ConfigureSection, PARAM> valueParser) { public @NotNull SELF parse(@NotNull DataFunction<ConfigureSection, UNIT> valueParser) {
return parse((p, section) -> valueParser.handle(section)); return parse((p, section) -> valueParser.handle(section));
} }
public @NotNull SELF parse(@NotNull ValueHandler<ConfigureSection, PARAM> valueParser) { public @NotNull SELF parse(@NotNull ValueHandler<ConfigureSection, UNIT> valueParser) {
this.parser = valueParser; this.parser = valueParser;
return self(); return self();
} }
public @NotNull SELF serialize(@NotNull ValueHandler<PARAM, ? extends Map<String, Object>> serializer) { public @NotNull SELF serialize(@NotNull ValueHandler<UNIT, ? extends Map<String, Object>> serializer) {
this.serializer = serializer; this.serializer = serializer;
return self(); return self();
} }
public @NotNull SELF serialize(@NotNull DataFunction<PARAM, ? extends Map<String, Object>> serializer) { public @NotNull SELF serialize(@NotNull DataFunction<UNIT, ? extends Map<String, Object>> serializer) {
return serialize((p, value) -> { return serialize((p, value) -> serializer.handle(value));
return serializer.handle(value);
});
} }
public @NotNull SELF serialize(@NotNull ValueConsumer<Map<String, Object>, PARAM> serializer) { public @NotNull SELF serialize(@NotNull ValueComposer<Map<String, Object>, UNIT> serializer) {
return serialize((h, value) -> { return serialize((h, value) -> {
Map<String, Object> map = new LinkedHashMap<>(); Map<String, Object> map = new LinkedHashMap<>();
serializer.accept(h, map, value); serializer.accept(h, map, value);
@@ -62,7 +60,7 @@ public abstract class AbstractSectionBuilder<
}); });
} }
protected ValueAdapter<PARAM> buildAdapter() { protected ValueAdapter<UNIT> buildAdapter() {
return new ValueAdapter<>(this.paramType) return new ValueAdapter<>(this.paramType)
.parser((p, type, data) -> { .parser((p, type, data) -> {
ConfigureSection section = p.deserialize(ConfigureSection.class, data); ConfigureSection section = p.deserialize(ConfigureSection.class, data);
@@ -9,19 +9,19 @@ import cc.carm.lib.configuration.value.ConfigValue;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public abstract class AbstractSourceBuilder< public abstract class AbstractSourceBuilder<
V, SOURCE, PARAM, RESULT extends ConfigValue<V>, V, SOURCE, UNIT, RESULT extends ConfigValue<V, UNIT>,
SELF extends AbstractSourceBuilder<V, SOURCE, PARAM, RESULT, SELF> SELF extends AbstractSourceBuilder<V, SOURCE, UNIT, RESULT, SELF>
> extends CommonConfigBuilder<V, RESULT, SELF> { > extends CommonConfigBuilder<V, UNIT, RESULT, SELF> {
protected final @NotNull ValueType<SOURCE> sourceType; protected final @NotNull ValueType<SOURCE> sourceType;
protected final @NotNull ValueType<PARAM> paramType; protected final @NotNull ValueType<UNIT> paramType;
protected @NotNull ValueHandler<SOURCE, PARAM> valueParser; protected @NotNull ValueHandler<SOURCE, UNIT> valueParser;
protected @NotNull ValueHandler<PARAM, SOURCE> valueSerializer; protected @NotNull ValueHandler<UNIT, SOURCE> valueSerializer;
protected AbstractSourceBuilder(@NotNull ValueType<V> type, protected AbstractSourceBuilder(@NotNull ValueType<V> type,
@NotNull ValueType<SOURCE> sourceType, @NotNull ValueType<PARAM> paramType, @NotNull ValueType<SOURCE> sourceType, @NotNull ValueType<UNIT> paramType,
@NotNull ValueHandler<SOURCE, PARAM> parser, @NotNull ValueHandler<SOURCE, UNIT> parser,
@NotNull ValueHandler<PARAM, SOURCE> serializer) { @NotNull ValueHandler<UNIT, SOURCE> serializer) {
super(type); super(type);
this.sourceType = sourceType; this.sourceType = sourceType;
this.paramType = paramType; this.paramType = paramType;
@@ -29,25 +29,25 @@ public abstract class AbstractSourceBuilder<
this.valueSerializer = serializer; this.valueSerializer = serializer;
} }
public @NotNull SELF parse(@NotNull DataFunction<SOURCE, PARAM> parser) { public @NotNull SELF parse(@NotNull DataFunction<SOURCE, UNIT> parser) {
return parse((p, source) -> parser.handle(source)); return parse((p, source) -> parser.handle(source));
} }
public @NotNull SELF parse(@NotNull ValueHandler<SOURCE, PARAM> parser) { public @NotNull SELF parse(@NotNull ValueHandler<SOURCE, UNIT> parser) {
this.valueParser = parser; this.valueParser = parser;
return self(); return self();
} }
public @NotNull SELF serialize(@NotNull ValueHandler<PARAM, SOURCE> serializer) { public @NotNull SELF serialize(@NotNull ValueHandler<UNIT, SOURCE> serializer) {
this.valueSerializer = serializer; this.valueSerializer = serializer;
return self(); return self();
} }
public @NotNull SELF serialize(@NotNull DataFunction<PARAM, SOURCE> serializer) { public @NotNull SELF serialize(@NotNull DataFunction<UNIT, SOURCE> serializer) {
return serialize((p, value) -> serializer.handle(value)); return serialize((p, value) -> serializer.handle(value));
} }
protected ValueAdapter<PARAM> buildAdapter() { protected ValueAdapter<UNIT> buildAdapter() {
return new ValueAdapter<>(this.paramType) return new ValueAdapter<>(this.paramType)
.parser((holder, type, data) -> { .parser((holder, type, data) -> {
SOURCE source = holder.deserialize(this.sourceType, data); SOURCE source = holder.deserialize(this.sourceType, data);
@@ -8,9 +8,11 @@ import cc.carm.lib.configuration.value.standard.ConfiguredList;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.*; import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
public class SectionListBuilder<V> extends AbstractSectionBuilder<List<V>, V, ConfiguredList<V>, SectionListBuilder<V>> { public class SectionListBuilder<V>
extends AbstractSectionBuilder<List<V>, V, ConfiguredList<V>, SectionListBuilder<V>> {
protected @NotNull Supplier<? extends List<V>> constructor; protected @NotNull Supplier<? extends List<V>> constructor;
@@ -32,6 +34,14 @@ public class SectionListBuilder<V> extends AbstractSectionBuilder<List<V>, V, Co
return defaults(new ArrayList<>(values)); return defaults(new ArrayList<>(values));
} }
public final @NotNull SectionListBuilder<V> defaults(@NotNull Consumer<List<V>> constructor) {
return defaults(() -> {
List<V> list = new ArrayList<>();
constructor.accept(list);
return list;
});
}
public SectionListBuilder<V> constructor(@NotNull Supplier<? extends List<V>> constructor) { public SectionListBuilder<V> constructor(@NotNull Supplier<? extends List<V>> constructor) {
this.constructor = constructor; this.constructor = constructor;
return this; return this;
@@ -10,6 +10,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
public class SourceListBuilder<SOURCE, V> public class SourceListBuilder<SOURCE, V>
@@ -34,6 +35,23 @@ public class SourceListBuilder<SOURCE, V>
return defaults(new ArrayList<>(values)); return defaults(new ArrayList<>(values));
} }
public final @NotNull SourceListBuilder<SOURCE, V> defaults(@NotNull Consumer<List<V>> constructor) {
return defaults(() -> {
List<V> list = new ArrayList<>();
constructor.accept(list);
return list;
});
}
public SourceListBuilder<SOURCE, V> constructor(@NotNull Supplier<? extends List<V>> constructor) {
this.constructor = constructor;
return this;
}
public <LIST extends List<V>> SourceListBuilder<SOURCE, V> construct(@NotNull LIST list) {
return constructor(() -> list);
}
@Override @Override
protected @NotNull SourceListBuilder<SOURCE, V> self() { protected @NotNull SourceListBuilder<SOURCE, V> self() {
return this; return this;
@@ -3,10 +3,7 @@ package cc.carm.lib.configuration.builder.map;
import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.ValueType;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.HashMap; import java.util.*;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Supplier; import java.util.function.Supplier;
public class ConfigMapCreator<K, V> { public class ConfigMapCreator<K, V> {
@@ -45,4 +42,8 @@ public class ConfigMapCreator<K, V> {
return constructor(TreeMap::new); return constructor(TreeMap::new);
} }
public @NotNull ConfigMapBuilder<TreeMap<K, V>, K, V> asTreeMap(@NotNull Comparator<? super K> comparator) {
return constructor(() -> new TreeMap<>(comparator));
}
} }
@@ -14,10 +14,7 @@ import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
public class SectionMapBuilder<MAP extends Map<K, V>, K, V> public class SectionMapBuilder<MAP extends Map<K, V>, K, V>
extends AbstractSectionBuilder< extends AbstractSectionBuilder<Map<K, V>, V, ConfiguredMap<K, V>, SectionMapBuilder<MAP, K, V>> {
Map<K, V>, V, ConfiguredMap<K, V>,
SectionMapBuilder<MAP, K, V>
> {
protected final @NotNull ValueType<K> keyType; protected final @NotNull ValueType<K> keyType;
@@ -75,6 +72,10 @@ public class SectionMapBuilder<MAP extends Map<K, V>, K, V>
}); });
} }
public @NotNull SectionMapBuilder<MAP, K, V> defaults(@NotNull K key, @NotNull V value) {
return defaults(map -> map.put(key, value));
}
public @NotNull ValueAdapter<K> buildKeyAdapter() { public @NotNull ValueAdapter<K> buildKeyAdapter() {
return new ValueAdapter<>(this.keyType) return new ValueAdapter<>(this.keyType)
.parser((holder, type, data) -> { .parser((holder, type, data) -> {
@@ -13,10 +13,7 @@ import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
public class SourceMapBuilder<MAP extends Map<K, V>, SOURCE, K, V> public class SourceMapBuilder<MAP extends Map<K, V>, SOURCE, K, V>
extends AbstractSourceBuilder< extends AbstractSourceBuilder<Map<K, V>, SOURCE, V, ConfiguredMap<K, V>, SourceMapBuilder<MAP, SOURCE, K, V>> {
Map<K, V>, SOURCE, V, ConfiguredMap<K, V>,
SourceMapBuilder<MAP, SOURCE, K, V>
> {
protected final @NotNull ValueType<K> keyType; protected final @NotNull ValueType<K> keyType;
@@ -53,6 +50,10 @@ public class SourceMapBuilder<MAP extends Map<K, V>, SOURCE, K, V>
}); });
} }
public @NotNull SourceMapBuilder<MAP, SOURCE, K, V> defaults(@NotNull K key, @NotNull V value) {
return defaults(map -> map.put(key, value));
}
public @NotNull SourceMapBuilder<MAP, SOURCE, K, V> parseKey(@NotNull DataFunction<String, K> keyParser) { public @NotNull SourceMapBuilder<MAP, SOURCE, K, V> parseKey(@NotNull DataFunction<String, K> keyParser) {
return parseKey((holder, data) -> keyParser.handle(data)); return parseKey((holder, data) -> keyParser.handle(data));
} }
@@ -1,7 +1,6 @@
package cc.carm.lib.configuration.builder.value; package cc.carm.lib.configuration.builder.value;
import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.impl.AbstractSectionBuilder;
import cc.carm.lib.configuration.function.ValueHandler; import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.source.section.ConfigureSection; import cc.carm.lib.configuration.source.section.ConfigureSection;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -6,7 +6,8 @@ import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class SourceValueBuilder<S, V> extends AbstractSourceBuilder<V, S, V, ConfiguredValue<V>, SourceValueBuilder<S, V>> { public class SourceValueBuilder<S, V>
extends AbstractSourceBuilder<V, S, V, ConfiguredValue<V>, SourceValueBuilder<S, V>> {
public SourceValueBuilder(@NotNull ValueType<S> sourceType, @NotNull ValueType<V> valueType, public SourceValueBuilder(@NotNull ValueType<S> sourceType, @NotNull ValueType<V> valueType,
@@ -0,0 +1,22 @@
package cc.carm.lib.configuration.function;
import org.jetbrains.annotations.NotNull;
@FunctionalInterface
public interface ConfigExceptionHandler {
void handle(@NotNull String path, @NotNull Throwable throwable);
static @NotNull ConfigExceptionHandler silence() {
return (path, throwable) -> {
};
}
static @NotNull ConfigExceptionHandler print() {
return (path, throwable) -> {
System.err.println("Error occurred at path: " + path);
throwable.printStackTrace();
};
}
}
@@ -0,0 +1,17 @@
package cc.carm.lib.configuration.function;
import org.jetbrains.annotations.Nullable;
@FunctionalInterface
public interface DataValidator<T> {
void validate(@Nullable T value) throws Exception;
default DataValidator<T> compose(DataValidator<? super T> other) {
return value -> {
validate(value);
other.validate(value);
};
}
}
@@ -0,0 +1,29 @@
package cc.carm.lib.configuration.function;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
@FunctionalInterface
public interface ValueComposer<T, U> {
/**
* Accept the value and the data, and then compose the value.
*
* @param holder The configuration holder
* @param type The value type, e.g. {@link java.util.List}, {@link java.util.Map}, etc.
* @param data The unit data
* @throws Exception If an error occurs
*/
void accept(@NotNull ConfigurationHolder<?> holder, @NotNull T type, @NotNull U data) throws Exception;
default ValueComposer<T, U> andThen(ValueComposer<? super T, ? super U> after) {
return (holder, unit, data) -> {
accept(holder, unit, data);
after.accept(holder, unit, data);
};
}
}
@@ -1,21 +0,0 @@
package cc.carm.lib.configuration.function;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
@FunctionalInterface
public interface ValueConsumer<U, T> {
void accept(@NotNull ConfigurationHolder<?> holder, @NotNull U unit, @NotNull T data) throws Exception;
default ValueConsumer<U, T> andThen(ValueConsumer<? super U, ? super T> after) {
return (holder, unit, data) -> {
accept(holder, unit, data);
after.accept(holder, unit, data);
};
}
}
@@ -0,0 +1,7 @@
package cc.carm.lib.configuration.function;
public interface ValueSupplier {
}
@@ -0,0 +1,47 @@
package cc.carm.lib.configuration.function;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@FunctionalInterface
public interface ValueValidator<T> {
void validate(@NotNull ConfigurationHolder<?> holder, @Nullable T value) throws Exception;
default ValueValidator<T> and(ValueValidator<? super T> other) {
return (holder, value) -> {
validate(holder, value);
other.validate(holder, value);
};
}
static <V> ValueValidator<V> none() {
return (holder, data) -> {
};
}
static <V> ValueValidator<V> nonnull() {
return nonnull("Value cannot be null");
}
static <V> ValueValidator<V> nonnull(String message) {
return (holder, data) -> {
if (data == null) throw new IllegalArgumentException(message);
};
}
static <V extends Number> ValueValidator<V> range(V min, V max) {
return range(min, max, "Value must be in range [" + min + ", " + max + "]");
}
static <V extends Number> ValueValidator<V> range(V min, V max, String message) {
return (holder, data) -> {
if (data.doubleValue() < min.doubleValue() || data.doubleValue() > max.doubleValue()) {
throw new IllegalArgumentException(message);
}
};
}
}
@@ -2,7 +2,9 @@ package cc.carm.lib.configuration.source;
import cc.carm.lib.configuration.adapter.*; import cc.carm.lib.configuration.adapter.*;
import cc.carm.lib.configuration.adapter.strandard.StandardAdapters; import cc.carm.lib.configuration.adapter.strandard.StandardAdapters;
import cc.carm.lib.configuration.function.ConfigExceptionHandler;
import cc.carm.lib.configuration.function.DataFunction; import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.function.ValueValidator;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
import cc.carm.lib.configuration.source.loader.PathGenerator; import cc.carm.lib.configuration.source.loader.PathGenerator;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder; import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
@@ -33,15 +35,17 @@ public abstract class ConfigurationFactory<
SELF SELF
> { > {
protected ValueAdapterRegistry adapters = new ValueAdapterRegistry(); protected @NotNull ValueAdapterRegistry adapters = new ValueAdapterRegistry();
protected ConfigurationOptionHolder options = new ConfigurationOptionHolder(); protected @NotNull ConfigurationOptionHolder options = new ConfigurationOptionHolder();
protected @NotNull Map<String, ConfigurationMetaHolder> metadata = new HashMap<>(); protected @NotNull Map<String, ConfigurationMetaHolder> metadata = new HashMap<>();
protected ConfigurationInitializer initializer = new ConfigurationInitializer(); protected @NotNull ConfigurationInitializer initializer = new ConfigurationInitializer();
protected @NotNull ConfigExceptionHandler exceptionHandler = ConfigExceptionHandler.print();
public ConfigurationFactory() { protected ConfigurationFactory() {
this.adapters.register(StandardAdapters.PRIMITIVES); this.adapters.register(StandardAdapters.PRIMITIVES);
this.adapters.register(StandardAdapters.SECTIONS); this.adapters.register(StandardAdapters.SECTIONS);
this.adapters.register(StandardAdapters.ENUMS); this.adapters.register(StandardAdapters.ENUMS);
this.adapters.register(StandardAdapters.UUID);
} }
protected abstract SELF self(); protected abstract SELF self();
@@ -146,6 +150,11 @@ public abstract class ConfigurationFactory<
return self(); return self();
} }
public SELF exceptionally(@NotNull ConfigExceptionHandler handler) {
this.exceptionHandler = handler;
return self();
}
/** /**
* Supply the base path generator for this configuration holder * Supply the base path generator for this configuration holder
* *
@@ -153,9 +162,7 @@ public abstract class ConfigurationFactory<
* @return this * @return this
*/ */
public SELF pathGenerator(PathGenerator generator) { public SELF pathGenerator(PathGenerator generator) {
return initializer(loader -> { return initializer(loader -> loader.pathGenerator(generator));
loader.pathGenerator(generator);
});
} }
/** /**
@@ -174,6 +181,19 @@ public abstract class ConfigurationFactory<
return initializer(loader -> loader.registerAnnotation(annotation, metadata, extractor)); return initializer(loader -> loader.registerAnnotation(annotation, metadata, extractor));
} }
/**
* Register a new annotation for {@link ValueValidator} to the configuration loader
*
* @param annotation The {@link Annotation}
* @param builder The {@link Function} to build the {@link ValueValidator} from the annotation
* @param <A> The annotation type
* @return this
*/
public <A extends Annotation> SELF validAnnotation(@NotNull Class<A> annotation,
@NotNull Function<A, ValueValidator<Object>> builder) {
return initializer(loader -> loader.registerValidAnnotation(annotation, builder));
}
/** /**
* Build the configuration holder. * Build the configuration holder.
* *
@@ -3,6 +3,7 @@ package cc.carm.lib.configuration.source;
import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; import cc.carm.lib.configuration.adapter.ValueAdapterRegistry;
import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.function.ConfigExceptionHandler;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder; import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
@@ -31,14 +32,25 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
protected final @NotNull ConfigurationInitializer initializer; protected final @NotNull ConfigurationInitializer initializer;
protected @NotNull ConfigExceptionHandler exceptionHandler;
public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters, public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters,
@NotNull ConfigurationOptionHolder options, @NotNull ConfigurationOptionHolder options,
@NotNull Map<String, ConfigurationMetaHolder> metadata, @NotNull Map<String, ConfigurationMetaHolder> metadata,
@NotNull ConfigurationInitializer initializer) { @NotNull ConfigurationInitializer initializer) {
this(adapters, options, metadata, initializer, ConfigExceptionHandler.print());
}
public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters,
@NotNull ConfigurationOptionHolder options,
@NotNull Map<String, ConfigurationMetaHolder> metadata,
@NotNull ConfigurationInitializer initializer,
@NotNull ConfigExceptionHandler exceptionHandler) {
this.initializer = initializer; this.initializer = initializer;
this.adapters = adapters; this.adapters = adapters;
this.options = options; this.options = options;
this.metadata = metadata; this.metadata = metadata;
this.exceptionHandler = exceptionHandler;
} }
public abstract @NotNull SOURCE config(); public abstract @NotNull SOURCE config();
@@ -86,7 +98,7 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
@NotNull @NotNull
@UnmodifiableView @UnmodifiableView
public Map<String, ConfigValue<?>> registeredValues() { public Map<String, ConfigValue<?, ?>> registeredValues() {
return extractMetadata(StandardMeta.VALUE); return extractMetadata(StandardMeta.VALUE);
} }
@@ -117,7 +129,7 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
try { try {
initializer.initialize(this, configClass); initializer.initialize(this, configClass);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); throwing(configClass.getName(), e);
} }
} }
@@ -125,12 +137,20 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
try { try {
initializer.initialize(this, config); initializer.initialize(this, config);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); throwing(config.getClass().getName(), e);
} }
} }
public void initialize(@NotNull ValueManifest<?> value) { public void initialize(@NotNull ValueManifest<?, ?> value) {
value.holder(this); value.holder(this);
} }
public void throwing(@NotNull String path, @NotNull Throwable e) {
this.exceptionHandler.handle(path, e);
}
public void exceptionally(@NotNull ConfigExceptionHandler handler) {
this.exceptionHandler = handler;
}
} }
@@ -8,7 +8,7 @@ import org.jetbrains.annotations.Nullable;
public interface ConfigInitializeHandler<T, V> { public interface ConfigInitializeHandler<T, V> {
static <T, V> ConfigInitializeHandler<T, V> start() { static <T, V> ConfigInitializeHandler<T, V> start() {
return (provider, path, value, instace) -> { return (provider, path, value, instance) -> {
}; };
} }
@@ -1,6 +1,7 @@
package cc.carm.lib.configuration.source.loader; package cc.carm.lib.configuration.source.loader;
import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.function.ValueValidator;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
import cc.carm.lib.configuration.source.meta.StandardMeta; import cc.carm.lib.configuration.source.meta.StandardMeta;
@@ -21,7 +22,7 @@ import java.util.function.Function;
public class ConfigurationInitializer { public class ConfigurationInitializer {
protected @NotNull PathGenerator pathGenerator; protected @NotNull PathGenerator pathGenerator;
protected @NotNull ConfigInitializeHandler<Field, ConfigValue<?>> valueInitializer; protected @NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> valueInitializer;
protected @NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer; protected @NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer;
public ConfigurationInitializer() { public ConfigurationInitializer() {
@@ -29,7 +30,7 @@ public class ConfigurationInitializer {
} }
public ConfigurationInitializer(@NotNull PathGenerator pathGenerator, public ConfigurationInitializer(@NotNull PathGenerator pathGenerator,
@NotNull ConfigInitializeHandler<Field, ConfigValue<?>> valueInitializer, @NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> valueInitializer,
@NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer) { @NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer) {
this.pathGenerator = pathGenerator; this.pathGenerator = pathGenerator;
this.valueInitializer = valueInitializer; this.valueInitializer = valueInitializer;
@@ -44,11 +45,11 @@ public class ConfigurationInitializer {
return pathGenerator; return pathGenerator;
} }
public ConfigInitializeHandler<Field, ConfigValue<?>> fieldInitializer() { public ConfigInitializeHandler<Field, ConfigValue<?, ?>> fieldInitializer() {
return valueInitializer; return valueInitializer;
} }
public void fieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?>> fieldInitializer) { public void fieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> fieldInitializer) {
this.valueInitializer = fieldInitializer; this.valueInitializer = fieldInitializer;
} }
@@ -60,7 +61,7 @@ public class ConfigurationInitializer {
this.classInitializer = classInitializer; this.classInitializer = classInitializer;
} }
public void appendFieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?>> fieldInitializer) { public void appendFieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> fieldInitializer) {
this.valueInitializer = this.valueInitializer.andThen(fieldInitializer); this.valueInitializer = this.valueInitializer.andThen(fieldInitializer);
} }
@@ -95,6 +96,14 @@ public class ConfigurationInitializer {
registerFieldAnnotation(annotation, metadata, extractor); registerFieldAnnotation(annotation, metadata, extractor);
} }
public <A extends Annotation> void registerValidAnnotation(@NotNull Class<A> annotation,
@NotNull Function<A, ValueValidator<Object>> builder) {
appendFieldInitializer((holder, path, field, instance) -> {
A data = field.getAnnotation(annotation);
if (data == null) return;
instance.validate((h, t) -> builder.apply(data).validate(h, t));
});
}
public @Nullable String getFieldPath(@NotNull ConfigurationHolder<?> holder, @Nullable String parentPath, @NotNull Field field) { public @Nullable String getFieldPath(@NotNull ConfigurationHolder<?> holder, @Nullable String parentPath, @NotNull Field field) {
return pathGenerator.getFieldPath(holder, parentPath, field); return pathGenerator.getFieldPath(holder, parentPath, field);
@@ -125,7 +134,7 @@ public class ConfigurationInitializer {
try { try {
this.classInitializer.whenInitialize(holder, path, root.getClass(), root); this.classInitializer.whenInitialize(holder, path, root.getClass(), root);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); holder.throwing(path, e);
} }
Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(holder, root, field, path)); Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(holder, root, field, path));
} }
@@ -142,7 +151,7 @@ public class ConfigurationInitializer {
try { try {
this.classInitializer.whenInitialize(holder, path, (Class<? extends Configuration>) clazz, configField); this.classInitializer.whenInitialize(holder, path, (Class<? extends Configuration>) clazz, configField);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); holder.throwing(path, e);
} }
for (Field field : clazz.getDeclaredFields()) { for (Field field : clazz.getDeclaredFields()) {
@@ -163,9 +172,9 @@ public class ConfigurationInitializer {
field.setAccessible(true); field.setAccessible(true);
Object object = field.get(source); Object object = field.get(source);
// //
if (object instanceof ConfigValue<?>) { if (object instanceof ConfigValue<?, ?>) {
// 目标是 ConfigValue 实例,进行具体的初始化注入 // 目标是 ConfigValue 实例,进行具体的初始化注入
ConfigValue<?> value = (ConfigValue<?>) object; ConfigValue<?, ?> value = (ConfigValue<?, ?>) object;
String path = getFieldPath(holder, parent, field); String path = getFieldPath(holder, parent, field);
if (path == null) return; if (path == null) return;
value.initialize(holder, path); value.initialize(holder, path);
@@ -176,7 +185,7 @@ public class ConfigurationInitializer {
try { try {
this.valueInitializer.whenInitialize(holder, path, field, value); this.valueInitializer.whenInitialize(holder, path, field, value);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); holder.throwing(path, e);
} }
if (holder.option(StandardOptions.PRELOAD)) { if (holder.option(StandardOptions.PRELOAD)) {
value.get(); // Preload the value by calling #get method. value.get(); // Preload the value by calling #get method.
@@ -7,6 +7,6 @@ public interface StandardMeta {
/** /**
* To mark the {@link ConfigValue} instance of specific path. * To mark the {@link ConfigValue} instance of specific path.
*/ */
ConfigurationMetadata<ConfigValue<?>> VALUE = ConfigurationMetadata.of(); ConfigurationMetadata<ConfigValue<?, ?>> VALUE = ConfigurationMetadata.of();
} }
@@ -48,7 +48,6 @@ public interface ConfigureSection {
return (parent().isRoot() ? "" : parent().fullPath() + pathSeparator()) + path(); return (parent().isRoot() ? "" : parent().fullPath() + pathSeparator()) + path();
} }
/** /**
* Get the path separator for the section. * Get the path separator for the section.
* *
@@ -143,6 +142,17 @@ public interface ConfigureSection {
return getValues(false); return getValues(false);
} }
/**
* Get this section as a map.
* <p>
* In this map, child {@link ConfigureSection}s will also be represented as {@link Map}s.
*
* @return Map of data values contained within this Section.
*/
@NotNull
@UnmodifiableView
Map<String, Object> asMap();
/** /**
* Create a stream of all values in this section. * Create a stream of all values in this section.
* *
@@ -153,7 +163,7 @@ public interface ConfigureSection {
} }
/** /**
* Iterates over all keys in this section. * Iterates over all key-values in this section (include child sections)
* *
* @param action The action to apply to each key. * @param action The action to apply to each key.
*/ */
@@ -107,6 +107,11 @@ public abstract class ConfigureSource<
return section().getKeys(deep); return section().getKeys(deep);
} }
@Override
public @NotNull @UnmodifiableView Map<String, Object> asMap() {
return section().asMap();
}
@Override @Override
public @NotNull ConfigureSection createSection(@NotNull String path, @NotNull Map<?, ?> data) { public @NotNull ConfigureSection createSection(@NotNull String path, @NotNull Map<?, ?> data) {
return section().createSection(path, data); return section().createSection(path, data);
@@ -33,9 +33,9 @@ import java.util.Optional;
* @see ValueManifest Base class providing metadata and default value handling * @see ValueManifest Base class providing metadata and default value handling
* @see ConfigurationHolder Responsible for configuration source persistence * @see ConfigurationHolder Responsible for configuration source persistence
*/ */
public abstract class ConfigValue<T> extends ValueManifest<T> { public abstract class ConfigValue<T, U> extends ValueManifest<T, U> {
protected ConfigValue(@NotNull ValueManifest<T> manifest) { protected ConfigValue(@NotNull ValueManifest<T, U> manifest) {
super(manifest); super(manifest);
} }
@@ -1,6 +1,7 @@
package cc.carm.lib.configuration.value; package cc.carm.lib.configuration.value;
import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.function.ValueValidator;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder; import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
import cc.carm.lib.configuration.source.section.ConfigureSource; import cc.carm.lib.configuration.source.section.ConfigureSource;
@@ -11,37 +12,48 @@ import org.jetbrains.annotations.Nullable;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Supplier; import java.util.function.Supplier;
public class ValueManifest<T> { public class ValueManifest<TYPE, UNIT> {
protected final @NotNull ValueType<T> type; protected final @NotNull ValueType<TYPE> type;
protected final @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer; protected final @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer;
protected @Nullable ConfigurationHolder<?> holder; protected @Nullable ConfigurationHolder<?> holder;
protected @Nullable String path; // Section path protected @Nullable String path; // Section path
protected @NotNull Supplier<@Nullable T> defaultSupplier; protected @NotNull ValueValidator<UNIT> validator;
protected @NotNull Supplier<@Nullable TYPE> defaultSupplier;
public ValueManifest(@NotNull ValueType<T> type) { public ValueManifest(@NotNull ValueType<TYPE> type) {
this(type, () -> null, EMPTY_INITIALIZER, null, null); this(type, () -> null, ValueValidator.none(), EMPTY_INITIALIZER, null, null);
} }
public ValueManifest(@NotNull T defaultValue) { public ValueManifest(@NotNull TYPE defaultValue) {
this(ValueType.of(defaultValue), () -> defaultValue); this(ValueType.of(defaultValue), () -> defaultValue);
} }
public ValueManifest(@NotNull ValueType<T> type, @NotNull Supplier<@Nullable T> defaultSupplier) { public ValueManifest(@NotNull ValueType<TYPE> type, @NotNull Supplier<@Nullable TYPE> defaultSupplier) {
this(type, defaultSupplier, EMPTY_INITIALIZER, null, null); this(type, defaultSupplier, ValueValidator.none(), EMPTY_INITIALIZER, null, null);
} }
public ValueManifest(@NotNull ValueType<T> type, @NotNull Supplier<@Nullable T> defaultSupplier, public ValueManifest(@NotNull ValueType<TYPE> type,
@NotNull Supplier<@Nullable TYPE> defaultSupplier,
@NotNull ValueValidator<UNIT> validator) {
this(type, defaultSupplier, validator, EMPTY_INITIALIZER, null, null);
}
public ValueManifest(@NotNull ValueType<TYPE> type, @NotNull Supplier<@Nullable TYPE> defaultSupplier,
@NotNull ValueValidator<UNIT> validator,
@NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer) { @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer) {
this(type, defaultSupplier, initializer, null, null); this(type, defaultSupplier, validator, initializer, null, null);
} }
public ValueManifest(@NotNull ValueType<T> type, @NotNull Supplier<@Nullable T> defaultSupplier, public ValueManifest(@NotNull ValueType<TYPE> type,
@NotNull Supplier<@Nullable TYPE> defaultSupplier,
@NotNull ValueValidator<UNIT> validator,
@NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer, @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> initializer,
@Nullable ConfigurationHolder<?> holder, @Nullable String path) { @Nullable ConfigurationHolder<?> holder, @Nullable String path) {
this.type = type; this.type = type;
this.validator = validator;
this.initializer = initializer; this.initializer = initializer;
this.defaultSupplier = defaultSupplier; this.defaultSupplier = defaultSupplier;
this.holder = holder; this.holder = holder;
@@ -49,8 +61,8 @@ public class ValueManifest<T> {
initialize(); initialize();
} }
protected ValueManifest(@NotNull ValueManifest<T> manifest) { protected ValueManifest(@NotNull ValueManifest<TYPE, UNIT> manifest) {
this(manifest.type, manifest.defaultSupplier, manifest.initializer, manifest.holder, manifest.path); this(manifest.type, manifest.defaultSupplier, manifest.validator, manifest.initializer, manifest.holder, manifest.path);
} }
public void initialize(@NotNull ConfigurationHolder<?> holder, @NotNull String path) { public void initialize(@NotNull ConfigurationHolder<?> holder, @NotNull String path) {
@@ -63,7 +75,7 @@ public class ValueManifest<T> {
if (holder != null && path != null) this.initializer.accept(holder, path); if (holder != null && path != null) this.initializer.accept(holder, path);
} }
public @NotNull ValueType<T> type() { public @NotNull ValueType<TYPE> type() {
return this.type; return this.type;
} }
@@ -75,20 +87,37 @@ public class ValueManifest<T> {
this.path = path; this.path = path;
} }
public @Nullable T defaults() { public @Nullable TYPE defaults() {
return this.defaultSupplier.get(); return this.defaultSupplier.get();
} }
public void defaults(@Nullable T defaultValue) { public void defaults(@Nullable TYPE defaultValue) {
defaults(() -> defaultValue); defaults(() -> defaultValue);
} }
public void defaults(@NotNull Supplier<@Nullable T> defaultValue) { public void defaults(@NotNull Supplier<@Nullable TYPE> defaultValue) {
this.defaultSupplier = defaultValue; this.defaultSupplier = defaultValue;
} }
public boolean hasDefaults() { public boolean hasDefaults() {
return this.defaultSupplier.get() != null; return defaults() != null;
}
public @NotNull ValueValidator<UNIT> validator() {
return this.validator;
}
public void validator(@NotNull ValueValidator<UNIT> validator) {
this.validator = validator;
}
public void validate(@NotNull ValueValidator<UNIT> validator) {
validator(this.validator.and(validator));
}
protected UNIT withValidated(@Nullable UNIT value) throws Exception {
validator.validate(holder(), value);
return value;
} }
public @NotNull String path() { public @NotNull String path() {
@@ -105,12 +134,12 @@ public class ValueManifest<T> {
return holder().config(); return holder().config();
} }
public ConfigurationMetaHolder metadata() { public @NotNull ConfigurationMetaHolder metadata() {
return holder().metadata(path()); return holder().metadata(path());
} }
@ApiStatus.Internal @ApiStatus.Internal
protected Object getData() { protected @Nullable Object getData() {
return config().get(path()); return config().get(path());
} }
@@ -119,6 +148,15 @@ public class ValueManifest<T> {
config().set(path(), value); config().set(path(), value);
} }
protected void throwing(@NotNull Throwable throwable) {
throwing(path, throwable);
}
protected void throwing(@NotNull String path, @NotNull Throwable throwable) {
if (holder == null) throwable.printStackTrace();
else holder.throwing(path, throwable);
}
private static final @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> EMPTY_INITIALIZER = (provider, valuePath) -> { private static final @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> EMPTY_INITIALIZER = (provider, valuePath) -> {
}; };
@@ -9,12 +9,12 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public abstract class CachedConfigValue<T> extends ConfigValue<T> { public abstract class CachedConfigValue<T, U> extends ConfigValue<T, U> {
protected @Nullable T cachedValue; protected @Nullable T cachedValue;
protected long parsedTime = -1; protected long parsedTime = -1;
protected CachedConfigValue(@NotNull ValueManifest<T> manifest) { protected CachedConfigValue(@NotNull ValueManifest<T, U> manifest) {
super(manifest); super(manifest);
} }
@@ -5,6 +5,7 @@ import cc.carm.lib.configuration.adapter.ValueParser;
import cc.carm.lib.configuration.adapter.ValueSerializer; import cc.carm.lib.configuration.adapter.ValueSerializer;
import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.list.ConfigListBuilder; import cc.carm.lib.configuration.builder.list.ConfigListBuilder;
import cc.carm.lib.configuration.builder.list.SourceListBuilder;
import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.ValueManifest;
import cc.carm.lib.configuration.value.impl.CachedConfigValue; import cc.carm.lib.configuration.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -15,7 +16,7 @@ import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements List<V> { public class ConfiguredList<V> extends CachedConfigValue<List<V>, V> implements List<V> {
public static <T> @NotNull ConfigListBuilder<T> builderOf(@NotNull Class<T> type) { public static <T> @NotNull ConfigListBuilder<T> builderOf(@NotNull Class<T> type) {
return builderOf(ValueType.of(type)); return builderOf(ValueType.of(type));
@@ -25,10 +26,26 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements Lis
return new ConfigListBuilder<>(type); return new ConfigListBuilder<>(type);
} }
public static <T> @NotNull SourceListBuilder<T, T> with(@NotNull Class<T> registeredType) {
return with(ValueType.of(registeredType));
}
public static <T> @NotNull SourceListBuilder<T, T> with(@NotNull ValueType<T> registeredType) {
return new ConfigListBuilder<>(registeredType).from(registeredType);
}
@SafeVarargs
public static <T> @NotNull ConfiguredList<T> of(@NotNull T value, @NotNull T... values) {
List<T> list = new ArrayList<>();
list.add(value);
Collections.addAll(list, values);
return with(ValueType.of(value)).defaults(list).build();
}
protected final @NotNull Supplier<? extends List<V>> constructor; protected final @NotNull Supplier<? extends List<V>> constructor;
protected final @NotNull ValueAdapter<V> paramAdapter; protected final @NotNull ValueAdapter<V> paramAdapter;
public ConfiguredList(@NotNull ValueManifest<List<V>> manifest, public ConfiguredList(@NotNull ValueManifest<List<V>, V> manifest,
@NotNull Supplier<? extends List<V>> constructor, @NotNull Supplier<? extends List<V>> constructor,
@NotNull ValueAdapter<V> paramAdapter) { @NotNull ValueAdapter<V> paramAdapter) {
super(manifest); super(manifest);
@@ -70,40 +87,46 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements Lis
if (!cacheExpired()) return getCachedOrDefault(createList()); if (!cacheExpired()) return getCachedOrDefault(createList());
// Data that is outdated and needs to be parsed again. // Data that is outdated and needs to be parsed again.
List<V> list = createList(); List<V> list = createList();
try {
List<?> data = config().contains(path()) ? config().getList(path()) : null; List<?> data = config().contains(path()) ? config().getList(path()) : null;
if (data == null) return getDefaultFirst(list); if (data == null) return getDefaultFirst(list);
ValueParser<V> parser = parser(); ValueParser<V> parser = parser();
if (parser == null) return getDefaultFirst(list); if (parser == null) return getDefaultFirst(list);
int i = 0;
for (Object dataVal : data) { for (Object dataVal : data) {
if (dataVal == null) continue; if (dataVal == null) continue;
try { try {
list.add(parser.parse(holder(), paramType(), dataVal)); list.add(withValidated(parser.parse(holder(), paramType(), dataVal)));
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); throwing(path + "[" + i + "]", e);
} }
} }
} catch (Exception ex) {
throwing(ex);
}
return updateCache(list); return updateCache(list);
} }
@Override @Override
public void set(@Nullable List<V> value) { public void set(@Nullable List<V> list) {
updateCache(value); updateCache(list);
if (value == null) { if (list == null) {
setData(null); setData(null);
return; return;
} }
ValueSerializer<V> serializer = serializer(); ValueSerializer<V> serializer = serializer();
if (serializer == null) return; if (serializer == null) return;
List<Object> data = new ArrayList<>(); List<Object> data = new ArrayList<>();
for (V val : value) { for (V val : list) {
if (val == null) continue; if (val == null) continue;
try { try {
data.add(serializer.serialize(holder(), paramType(), val)); data.add(serializer.serialize(holder(), paramType(), withValidated(val)));
} catch (Exception ex) { } catch (Exception ex) {
ex.printStackTrace(); throwing(ex);
} }
} }
setData(data); setData(data);
@@ -17,7 +17,11 @@ import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements Map<K, V> { public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>, V> implements Map<K, V> {
public static <V> ConfigMapCreator<String, V> builderOf(@NotNull Class<V> valueType) {
return builderOf(String.class, valueType);
}
public static <K, V> ConfigMapCreator<K, V> builderOf(@NotNull ValueType<K> keyType, @NotNull ValueType<V> valueType) { public static <K, V> ConfigMapCreator<K, V> builderOf(@NotNull ValueType<K> keyType, @NotNull ValueType<V> valueType) {
return new ConfigMapCreator<>(keyType, valueType); return new ConfigMapCreator<>(keyType, valueType);
@@ -38,7 +42,7 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
protected final @NotNull ValueAdapter<K> keyAdapter; protected final @NotNull ValueAdapter<K> keyAdapter;
protected final @NotNull ValueAdapter<V> valueAdapter; protected final @NotNull ValueAdapter<V> valueAdapter;
public ConfiguredMap(@NotNull ValueManifest<Map<K, V>> manifest, public ConfiguredMap(@NotNull ValueManifest<Map<K, V>, V> manifest,
@NotNull Supplier<? extends Map<K, V>> constructor, @NotNull Supplier<? extends Map<K, V>> constructor,
@NotNull ValueAdapter<K> keyAdapter, @NotNull ValueAdapter<V> valueAdapter) { @NotNull ValueAdapter<K> keyAdapter, @NotNull ValueAdapter<V> valueAdapter) {
super(manifest); super(manifest);
@@ -73,6 +77,7 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
// If the value is expired, we need to update it // If the value is expired, we need to update it
Map<K, V> map = createMap(); Map<K, V> map = createMap();
try {
ConfigureSection section = config().getSection(path()); ConfigureSection section = config().getSection(path());
if (section == null) return getDefaultFirst(map); if (section == null) return getDefaultFirst(map);
@@ -80,8 +85,9 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
if (keys.isEmpty()) return getDefaultFirst(map); if (keys.isEmpty()) return getDefaultFirst(map);
ValueParser<K> keyParser = parserFor(keyAdapter); ValueParser<K> keyParser = parserFor(keyAdapter);
if (keyParser == null) return getDefaultFirst(map);
ValueParser<V> valueParser = parserFor(valueAdapter); ValueParser<V> valueParser = parserFor(valueAdapter);
if (keyParser == null || valueParser == null) return getDefaultFirst(map); if (valueParser == null) return getDefaultFirst(map);
for (String dataKey : keys) { for (String dataKey : keys) {
Object dataVal = section.get(dataKey); Object dataVal = section.get(dataKey);
@@ -89,11 +95,14 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
try { try {
K key = keyParser.parse(holder(), keyType(), dataKey); K key = keyParser.parse(holder(), keyType(), dataKey);
V value = valueParser.parse(holder(), valueType(), dataVal); V value = valueParser.parse(holder(), valueType(), dataVal);
map.put(key, value); map.put(key, withValidated(value));
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); throwing(path + "." + dataKey, e);
} }
} }
} catch (Exception ex) {
throwing(ex);
}
return updateCache(map); return updateCache(map);
} }
@@ -115,9 +124,11 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
return; return;
} }
try {
ValueSerializer<K> keySerializer = serializerFor(keyAdapter); ValueSerializer<K> keySerializer = serializerFor(keyAdapter);
if (keySerializer == null) return;
ValueSerializer<V> valueSerializer = serializerFor(valueAdapter); ValueSerializer<V> valueSerializer = serializerFor(valueAdapter);
if (keySerializer == null || valueSerializer == null) return; if (valueSerializer == null) return;
Map<Object, Object> data = new LinkedHashMap<>(); Map<Object, Object> data = new LinkedHashMap<>();
@@ -125,13 +136,16 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
try { try {
data.put( data.put(
keySerializer.serialize(holder(), keyType(), entry.getKey()), keySerializer.serialize(holder(), keyType(), entry.getKey()),
valueSerializer.serialize(holder(), valueType(), entry.getValue()) valueSerializer.serialize(holder(), valueType(), withValidated(entry.getValue()))
); );
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); throwing(path + "." + entry.getKey(), e);
} }
} }
setData(data); setData(data);
} catch (Exception ex) {
throwing(ex);
}
} }
public <T> @NotNull T handle(Function<Map<K, V>, T> function) { public <T> @NotNull T handle(Function<Map<K, V>, T> function) {
@@ -5,6 +5,8 @@ import cc.carm.lib.configuration.adapter.ValueParser;
import cc.carm.lib.configuration.adapter.ValueSerializer; import cc.carm.lib.configuration.adapter.ValueSerializer;
import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.value.ConfigValueBuilder; import cc.carm.lib.configuration.builder.value.ConfigValueBuilder;
import cc.carm.lib.configuration.builder.value.SourceValueBuilder;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.ValueManifest;
import cc.carm.lib.configuration.value.impl.CachedConfigValue; import cc.carm.lib.configuration.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -12,16 +14,54 @@ import org.jetbrains.annotations.Nullable;
import java.util.function.Supplier; import java.util.function.Supplier;
public class ConfiguredValue<V> extends CachedConfigValue<V> { public class ConfiguredValue<V> extends CachedConfigValue<V, V> {
/**
* Create a new value builder.
*
* @param type The type of the value.
* @param <V> The type of the value.
* @return a {@link ConfigValueBuilder} with the specified type.
*/
public static <V> ConfigValueBuilder<V> builderOf(@NotNull Class<V> type) { public static <V> ConfigValueBuilder<V> builderOf(@NotNull Class<V> type) {
return new ConfigValueBuilder<>(ValueType.of(type)); return new ConfigValueBuilder<>(ValueType.of(type));
} }
/**
* Create a new value builder.
*
* @param type The type of the value.
* @param <V> The type of the value.
* @return a {@link ConfigValueBuilder} with the specified type.
*/
public static <V> ConfigValueBuilder<V> builderOf(@NotNull ValueType<V> type) { public static <V> ConfigValueBuilder<V> builderOf(@NotNull ValueType<V> type) {
return new ConfigValueBuilder<>(type); return new ConfigValueBuilder<>(type);
} }
/**
* Create a new value builder with the specified {@link ConfigurationHolder#registeredValues()} type.
*
* @param registeredType The type of the value.
* @param <V> The type of the value.
* @return a {@link SourceValueBuilder} with the specified registered type.
* @see ValueAdapter
*/
public static <V> SourceValueBuilder<V, V> with(@NotNull Class<V> registeredType) {
return with(ValueType.of(registeredType));
}
/**
* Create a new value builder with the specified {@link ConfigurationHolder#registeredValues()} type.
*
* @param registeredType The type of the value.
* @param <V> The type of the value.
* @return a {@link SourceValueBuilder} with the specified registered type.
* @see ValueAdapter
*/
public static <V> SourceValueBuilder<V, V> with(@NotNull ValueType<V> registeredType) {
return new ConfigValueBuilder<>(registeredType).from(registeredType);
}
public static <V> ConfiguredValue<V> of(@NotNull V defaults) { public static <V> ConfiguredValue<V> of(@NotNull V defaults) {
return of(ValueType.of(defaults), () -> defaults); return of(ValueType.of(defaults), () -> defaults);
} }
@@ -51,7 +91,7 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
); );
} }
public static <V> ConfiguredValue<V> of(@NotNull ValueManifest<V> manifest, public static <V> ConfiguredValue<V> of(@NotNull ValueManifest<V, V> manifest,
@Nullable ValueParser<V> parser, @Nullable ValueParser<V> parser,
@Nullable ValueSerializer<V> serializer) { @Nullable ValueSerializer<V> serializer) {
ValueAdapter<V> adapter = new ValueAdapter<>(manifest.type()); ValueAdapter<V> adapter = new ValueAdapter<>(manifest.type());
@@ -60,13 +100,13 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
return of(manifest, adapter); return of(manifest, adapter);
} }
public static <V> ConfiguredValue<V> of(@NotNull ValueManifest<V> manifest, @NotNull ValueAdapter<V> adapter) { public static <V> ConfiguredValue<V> of(@NotNull ValueManifest<V, V> manifest, @NotNull ValueAdapter<V> adapter) {
return new ConfiguredValue<>(manifest, adapter); return new ConfiguredValue<>(manifest, adapter);
} }
protected final @NotNull ValueAdapter<V> adapter; protected final @NotNull ValueAdapter<V> adapter;
public ConfiguredValue(@NotNull ValueManifest<V> manifest, @NotNull ValueAdapter<V> adapter) { public ConfiguredValue(@NotNull ValueManifest<V, V> manifest, @NotNull ValueAdapter<V> adapter) {
super(manifest); super(manifest);
this.adapter = adapter; this.adapter = adapter;
} }
@@ -97,18 +137,19 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
if (!cacheExpired()) return getCachedOrDefault(); if (!cacheExpired()) return getCachedOrDefault();
// Data that is outdated and needs to be parsed again. // Data that is outdated and needs to be parsed again.
try {
Object data = getData(); Object data = getData();
if (data == null) return defaults(); if (data == null) return defaults();
ValueParser<V> parser = parser(); ValueParser<V> parser = parser();
if (parser == null) return defaults(); // No parser, return default value. if (parser == null) return defaults(); // No parser, return default value.
try {
// If there are no errors, update the cache and return. // If there are no errors, update the cache and return.
return updateCache(parser.parse(holder(), type(), data)); V parsed = parser.parse(holder(), type(), data);
return updateCache(withValidated(parsed));
} catch (Exception e) { } catch (Exception e) {
// There was a parsing error, prompted and returned the default value. // There was a validate or parsing error, prompted and returned the default value.
e.printStackTrace(); throwing(e);
return defaults(); return defaults();
} }
@@ -121,20 +162,20 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
* @param value The value to be set * @param value The value to be set
*/ */
@Override @Override
public void set(V value) { public void set(@Nullable V value) {
updateCache(value); // Update cache updateCache(value); // Update cache
if (value == null) { if (value == null) {
setData(null); setData(null);
return; return;
} }
try {
ValueSerializer<V> serializer = serializer(); ValueSerializer<V> serializer = serializer();
if (serializer == null) return; // No serializer, do nothing. if (serializer == null) return; // No serializer, do nothing.
try { setData(serializer.serialize(holder(), type(), withValidated(value)));
setData(serializer.serialize(holder(), type(), value));
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); throwing(e);
} }
} }
+11 -9
View File
@@ -3,9 +3,9 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>4.0.8</version> <version>4.1.1</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<properties> <properties>
@@ -13,36 +13,38 @@
<maven.compiler.target>${project.jdk.version}</maven.compiler.target> <maven.compiler.target>${project.jdk.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties> </properties>
<artifactId>easyconfiguration-demo</artifactId> <artifactId>configured-demo</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-commentable</artifactId> <artifactId>configured-feature-commentable</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-versioned</artifactId> <artifactId>configured-feature-versioned</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-versioned</artifactId> <artifactId>configured-feature-validators</artifactId>
<version>4.0.8</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -3,7 +3,6 @@ package cc.carm.lib.configuration.demo;
import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.annotation.ConfigPath; import cc.carm.lib.configuration.annotation.ConfigPath;
import cc.carm.lib.configuration.annotation.HeaderComments; import cc.carm.lib.configuration.annotation.HeaderComments;
import cc.carm.lib.configuration.value.ConfigValue;
import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue;
@HeaderComments({"", "数据库配置", " 用于提供数据库连接,进行数据库操作。"}) @HeaderComments({"", "数据库配置", " 用于提供数据库连接,进行数据库操作。"})
@@ -16,17 +15,17 @@ public interface DatabaseConfiguration extends Configuration {
"- MySQL(新): com.mysql.cj.jdbc.Driver", "- MySQL(新): com.mysql.cj.jdbc.Driver",
"- MariaDB(推荐): org.mariadb.jdbc.Driver", "- MariaDB(推荐): org.mariadb.jdbc.Driver",
}) })
ConfigValue<String> DRIVER_NAME = ConfiguredValue.of( ConfiguredValue<String> DRIVER_NAME = ConfiguredValue.of(
String.class, "com.mysql.cj.jdbc.Driver" String.class, "com.mysql.cj.jdbc.Driver"
); );
ConfigValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1"); ConfiguredValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1");
ConfigValue<Integer> PORT = ConfiguredValue.of(Integer.class, 3306); ConfiguredValue<Integer> PORT = ConfiguredValue.of(Integer.class, 3306);
ConfigValue<String> DATABASE = ConfiguredValue.of(String.class, "minecraft"); ConfiguredValue<String> DATABASE = ConfiguredValue.of(String.class, "minecraft");
ConfigValue<String> USERNAME = ConfiguredValue.of(String.class, "root"); ConfiguredValue<String> USERNAME = ConfiguredValue.of(String.class, "root");
ConfigValue<String> PASSWORD = ConfiguredValue.of(String.class, "password"); ConfiguredValue<String> PASSWORD = ConfiguredValue.of(String.class, "password");
ConfigValue<String> EXTRA = ConfiguredValue.of(String.class, "?useSSL=false"); ConfiguredValue<String> EXTRA = ConfiguredValue.of(String.class, "?useSSL=false");
static String buildJDBC() { static String buildJDBC() {
return String.format("jdbc:mysql://%s:%s/%s%s", HOST.get(), PORT.get(), DATABASE.get(), EXTRA.get()); return String.format("jdbc:mysql://%s:%s/%s%s", HOST.get(), PORT.get(), DATABASE.get(), EXTRA.get());
@@ -4,7 +4,6 @@ import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.annotation.*; import cc.carm.lib.configuration.annotation.*;
import cc.carm.lib.configuration.demo.tests.model.ItemStack; import cc.carm.lib.configuration.demo.tests.model.ItemStack;
import cc.carm.lib.configuration.demo.tests.model.UserRecord; import cc.carm.lib.configuration.demo.tests.model.UserRecord;
import cc.carm.lib.configuration.value.ConfigValue;
import cc.carm.lib.configuration.value.standard.ConfiguredList; import cc.carm.lib.configuration.value.standard.ConfiguredList;
import cc.carm.lib.configuration.value.standard.ConfiguredMap; import cc.carm.lib.configuration.value.standard.ConfiguredMap;
import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue;
@@ -20,21 +19,27 @@ import java.util.UUID;
"------------------------------------------------", "------------------------------------------------",
"此处内容将显示在配置文件的最下方", "此处内容将显示在配置文件的最下方",
"可用于显示版权信息等", "可用于显示版权信息等",
"感谢您使用 https://github.com/CarmJos/EasyConfiguration !" "感谢您使用 https://github.com/CarmJos/configured !"
}) })
public interface DemoConfiguration extends Configuration { public interface DemoConfiguration extends Configuration {
@ConfigPath(root = true) @ConfigPath(root = true)
@ConfigVersion(2) @ConfigVersion(2)
ConfigValue<Double> VERSION = ConfiguredValue.of(Double.class, 2.0D); ConfiguredValue<Double> VERSION = ConfiguredValue.of(Double.class, 2.0D);
@ConfigPath(root = true) @ConfigPath(root = true)
@FooterComments({"此处内容将显示在配置条目的下方", "可用于补充说明,但一般不建议使用"}) @FooterComments({"此处内容将显示在配置条目的下方", "可用于补充说明,但一般不建议使用"})
ConfigValue<Long> TEST_NUMBER = ConfiguredValue.of(1000000L); ConfiguredValue<Long> TEST_NUMBER = ConfiguredValue.with(Long.class).defaults(123456789L).build();
@HeaderComments({"枚举类型测试"}) @HeaderComments({"枚举类型测试"})
@FooterComments({"上述的枚举内容本质上是通过STRING解析的"}) @FooterComments({"上述的枚举内容本质上是通过STRING解析的"})
ConfigValue<ChronoUnit> TEST_ENUM = ConfiguredValue.of(ChronoUnit.class, ChronoUnit.DAYS); ConfiguredValue<ChronoUnit> TEST_ENUM = ConfiguredValue.of(ChronoUnit.class, ChronoUnit.DAYS);
@HeaderComments({"空值测试"})
@InlineComment("空值Inline注释")
ConfiguredMap<String, String> EMPTY = ConfiguredMap.builderOf(String.class, String.class)
.asLinkedMap().fromString()
.build();
@ConfigPath("registered_users") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。 @ConfigPath("registered_users") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
@HeaderComments({"Section类型数据测试"}) // 通过注解给配置添加注释。 @HeaderComments({"Section类型数据测试"}) // 通过注解给配置添加注释。
@@ -66,7 +71,7 @@ public interface DemoConfiguration extends Configuration {
class SUB implements Configuration { class SUB implements Configuration {
@ConfigPath(value = "uuid-value", root = true) @ConfigPath(value = "uuid-value", root = true)
public static final ConfigValue<UUID> UUID_CONFIG_VALUE = ConfiguredValue public static final ConfiguredValue<UUID> UUID_CONFIG_VALUE = ConfiguredValue
.builderOf(UUID.class).fromString() .builderOf(UUID.class).fromString()
.parse((holder, data) -> UUID.fromString(data)) .parse((holder, data) -> UUID.fromString(data))
.build(); .build();
@@ -2,12 +2,13 @@ package cc.carm.lib.configuration.demo.tests.conf;
import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.annotation.HeaderComments; import cc.carm.lib.configuration.annotation.HeaderComments;
import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.annotation.ValueRange;
import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue;
@HeaderComments("Inner Test") @HeaderComments("service")
public class InstanceConfig implements Configuration { public class InstanceConfig implements Configuration {
public final ConfigValue<Double> STATUS = ConfiguredValue.of(1.0D); @ValueRange(min = 0, max = 100, message = "The value must be between 0 and 100")
public final ConfiguredValue<Double> STATUS = ConfiguredValue.of(1.0D);
} }
@@ -6,7 +6,6 @@ import cc.carm.lib.configuration.annotation.FooterComments;
import cc.carm.lib.configuration.annotation.HeaderComments; import cc.carm.lib.configuration.annotation.HeaderComments;
import cc.carm.lib.configuration.annotation.InlineComment; import cc.carm.lib.configuration.annotation.InlineComment;
import cc.carm.lib.configuration.demo.tests.model.UserRecord; import cc.carm.lib.configuration.demo.tests.model.UserRecord;
import cc.carm.lib.configuration.value.ConfigValue;
import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue;
import java.util.UUID; import java.util.UUID;
@@ -20,7 +19,7 @@ public class RegistryConfig implements Configuration {
@FooterComments({"12313213212"}) @FooterComments({"12313213212"})
@InlineComment(value = "用户名(匹配注释)", regex = "name") // 通过注解给配置添加注释。 @InlineComment(value = "用户名(匹配注释)", regex = "name") // 通过注解给配置添加注释。
@InlineComment(value = "信息", regex = {"info.*", "info.game.*"}) // 通过注解给配置添加注释。 @InlineComment(value = "信息", regex = {"info.*", "info.game.*"}) // 通过注解给配置添加注释。
public final ConfigValue<UserRecord> OWNER = ConfiguredValue.builderOf(UserRecord.class).fromSection() public final ConfiguredValue<UserRecord> OWNER = ConfiguredValue.builderOf(UserRecord.class).fromSection()
.defaults(new UserRecord("Carm", UUID.randomUUID())) .defaults(new UserRecord("Carm", UUID.randomUUID()))
.parse((holder, section) -> UserRecord.deserialize(section)) .parse((holder, section) -> UserRecord.deserialize(section))
.serialize((holder, data) -> data.serialize()).build(); .serialize((holder, data) -> data.serialize()).build();
+4 -4
View File
@@ -5,8 +5,8 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<version>4.0.8</version> <version>4.1.1</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -16,13 +16,13 @@
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties> </properties>
<artifactId>easyconfiguration-feature-commentable</artifactId> <artifactId>configured-feature-commentable</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
@@ -49,6 +49,17 @@ public interface CommentableMeta {
FooterComments.class, FOOTER, FooterComments.class, FOOTER,
a -> Arrays.asList(a.value()) a -> Arrays.asList(a.value())
); );
initializer.registerAnnotation(InlineComment.class, INLINE, a -> {
Map<String, String> map = new HashMap<>();
if (a.regex().length == 0) { // for current path
map.put(null, a.value());
return map;
}
for (String regex : a.regex()) { // for specified path
map.put(regex, a.value());
}
return map;
});
initializer.registerAnnotation(InlineComments.class, INLINE, a -> { initializer.registerAnnotation(InlineComments.class, INLINE, a -> {
Map<String, String> map = new HashMap<>(); Map<String, String> map = new HashMap<>();
for (InlineComment comment : a.value()) { for (InlineComment comment : a.value()) {
+4 -4
View File
@@ -5,8 +5,8 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<version>4.0.8</version> <version>4.1.1</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -16,13 +16,13 @@
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties> </properties>
<artifactId>easyconfiguration-feature-file</artifactId> <artifactId>configured-feature-file</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
+4 -4
View File
@@ -5,8 +5,8 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<version>4.0.8</version> <version>4.1.1</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -16,13 +16,13 @@
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties> </properties>
<artifactId>easyconfiguration-feature-section</artifactId> <artifactId>configured-feature-section</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
@@ -75,17 +75,18 @@ public abstract class AbstractMapSection<R extends AbstractMapSection<R>> implem
return deep ? getKeys(true).size() : this.data.size(); return deep ? getKeys(true).size() : this.data.size();
} }
@Override
@UnmodifiableView @UnmodifiableView
public @NotNull Map<String, Object> rawMap() { public @NotNull Map<String, Object> asMap() {
Map<String, Object> output = new LinkedHashMap<>(); Map<String, Object> output = new LinkedHashMap<>();
for (Map.Entry<String, Object> entry : this.data.entrySet()) { for (Map.Entry<String, Object> entry : this.data.entrySet()) {
if (entry.getValue() instanceof AbstractMapSection<?>) { if (entry.getValue() instanceof AbstractMapSection<?>) {
output.put(entry.getKey(), ((AbstractMapSection<?>) entry.getValue()).rawMap()); output.put(entry.getKey(), ((AbstractMapSection<?>) entry.getValue()).asMap());
} else if (entry.getValue() instanceof List<?>) { } else if (entry.getValue() instanceof List<?>) {
List<Object> list = new ArrayList<>(); List<Object> list = new ArrayList<>();
for (Object obj : (List<?>) entry.getValue()) { for (Object obj : (List<?>) entry.getValue()) {
if (obj instanceof AbstractMapSection<?>) { if (obj instanceof AbstractMapSection<?>) {
list.add(((AbstractMapSection<?>) obj).rawMap()); list.add(((AbstractMapSection<?>) obj).asMap());
} else { } else {
list.add(obj); list.add(obj);
} }
@@ -20,13 +20,18 @@ public class ImmutableSection implements ConfigureSection {
} }
protected final @Nullable ImmutableSection parent; protected final @Nullable ImmutableSection parent;
protected final @NotNull ConfigureSection section; protected final @NotNull ConfigureSection raw;
private ImmutableSection(@Nullable ImmutableSection parent, @NotNull ConfigureSection section) { private ImmutableSection(@Nullable ImmutableSection parent, @NotNull ConfigureSection raw) {
this.parent = parent; this.parent = parent;
this.section = section; this.raw = raw;
} }
private @NotNull ConfigureSection raw() {
return raw;
}
@Override @Override
public @Nullable ImmutableSection parent() { public @Nullable ImmutableSection parent() {
return this.parent; return this.parent;
@@ -34,16 +39,12 @@ public class ImmutableSection implements ConfigureSection {
@Override @Override
public @NotNull String path() { public @NotNull String path() {
return section().path(); return raw().path();
}
private @NotNull ConfigureSection section() {
return section;
} }
@Override @Override
public @NotNull @UnmodifiableView Map<String, Object> getValues(boolean deep) { public @NotNull @UnmodifiableView Map<String, Object> getValues(boolean deep) {
return section().getValues(deep); return raw().getValues(deep);
} }
@Override @Override
@@ -58,12 +59,12 @@ public class ImmutableSection implements ConfigureSection {
@Override @Override
public @NotNull ImmutableSection createSection(@NotNull String path, @NotNull Map<?, ?> data) { public @NotNull ImmutableSection createSection(@NotNull String path, @NotNull Map<?, ?> data) {
return new ImmutableSection(this, section().createSection(path, data)); return new ImmutableSection(this, raw().createSection(path, data));
} }
@Override @Override
public @Nullable Object get(@NotNull String path) { public @Nullable Object get(@NotNull String path) {
Object value = section().get(path); Object value = raw().get(path);
if (value instanceof ConfigureSection && !(value instanceof ImmutableSection)) { if (value instanceof ConfigureSection && !(value instanceof ImmutableSection)) {
return new ImmutableSection(this, (ConfigureSection) value); return new ImmutableSection(this, (ConfigureSection) value);
} }
@@ -72,7 +73,7 @@ public class ImmutableSection implements ConfigureSection {
@Override @Override
public @Nullable ConfigureSection getSection(@NotNull String path) { public @Nullable ConfigureSection getSection(@NotNull String path) {
ConfigureSection get = section().getSection(path); ConfigureSection get = raw().getSection(path);
if (get != null && !(get instanceof ImmutableSection)) { if (get != null && !(get instanceof ImmutableSection)) {
return new ImmutableSection(this, get); return new ImmutableSection(this, get);
} }
@@ -81,297 +82,302 @@ public class ImmutableSection implements ConfigureSection {
@Override @Override
public char pathSeparator() { public char pathSeparator() {
return section().pathSeparator(); return raw().pathSeparator();
} }
@Override @Override
public boolean isRoot() { public boolean isRoot() {
return section().isRoot(); return raw().isRoot();
} }
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
return section().isEmpty(); return raw().isEmpty();
} }
@Override @Override
public @NotNull @UnmodifiableView Set<String> getKeys(boolean deep) { public @NotNull @UnmodifiableView Set<String> getKeys(boolean deep) {
return section().getKeys(deep); return raw().getKeys(deep);
} }
@Override @Override
public @NotNull @UnmodifiableView Set<String> keys() { public @NotNull @UnmodifiableView Set<String> keys() {
return section().keys(); return raw().keys();
} }
@Override @Override
public @NotNull @UnmodifiableView Map<String, Object> values() { public @NotNull @UnmodifiableView Map<String, Object> values() {
return section().values(); return raw().values();
}
@Override
public @NotNull @UnmodifiableView Map<String, Object> asMap() {
return raw().asMap();
} }
@Override @Override
public Stream<Map.Entry<String, Object>> stream() { public Stream<Map.Entry<String, Object>> stream() {
return section().stream(); return raw().stream();
} }
@Override @Override
public void forEach(@NotNull BiConsumer<String, Object> action) { public void forEach(@NotNull BiConsumer<String, Object> action) {
section().forEach(action); raw().forEach(action);
} }
@Override @Override
public boolean contains(@NotNull String path) { public boolean contains(@NotNull String path) {
return section().contains(path); return raw().contains(path);
} }
@Override @Override
public boolean containsValue(@NotNull String path) { public boolean containsValue(@NotNull String path) {
return section().containsValue(path); return raw().containsValue(path);
} }
@Override @Override
public <T> boolean isType(@NotNull String path, @NotNull Class<T> typeClass) { public <T> boolean isType(@NotNull String path, @NotNull Class<T> typeClass) {
return section().isType(path, typeClass); return raw().isType(path, typeClass);
} }
@Override @Override
public boolean isList(@NotNull String path) { public boolean isList(@NotNull String path) {
return section().isList(path); return raw().isList(path);
} }
@Override @Override
public @Nullable List<?> getList(@NotNull String path) { public @Nullable List<?> getList(@NotNull String path) {
return section().getList(path); return raw().getList(path);
} }
@Override @Override
public boolean isSection(@NotNull String path) { public boolean isSection(@NotNull String path) {
return section().isSection(path); return raw().isSection(path);
} }
@Override @Override
public <T> @Nullable T get(@NotNull String path, @NotNull Class<T> type) { public <T> @Nullable T get(@NotNull String path, @NotNull Class<T> type) {
return section().get(path, type); return raw().get(path, type);
} }
@Override @Override
public <T> @Nullable T get(@NotNull String path, @NotNull DataFunction<@Nullable Object, T> parser) { public <T> @Nullable T get(@NotNull String path, @NotNull DataFunction<@Nullable Object, T> parser) {
return section().get(path, parser); return raw().get(path, parser);
} }
@Override @Override
public <T> @Nullable T get(@NotNull String path, @Nullable T defaults, @NotNull Class<T> clazz) { public <T> @Nullable T get(@NotNull String path, @Nullable T defaults, @NotNull Class<T> clazz) {
return section().get(path, defaults, clazz); return raw().get(path, defaults, clazz);
} }
@Override @Override
public <T> @Nullable T get(@NotNull String path, @Nullable T defaultValue, @NotNull DataFunction<Object, T> parser) { public <T> @Nullable T get(@NotNull String path, @Nullable T defaultValue, @NotNull DataFunction<Object, T> parser) {
return section().get(path, defaultValue, parser); return raw().get(path, defaultValue, parser);
} }
@Override @Override
public boolean isBoolean(@NotNull String path) { public boolean isBoolean(@NotNull String path) {
return section().isBoolean(path); return raw().isBoolean(path);
} }
@Override @Override
public boolean getBoolean(@NotNull String path) { public boolean getBoolean(@NotNull String path) {
return section().getBoolean(path); return raw().getBoolean(path);
} }
@Override @Override
public @Nullable Boolean getBoolean(@NotNull String path, @Nullable Boolean def) { public @Nullable Boolean getBoolean(@NotNull String path, @Nullable Boolean def) {
return section().getBoolean(path, def); return raw().getBoolean(path, def);
} }
@Override @Override
public @Nullable Boolean isByte(@NotNull String path) { public @Nullable Boolean isByte(@NotNull String path) {
return section().isByte(path); return raw().isByte(path);
} }
@Override @Override
public @Nullable Byte getByte(@NotNull String path) { public @Nullable Byte getByte(@NotNull String path) {
return section().getByte(path); return raw().getByte(path);
} }
@Override @Override
public @Nullable Byte getByte(@NotNull String path, @Nullable Byte def) { public @Nullable Byte getByte(@NotNull String path, @Nullable Byte def) {
return section().getByte(path, def); return raw().getByte(path, def);
} }
@Override @Override
public boolean isShort(@NotNull String path) { public boolean isShort(@NotNull String path) {
return section().isShort(path); return raw().isShort(path);
} }
@Override @Override
public @Nullable Short getShort(@NotNull String path) { public @Nullable Short getShort(@NotNull String path) {
return section().getShort(path); return raw().getShort(path);
} }
@Override @Override
public @Nullable Short getShort(@NotNull String path, @Nullable Short def) { public @Nullable Short getShort(@NotNull String path, @Nullable Short def) {
return section().getShort(path, def); return raw().getShort(path, def);
} }
@Override @Override
public boolean isInt(@NotNull String path) { public boolean isInt(@NotNull String path) {
return section().isInt(path); return raw().isInt(path);
} }
@Override @Override
public @Nullable Integer getInt(@NotNull String path) { public @Nullable Integer getInt(@NotNull String path) {
return section().getInt(path); return raw().getInt(path);
} }
@Override @Override
public @Nullable Integer getInt(@NotNull String path, @Nullable Integer def) { public @Nullable Integer getInt(@NotNull String path, @Nullable Integer def) {
return section().getInt(path, def); return raw().getInt(path, def);
} }
@Override @Override
public boolean isLong(@NotNull String path) { public boolean isLong(@NotNull String path) {
return section().isLong(path); return raw().isLong(path);
} }
@Override @Override
public @Nullable Long getLong(@NotNull String path) { public @Nullable Long getLong(@NotNull String path) {
return section().getLong(path); return raw().getLong(path);
} }
@Override @Override
public @Nullable Long getLong(@NotNull String path, @Nullable Long def) { public @Nullable Long getLong(@NotNull String path, @Nullable Long def) {
return section().getLong(path, def); return raw().getLong(path, def);
} }
@Override @Override
public boolean isFloat(@NotNull String path) { public boolean isFloat(@NotNull String path) {
return section().isFloat(path); return raw().isFloat(path);
} }
@Override @Override
public @Nullable Float getFloat(@NotNull String path) { public @Nullable Float getFloat(@NotNull String path) {
return section().getFloat(path); return raw().getFloat(path);
} }
@Override @Override
public @Nullable Float getFloat(@NotNull String path, @Nullable Float def) { public @Nullable Float getFloat(@NotNull String path, @Nullable Float def) {
return section().getFloat(path, def); return raw().getFloat(path, def);
} }
@Override @Override
public boolean isDouble(@NotNull String path) { public boolean isDouble(@NotNull String path) {
return section().isDouble(path); return raw().isDouble(path);
} }
@Override @Override
public @Nullable Double getDouble(@NotNull String path) { public @Nullable Double getDouble(@NotNull String path) {
return section().getDouble(path); return raw().getDouble(path);
} }
@Override @Override
public @Nullable Double getDouble(@NotNull String path, @Nullable Double def) { public @Nullable Double getDouble(@NotNull String path, @Nullable Double def) {
return section().getDouble(path, def); return raw().getDouble(path, def);
} }
@Override @Override
public boolean isChar(@NotNull String path) { public boolean isChar(@NotNull String path) {
return section().isChar(path); return raw().isChar(path);
} }
@Override @Override
public @Nullable Character getChar(@NotNull String path) { public @Nullable Character getChar(@NotNull String path) {
return section().getChar(path); return raw().getChar(path);
} }
@Override @Override
public @Nullable Character getChar(@NotNull String path, @Nullable Character def) { public @Nullable Character getChar(@NotNull String path, @Nullable Character def) {
return section().getChar(path, def); return raw().getChar(path, def);
} }
@Override @Override
public boolean isString(@NotNull String path) { public boolean isString(@NotNull String path) {
return section().isString(path); return raw().isString(path);
} }
@Override @Override
public @Nullable String getString(@NotNull String path) { public @Nullable String getString(@NotNull String path) {
return section().getString(path); return raw().getString(path);
} }
@Override @Override
public @Nullable String getString(@NotNull String path, @Nullable String def) { public @Nullable String getString(@NotNull String path, @Nullable String def) {
return section().getString(path, def); return raw().getString(path, def);
} }
@Override @Override
public @NotNull <V> List<V> getList(@NotNull String path, @NotNull DataFunction<Object, V> parser) { public @NotNull <V> List<V> getList(@NotNull String path, @NotNull DataFunction<Object, V> parser) {
return section().getList(path, parser); return raw().getList(path, parser);
} }
@Override @Override
public @NotNull List<String> getStringList(@NotNull String path) { public @NotNull List<String> getStringList(@NotNull String path) {
return section().getStringList(path); return raw().getStringList(path);
} }
@Override @Override
public @NotNull List<Integer> getIntegerList(@NotNull String path) { public @NotNull List<Integer> getIntegerList(@NotNull String path) {
return section().getIntegerList(path); return raw().getIntegerList(path);
} }
@Override @Override
public @NotNull List<Long> getLongList(@NotNull String path) { public @NotNull List<Long> getLongList(@NotNull String path) {
return section().getLongList(path); return raw().getLongList(path);
} }
@Override @Override
public @NotNull List<Double> getDoubleList(@NotNull String path) { public @NotNull List<Double> getDoubleList(@NotNull String path) {
return section().getDoubleList(path); return raw().getDoubleList(path);
} }
@Override @Override
public @NotNull List<Float> getFloatList(@NotNull String path) { public @NotNull List<Float> getFloatList(@NotNull String path) {
return section().getFloatList(path); return raw().getFloatList(path);
} }
@Override @Override
public @NotNull List<Byte> getByteList(@NotNull String path) { public @NotNull List<Byte> getByteList(@NotNull String path) {
return section().getByteList(path); return raw().getByteList(path);
} }
@Override @Override
public @NotNull List<Character> getCharList(@NotNull String path) { public @NotNull List<Character> getCharList(@NotNull String path) {
return section().getCharList(path); return raw().getCharList(path);
} }
@Override @Override
public <T, C extends Collection<T>> @NotNull C getCollection(@NotNull String path, @NotNull Supplier<C> constructor, @NotNull DataFunction<Object, T> parser) { public <T, C extends Collection<T>> @NotNull C getCollection(@NotNull String path, @NotNull Supplier<C> constructor, @NotNull DataFunction<Object, T> parser) {
return section().getCollection(path, constructor, parser); return raw().getCollection(path, constructor, parser);
} }
@Override @Override
public @NotNull Stream<?> stream(@NotNull String path) { public @NotNull Stream<?> stream(@NotNull String path) {
return section().stream(path); return raw().stream(path);
} }
@Override @Override
public @NotNull <T> Stream<T> stream(@NotNull String path, @NotNull Function<Object, T> parser) { public @NotNull <T> Stream<T> stream(@NotNull String path, @NotNull Function<Object, T> parser) {
return section().stream(path, parser); return raw().stream(path, parser);
} }
@Override @Override
public String childPath(String path) { public String childPath(String path) {
return section().childPath(path); return raw().childPath(path);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return section.hashCode(); return raw.hashCode();
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
return Objects.equals(section, obj); return Objects.equals(raw, obj);
} }
} }
@@ -40,6 +40,12 @@ public class ShadedSection implements ConfigureSection {
return merge(template, source).getValues(deep); return merge(template, source).getValues(deep);
} }
@Override
public @NotNull @UnmodifiableView Map<String, Object> asMap() {
if (source == null) return template.asMap();
return merge(template, source).asMap();
}
@Override @Override
public @NotNull @UnmodifiableView Set<String> getKeys(boolean deep) { public @NotNull @UnmodifiableView Set<String> getKeys(boolean deep) {
Set<String> keys = new HashSet<>(template.getKeys(deep)); Set<String> keys = new HashSet<>(template.getKeys(deep));
+5 -5
View File
@@ -5,8 +5,8 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<version>4.0.8</version> <version>4.1.1</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -16,20 +16,20 @@
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties> </properties>
<artifactId>easyconfiguration-feature-text</artifactId> <artifactId>configured-feature-text</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>easyconfiguration-yaml</artifactId> <artifactId>configured-gson</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@@ -22,7 +22,7 @@ import java.util.function.Consumer;
*/ */
public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents> { public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents> {
public static <M, R> Builder<M, R, ?> builder() { public static <M, R> Builder<M, R, ?> create() {
return new StardardBuilder<>(); return new StardardBuilder<>();
} }
@@ -38,7 +38,7 @@ public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents>
protected final @NotNull String[] params; // The parameters of the message. protected final @NotNull String[] params; // The parameters of the message.
public ConfiguredText(@NotNull ValueManifest<TextContents> manifest, public ConfiguredText(@NotNull ValueManifest<TextContents, TextContents> manifest,
@NotNull BiFunction<RECEIVER, String, String> parser, @NotNull BiFunction<RECEIVER, String, String> parser,
@NotNull BiFunction<RECEIVER, String, MSG> compiler, @NotNull BiFunction<RECEIVER, String, MSG> compiler,
@NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher, @NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher,
@@ -121,7 +121,7 @@ public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents>
} }
public abstract static class Builder<MSG, RECEIVER, SELF extends Builder<MSG, RECEIVER, SELF>> public abstract static class Builder<MSG, RECEIVER, SELF extends Builder<MSG, RECEIVER, SELF>>
extends AbstractConfigBuilder<TextContents, ConfiguredText<MSG, RECEIVER>, ConfigurationHolder<?>, SELF> { extends AbstractConfigBuilder<TextContents, TextContents, ConfiguredText<MSG, RECEIVER>, ConfigurationHolder<?>, SELF> {
protected @NotNull TextContents.Builder defaultBuilder = TextContents.builder(); protected @NotNull TextContents.Builder defaultBuilder = TextContents.builder();
protected @NotNull String[] params = new String[0]; protected @NotNull String[] params = new String[0];
@@ -16,11 +16,12 @@ import java.util.stream.IntStream;
public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEIVER, SELF>> { public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEIVER, SELF>> {
/** /**
* Used to match the message insertion * Used to match the message insertion.
* <p> * <p>
* format: * format:
* <br>- to insert parsed line {prefix}#content-id#{offset-above,offset-down} * <br>- to insert parsed line {prefix}#content-id#{offset-above,offset-down}
* <br>- to insert original line {prefix}@content-id@{offset-above,offset-down} * <br>- to insert original line {prefix}@content-id@{offset-above,offset-down}
* <br> original lines will not be parsed
* <br> example: * <br> example:
* <ul> * <ul>
* <li>{- }#content-id#{1,1}</li> * <li>{- }#content-id#{1,1}</li>
@@ -30,6 +31,21 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
public static final @NotNull Pattern INSERT_PATTERN = Pattern.compile( public static final @NotNull Pattern INSERT_PATTERN = Pattern.compile(
"^(?:\\{(?<prefix>.*)})?(?<type>[#@])(?<id>.*)[#@](?:\\{(?<above>-?\\d+)(?:,(?<down>-?\\d+))?})?$" "^(?:\\{(?<prefix>.*)})?(?<type>[#@])(?<id>.*)[#@](?:\\{(?<above>-?\\d+)(?:,(?<down>-?\\d+))?})?$"
); );
/**
* Used to match the message which can be inserted
* <p>
* format:
* <br>- ?[id]Message content
* <br> example:
* <ul>
* <li>?[click]Click to use this item!</li>
* </ul>
*/
public static final @NotNull Pattern ENABLE_PATTERN = Pattern.compile(
"^\\?\\[(?<id>.+)](?<content>.*)$"
);
public static final @NotNull UnaryOperator<String> DEFAULT_PARAM_BUILDER = s -> "%(" + s + ")"; public static final @NotNull UnaryOperator<String> DEFAULT_PARAM_BUILDER = s -> "%(" + s + ")";
protected BiFunction<RECEIVER, String, String> parser = (receiver, value) -> value; protected BiFunction<RECEIVER, String, String> parser = (receiver, value) -> value;
@@ -45,7 +61,7 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
/** /**
* Used to store the insertion of the message * Used to store the insertion of the message
*/ */
protected @NotNull Map<String, Function<RECEIVER, List<String>>> insertion = new HashMap<>(); protected @NotNull Map<String, @Nullable Function<RECEIVER, List<String>>> insertion = new HashMap<>();
protected boolean disableInsertion = false; protected boolean disableInsertion = false;
public abstract SELF self(); public abstract SELF self();
@@ -139,6 +155,17 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
return self(); return self();
} }
/**
* Insert the specific contents by the id.
*
* @param id the id of the insertion text
* @return the current {@link ContentHandler} instance
*/
public SELF insert(@NotNull String id) {
this.insertion.put(id, null);
return self();
}
/** /**
* Insert the specific contents by the id. * Insert the specific contents by the id.
* *
@@ -205,17 +232,31 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
} }
for (String line : contents.lines()) { for (String line : contents.lines()) {
Matcher matcher = INSERT_PATTERN.matcher(line); Matcher insertMatcher = INSERT_PATTERN.matcher(line);
if (!matcher.matches()) { if (insertMatcher.matches()) {
lineConsumer.accept(parse(receiver, line)); doInsert(insertMatcher, receiver, lineConsumer);
continue; continue;
} }
Matcher enableMatcher = ENABLE_PATTERN.matcher(line);
if (enableMatcher.matches()) {
if (this.insertion.containsKey(enableMatcher.group("id"))) {
lineConsumer.accept(parse(receiver, enableMatcher.group("content")));
}
continue;
}
lineConsumer.accept(parse(receiver, line));
}
}
private void doInsert(Matcher matcher, @Nullable RECEIVER receiver,
@NotNull Consumer<String> lineConsumer) {
String id = matcher.group("id"); String id = matcher.group("id");
List<String> values = Optional.ofNullable(this.insertion.get(id)) List<String> values = Optional.ofNullable(this.insertion.get(id))
.map(f -> f.apply(receiver)) .map(f -> f.apply(receiver))
.orElse(null); .orElse(null);
if (values == null || values.isEmpty()) continue; if (values == null || values.isEmpty()) return; // No values to insert
String prefix = matcher.group("prefix"); String prefix = matcher.group("prefix");
String type = matcher.group("type"); String type = matcher.group("type");
@@ -234,7 +275,6 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
} }
IntStream.range(0, Math.max(0, offsetDown)).mapToObj(i -> "").forEach(lineConsumer); IntStream.range(0, Math.max(0, offsetDown)).mapToObj(i -> "").forEach(lineConsumer);
} }
}
public static String setPlaceholders(@NotNull String messages, public static String setPlaceholders(@NotNull String messages,
@NotNull Map<String, Object> placeholders) { @NotNull Map<String, Object> placeholders) {
@@ -2,10 +2,12 @@ package cc.carm.lib.configuration.value.text.tests;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.yaml.YAMLConfigFactory; import cc.carm.lib.configuration.source.json.JSONConfigFactory;
import cc.carm.lib.configuration.value.text.tests.conf.AppMessages; import cc.carm.lib.configuration.value.text.tests.conf.AppMessages;
import org.junit.Test; import org.junit.Test;
import java.io.File;
public class ConfigTest { public class ConfigTest {
@@ -19,7 +21,7 @@ public class ConfigTest {
@Test @Test
public void test() { public void test() {
ConfigurationHolder<?> holder = YAMLConfigFactory.from("target/messages.yml").build(); ConfigurationHolder<?> holder = JSONConfigFactory.from(new File("target/messages.json")).build();
holder.initialize(AppMessages.class); holder.initialize(AppMessages.class);
@@ -20,7 +20,9 @@ public class ParseTest {
lines.add("#guidance#"); lines.add("#guidance#");
lines.add("{- }#websites#{0,1}"); lines.add("{- }#websites#{0,1}");
lines.add("Thanks for your reading!"); lines.add("Thanks for your reading!");
lines.add("?[click]");
lines.add("?[click]Click to see more!");
lines.add("?[hidden]This entry should be hidden!");
Map<String, List<String>> optional = new HashMap<>(); Map<String, List<String>> optional = new HashMap<>();
optional.put("guidance", Arrays.asList("To get more information for %(name), see:")); optional.put("guidance", Arrays.asList("To get more information for %(name), see:"));
@@ -35,6 +37,7 @@ public class ParseTest {
msg.placeholder("name", "Carm") msg.placeholder("name", "Carm")
.insert("guidance") .insert("guidance")
.insert("click")
.insert("websites", "Baidu", "Bilibili", "Google"); .insert("websites", "Baidu", "Bilibili", "Google");
System.out.println("----------------------------"); System.out.println("----------------------------");
@@ -17,7 +17,8 @@ public class ConfiguredMsg extends ConfiguredText<String, PrintStream> {
return builder().defaults(text).build(); return builder().defaults(text).build();
} }
public ConfiguredMsg(@NotNull ValueManifest<TextContents> manifest, @NotNull String[] params) { public ConfiguredMsg(@NotNull ValueManifest<TextContents, TextContents> manifest,
@NotNull String[] params) {
super( super(
manifest, manifest,
(p, s) -> s, (p, s) -> s,
+51
View File
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-parent</artifactId>
<version>4.1.1</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties>
<artifactId>configured-feature-validators</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>configured-core</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,16 @@
package cc.carm.lib.configuration.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValuePattern {
String value();
String message() default "Invalid value format!";
}
@@ -0,0 +1,18 @@
package cc.carm.lib.configuration.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValueRange {
long min() default Long.MIN_VALUE;
long max() default Long.MAX_VALUE;
String message() default "Value out of range.";
}
@@ -0,0 +1,44 @@
package cc.carm.lib.configuration.validators;
import cc.carm.lib.configuration.annotation.ValuePattern;
import cc.carm.lib.configuration.annotation.ValueRange;
import cc.carm.lib.configuration.function.ValueValidator;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.regex.Pattern;
public class Validators {
private Validators() {
throw new UnsupportedOperationException("API Register.");
}
public static void activate(ConfigurationHolder<?> holder) {
holder.initializer().registerValidAnnotation(ValueRange.class, r -> (ho, value) -> {
if (!(value instanceof Number)) {
throw new IllegalArgumentException("Value is not a number: " + value);
}
Number number = (Number) value;
if (number.doubleValue() < r.min() || number.doubleValue() > r.max()) {
throw new IllegalArgumentException(r.message());
}
});
holder.initializer().registerValidAnnotation(ValuePattern.class, r -> new ValueValidator<Object>() {
private final Pattern pattern = Pattern.compile(r.value());
@Override
public void validate(@NotNull ConfigurationHolder<?> holder, @Nullable Object value) throws Exception {
if (value == null) return;
if (!pattern.matcher(value.toString()).matches()) {
throw new IllegalArgumentException(r.message());
}
}
});
}
}
+4 -4
View File
@@ -5,8 +5,8 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<version>4.0.8</version> <version>4.1.1</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -16,13 +16,13 @@
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties> </properties>
<artifactId>easyconfiguration-feature-versioned</artifactId> <artifactId>configured-feature-versioned</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
+15 -14
View File
@@ -13,29 +13,30 @@
</properties> </properties>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
<version>4.0.8</version> <version>4.1.1</version>
<modules> <modules>
<module>core</module> <module>core</module>
<module>features/section</module> <module>features/section</module>
<module>features/file</module> <module>features/file</module>
<module>features/commentable</module> <module>features/commentable</module>
<module>features/versioned</module> <module>features/versioned</module>
<module>features/validators</module>
<module>features/text</module> <module>features/text</module>
<module>providers/yaml</module> <module>providers/yaml</module>
<module>providers/gson</module> <module>providers/gson</module>
<!-- <module>providers/hocon</module>--> <module>providers/hocon</module>
<module>providers/sql</module> <module>providers/sql</module>
<module>providers/mongodb</module> <module>providers/mongodb</module>
<module>demo</module> <module>demo</module>
</modules> </modules>
<name>EasyConfiguration</name> <name>configured</name>
<description>A simple, easy-to-use and universal solution for managing configuration files.</description> <description>A simple, easy-to-use and universal solution for managing configuration files.</description>
<url>https://github.com/CarmJos/EasyConfiguration</url> <url>https://github.com/CarmJos/configured</url>
<developers> <developers>
<developer> <developer>
@@ -48,9 +49,9 @@
</developers> </developers>
<scm> <scm>
<connection>scm:git:git@github.com:CarmJos/Easy.EasyConfiguration</connection> <connection>scm:git:git@github.com:CarmJos/Easy.configured</connection>
<developerConnection>scm:git:git@github.com:CarmJos/EasyConfiguration.git</developerConnection> <developerConnection>scm:git:git@github.com:CarmJos/configured.git</developerConnection>
<url>https://github.com/CarmJos/EasyConfiguration</url> <url>https://github.com/CarmJos/configured</url>
<tag>HEAD</tag> <tag>HEAD</tag>
</scm> </scm>
@@ -63,12 +64,12 @@
<issueManagement> <issueManagement>
<system>GitHub Issues</system> <system>GitHub Issues</system>
<url>https://github.com/CarmJos/EasyConfiguration/issues</url> <url>https://github.com/CarmJos/configured/issues</url>
</issueManagement> </issueManagement>
<ciManagement> <ciManagement>
<system>GitHub Actions</system> <system>GitHub Actions</system>
<url>https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml</url> <url>https://github.com/CarmJos/configured/actions/workflows/maven.yml</url>
</ciManagement> </ciManagement>
<repositories> <repositories>
@@ -92,11 +93,11 @@
</repositories> </repositories>
<distributionManagement> <distributionManagement>
<downloadUrl>https://github.com/CarmJos/EasyConfiguration/releases</downloadUrl> <downloadUrl>https://github.com/CarmJos/configured/releases</downloadUrl>
<site> <site>
<id>javadoc</id> <id>javadoc</id>
<name>EasyConfiguration JavaDoc (on GitHub Pages)</name> <name>configured JavaDoc (on GitHub Pages)</name>
<url>https://CarmJos.github.io/EasyConfiguration</url> <url>https://CarmJos.github.io/configured</url>
</site> </site>
</distributionManagement> </distributionManagement>
@@ -292,7 +293,7 @@
<repository> <repository>
<id>github</id> <id>github</id>
<name>GitHub Packages</name> <name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url> <url>https://maven.pkg.github.com/CarmJos/configured</url>
</repository> </repository>
</distributionManagement> </distributionManagement>
</profile> </profile>
+6 -6
View File
@@ -1,4 +1,4 @@
# EasyConfiguration-JSON # configured-JSON
JSON file-based implementation, compatible with all Java environments. JSON file-based implementation, compatible with all Java environments.
@@ -22,9 +22,9 @@ JSON file-based implementation, compatible with all Java environments.
<repository> <repository>
<!-- Using GitHub dependencies for real-time updates, configuration required (recommended). --> <!-- Using GitHub dependencies for real-time updates, configuration required (recommended). -->
<id>EasyConfiguration</id> <id>configured</id>
<name>GitHub Packages</name> <name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url> <url>https://maven.pkg.github.com/CarmJos/configured</url>
</repository> </repository>
</repositories> </repositories>
@@ -37,7 +37,7 @@ JSON file-based implementation, compatible with all Java environments.
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-json</artifactId> <artifactId>configured-json</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -54,14 +54,14 @@ repositories {
mavenCentral() mavenCentral()
// Using GitHub dependencies for real-time updates, configuration required (recommended). // Using GitHub dependencies for real-time updates, configuration required (recommended).
maven { url 'https://maven.pkg.github.com/CarmJos/EasyConfiguration' } maven { url 'https://maven.pkg.github.com/CarmJos/configured' }
} }
``` ```
```groovy ```groovy
dependencies { dependencies {
api "cc.carm.lib:easyconfiguration-json:[LATEST RELEASE]" api "cc.carm.lib:configured-json:[LATEST RELEASE]"
} }
``` ```
+7 -7
View File
@@ -3,9 +3,9 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>4.0.8</version> <version>4.1.1</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -15,35 +15,35 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties> </properties>
<artifactId>easyconfiguration-gson</artifactId> <artifactId>configured-gson</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-file</artifactId> <artifactId>configured-feature-file</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-section</artifactId> <artifactId>configured-feature-section</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-demo</artifactId> <artifactId>configured-demo</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@@ -1,10 +1,8 @@
package config; package config;
import cc.carm.lib.configuration.demo.tests.ConfigurationTest; import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
import cc.carm.lib.configuration.source.json.JSONConfigFactory;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.source.json.JSONConfigFactory;
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
import org.junit.Test; import org.junit.Test;
import java.io.File; import java.io.File;
@@ -18,12 +16,6 @@ public class JSONConfigTest {
@Test @Test
public void onTest() { public void onTest() {
ConfigValue<Boolean> EXAMPLE = ConfiguredValue.of(false);
EXAMPLE.initialize(this.holder, "example");
System.out.println("Example: " + EXAMPLE.get());
ConfigurationTest.testDemo(this.holder); ConfigurationTest.testDemo(this.holder);
ConfigurationTest.testInner(this.holder); ConfigurationTest.testInner(this.holder);
+6 -6
View File
@@ -1,4 +1,4 @@
# EasyConfiguration-HOCON # configured-HOCON
HOCON file-based implementation, compatible with all Java environments. HOCON file-based implementation, compatible with all Java environments.
@@ -20,9 +20,9 @@ HOCON file-based implementation, compatible with all Java environments.
<repository> <repository>
<!-- Using GitHub dependencies for real-time updates, configuration required (recommended). --> <!-- Using GitHub dependencies for real-time updates, configuration required (recommended). -->
<id>EasyConfiguration</id> <id>configured</id>
<name>GitHub Packages</name> <name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url> <url>https://maven.pkg.github.com/CarmJos/configured</url>
</repository> </repository>
</repositories> </repositories>
@@ -35,7 +35,7 @@ HOCON file-based implementation, compatible with all Java environments.
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-hocon</artifactId> <artifactId>configured-hocon</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -52,14 +52,14 @@ repositories {
mavenCentral() mavenCentral()
// Using GitHub dependencies for real-time updates, configuration required (recommended). // Using GitHub dependencies for real-time updates, configuration required (recommended).
maven { url 'https://maven.pkg.github.com/CarmJos/EasyConfiguration' } maven { url 'https://maven.pkg.github.com/CarmJos/configured' }
} }
``` ```
```groovy ```groovy
dependencies { dependencies {
api "cc.carm.lib:easyconfiguration-hocon:[LATEST RELEASE]" api "cc.carm.lib:configured-hocon:[LATEST RELEASE]"
} }
``` ```
+9 -9
View File
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<version>4.0.0</version> <version>4.1.1</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -15,38 +15,38 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties> </properties>
<artifactId>easyconfiguration-hocon</artifactId> <artifactId>configured-hocon</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-commentable</artifactId> <artifactId>configured-feature-commentable</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-file</artifactId> <artifactId>configured-feature-file</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-section</artifactId> <artifactId>configured-feature-section</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-demo</artifactId> <artifactId>configured-demo</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@@ -1,36 +0,0 @@
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);
}
}
@@ -1,116 +0,0 @@
package cc.carm.lib.configuration.hocon;
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;
}
}
@@ -1,105 +0,0 @@
package cc.carm.lib.configuration.hocon;
import cc.carm.lib.configuration.source.comment.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);
}
}
@@ -1,19 +0,0 @@
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);
}
}
@@ -1,110 +0,0 @@
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,48 @@
package cc.carm.lib.configuration.source.hocon;
import cc.carm.lib.configuration.commentable.Commentable;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.file.FileConfigFactory;
import org.jetbrains.annotations.NotNull;
import java.io.File;
public class HOCONConfigFactory extends FileConfigFactory<HOCONSource, ConfigurationHolder<HOCONSource>, HOCONConfigFactory> {
public static HOCONConfigFactory from(@NotNull String path) {
return new HOCONConfigFactory(new File(path));
}
public static HOCONConfigFactory from(@NotNull File file) {
return new HOCONConfigFactory(file);
}
public static HOCONConfigFactory from(@NotNull File parent, @NotNull String configName) {
return new HOCONConfigFactory(new File(parent, configName));
}
public HOCONConfigFactory(@NotNull File file) {
super(file);
}
@Override
protected HOCONConfigFactory self() {
return this;
}
@Override
public @NotNull ConfigurationHolder<HOCONSource> build() {
File configFile = this.file;
String sourcePath = this.resourcePath;
Commentable.registerMeta(this.initializer); // Register commentable meta types
return new ConfigurationHolder<HOCONSource>(this.adapters, this.options, this.metadata, this.initializer) {
final @NotNull HOCONSource source = new HOCONSource(this, configFile, sourcePath);
@Override
public @NotNull HOCONSource config() {
return this.source;
}
};
}
}
@@ -1,69 +0,0 @@
package cc.carm.lib.configuration.source.hocon;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import com.typesafe.config.Config;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnmodifiableView;
import java.util.List;
import java.util.Map;
public class HOCONSection implements ConfigureSection {
protected final @NotNull HOCONSource source;
protected final @Nullable HOCONSection parent;
protected final @NotNull Config data;
public HOCONSection(@NotNull HOCONSource source, @Nullable HOCONSection parent,
@NotNull Config data) {
this.source = source;
this.parent = parent;
this.data = data;
}
public @NotNull Config data() {
return this.data;
}
@Override
public @NotNull HOCONSource source() {
return this.source;
}
@Override
public @Nullable HOCONSection parent() {
return this.parent;
}
@Override
public @NotNull @UnmodifiableView Map<String, Object> getValues(boolean deep) {
return data().root().unwrapped();
}
@Override
public void set(@NotNull String path, @Nullable Object value) {
}
@Override
public boolean contains(@NotNull String path) {
return data().hasPath(path);
}
@Override
public @Nullable List<?> getList(@NotNull String path) {
return data().getAnyRefList(path);
}
@Override
public @Nullable HOCONSection getSection(@NotNull String path) {
return data().getConfig(path) == null ? null : new HOCONSection(source, this, data().getConfig(path));
}
@Override
public @Nullable Object get(@NotNull String path) {
return data().getAnyRef(path);
}
}
@@ -1,44 +1,104 @@
package cc.carm.lib.configuration.source.hocon; package cc.carm.lib.configuration.source.hocon;
import cc.carm.lib.configuration.commentable.Commentable;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.section.ConfigureSource; import cc.carm.lib.configuration.source.file.FileConfigSource;
import com.typesafe.config.Config; import cc.carm.lib.configuration.source.section.SourcedSection;
import com.typesafe.config.*;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects; import java.io.File;
import java.util.*;
public class HOCONSource extends ConfigureSource<HOCONSection, Config, HOCONSource> { public class HOCONSource
extends FileConfigSource<SourcedSection, Map<String, Object>, HOCONSource> {
protected @Nullable SourcedSection rootSection;
protected HOCONSource(
@NotNull ConfigurationHolder<? extends HOCONSource> holder,
@NotNull File file, @Nullable String resourcePath
) {
super(holder, 0, file, resourcePath);
private HOCONSection rootSection; this.initialize();
}
protected HOCONSource(@NotNull ConfigurationHolder<? extends HOCONSource> holder, long lastUpdateMillis) { public void initialize() {
super(holder, lastUpdateMillis); try {
this.initializeFile();
this.onReload();
} catch (Exception e) {
//noinspection CallToPrintStackTrace
e.printStackTrace();
}
} }
@Override @Override
protected HOCONSource self() { protected @NotNull HOCONSource self() {
return this; return this;
} }
@Override @Override
public @NotNull Config original() { public @NotNull Map<String, Object> original() {
return section().data(); return this.section().data();
} }
@Override @Override
public @NotNull HOCONSection section() { public @NotNull SourcedSection section() {
return Objects.requireNonNull(rootSection, "RootSection is not initialized"); return Objects.requireNonNull(this.rootSection, "Root section is not initialized.");
}
public @NotNull String saveToString() {
// identity: 创建新的空 typesafe config
// accumulator: 将 Section 中的信息为 typesafe config 添加并返回
// combiner: 合并两个配置文件
Config config = this.getValues(true).entrySet().stream().reduce(
ConfigFactory.empty(),
(cfg, entry) -> {
String key = entry.getKey(); // 源数据 key
Object value = entry.getValue(); // 源数据 value
ConfigValue result; // 最终转换为 typesafe 的 ConfigValue 类型
if (value == null || value instanceof Boolean || value instanceof String || value instanceof Number) {
result = ConfigValueFactory.fromAnyRef(value); // 原始数据类型
} else if (value instanceof Iterator) {
result = ConfigValueFactory.fromIterable((Iterable<?>) value);
} else if (value instanceof Map) {
//noinspection unchecked
result = ConfigValueFactory.fromMap((Map<String, ?>) value);
} else {
result = ConfigValueFactory.fromAnyRef(String.valueOf(value));
}
List<String> headerComments = HOCONSource.this.getHeaderComments(key); // 获取其注释
result = result.withOrigin(result.origin().withComments(headerComments)); // 赋予其注释
return cfg.withValue(key, result); // 将其添加到根 config 中
},
Config::withFallback
);
return config.root().render(
ConfigRenderOptions.defaults()
.setJson(false)
.setOriginComments(false)
);
} }
@Override @Override
public void save() throws Exception { public void save() throws Exception {
this.fileWriter(w -> w.write(HOCONSource.this.saveToString()));
} }
@Override @Override
protected void onReload() throws Exception { protected void onReload() throws Exception {
this.rootSection = this.fileReadString(this::loadFromString);
} }
protected @NotNull SourcedSection loadFromString(@NotNull String data) {
ConfigObject config = ConfigFactory.parseString(data).root();
return SourcedSection.root(this, config.unwrapped());
}
public @Nullable List<String> getHeaderComments(@Nullable String key) {
return Commentable.getHeaderComments(holder(), key);
}
} }
@@ -1,18 +0,0 @@
package online.flowerinsnow.test.easyconfiguration;
public class HOCONTest {
// @Test
// public void onTest() {
// HOCONFileConfigProvider provider = EasyConfiguration.from(new File("target/hocon.conf"));
//
// ConfigurationTest.testDemo(provider);
// ConfigurationTest.testInner(provider);
//
// try {
// provider.save();
// provider.reload();
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
}
@@ -0,0 +1,38 @@
package sample;
import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.annotation.ConfigPath;
import cc.carm.lib.configuration.annotation.HeaderComments;
import cc.carm.lib.configuration.value.standard.ConfiguredList;
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
import java.util.UUID;
@ConfigPath(root = true)
@HeaderComments("Configurations for sample")
public interface SampleConfig extends Configuration {
ConfiguredValue<Boolean> ENABLED = ConfiguredValue.of(true);
@HeaderComments("Server configurations") // Header comment
ConfiguredValue<Integer> PORT = ConfiguredValue.of(Integer.class);
@HeaderComments({"[ UUID >-----------------------------------", "A lot of UUIDs"})
ConfiguredList<UUID> UUIDS = ConfiguredList.builderOf(UUID.class).fromString()
.parse(UUID::fromString).serialize(UUID::toString)
.defaults(
UUID.fromString("00000000-0000-0000-0000-000000000000"),
UUID.fromString("00000000-0000-0000-0000-000000000001")
).build();
@ConfigPath("info") // Custom path
interface INFO extends Configuration {
@HeaderComments("Configure your name!") // Header comment
ConfiguredValue<String> NAME = ConfiguredValue.of("Joker");
@ConfigPath("how-old-are-you") // Custom path
ConfiguredValue<Integer> AGE = ConfiguredValue.of(24);
}
}
@@ -0,0 +1,27 @@
package sample;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.hocon.HOCONConfigFactory;
import org.junit.Test;
public class SampleTest {
@Test
public void test() {
// 1. Make a configuration provider from a file.
ConfigurationHolder<?> holder = HOCONConfigFactory.from("target/config.conf")
.resourcePath("configs/sample.conf")
.build();
// 2. Initialize the configuration classes or instances.
holder.initialize(SampleConfig.class);
// 3. Enjoy using the configuration!
System.out.println("Enabled? -> " + SampleConfig.ENABLED.resolve());
SampleConfig.ENABLED.set(false);
System.out.println("And now? -> " + SampleConfig.ENABLED.resolve());
// p.s. Changes not save so enable value will still be true in the next run.
System.out.println("Your name is " + SampleConfig.INFO.NAME.resolve() + " (age=" + SampleConfig.INFO.AGE.resolve() + ")!");
}
}
@@ -0,0 +1,2 @@
version = 1.0
test-save = false
+7 -7
View File
@@ -3,9 +3,9 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>4.0.8</version> <version>4.1.1</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -18,20 +18,20 @@
<deps.mongodb.version>5.3.1</deps.mongodb.version> <deps.mongodb.version>5.3.1</deps.mongodb.version>
<log4j.version>2.24.3</log4j.version> <log4j.version>2.24.3</log4j.version>
</properties> </properties>
<artifactId>easyconfiguration-mongodb</artifactId> <artifactId>configured-mongodb</artifactId>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-section</artifactId> <artifactId>configured-feature-section</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -65,14 +65,14 @@
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-demo</artifactId> <artifactId>configured-demo</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-gson</artifactId> <artifactId>configured-gson</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@@ -55,7 +55,7 @@ public class MongoSource extends ConfigureSource<SourcedSection, Map<String, Obj
@Override @Override
public void save() throws Exception { public void save() throws Exception {
Map<String, Object> data = this.rootSection.rawMap(); Map<String, Object> data = this.rootSection.asMap();
if (data.isEmpty()) return; // Skip saving if empty if (data.isEmpty()) return; // Skip saving if empty
if (data.containsKey("_id") && data.size() == 1) return; // Skip saving if only contains _id if (data.containsKey("_id") && data.size() == 1) return; // Skip saving if only contains _id
+6 -6
View File
@@ -1,4 +1,4 @@
# EasyConfiguration-SQL # configured-SQL
SQL database implementation, support for MySQL or MariaDB. SQL database implementation, support for MySQL or MariaDB.
@@ -39,9 +39,9 @@ CREATE TABLE IF NOT EXISTS conf
<repository> <repository>
<!-- Using GitHub dependencies for real-time updates, configuration required (recommended). --> <!-- Using GitHub dependencies for real-time updates, configuration required (recommended). -->
<id>EasyConfiguration</id> <id>configured</id>
<name>GitHub Packages</name> <name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url> <url>https://maven.pkg.github.com/CarmJos/configured</url>
</repository> </repository>
</repositories> </repositories>
@@ -54,7 +54,7 @@ CREATE TABLE IF NOT EXISTS conf
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-sql</artifactId> <artifactId>configured-sql</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -71,13 +71,13 @@ repositories {
mavenCentral() mavenCentral()
// Using GitHub dependencies for real-time updates, configuration required (recommended). // Using GitHub dependencies for real-time updates, configuration required (recommended).
maven { url 'https://maven.pkg.github.com/CarmJos/EasyConfiguration' } maven { url 'https://maven.pkg.github.com/CarmJos/configured' }
} }
``` ```
```groovy ```groovy
dependencies { dependencies {
api "cc.carm.lib:easyconfiguration-sql:[LATEST RELEASE]" api "cc.carm.lib:configured-sql:[LATEST RELEASE]"
} }
``` ```
+9 -9
View File
@@ -4,9 +4,9 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>4.0.8</version> <version>4.1.1</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -18,33 +18,33 @@
<deps.mysql-driver.version>8.0.33</deps.mysql-driver.version> <deps.mysql-driver.version>8.0.33</deps.mysql-driver.version>
<deps.log4j.version>2.24.3</deps.log4j.version> <deps.log4j.version>2.24.3</deps.log4j.version>
</properties> </properties>
<artifactId>easyconfiguration-sql</artifactId> <artifactId>configured-sql</artifactId>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-commentable</artifactId> <artifactId>configured-feature-commentable</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-section</artifactId> <artifactId>configured-feature-section</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-versioned</artifactId> <artifactId>configured-feature-versioned</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -70,7 +70,7 @@
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-demo</artifactId> <artifactId>configured-demo</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@@ -98,7 +98,7 @@
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-gson</artifactId> <artifactId>configured-gson</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@@ -7,12 +7,17 @@ import cc.carm.lib.configuration.source.ConfigurationFactory;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.versioned.VersionedMetaTypes; import cc.carm.lib.configuration.versioned.VersionedMetaTypes;
import cc.carm.lib.easysql.api.SQLManager; import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.api.SQLTable;
import cc.carm.lib.easysql.api.builder.TableCreateBuilder;
import cc.carm.lib.easysql.api.enums.IndexType;
import cc.carm.lib.easysql.api.function.SQLHandler;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Range; import org.jetbrains.annotations.Range;
import java.util.HashMap; import java.util.HashMap;
import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
@@ -26,11 +31,43 @@ public class SQLConfigFactory extends ConfigurationFactory<SQLSource, Configurat
return from(() -> manager); return from(() -> manager);
} }
protected static final @NotNull Gson DEFAULT_GSON = new GsonBuilder()
.serializeNulls().disableHtmlEscaping().create();
protected static final @NotNull BiConsumer<String, TableCreateBuilder> DEFAULT_TABLE_SCHEMA = (tableName, builder) -> {
builder.addColumn("namespace", "VARCHAR(32) NOT NULL");
builder.addColumn("path", "VARCHAR(96) NOT NULL");
builder.addColumn("value", "TEXT");
builder.addColumn("inline_comment", "TEXT");
builder.addColumn("header_comments", "MEDIUMTEXT");
builder.addColumn("footer_comments", "MEDIUMTEXT");
builder.addColumn("type", "TINYINT NOT NULL DEFAULT 0");
builder.addColumn("version", "MEDIUMINT UNSIGNED NOT NULL DEFAULT 0");
builder.addColumn(
"create_time",
"TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP"
);
builder.addColumn(
"update_time",
"TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"
);
builder.setIndex(
IndexType.PRIMARY_KEY, "pk_" + tableName.toLowerCase(),
"namespace", "path"
);
builder.setTableSettings("ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
};
protected @NotNull Supplier<SQLManager> managerSupplier; protected @NotNull Supplier<SQLManager> managerSupplier;
protected Supplier<Gson> gsonSupplier = () -> SQLSource.DEFAULT_GSON; protected Supplier<Gson> gsonSupplier = () -> DEFAULT_GSON;
protected HashMap<Integer, SQLValueResolver<?>> resolvers = new HashMap<>(SQLValueResolver.STANDARD_RESOLVERS); protected HashMap<Integer, SQLValueResolver<?>> resolvers = new HashMap<>(SQLValueResolver.STANDARD_RESOLVERS);
protected String tableName = "configs"; protected SQLTable tableName = SQLTable.of("config", (table) -> DEFAULT_TABLE_SCHEMA.accept("config", table));
protected String namespace = "default"; protected String namespace = "default";
public SQLConfigFactory(@NotNull Supplier<SQLManager> managerSupplier) { public SQLConfigFactory(@NotNull Supplier<SQLManager> managerSupplier) {
@@ -95,11 +132,19 @@ public class SQLConfigFactory extends ConfigurationFactory<SQLSource, Configurat
return resolver(id, SQLValueResolver.of(type, parser, serializer)); return resolver(id, SQLValueResolver.of(type, parser, serializer));
} }
public SQLConfigFactory tableName(@NotNull String tableName) { public SQLConfigFactory table(@NotNull SQLTable table) {
this.tableName = tableName; this.tableName = table;
return self(); return self();
} }
public SQLConfigFactory table(@NotNull String tableName, @NotNull SQLHandler<TableCreateBuilder> builder) {
return table(SQLTable.of(tableName, builder));
}
public SQLConfigFactory tableName(@NotNull String tableName) {
return table(tableName, table -> DEFAULT_TABLE_SCHEMA.accept(tableName, table));
}
public SQLConfigFactory namespace(@NotNull String namespace) { public SQLConfigFactory namespace(@NotNull String namespace) {
this.namespace = namespace; this.namespace = namespace;
return self(); return self();
@@ -9,9 +9,7 @@ import cc.carm.lib.configuration.versioned.VersionedMetaTypes;
import cc.carm.lib.easysql.api.SQLManager; import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.api.SQLQuery; import cc.carm.lib.easysql.api.SQLQuery;
import cc.carm.lib.easysql.api.SQLTable; import cc.carm.lib.easysql.api.SQLTable;
import cc.carm.lib.easysql.api.enums.IndexType;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -21,9 +19,6 @@ import java.util.*;
public class SQLSource extends ConfigureSource<SourcedSection, Map<String, Object>, SQLSource> { public class SQLSource extends ConfigureSource<SourcedSection, Map<String, Object>, SQLSource> {
protected static final @NotNull Gson DEFAULT_GSON = new GsonBuilder()
.serializeNulls().disableHtmlEscaping().create();
protected final @NotNull Gson gson; protected final @NotNull Gson gson;
protected final @NotNull SQLManager sqlManager; protected final @NotNull SQLManager sqlManager;
protected final @NotNull String namespace; protected final @NotNull String namespace;
@@ -35,35 +30,13 @@ public class SQLSource extends ConfigureSource<SourcedSection, Map<String, Objec
public SQLSource(@NotNull ConfigurationHolder<? extends SQLSource> holder, long lastUpdateMillis, public SQLSource(@NotNull ConfigurationHolder<? extends SQLSource> holder, long lastUpdateMillis,
@NotNull Gson gson, @NotNull SQLManager sqlManager, @NotNull Gson gson, @NotNull SQLManager sqlManager,
@NotNull Map<Integer, SQLValueResolver<?>> resolvers, @NotNull Map<Integer, SQLValueResolver<?>> resolvers,
@NotNull String tableName, @NotNull String namespace) { @NotNull SQLTable table, @NotNull String namespace) {
super(holder, lastUpdateMillis); super(holder, lastUpdateMillis);
this.gson = gson; this.gson = gson;
this.sqlManager = sqlManager; this.sqlManager = sqlManager;
this.resolvers = resolvers; this.resolvers = resolvers;
this.namespace = namespace; this.namespace = namespace;
this.table = SQLTable.of(tableName, builder -> { this.table = table;
builder.addColumn("namespace", "VARCHAR(32) NOT NULL");
builder.addColumn("path", "VARCHAR(96) NOT NULL");
builder.addColumn("value", "TEXT");
builder.addColumn("inline_comment", "TEXT");
builder.addColumn("header_comments", "MEDIUMTEXT");
builder.addColumn("footer_comments", "MEDIUMTEXT");
builder.addColumn("type", "TINYINT NOT NULL DEFAULT 0");
builder.addColumn("version", "MEDIUMINT UNSIGNED NOT NULL DEFAULT 0");
builder.addColumn("create_time", "TIMESTAMP NOT NULL");
builder.addColumn("update_time", "TIMESTAMP NOT NULL");
builder.setIndex(
IndexType.PRIMARY_KEY, "pk_" + tableName.toLowerCase(),
"namespace", "path"
);
builder.setTableSettings("ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
});
try { try {
this.table.create(this.sqlManager); this.table.create(this.sqlManager);
@@ -102,19 +75,19 @@ public class SQLSource extends ConfigureSource<SourcedSection, Map<String, Objec
List<Object[]> dataValues = new ArrayList<>(); List<Object[]> dataValues = new ArrayList<>();
SourcedSection section = section(); SourcedSection section = section();
Map<String, ConfigValue<?>> values = holder().registeredValues(); Map<String, ConfigValue<?, ?>> values = holder().registeredValues();
for (Map.Entry<String, ConfigValue<?>> entry : values.entrySet()) { for (Map.Entry<String, ConfigValue<?, ?>> entry : values.entrySet()) {
@NotNull String path = entry.getKey(); @NotNull String path = entry.getKey();
@NotNull ConfigValue<?> config = entry.getValue(); @NotNull ConfigValue<?, ?> config = entry.getValue();
@Nullable Object value = section.get(path); @Nullable Object value = section.get(path);
if (value instanceof SourcedSection) { if (value instanceof SourcedSection) {
value = ((SourcedSection) value).rawMap(); value = ((SourcedSection) value).asMap();
} else if (value instanceof List<?>) { } else if (value instanceof List<?>) {
List<Object> list = new ArrayList<>(); List<Object> list = new ArrayList<>();
for (Object obj : (List<?>) value) { for (Object obj : (List<?>) value) {
if (obj instanceof SourcedSection) { if (obj instanceof SourcedSection) {
list.add(((SourcedSection) obj).rawMap()); list.add(((SourcedSection) obj).asMap());
} else { } else {
list.add(obj); list.add(obj);
} }
+6 -6
View File
@@ -1,4 +1,4 @@
# EasyConfiguration-YAML # configured-YAML
YAML file-based implementation, compatible with all Java environments. YAML file-based implementation, compatible with all Java environments.
@@ -20,9 +20,9 @@ YAML file-based implementation, compatible with all Java environments.
<repository> <repository>
<!-- Using GitHub dependencies for real-time updates, configuration required (recommended). --> <!-- Using GitHub dependencies for real-time updates, configuration required (recommended). -->
<id>EasyConfiguration</id> <id>configured</id>
<name>GitHub Packages</name> <name>GitHub Packages</name>
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url> <url>https://maven.pkg.github.com/CarmJos/configured</url>
</repository> </repository>
</repositories> </repositories>
@@ -35,7 +35,7 @@ YAML file-based implementation, compatible with all Java environments.
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-yaml</artifactId> <artifactId>configured-yaml</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -52,13 +52,13 @@ repositories {
mavenCentral() mavenCentral()
// Using GitHub dependencies for real-time updates, configuration required (recommended). // Using GitHub dependencies for real-time updates, configuration required (recommended).
maven { url 'https://maven.pkg.github.com/CarmJos/EasyConfiguration' } maven { url 'https://maven.pkg.github.com/CarmJos/configured' }
} }
``` ```
```groovy ```groovy
dependencies { dependencies {
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]" api "cc.carm.lib:configured-yaml:[LATEST RELEASE]"
} }
``` ```
+9 -9
View File
@@ -4,9 +4,9 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>4.0.8</version> <version>4.1.1</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -14,38 +14,38 @@
<maven.compiler.target>${project.jdk.version}</maven.compiler.target> <maven.compiler.target>${project.jdk.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<deps.yamlcommentwriter.version>1.2.0</deps.yamlcommentwriter.version> <deps.yamlcommentwriter.version>1.2.1</deps.yamlcommentwriter.version>
</properties> </properties>
<artifactId>easyconfiguration-yaml</artifactId> <artifactId>configured-yaml</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-file</artifactId> <artifactId>configured-feature-file</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-section</artifactId> <artifactId>configured-feature-section</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-feature-commentable</artifactId> <artifactId>configured-feature-commentable</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -66,7 +66,7 @@
<dependency> <dependency>
<groupId>${project.parent.groupId}</groupId> <groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-demo</artifactId> <artifactId>configured-demo</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@@ -5,6 +5,7 @@ import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.yaml.YAMLConfigFactory; import cc.carm.lib.configuration.source.yaml.YAMLConfigFactory;
import cc.carm.lib.configuration.source.yaml.YAMLSource; import cc.carm.lib.configuration.source.yaml.YAMLSource;
import cc.carm.lib.configuration.validators.Validators;
import org.junit.Test; import org.junit.Test;
import java.util.List; import java.util.List;
@@ -18,10 +19,11 @@ public class YamlTests {
ConfigurationHolder<YAMLSource> holder = YAMLConfigFactory.from("target/tests.yml") ConfigurationHolder<YAMLSource> holder = YAMLConfigFactory.from("target/tests.yml")
.resourcePath("configs/sample.yml").build(); .resourcePath("configs/sample.yml").build();
Validators.activate(holder);
ConfigurationTest.testDemo(holder); ConfigurationTest.testDemo(holder);
ConfigurationTest.testInner(holder); ConfigurationTest.testInner(holder);
Map<String, List<String>> headers = holder.extractMetadata(CommentableMeta.HEADER); Map<String, List<String>> headers = holder.extractMetadata(CommentableMeta.HEADER);
System.out.println("Header comments: "); System.out.println("Header comments: ");
headers.forEach((k, v) -> { headers.forEach((k, v) -> {