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

Compare commits

..

34 Commits

Author SHA1 Message Date
carm 70a3b893a6 chore(text): Add missing text functions 2025-03-21 03:30:47 +08:00
carm c32a941906 docs: Edit logo size 2025-03-21 02:32:33 +08:00
carm 8b597d10f9 feat: Optimized ContentHandler with Replacer & Inserter. 2025-03-21 02:31:04 +08:00
carm cedfcfd262 docs: Update banners and icons 2025-03-21 02:30:35 +08:00
carm 12add75232 feat: Enhanced text content replacer 2025-03-20 20:28:33 +08:00
carm 4d29a24768 docs: Edited readme 2025-03-20 17:16:33 +08:00
carm 8626b86961 chore: Change logo 2025-03-20 16:08:17 +08:00
carm 754dc1de1f feat: Change logo 2025-03-20 16:04:50 +08:00
carm 3d1d4ca609 chore: Add logo & icon. 2025-03-20 15:32:27 +08:00
carm 990b10b6f0 chore: Add logo & icon. 2025-03-20 15:30:34 +08:00
carm 7462cd720e chore: Optimize code format & functions. 2025-03-19 18:36:08 +08:00
carm 6bc83eb3b3 chore: Optimize code format & functions. 2025-03-19 18:35:45 +08:00
carm dbec551c84 chore: Fixed the param errors. 2025-03-17 01:39:08 +08:00
carm 82cca5eca2 feat(exception): Supported ConfigExceptionHandler for holders. 2025-03-17 01:06:57 +08:00
carm 65f3cc1b3d feat(validator): Support validators for config values.
BREAKING CHANGE: `ValueManifest` and `ConfigValue` added a new type "UNIT" to mark the minimal unit value of this instance.

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

link #132
2025-03-16 23:56:36 +08:00
carm 854e3df49f feat: Upgrade configured to v4.1.0 2025-03-15 01:52:52 +08:00
carm f6167c3b5e docs: Update license [skip ci] 2025-03-15 01:51:07 +08:00
carm ffe3e88b3b docs: Translated to English 2025-03-14 19:34:06 +08:00
carm caa3077f48 chore: Add missing @Nullable 2025-03-14 19:33:30 +08:00
carm 05dbf0b504 docs: Redesign readme 2025-03-14 19:20:31 +08:00
carm 810e95198e docs: Redesign readme 2025-03-14 19:17:26 +08:00
carm 10004f16b4 docs(logo): Add project banner & logo 2025-03-14 19:09:43 +08:00
carm 8e19748c7c feat(map): Add more builder functions 2025-03-12 04:04:00 +08:00
carm 17762a2e70 refactor(proj): Change project name to "configured" 2025-03-12 03:27:35 +08:00
carm 7dbd607a3f refactor(proj): Change project name to "configured" 2025-03-12 03:22:40 +08:00
carm 035e8a227e test(parse): Add more tests 2025-03-06 20:12:33 +08:00
carm 04eaf6606d feat: Jump to 4.0.11 2025-03-06 18:19:25 +08:00
carm e558e93410 feat(sql): Support custom sql table schema 2025-03-06 18:19:06 +08:00
flowerinsnow e55fe3a8d5 feat: hocon supported 2025-03-06 18:03:27 +08:00
carm 8f075b99b5 chore(deps): use parent dependencies' version 2025-03-04 11:58:01 +08:00
carm 09a0b3c373 chore(deps): use parent dependencies' version 2025-03-04 11:34:16 +08:00
carm 4df4977733 feat(msg): add enhanced text support 2025-03-04 04:21:58 +08:00
carm 6434feb980 fix(sql): Fixed sql table format 2025-03-04 01:57:04 +08:00
100 changed files with 1930 additions and 1114 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: 112 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

+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."
+2 -1
View File
@@ -1,3 +1,4 @@
.idea/ .idea/*
!.idea/icon.svg
**/target/ **/target/
**.iml **.iml
+36
View File
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

+1
View File
@@ -1,6 +1,7 @@
GNU LESSER GENERAL PUBLIC LICENSE GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007 Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.
+66 -64
View File
@@ -1,26 +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) ]
</div>
# EasyConfiguration # configured _(config framework)_
[![version](https://img.shields.io/github/v/release/CarmJos/EasyConfiguration)](https://github.com/CarmJos/EasyConfiguration/releases) <img src=".doc/images/logo-bg.svg" width="150px" alt="logo" align="right" style="float: right"/>
[![License](https://img.shields.io/github/license/CarmJos/EasyConfiguration)](https://www.gnu.org/licenses/lgpl-3.0.html)
[![workflow](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml)
[![CodeFactor](https://www.codefactor.io/repository/github/carmjos/easyconfiguration/badge)](https://www.codefactor.io/repository/github/carmjos/easyconfiguration)
![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/EasyConfiguration)
![](https://visitor-badge.glitch.me/badge?page_id=EasyConfiguration.readme)
**Easy _(to make)_ Configurations!** _**"Once set, Simple get."**_
A simple, easy-to-use and universal solution for managing configuration files. A simple, easy-to-use and universal solution for managing, loading, reading,
Enjoy the ease of use with customizable formats for loading, reading, and updating your configuration files. and updating configuration files.
Supported **JSON**, **YAML**, **Hocon**, **TOML**, **SQL**, **MongoDB**... and much more!
## Features & Advantages ## Features & Advantages
@@ -35,13 +35,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 ### Preview
To quickly demonstrate the applicability of the project, here are a few practical demonstrations: To quickly demonstrate the applicability of the project, here are a few practical demonstrations:
- [Database configuration.](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java) - [Database configuration.](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java)
- [Demonstration of all types of configuration instance classes.](demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java) - [Demonstration of all types of configuration instance classes.](demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java)
@@ -49,35 +50,36 @@ 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 {
@InlineComment("Enabled?") // Inline comment @InlineComment("Enabled?") // Inline comment
ConfiguredValue<Boolean> ENABLED = ConfiguredValue.of(true); ConfiguredValue<Boolean> ENABLED = ConfiguredValue.of(true);
@HeaderComments("Server configurations") // Header comment @HeaderComments("Server configurations") // Header comment
ConfiguredValue<Integer> PORT = ConfiguredValue.of(Integer.class); ConfiguredValue<Integer> PORT = ConfiguredValue.of(Integer.class);
@HeaderComments({"[ UUID >-----------------------------------", "A lot of UUIDs"}) @HeaderComments({"[ UUID >-----------------------------------", "A lot of UUIDs"})
@FooterComments("[ UUID >-----------------------------------") @FooterComments("[ UUID >-----------------------------------")
ConfiguredList<UUID> UUIDS = ConfiguredList.builderOf(UUID.class).fromString() ConfiguredList<UUID> UUIDS = ConfiguredList.builderOf(UUID.class).fromString()
.parse(UUID::fromString).serialize(UUID::toString) .parse(UUID::fromString).serialize(UUID::toString)
.defaults( .defaults(
UUID.fromString("00000000-0000-0000-0000-000000000000"), UUID.fromString("00000000-0000-0000-0000-000000000000"),
UUID.fromString("00000000-0000-0000-0000-000000000001") UUID.fromString("00000000-0000-0000-0000-000000000001")
).build(); ).build();
@ConfigPath("info") // Custom path @ConfigPath("info") // Custom path
interface INFO extends Configuration { interface INFO extends Configuration {
@HeaderComments("Configure your name!") // Header comment @HeaderComments("Configure your name!") // Header comment
ConfiguredValue<String> NAME = ConfiguredValue.of("Joker"); ConfiguredValue<String> NAME = ConfiguredValue.of("Joker");
@ConfigPath("how-old-are-you") // Custom path @ConfigPath("how-old-are-you") // Custom path
ConfiguredValue<Integer> AGE = ConfiguredValue.of(24); ConfiguredValue<Integer> AGE = ConfiguredValue.of(24);
} }
} }
@@ -85,23 +87,23 @@ public interface SampleConfig extends Configuration {
```java ```java
public class Sample { public class Sample {
public static void main(String[] args) { public static void main(String[] args) {
// 1. Make a configuration provider from a file. // 1. Make a configuration provider from a file.
ConfigurationHolder<?> holder = YAMLConfigFactory.from("target/config.yml") ConfigurationHolder<?> holder = YAMLConfigFactory.from("target/config.yml")
.resourcePath("configs/sample.yml") .resourcePath("configs/sample.yml")
.indent(4) // Optional: Set the indentation of the configuration file. .indent(4) // Optional: Set the indentation of the configuration file.
.build(); .build();
// 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 +150,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 +171,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 +179,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 +187,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 +210,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 +225,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 +242,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 +256,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!
+31 -32
View File
@@ -1,29 +1,28 @@
```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 _(配置文件框架)_
[![License](https://img.shields.io/github/license/CarmJos/EasyConfiguration)](https://www.gnu.org/licenses/lgpl-3.0.html)
[![workflow](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml)
[![CodeFactor](https://www.codefactor.io/repository/github/carmjos/easyconfiguration/badge)](https://www.codefactor.io/repository/github/carmjos/easyconfiguration)
![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/EasyConfiguration)
![](https://visitor-badge.glitch.me/badge?page_id=EasyConfiguration.readme)
**轻松(做)配置!** <img src=".doc/images/logo-bg.svg" width="150px" alt="logo" align="right" style="float: right"/>
**一次配置,轻松读取!**
一款简单便捷的通用配置文件加载、读取与更新工具,可自定义配置的格式。 一款简单便捷的通用配置文件加载、读取与更新工具,可自定义配置的格式。
## 特性 & 优势 ## 特性 & 优势
支持 [YAML](impl/yaml), [JSON](impl/json), [HOCON](impl/hocon) 和 [SQL](impl/sql) 等多种配置文件格式。 支持 [YAML](providers/yaml), [JSON](providers/gson), [HOCON](providers/hocon) 和 [SQL](providers/sql) 等多种配置文件格式。
- 基于类的配置文件初始化、加载、获取与更新机制,方便快捷。 - 基于类的配置文件初始化、加载、获取与更新机制,方便快捷。
- 支持复杂配置的手动序列化、反序列化。 - 支持复杂配置的手动序列化、反序列化。
@@ -33,7 +32,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 +141,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 +169,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 +177,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 +186,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 +223,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 +240,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 +262,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 +275,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.9</version> <version>4.1.3</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,21 @@ public class ValueAdapter<TYPE>
} }
@Override @Override
public Object serialize(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<? super TYPE> type, @NotNull TYPE value) throws Exception { public @Nullable Object serialize(
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type,
@NotNull TYPE value
) throws Exception {
if (serializer == null) throw new UnsupportedOperationException("Serializer is not supported"); if (serializer == null) throw new UnsupportedOperationException("Serializer is not supported");
return serializer.serialize(holder, type, value); return serializer.serialize(holder, type, value);
} }
@Override @Override
public TYPE parse(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<? super TYPE> type, @NotNull Object value) throws Exception { public @Nullable TYPE parse(
@NotNull ConfigurationHolder<?> holder,
@NotNull ValueType<? super TYPE> type,
@NotNull Object value
) throws Exception {
if (deserializer == null) throw new UnsupportedOperationException("Deserializer is not supported"); if (deserializer == null) throw new UnsupportedOperationException("Deserializer is not supported");
return deserializer.parse(holder, type, value); return deserializer.parse(holder, type, value);
} }
@@ -2,7 +2,6 @@ package cc.carm.lib.configuration.adapter;
import cc.carm.lib.configuration.function.DataFunction; import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -61,7 +60,9 @@ public class ValueAdapterRegistry {
} }
} }
public <T> void register(@NotNull ValueType<T> type, @Nullable ValueSerializer<T> serializer, @Nullable ValueParser<T> deserializer) { public <T> void register(@NotNull ValueType<T> type,
@Nullable ValueSerializer<T> serializer,
@Nullable ValueParser<T> deserializer) {
if (serializer == null && deserializer == null) return; if (serializer == null && deserializer == null) return;
ValueAdapter<T> existing = adapterOf(type); ValueAdapter<T> existing = adapterOf(type);
if (existing != null) { if (existing != null) {
@@ -82,7 +83,9 @@ public class ValueAdapterRegistry {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> @Nullable ValueAdapter<T> adapterOf(@NotNull ValueType<T> type) { public <T> @Nullable ValueAdapter<T> adapterOf(@NotNull ValueType<T> type) {
ValueAdapter<?> matched = adapters.stream().filter(adapter -> adapter.type().equals(type)).findFirst().orElse(null); ValueAdapter<?> matched = adapters.stream()
.filter(adapter -> adapter.type().equals(type))
.findFirst().orElse(null);
if (matched != null) return (ValueAdapter<T>) matched; if (matched != null) return (ValueAdapter<T>) matched;
// If no adapter found, try to find the adapter for the super type // If no adapter found, try to find the adapter for the super type
@@ -99,12 +102,10 @@ public class ValueAdapterRegistry {
return adapterOf(ValueType.of(type)); return adapterOf(ValueType.of(type));
} }
@Contract("_,_,null -> null")
public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull Class<T> type, @Nullable Object source) throws Exception { public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull Class<T> type, @Nullable Object source) throws Exception {
return deserialize(holder, ValueType.of(type), source); return deserialize(holder, ValueType.of(type), source);
} }
@Contract("_,_,null -> null")
public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> type, @Nullable Object source) throws Exception { public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> type, @Nullable Object source) throws Exception {
if (source == null) return null; // Null check if (source == null) return null; // Null check
if (type.isInstance(source)) return type.cast(source); // Not required to deserialize if (type.isInstance(source)) return type.cast(source); // Not required to deserialize
@@ -113,7 +114,7 @@ public class ValueAdapterRegistry {
return adapter.parse(holder, type, source); return adapter.parse(holder, type, source);
} }
@Contract("_,null -> null") @Nullable
public <T> Object serialize(@NotNull ConfigurationHolder<?> holder, @Nullable T value) throws Exception { public <T> Object serialize(@NotNull ConfigurationHolder<?> holder, @Nullable T value) throws Exception {
if (value == null) return null; // Null check if (value == null) return null; // Null check
ValueType<T> type = ValueType.of(value); ValueType<T> type = ValueType.of(value);
@@ -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,7 +5,6 @@ import org.jetbrains.annotations.NotNull;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
/** /**
@@ -56,10 +55,14 @@ public abstract class ValueType<T> {
}; };
} }
public static <T> ValueType<T> of(final Class<T> clazz) { public static <T> ValueType<T> of(final @NotNull Class<T> clazz) {
return of((Type) clazz); return of((Type) clazz);
} }
public static <T> ValueType<List<T>> ofList(final @NotNull Class<T> paramType) {
return of(List.class, paramType);
}
/** /**
* Get the generic type of the complex type. * Get the generic type of the complex type.
* *
@@ -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,47 @@
package cc.carm.lib.configuration.function;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@FunctionalInterface
public interface ValueValidator<T> {
void validate(@NotNull ConfigurationHolder<?> holder, @Nullable T value) throws Exception;
default ValueValidator<T> and(ValueValidator<? super T> other) {
return (holder, value) -> {
validate(holder, value);
other.validate(holder, value);
};
}
static <V> ValueValidator<V> none() {
return (holder, data) -> {
};
}
static <V> ValueValidator<V> nonnull() {
return nonnull("Value cannot be null");
}
static <V> ValueValidator<V> nonnull(String message) {
return (holder, data) -> {
if (data == null) throw new IllegalArgumentException(message);
};
}
static <V extends Number> ValueValidator<V> range(V min, V max) {
return range(min, max, "Value must be in range [" + min + ", " + max + "]");
}
static <V extends Number> ValueValidator<V> range(V min, V max, String message) {
return (holder, data) -> {
if (data.doubleValue() < min.doubleValue() || data.doubleValue() > max.doubleValue()) {
throw new IllegalArgumentException(message);
}
};
}
}
@@ -2,7 +2,9 @@ package cc.carm.lib.configuration.source;
import cc.carm.lib.configuration.adapter.*; import cc.carm.lib.configuration.adapter.*;
import cc.carm.lib.configuration.adapter.strandard.StandardAdapters; import cc.carm.lib.configuration.adapter.strandard.StandardAdapters;
import cc.carm.lib.configuration.function.ConfigExceptionHandler;
import cc.carm.lib.configuration.function.DataFunction; import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.function.ValueValidator;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
import cc.carm.lib.configuration.source.loader.PathGenerator; import cc.carm.lib.configuration.source.loader.PathGenerator;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder; import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
@@ -33,15 +35,17 @@ public abstract class ConfigurationFactory<
SELF SELF
> { > {
protected ValueAdapterRegistry adapters = new ValueAdapterRegistry(); protected @NotNull ValueAdapterRegistry adapters = new ValueAdapterRegistry();
protected ConfigurationOptionHolder options = new ConfigurationOptionHolder(); protected @NotNull ConfigurationOptionHolder options = new ConfigurationOptionHolder();
protected @NotNull Map<String, ConfigurationMetaHolder> metadata = new HashMap<>(); protected @NotNull Map<String, ConfigurationMetaHolder> metadata = new HashMap<>();
protected ConfigurationInitializer initializer = new ConfigurationInitializer(); protected @NotNull ConfigurationInitializer initializer = new ConfigurationInitializer();
protected @NotNull ConfigExceptionHandler exceptionHandler = ConfigExceptionHandler.print();
public ConfigurationFactory() { protected ConfigurationFactory() {
this.adapters.register(StandardAdapters.PRIMITIVES); this.adapters.register(StandardAdapters.PRIMITIVES);
this.adapters.register(StandardAdapters.SECTIONS); this.adapters.register(StandardAdapters.SECTIONS);
this.adapters.register(StandardAdapters.ENUMS); this.adapters.register(StandardAdapters.ENUMS);
this.adapters.register(StandardAdapters.UUID);
} }
protected abstract SELF self(); protected abstract SELF self();
@@ -146,6 +150,11 @@ public abstract class ConfigurationFactory<
return self(); return self();
} }
public SELF exceptionally(@NotNull ConfigExceptionHandler handler) {
this.exceptionHandler = handler;
return self();
}
/** /**
* Supply the base path generator for this configuration holder * Supply the base path generator for this configuration holder
* *
@@ -153,9 +162,7 @@ public abstract class ConfigurationFactory<
* @return this * @return this
*/ */
public SELF pathGenerator(PathGenerator generator) { public SELF pathGenerator(PathGenerator generator) {
return initializer(loader -> { return initializer(loader -> loader.pathGenerator(generator));
loader.pathGenerator(generator);
});
} }
/** /**
@@ -174,6 +181,19 @@ public abstract class ConfigurationFactory<
return initializer(loader -> loader.registerAnnotation(annotation, metadata, extractor)); return initializer(loader -> loader.registerAnnotation(annotation, metadata, extractor));
} }
/**
* Register a new annotation for {@link ValueValidator} to the configuration loader
*
* @param annotation The {@link Annotation}
* @param builder The {@link Function} to build the {@link ValueValidator} from the annotation
* @param <A> The annotation type
* @return this
*/
public <A extends Annotation> SELF validAnnotation(@NotNull Class<A> annotation,
@NotNull Function<A, ValueValidator<Object>> builder) {
return initializer(loader -> loader.registerValidAnnotation(annotation, builder));
}
/** /**
* Build the configuration holder. * Build the configuration holder.
* *
@@ -3,6 +3,7 @@ package cc.carm.lib.configuration.source;
import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; import cc.carm.lib.configuration.adapter.ValueAdapterRegistry;
import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.function.ConfigExceptionHandler;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder; import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
@@ -12,7 +13,6 @@ import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder;
import cc.carm.lib.configuration.source.section.ConfigureSource; import cc.carm.lib.configuration.source.section.ConfigureSource;
import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.ConfigValue;
import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.ValueManifest;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnmodifiableView; import org.jetbrains.annotations.UnmodifiableView;
@@ -31,14 +31,25 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
protected final @NotNull ConfigurationInitializer initializer; protected final @NotNull ConfigurationInitializer initializer;
protected @NotNull ConfigExceptionHandler exceptionHandler;
public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters, public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters,
@NotNull ConfigurationOptionHolder options, @NotNull ConfigurationOptionHolder options,
@NotNull Map<String, ConfigurationMetaHolder> metadata, @NotNull Map<String, ConfigurationMetaHolder> metadata,
@NotNull ConfigurationInitializer initializer) { @NotNull ConfigurationInitializer initializer) {
this(adapters, options, metadata, initializer, ConfigExceptionHandler.print());
}
public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters,
@NotNull ConfigurationOptionHolder options,
@NotNull Map<String, ConfigurationMetaHolder> metadata,
@NotNull ConfigurationInitializer initializer,
@NotNull ConfigExceptionHandler exceptionHandler) {
this.initializer = initializer; this.initializer = initializer;
this.adapters = adapters; this.adapters = adapters;
this.options = options; this.options = options;
this.metadata = metadata; this.metadata = metadata;
this.exceptionHandler = exceptionHandler;
} }
public abstract @NotNull SOURCE config(); public abstract @NotNull SOURCE config();
@@ -75,7 +86,7 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
@NotNull @NotNull
@UnmodifiableView @UnmodifiableView
public <M> Map<String, M> extractMetadata(@NotNull ConfigurationMetadata<M> type, @NotNull Predicate<M> filter) { public <M> Map<String, M> extractMetadata(@NotNull ConfigurationMetadata<M> type, @NotNull Predicate<@Nullable M> filter) {
Map<String, M> metas = new LinkedHashMap<>(); Map<String, M> metas = new LinkedHashMap<>();
for (Map.Entry<String, ConfigurationMetaHolder> entry : this.metadata.entrySet()) { for (Map.Entry<String, ConfigurationMetaHolder> entry : this.metadata.entrySet()) {
M data = entry.getValue().get(type); M data = entry.getValue().get(type);
@@ -86,7 +97,7 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
@NotNull @NotNull
@UnmodifiableView @UnmodifiableView
public Map<String, ConfigValue<?>> registeredValues() { public Map<String, ConfigValue<?, ?>> registeredValues() {
return extractMetadata(StandardMeta.VALUE); return extractMetadata(StandardMeta.VALUE);
} }
@@ -98,17 +109,17 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
return initializer; return initializer;
} }
@Contract("_,null -> null") @Nullable
public <T> T deserialize(@NotNull Class<T> type, @Nullable Object source) throws Exception { public <T> T deserialize(@NotNull Class<T> type, @Nullable Object source) throws Exception {
return adapters().deserialize(this, type, source); return adapters().deserialize(this, type, source);
} }
@Contract("_,null -> null") @Nullable
public <T> T deserialize(@NotNull ValueType<T> type, @Nullable Object source) throws Exception { public <T> T deserialize(@NotNull ValueType<T> type, @Nullable Object source) throws Exception {
return adapters().deserialize(this, type, source); return adapters().deserialize(this, type, source);
} }
@Contract("null -> null") @Nullable
public <T> Object serialize(@Nullable T value) throws Exception { public <T> Object serialize(@Nullable T value) throws Exception {
return adapters().serialize(this, value); return adapters().serialize(this, value);
} }
@@ -117,7 +128,7 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
try { try {
initializer.initialize(this, configClass); initializer.initialize(this, configClass);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); throwing(configClass.getName(), e);
} }
} }
@@ -125,12 +136,20 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
try { try {
initializer.initialize(this, config); initializer.initialize(this, config);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); throwing(config.getClass().getName(), e);
} }
} }
public void initialize(@NotNull ValueManifest<?> value) { public void initialize(@NotNull ValueManifest<?, ?> value) {
value.holder(this); value.holder(this);
} }
public void throwing(@NotNull String path, @NotNull Throwable e) {
this.exceptionHandler.handle(path, e);
}
public void exceptionally(@NotNull ConfigExceptionHandler handler) {
this.exceptionHandler = handler;
}
} }
@@ -8,7 +8,7 @@ import org.jetbrains.annotations.Nullable;
public interface ConfigInitializeHandler<T, V> { public interface ConfigInitializeHandler<T, V> {
static <T, V> ConfigInitializeHandler<T, V> start() { static <T, V> ConfigInitializeHandler<T, V> start() {
return (provider, path, value, instace) -> { return (provider, path, value, instance) -> {
}; };
} }
@@ -1,6 +1,7 @@
package cc.carm.lib.configuration.source.loader; package cc.carm.lib.configuration.source.loader;
import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.function.ValueValidator;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
import cc.carm.lib.configuration.source.meta.StandardMeta; import cc.carm.lib.configuration.source.meta.StandardMeta;
@@ -21,7 +22,7 @@ import java.util.function.Function;
public class ConfigurationInitializer { public class ConfigurationInitializer {
protected @NotNull PathGenerator pathGenerator; protected @NotNull PathGenerator pathGenerator;
protected @NotNull ConfigInitializeHandler<Field, ConfigValue<?>> valueInitializer; protected @NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> valueInitializer;
protected @NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer; protected @NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer;
public ConfigurationInitializer() { public ConfigurationInitializer() {
@@ -29,7 +30,7 @@ public class ConfigurationInitializer {
} }
public ConfigurationInitializer(@NotNull PathGenerator pathGenerator, public ConfigurationInitializer(@NotNull PathGenerator pathGenerator,
@NotNull ConfigInitializeHandler<Field, ConfigValue<?>> valueInitializer, @NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> valueInitializer,
@NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer) { @NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer) {
this.pathGenerator = pathGenerator; this.pathGenerator = pathGenerator;
this.valueInitializer = valueInitializer; this.valueInitializer = valueInitializer;
@@ -44,11 +45,11 @@ public class ConfigurationInitializer {
return pathGenerator; return pathGenerator;
} }
public ConfigInitializeHandler<Field, ConfigValue<?>> fieldInitializer() { public ConfigInitializeHandler<Field, ConfigValue<?, ?>> fieldInitializer() {
return valueInitializer; return valueInitializer;
} }
public void fieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?>> fieldInitializer) { public void fieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> fieldInitializer) {
this.valueInitializer = fieldInitializer; this.valueInitializer = fieldInitializer;
} }
@@ -60,7 +61,7 @@ public class ConfigurationInitializer {
this.classInitializer = classInitializer; this.classInitializer = classInitializer;
} }
public void appendFieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?>> fieldInitializer) { public void appendFieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> fieldInitializer) {
this.valueInitializer = this.valueInitializer.andThen(fieldInitializer); this.valueInitializer = this.valueInitializer.andThen(fieldInitializer);
} }
@@ -95,6 +96,14 @@ public class ConfigurationInitializer {
registerFieldAnnotation(annotation, metadata, extractor); registerFieldAnnotation(annotation, metadata, extractor);
} }
public <A extends Annotation> void registerValidAnnotation(@NotNull Class<A> annotation,
@NotNull Function<A, ValueValidator<Object>> builder) {
appendFieldInitializer((holder, path, field, instance) -> {
A data = field.getAnnotation(annotation);
if (data == null) return;
instance.validate((h, t) -> builder.apply(data).validate(h, t));
});
}
public @Nullable String getFieldPath(@NotNull ConfigurationHolder<?> holder, @Nullable String parentPath, @NotNull Field field) { public @Nullable String getFieldPath(@NotNull ConfigurationHolder<?> holder, @Nullable String parentPath, @NotNull Field field) {
return pathGenerator.getFieldPath(holder, parentPath, field); return pathGenerator.getFieldPath(holder, parentPath, field);
@@ -125,7 +134,7 @@ public class ConfigurationInitializer {
try { try {
this.classInitializer.whenInitialize(holder, path, root.getClass(), root); this.classInitializer.whenInitialize(holder, path, root.getClass(), root);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); holder.throwing(path, e);
} }
Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(holder, root, field, path)); Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(holder, root, field, path));
} }
@@ -142,7 +151,7 @@ public class ConfigurationInitializer {
try { try {
this.classInitializer.whenInitialize(holder, path, (Class<? extends Configuration>) clazz, configField); this.classInitializer.whenInitialize(holder, path, (Class<? extends Configuration>) clazz, configField);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); holder.throwing(path, e);
} }
for (Field field : clazz.getDeclaredFields()) { for (Field field : clazz.getDeclaredFields()) {
@@ -163,9 +172,9 @@ public class ConfigurationInitializer {
field.setAccessible(true); field.setAccessible(true);
Object object = field.get(source); Object object = field.get(source);
// //
if (object instanceof ConfigValue<?>) { if (object instanceof ConfigValue<?, ?>) {
// 目标是 ConfigValue 实例,进行具体的初始化注入 // 目标是 ConfigValue 实例,进行具体的初始化注入
ConfigValue<?> value = (ConfigValue<?>) object; ConfigValue<?, ?> value = (ConfigValue<?, ?>) object;
String path = getFieldPath(holder, parent, field); String path = getFieldPath(holder, parent, field);
if (path == null) return; if (path == null) return;
value.initialize(holder, path); value.initialize(holder, path);
@@ -176,7 +185,7 @@ public class ConfigurationInitializer {
try { try {
this.valueInitializer.whenInitialize(holder, path, field, value); this.valueInitializer.whenInitialize(holder, path, field, value);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); holder.throwing(path, e);
} }
if (holder.option(StandardOptions.PRELOAD)) { if (holder.option(StandardOptions.PRELOAD)) {
value.get(); // Preload the value by calling #get method. value.get(); // Preload the value by calling #get method.
@@ -7,6 +7,6 @@ public interface StandardMeta {
/** /**
* To mark the {@link ConfigValue} instance of specific path. * To mark the {@link ConfigValue} instance of specific path.
*/ */
ConfigurationMetadata<ConfigValue<?>> VALUE = ConfigurationMetadata.of(); ConfigurationMetadata<ConfigValue<?, ?>> VALUE = ConfigurationMetadata.of();
} }
@@ -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();
List<?> data = config().contains(path()) ? config().getList(path()) : null; try {
if (data == null) return getDefaultFirst(list); List<?> data = config().contains(path()) ? config().getList(path()) : null;
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);
for (Object dataVal : data) { int i = 0;
if (dataVal == null) continue; for (Object dataVal : data) {
try { if (dataVal == null) continue;
list.add(parser.parse(holder(), paramType(), dataVal)); try {
} catch (Exception e) { list.add(withValidated(parser.parse(holder(), paramType(), dataVal)));
e.printStackTrace(); } catch (Exception e) {
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,26 +77,31 @@ 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();
ConfigureSection section = config().getSection(path()); try {
if (section == null) return getDefaultFirst(map); ConfigureSection section = config().getSection(path());
if (section == null) return getDefaultFirst(map);
Set<String> keys = section.getKeys(false); Set<String> keys = section.getKeys(false);
if (keys.isEmpty()) return getDefaultFirst(map); if (keys.isEmpty()) return getDefaultFirst(map);
ValueParser<K> keyParser = parserFor(keyAdapter); ValueParser<K> keyParser = parserFor(keyAdapter);
ValueParser<V> valueParser = parserFor(valueAdapter); if (keyParser == null) return getDefaultFirst(map);
if (keyParser == null || valueParser == null) return getDefaultFirst(map); ValueParser<V> valueParser = parserFor(valueAdapter);
if (valueParser == null) return getDefaultFirst(map);
for (String dataKey : keys) { for (String dataKey : keys) {
Object dataVal = section.get(dataKey); Object dataVal = section.get(dataKey);
if (dataVal == null) continue; if (dataVal == null) continue;
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,23 +124,28 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
return; return;
} }
ValueSerializer<K> keySerializer = serializerFor(keyAdapter); try {
ValueSerializer<V> valueSerializer = serializerFor(valueAdapter); ValueSerializer<K> keySerializer = serializerFor(keyAdapter);
if (keySerializer == null || valueSerializer == null) return; if (keySerializer == null) return;
ValueSerializer<V> valueSerializer = serializerFor(valueAdapter);
if (valueSerializer == null) return;
Map<Object, Object> data = new LinkedHashMap<>(); Map<Object, Object> data = new LinkedHashMap<>();
for (Map.Entry<K, V> entry : value.entrySet()) { for (Map.Entry<K, V> entry : value.entrySet()) {
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);
} catch (Exception ex) {
throwing(ex);
} }
setData(data);
} }
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.
Object data = getData();
if (data == null) return defaults();
ValueParser<V> parser = parser();
if (parser == null) return defaults(); // No parser, return default value.
try { try {
Object data = getData();
if (data == null) return defaults();
ValueParser<V> parser = parser();
if (parser == null) return defaults(); // No parser, return default value.
// 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;
} }
ValueSerializer<V> serializer = serializer();
if (serializer == null) return; // No serializer, do nothing.
try { try {
setData(serializer.serialize(holder(), type(), value)); ValueSerializer<V> serializer = serializer();
if (serializer == null) return; // No serializer, do nothing.
setData(serializer.serialize(holder(), type(), withValidated(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.9</version> <version>4.1.3</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,21 @@ import java.util.UUID;
"------------------------------------------------", "------------------------------------------------",
"此处内容将显示在配置文件的最下方", "此处内容将显示在配置文件的最下方",
"可用于显示版权信息等", "可用于显示版权信息等",
"感谢您使用 https://github.com/CarmJos/EasyConfiguration !" "感谢您使用 https://github.com/CarmJos/configured !"
}) })
public interface DemoConfiguration extends Configuration { public interface DemoConfiguration extends Configuration {
@ConfigPath(root = true) @ConfigPath(root = true)
@ConfigVersion(2) @ConfigVersion(2)
ConfigValue<Double> VERSION = ConfiguredValue.of(Double.class, 2.0D); ConfiguredValue<Double> VERSION = ConfiguredValue.of(Double.class, 2.0D);
@ConfigPath(root = true) @ConfigPath(root = true)
@FooterComments({"此处内容将显示在配置条目的下方", "可用于补充说明,但一般不建议使用"}) @FooterComments({"此处内容将显示在配置条目的下方", "可用于补充说明,但一般不建议使用"})
ConfigValue<Long> TEST_NUMBER = ConfiguredValue.of(1000000L); ConfiguredValue<Long> TEST_NUMBER = ConfiguredValue.with(Long.class).defaults(123456789L).build();
@HeaderComments({"枚举类型测试"}) @HeaderComments({"枚举类型测试"})
@FooterComments({"上述的枚举内容本质上是通过STRING解析的"}) @FooterComments({"上述的枚举内容本质上是通过STRING解析的"})
ConfigValue<ChronoUnit> TEST_ENUM = ConfiguredValue.of(ChronoUnit.class, ChronoUnit.DAYS); ConfiguredValue<ChronoUnit> TEST_ENUM = ConfiguredValue.of(ChronoUnit.class, ChronoUnit.DAYS);
@HeaderComments({"空值测试"}) @HeaderComments({"空值测试"})
@InlineComment("空值Inline注释") @InlineComment("空值Inline注释")
@@ -72,7 +71,7 @@ public interface DemoConfiguration extends Configuration {
class SUB implements Configuration { class SUB implements Configuration {
@ConfigPath(value = "uuid-value", root = true) @ConfigPath(value = "uuid-value", root = true)
public static final ConfigValue<UUID> UUID_CONFIG_VALUE = ConfiguredValue public static final ConfiguredValue<UUID> UUID_CONFIG_VALUE = ConfiguredValue
.builderOf(UUID.class).fromString() .builderOf(UUID.class).fromString()
.parse((holder, data) -> UUID.fromString(data)) .parse((holder, data) -> UUID.fromString(data))
.build(); .build();
@@ -2,12 +2,13 @@ package cc.carm.lib.configuration.demo.tests.conf;
import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.annotation.HeaderComments; import cc.carm.lib.configuration.annotation.HeaderComments;
import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.annotation.ValueRange;
import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue;
@HeaderComments("Inner Test") @HeaderComments("service")
public class InstanceConfig implements Configuration { public class InstanceConfig implements Configuration {
public final ConfigValue<Double> STATUS = ConfiguredValue.of(1.0D); @ValueRange(min = 0, max = 100, message = "The value must be between 0 and 100")
public final ConfiguredValue<Double> STATUS = ConfiguredValue.of(1.0D);
} }
@@ -6,7 +6,6 @@ import cc.carm.lib.configuration.annotation.FooterComments;
import cc.carm.lib.configuration.annotation.HeaderComments; import cc.carm.lib.configuration.annotation.HeaderComments;
import cc.carm.lib.configuration.annotation.InlineComment; import cc.carm.lib.configuration.annotation.InlineComment;
import cc.carm.lib.configuration.demo.tests.model.UserRecord; import cc.carm.lib.configuration.demo.tests.model.UserRecord;
import cc.carm.lib.configuration.value.ConfigValue;
import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue;
import java.util.UUID; import java.util.UUID;
@@ -20,7 +19,7 @@ public class RegistryConfig implements Configuration {
@FooterComments({"12313213212"}) @FooterComments({"12313213212"})
@InlineComment(value = "用户名(匹配注释)", regex = "name") // 通过注解给配置添加注释。 @InlineComment(value = "用户名(匹配注释)", regex = "name") // 通过注解给配置添加注释。
@InlineComment(value = "信息", regex = {"info.*", "info.game.*"}) // 通过注解给配置添加注释。 @InlineComment(value = "信息", regex = {"info.*", "info.game.*"}) // 通过注解给配置添加注释。
public final ConfigValue<UserRecord> OWNER = ConfiguredValue.builderOf(UserRecord.class).fromSection() public final ConfiguredValue<UserRecord> OWNER = ConfiguredValue.builderOf(UserRecord.class).fromSection()
.defaults(new UserRecord("Carm", UUID.randomUUID())) .defaults(new UserRecord("Carm", UUID.randomUUID()))
.parse((holder, section) -> UserRecord.deserialize(section)) .parse((holder, section) -> UserRecord.deserialize(section))
.serialize((holder, data) -> data.serialize()).build(); .serialize((holder, data) -> data.serialize()).build();
@@ -33,11 +33,11 @@ public class ItemStack {
return amount; return amount;
} }
public String getName() { public @Nullable String getName() {
return name; return name;
} }
public List<String> getLore() { public @Nullable List<String> getLore() {
return lore; return lore;
} }
@@ -49,11 +49,11 @@ public class ItemStack {
this.amount = amount; this.amount = amount;
} }
public void setName(String name) { public void setName(@Nullable String name) {
this.name = name; this.name = name;
} }
public void setLore(List<String> lore) { public void setLore(@Nullable List<String> lore) {
this.lore = lore; this.lore = lore;
} }
+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.9</version> <version>4.1.3</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -16,13 +16,13 @@
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties> </properties>
<artifactId>easyconfiguration-feature-commentable</artifactId> <artifactId>configured-feature-commentable</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId> <artifactId>configured-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
+4 -4
View File
@@ -5,8 +5,8 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>configured-parent</artifactId>
<version>4.0.9</version> <version>4.1.3</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.9</version> <version>4.1.3</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>
@@ -166,12 +166,12 @@ public class ImmutableSection implements ConfigureSection {
} }
@Override @Override
public <T> @Nullable T get(@NotNull String path, @Nullable T defaults, @NotNull Class<T> clazz) { public <T> @Nullable T get(@NotNull String path, T defaults, @NotNull Class<T> clazz) {
return raw().get(path, defaults, clazz); return raw().get(path, defaults, clazz);
} }
@Override @Override
public <T> @Nullable T get(@NotNull String path, @Nullable T defaultValue, @NotNull DataFunction<Object, T> parser) { public <T> @Nullable T get(@NotNull String path, T defaultValue, @NotNull DataFunction<Object, T> parser) {
return raw().get(path, defaultValue, parser); return raw().get(path, defaultValue, parser);
} }
+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.9</version> <version>4.1.3</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>
@@ -7,7 +7,6 @@ import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.ValueManifest;
import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue;
import cc.carm.lib.configuration.value.text.data.TextContents; import cc.carm.lib.configuration.value.text.data.TextContents;
import cc.carm.lib.configuration.value.text.function.TextDispatcher;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -22,7 +21,7 @@ import java.util.function.Consumer;
*/ */
public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents> { public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents> {
public static <M, R> Builder<M, R, ?> builder() { public static <M, R> Builder<M, R, ?> create() {
return new StardardBuilder<>(); return new StardardBuilder<>();
} }
@@ -38,7 +37,7 @@ public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents>
protected final @NotNull String[] params; // The parameters of the message. protected final @NotNull String[] params; // The parameters of the message.
public ConfiguredText(@NotNull ValueManifest<TextContents> manifest, public ConfiguredText(@NotNull ValueManifest<TextContents, TextContents> manifest,
@NotNull BiFunction<RECEIVER, String, String> parser, @NotNull BiFunction<RECEIVER, String, String> parser,
@NotNull BiFunction<RECEIVER, String, MSG> compiler, @NotNull BiFunction<RECEIVER, String, MSG> compiler,
@NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher, @NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher,
@@ -50,7 +49,7 @@ public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents>
this.params = params; this.params = params;
} }
public TextDispatcher<MSG, RECEIVER, ?> prepare(@NotNull Object... values) { public PreparedText<MSG, RECEIVER> prepare(@NotNull Object... values) {
return new PreparedText<MSG, RECEIVER>(resolve(), this.params) return new PreparedText<MSG, RECEIVER>(resolve(), this.params)
.parser(this.parser).compiler(this.compiler) .parser(this.parser).compiler(this.compiler)
.dispatcher(this.dispatcher).placeholders(values); .dispatcher(this.dispatcher).placeholders(values);
@@ -121,7 +120,7 @@ public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents>
} }
public abstract static class Builder<MSG, RECEIVER, SELF extends Builder<MSG, RECEIVER, SELF>> public abstract static class Builder<MSG, RECEIVER, SELF extends Builder<MSG, RECEIVER, SELF>>
extends AbstractConfigBuilder<TextContents, ConfiguredText<MSG, RECEIVER>, ConfigurationHolder<?>, SELF> { extends AbstractConfigBuilder<TextContents, TextContents, ConfiguredText<MSG, RECEIVER>, ConfigurationHolder<?>, SELF> {
protected @NotNull TextContents.Builder defaultBuilder = TextContents.builder(); protected @NotNull TextContents.Builder defaultBuilder = TextContents.builder();
protected @NotNull String[] params = new String[0]; protected @NotNull String[] params = new String[0];
@@ -1,36 +1,27 @@
package cc.carm.lib.configuration.value.text.function; package cc.carm.lib.configuration.value.text.function;
import cc.carm.lib.configuration.value.text.data.TextContents; import cc.carm.lib.configuration.value.text.data.TextContents;
import cc.carm.lib.configuration.value.text.function.common.AppendLineInserter;
import cc.carm.lib.configuration.value.text.function.common.OptionalLineInserter;
import cc.carm.lib.configuration.value.text.function.common.ParamReplacer;
import cc.carm.lib.configuration.value.text.function.inserter.ContentInserter;
import cc.carm.lib.configuration.value.text.function.inserter.Insertable;
import cc.carm.lib.configuration.value.text.function.replacer.ContentReplacer;
import cc.carm.lib.configuration.value.text.function.replacer.Replaceable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.*; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.IntStream;
public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEIVER, SELF>> { public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEIVER, SELF>>
implements Replaceable<RECEIVER, SELF>, Insertable<RECEIVER, SELF> {
/**
* Used to match the message insertion
* <p>
* format:
* <br>- to insert parsed line {prefix}#content-id#{offset-above,offset-down}
* <br>- to insert original line {prefix}@content-id@{offset-above,offset-down}
* <br> example:
* <ul>
* <li>{- }#content-id#{1,1}</li>
* <li>@content-id@{1,1}</li>
* </ul>
*/
public static final @NotNull Pattern INSERT_PATTERN = Pattern.compile(
"^(?:\\{(?<prefix>.*)})?(?<type>[#@])(?<id>.*)[#@](?:\\{(?<above>-?\\d+)(?:,(?<down>-?\\d+))?})?$"
);
public static final @NotNull UnaryOperator<String> DEFAULT_PARAM_BUILDER = s -> "%(" + s + ")";
protected BiFunction<RECEIVER, String, String> parser = (receiver, value) -> value; protected BiFunction<RECEIVER, String, String> parser = (receiver, value) -> value;
protected String lineSeparator = System.lineSeparator(); protected String lineSeparator = System.lineSeparator();
@@ -38,16 +29,24 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
/** /**
* Used to store the placeholders of the message * Used to store the placeholders of the message
*/ */
protected @NotNull Map<String, Object> placeholders = new HashMap<>(); protected @NotNull ParamReplacer<RECEIVER> paramReplacer = ParamReplacer.defaults();
protected @NotNull UnaryOperator<String> paramFormatter = DEFAULT_PARAM_BUILDER;
protected @NotNull String[] params; protected @NotNull String[] params;
protected @NotNull List<ContentReplacer<RECEIVER>> replacers = new ArrayList<>();
protected @NotNull List<ContentInserter<RECEIVER>> inserters = new ArrayList<>();
/** /**
* Used to store the insertion of the message * Used to store the insertion of the message
*/ */
protected @NotNull Map<String, Function<RECEIVER, List<String>>> insertion = new HashMap<>(); protected final @NotNull Map<String, @Nullable Function<RECEIVER, List<String>>> insertion = new HashMap<>();
protected boolean disableInsertion = false; protected boolean disableInsertion = false;
public ContentHandler() {
inserters.add(new AppendLineInserter<>(0));
inserters.add(new OptionalLineInserter<>(0));
}
public abstract SELF self(); public abstract SELF self();
/** /**
@@ -71,6 +70,11 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
return self(); return self();
} }
@Override
public boolean noneInsertion() {
return this.insertion.isEmpty();
}
/** /**
* Set the line separator for the text. * Set the line separator for the text.
* *
@@ -90,7 +94,7 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
* @return the current {@link ContentHandler} instance * @return the current {@link ContentHandler} instance
*/ */
public SELF placeholders(@NotNull Map<String, Object> placeholders) { public SELF placeholders(@NotNull Map<String, Object> placeholders) {
this.placeholders = placeholders; this.paramReplacer.set(placeholders);
return self(); return self();
} }
@@ -101,7 +105,7 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
* @return the current {@link ContentHandler} instance * @return the current {@link ContentHandler} instance
*/ */
public SELF placeholders(@NotNull Consumer<Map<String, Object>> consumer) { public SELF placeholders(@NotNull Consumer<Map<String, Object>> consumer) {
consumer.accept(this.placeholders); consumer.accept(this.paramReplacer.placeholders());
return self(); return self();
} }
@@ -112,7 +116,8 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
* @return the current {@link ContentHandler} instance * @return the current {@link ContentHandler} instance
*/ */
public SELF placeholders(@Nullable Object... values) { public SELF placeholders(@Nullable Object... values) {
return placeholders(map -> map.putAll(buildParams(this.paramFormatter, this.params, values))); this.paramReplacer.putAll(this.params, values);
return self();
} }
/** /**
@@ -123,7 +128,7 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
* @return the current {@link ContentHandler} instance * @return the current {@link ContentHandler} instance
*/ */
public SELF placeholder(@NotNull String key, @Nullable Object value) { public SELF placeholder(@NotNull String key, @Nullable Object value) {
this.placeholders.put(paramFormatter.apply(key), value); this.paramReplacer.put(key, value);
return self(); return self();
} }
@@ -139,38 +144,57 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
return self(); return self();
} }
/** @Override
* Insert the specific contents by the id. public List<ContentReplacer<RECEIVER>> replacers() {
* return this.replacers;
* @param id the id of the insertion text }
* @param linesSupplier to supply the lines to insert
* @return the current {@link ContentHandler} instance @Override
*/ public SELF replacer(@NotNull ContentReplacer<RECEIVER> replacer) {
public SELF insert(@NotNull String id, @NotNull Function<RECEIVER, List<String>> linesSupplier) { this.replacers.add(replacer);
this.insertion.put(id, linesSupplier); this.replacers.sort(ContentReplacer::compareTo);
return self(); return self();
} }
/** public SELF paramReplacer(@NotNull ParamReplacer<RECEIVER> paramReplacer) {
* Insert the specific contents by the id. this.paramReplacer = paramReplacer;
* return self();
* @param id the id of the insertion text
* @param lines the lines to insert
* @return the current {@link ContentHandler} instance
*/
public SELF insert(@NotNull String id, @NotNull String... lines) {
return insert(id, Arrays.asList(lines));
} }
/** @Override
* Insert the specific contents by the id. public List<ContentInserter<RECEIVER>> inserters() {
* return this.inserters;
* @param id the id of the insertion text }
* @param lines the lines to insert
* @return the current {@link ContentHandler} instance @Override
*/ public SELF inserter(@NotNull ContentInserter<RECEIVER> inserter) {
public SELF insert(@NotNull String id, @NotNull List<String> lines) { this.inserters.add(inserter);
return insert(id, receiver -> lines); this.inserters.sort(ContentInserter::compareTo);
return self();
}
@Override
public SELF insert(@NotNull String id, @Nullable Function<RECEIVER, List<String>> supplier) {
this.insertion.put(id, supplier);
return self();
}
@Override
public boolean inserting(@NotNull String id) {
return this.insertion.keySet().stream().anyMatch(key -> key.equalsIgnoreCase(id));
}
@Override
public @Nullable List<String> getInsertion(@NotNull String id, @Nullable RECEIVER receiver) {
Function<RECEIVER, List<String>> function = this.insertion.get(id);
if (function == null) return null;
return function.apply(receiver);
}
@Override
public SELF removeInsert(@NotNull String id) {
this.insertion.remove(id);
return self();
} }
/** /**
@@ -192,47 +216,38 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
* @return the parsed text * @return the parsed text
*/ */
protected @Nullable String parse(@Nullable RECEIVER receiver, @NotNull String text) { protected @Nullable String parse(@Nullable RECEIVER receiver, @NotNull String text) {
return this.parser.apply(receiver, setPlaceholders(text, this.placeholders)); text = applyReplacements(receiver, text); // First, apply the custom replacements
text = this.paramReplacer.replace(text, receiver); // Then, apply the static placeholders
return this.parser.apply(receiver, text); // Finally, parse the text
} }
public void handle(@NotNull TextContents contents, @Nullable RECEIVER receiver, public void handle(@NotNull TextContents contents, @Nullable RECEIVER receiver,
@NotNull Consumer<String> lineConsumer) { @NotNull Consumer<String> lineConsumer) {
if (contents.isEmpty()) return; // Nothing to parse if (contents.isEmpty()) return; // Nothing to parse
if (this.disableInsertion) { if (this.disableInsertion || noneInsertion()) {
contents.lines().forEach(line -> lineConsumer.accept(parse(receiver, line))); contents.lines().forEach(line -> lineConsumer.accept(parse(receiver, line)));
return; // Simple parsed return; // Simple parsed
} }
// Set the default insertion of the text
for (Map.Entry<String, @Nullable Function<RECEIVER, List<String>>> entry : this.insertion.entrySet()) {
if (entry.getValue() != null) continue;
List<String> lines = contents.optionalLines().get(entry.getKey());
if (lines == null) continue;
entry.setValue(r -> lines);
}
lines:
for (String line : contents.lines()) { for (String line : contents.lines()) {
Matcher matcher = INSERT_PATTERN.matcher(line); for (ContentInserter<RECEIVER> inserter : inserters) {
if (!matcher.matches()) { List<String> inserted = inserter.handle(receiver, line, this);
lineConsumer.accept(parse(receiver, line)); if (inserted != null) { // Found the insertion
continue; inserted.forEach(l -> lineConsumer.accept(parse(receiver, l)));
continue lines; // Go to the next line
}
} }
lineConsumer.accept(parse(receiver, line));
String id = matcher.group("id");
List<String> values = Optional.ofNullable(this.insertion.get(id))
.map(f -> f.apply(receiver))
.orElse(null);
if (values == null || values.isEmpty()) continue;
String prefix = matcher.group("prefix");
String type = matcher.group("type");
boolean original = type.equals("@");
int offsetAbove = Optional.ofNullable(matcher.group("above"))
.map(Integer::parseInt).orElse(0);
int offsetDown = Optional.ofNullable(matcher.group("down"))
.map(Integer::parseInt).orElse(offsetAbove); // If offsetDown is not set, use offsetAbove
IntStream.range(0, Math.max(0, offsetAbove)).mapToObj(i -> "").forEach(lineConsumer);
String prefixContent = Optional.ofNullable(prefix).map(p -> parse(receiver, p)).orElse("");
if (original) {
values.stream().map(value -> prefixContent + value).forEach(lineConsumer);
} else {
values.stream().map(value -> prefixContent + parse(receiver, value)).forEach(lineConsumer);
}
IntStream.range(0, Math.max(0, offsetDown)).mapToObj(i -> "").forEach(lineConsumer);
} }
} }
@@ -0,0 +1,67 @@
package cc.carm.lib.configuration.value.text.function.common;
import cc.carm.lib.configuration.value.text.function.inserter.ContentInserter;
import cc.carm.lib.configuration.value.text.function.inserter.Insertable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.IntStream;
public class AppendLineInserter<RECEIVER> extends ContentInserter<RECEIVER> {
/**
* Used to match the message insertion.
* <p>
* format:
* <br>- to insert parsed line {prefix}#content-id#{offset-above,offset-down}
* <br>- to insert original line {prefix}@content-id@{offset-above,offset-down}
* <br> original lines will not be parsed
* <br> example:
* <ul>
* <li>{- }#content-id#{1,1}</li>
* <li>@content-id@{1,1}</li>
* </ul>
*/
public static final @NotNull Pattern APPEND_PATTERN = Pattern.compile(
"^(?:\\{(?<prefix>.*)})?#(?<id>.*)#(?:\\{(?<above>-?\\d+)(?:,(?<down>-?\\d+))?})?$"
);
public AppendLineInserter(int priority) {
super(priority, APPEND_PATTERN);
}
@Override
protected @Nullable String extractID(@NotNull Matcher matcher) {
return matcher.group("id");
}
@Override
protected @NotNull List<String> get(@Nullable RECEIVER receiver, @NotNull Matcher matcher,
@NotNull Insertable<RECEIVER, ?> insertion) {
String id = extractID(matcher);
List<String> values = insertion.getInsertion(id, receiver);
if (values == null || values.isEmpty()) return Collections.emptyList(); // No values to insert
String prefix = Optional.ofNullable(matcher.group("prefix")).orElse("");
int offsetAbove = Optional.ofNullable(matcher.group("above"))
.map(Integer::parseInt).orElse(0);
int offsetDown = Optional.ofNullable(matcher.group("down"))
.map(Integer::parseInt).orElse(offsetAbove); // If offsetDown is not set, use offsetAbove
List<String> contents = new ArrayList<>();
IntStream.range(0, Math.max(0, offsetAbove)).mapToObj(i -> "").forEach(contents::add);
values.stream().map(value -> prefix + value).forEach(contents::add);
IntStream.range(0, Math.max(0, offsetDown)).mapToObj(i -> "").forEach(contents::add);
return contents;
}
}
@@ -0,0 +1,46 @@
package cc.carm.lib.configuration.value.text.function.common;
import cc.carm.lib.configuration.value.text.function.inserter.ContentInserter;
import cc.carm.lib.configuration.value.text.function.inserter.Insertable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class OptionalLineInserter<RECEIVER> extends ContentInserter<RECEIVER> {
/**
* Used to match the message which can be inserted
* <p>
* format:
* <br>- ?[id]Message content
* <br> example:
* <ul>
* <li>?[click]Click to use this item!</li>
* </ul>
*/
public static final @NotNull Pattern OPTIONAL_PATTERN = Pattern.compile(
"^\\?\\[(?<id>.+)](?<content>.*)$"
);
public OptionalLineInserter(int priority) {
super(priority, OPTIONAL_PATTERN);
}
@Override
protected @Nullable String extractID(@NotNull Matcher matcher) {
return matcher.group("id");
}
@Override
protected @NotNull List<String> get(@Nullable RECEIVER receiver, @NotNull Matcher matcher,
@NotNull Insertable<RECEIVER, ?> insertion) {
String content = matcher.group("content");
if (content == null) return Collections.emptyList();
return Collections.singletonList(content);
}
}
@@ -0,0 +1,71 @@
package cc.carm.lib.configuration.value.text.function.common;
import cc.carm.lib.configuration.value.text.function.replacer.ContentReplacer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ParamReplacer<RECEIVER> extends ContentReplacer<RECEIVER> {
public static final @NotNull Pattern DEFAULT_PARAM_PATTERN = Pattern.compile("%\\((?<id>[^)]+)\\)");
public static <R> ParamReplacer<R> defaults() {
return create(DEFAULT_PARAM_PATTERN, m -> m.group("id"));
}
public static <R> ParamReplacer<R> create(@NotNull Pattern pattern, @NotNull Function<Matcher, String> extractor) {
return new ParamReplacer<>(0, pattern, extractor);
}
protected final @NotNull Function<Matcher, @Nullable String> extractor;
protected @NotNull Map<String, Object> placeholders = new HashMap<>();
public ParamReplacer(int priority, @NotNull Pattern pattern, @NotNull Function<Matcher, String> extractor) {
super(priority, pattern);
this.extractor = extractor;
}
public @NotNull Map<String, Object> placeholders() {
return placeholders;
}
@Override
protected @Nullable String get(@NotNull RECEIVER receiver, @NotNull Matcher matcher) {
@Nullable String id = extractor.apply(matcher);
if (id == null) return null;
Object value = placeholders.get(id);
if (value == null) return null;
return value.toString();
}
public void set(@NotNull Map<String, Object> placeholders) {
this.placeholders = placeholders;
}
public void put(@NotNull String id, @Nullable Object value) {
placeholders.put(id, value);
}
public void remove(@NotNull String id) {
placeholders.remove(id);
}
public void putAll(@NotNull Map<String, Object> placeholders) {
this.placeholders.putAll(placeholders);
}
public void putAll(@NotNull String[] params, @NotNull Object[] values) {
for (int i = 0; i < params.length; i++) {
placeholders.put(params[i], (values != null && values.length > i) ? values[i] : "?");
}
}
public void clear() {
placeholders.clear();
}
}
@@ -0,0 +1,51 @@
package cc.carm.lib.configuration.value.text.function.inserter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class ContentInserter<RECEIVER> implements Comparable<ContentInserter<RECEIVER>> {
protected final int priority;
protected @NotNull Pattern pattern;
public ContentInserter(int priority, @NotNull Pattern pattern) {
this.priority = priority;
this.pattern = pattern;
}
public int priority() {
return priority;
}
public void setPattern(@NotNull Pattern pattern) {
this.pattern = pattern;
}
public @NotNull Matcher matcher(@NotNull String text) {
return pattern.matcher(text);
}
protected abstract @Nullable String extractID(@NotNull Matcher matcher);
protected abstract @NotNull List<String> get(@Nullable RECEIVER receiver, @NotNull Matcher matcher,
@NotNull Insertable<RECEIVER, ?> insertions);
public @Nullable List<String> handle(@Nullable RECEIVER receiver, @NotNull String line,
@NotNull Insertable<RECEIVER, ?> insertions) {
Matcher matcher = matcher(line);
if (!matcher.matches()) return null;
if (!insertions.inserting(extractID(matcher))) return Collections.emptyList();
return get(receiver, matcher, insertions);
}
@Override
public int compareTo(@NotNull ContentInserter<RECEIVER> o) {
return Integer.compare(o.priority, priority);
}
}
@@ -0,0 +1,66 @@
package cc.carm.lib.configuration.value.text.function.inserter;
import cc.carm.lib.configuration.value.text.function.ContentHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
public interface Insertable<RECEIVER, SELF> {
List<ContentInserter<RECEIVER>> inserters();
SELF inserter(@NotNull ContentInserter<RECEIVER> inserter);
boolean noneInsertion();
boolean inserting(@NotNull String id);
@Nullable List<String> getInsertion(@NotNull String id, @Nullable RECEIVER receiver);
/**
* Insert the specific contents by the id.
*
* @param id the id of the insertion text
* @param supplier to supply the lines to insert
* @return the current {@link ContentHandler} instance
*/
SELF insert(@NotNull String id, @Nullable Function<RECEIVER, List<String>> supplier);
/**
* Insert the specific contents by the id.
*
* @param id the id of the insertion text
* @return the current {@link ContentHandler} instance
*/
default SELF insert(@NotNull String id) {
return insert(id, (Function<RECEIVER, List<String>>) null);
}
/**
* Insert the specific contents by the id.
*
* @param id the id of the insertion text
* @param contents the lines to insert
* @return the current {@link ContentHandler} instance
*/
default SELF insert(@NotNull String id, @NotNull List<String> contents) {
return insert(id, receiver -> contents);
}
/**
* Insert the specific contents by the id.
*
* @param id the id of the insertion text
* @param contents the lines to insert
* @return the current {@link ContentHandler} instance
*/
default SELF insert(@NotNull String id, @NotNull String... contents) {
return insert(id, Arrays.asList(contents));
}
SELF removeInsert(@NotNull String id);
}
@@ -0,0 +1,105 @@
package cc.carm.lib.configuration.value.text.function.replacer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class ContentReplacer<RECEIVER> implements Comparable<ContentReplacer<RECEIVER>> {
public static <R> ContentReplacer.Builder<R> match(@NotNull Pattern pattern) {
return new Builder<>(pattern);
}
public static <R> ContentReplacer.Builder<R> match(@NotNull String pattern) {
return match(Pattern.compile(pattern));
}
public static <R> ContentReplacer.Builder<R> replace(@NotNull String text) {
return match(Pattern.quote(text));
}
protected final int priority;
protected @NotNull Pattern pattern;
public ContentReplacer(int priority, @NotNull Pattern pattern) {
this.priority = priority;
this.pattern = pattern;
}
public int priority() {
return priority;
}
public void pattern(@NotNull Pattern pattern) {
this.pattern = pattern;
}
public @NotNull Matcher matcher(@NotNull String text) {
return pattern.matcher(text);
}
public String replace(@NotNull String text, @Nullable RECEIVER receiver) {
Matcher matcher = matcher(text);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
String replaced = get(receiver, matcher);
matcher.appendReplacement(sb, replaced == null ? "" : replaced);
}
matcher.appendTail(sb);
return sb.toString();
}
protected abstract @Nullable String get(@Nullable RECEIVER receiver, @NotNull Matcher matcher);
@Override
public int compareTo(@NotNull ContentReplacer<RECEIVER> o) {
return Integer.compare(o.priority, this.priority);
}
public static class Builder<R> {
protected final @NotNull Pattern pattern;
protected int priority = 0;
public Builder(@NotNull Pattern pattern) {
this.pattern = pattern;
}
public @NotNull Builder<R> priority(int priority) {
this.priority = priority;
return this;
}
public @NotNull ContentReplacer<R> to(BiFunction<@Nullable R, @NotNull Matcher, @Nullable String> supplier) {
return new ContentReplacer<R>(this.priority, this.pattern) {
@Override
protected @Nullable String get(@NotNull R receiver, @NotNull Matcher matcher) {
return supplier.apply(receiver, matcher);
}
};
}
public @NotNull ContentReplacer<R> to(Function<@Nullable R, @Nullable String> supplier) {
return to((receiver, matchedParam) -> supplier.apply(receiver));
}
public @NotNull ContentReplacer<R> to(Supplier<@Nullable String> supplier) {
return to((receiver, matchedParam) -> supplier.get());
}
public @NotNull ContentReplacer<R> to(@NotNull String content) {
return to(() -> content);
}
}
@FunctionalInterface
public interface Constructor<R> extends Function<ContentReplacer.Builder<R>, ContentReplacer<R>> {
}
}
@@ -0,0 +1,63 @@
package cc.carm.lib.configuration.value.text.function.replacer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public interface Replaceable<RECEIVER, SELF> {
List<ContentReplacer<RECEIVER>> replacers();
default String applyReplacements(@Nullable RECEIVER receiver, @NotNull String text) {
for (ContentReplacer<RECEIVER> replacer : replacers()) {
text = replacer.replace(text, receiver);
}
return text;
}
SELF replacer(@NotNull ContentReplacer<RECEIVER> replacer);
default SELF replacer(@NotNull Pattern pattern, @NotNull ContentReplacer.Constructor<RECEIVER> constructor) {
ContentReplacer.Builder<RECEIVER> builder = ContentReplacer.match(pattern);
return replacer(constructor.apply(builder));
}
default SELF replace(@NotNull Pattern pattern,
@NotNull BiFunction<@Nullable RECEIVER, @NotNull Matcher, @Nullable String> supplier) {
return replacer(pattern, builder -> builder.to(supplier));
}
default SELF replace(@NotNull Pattern pattern,
@NotNull Function<@Nullable RECEIVER, @Nullable String> supplier) {
return replacer(pattern, builder -> builder.to(supplier));
}
default SELF replace(@NotNull Pattern pattern,
@NotNull Supplier<@Nullable String> supplier) {
return replacer(pattern, builder -> builder.to(supplier));
}
default SELF replace(@NotNull Pattern pattern, @NotNull String replacement) {
return replacer(pattern, builder -> builder.to(replacement));
}
default SELF replace(@NotNull String text, @NotNull String replacement) {
return replacer(Pattern.compile(Pattern.quote(text)), builder -> builder.to(replacement));
}
default SELF replace(@NotNull String text, @NotNull Supplier<@Nullable String> supplier) {
return replacer(Pattern.compile(Pattern.quote(text)), builder -> builder.to(supplier));
}
default SELF replace(@NotNull String text,
@NotNull Function<@Nullable RECEIVER, @Nullable String> supplier) {
return replacer(Pattern.compile(Pattern.quote(text)), builder -> builder.to(supplier));
}
}
@@ -2,12 +2,14 @@ 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;
public class ConfigTest { import java.io.File;
import java.util.List;
public class ConfigTest {
public static final String[] WEBSITES = new String[]{ public static final String[] WEBSITES = new String[]{
"https://carm.cc", "https://carm.cc",
@@ -15,21 +17,20 @@ public class ConfigTest {
"https://www.google.com" "https://www.google.com"
}; };
@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);
System.out.println("--------------------------"); System.out.println("--------------------------");
AppMessages.WELCOME.prepare() List<String> str = AppMessages.WELCOME.prepare()
.placeholders("Carm") .placeholders("Carm")
.insert("guidance") .insert("guidance")
.insert("websites", WEBSITES) .insert("websites", WEBSITES)
.to(System.out); .compile(System.out);
System.out.println("--------------------------"); System.out.println("--------------------------");
@@ -7,6 +7,7 @@ import org.junit.Test;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.*; import java.util.*;
public class ParseTest { public class ParseTest {
@@ -18,12 +19,15 @@ public class ParseTest {
lines.add("#more-creating#{1}"); lines.add("#more-creating#{1}");
lines.add("This is a test message"); lines.add("This is a test message");
lines.add("#guidance#"); lines.add("#guidance#");
lines.add("{- }#websites#{0,1}"); lines.add("{ - }#websites#{0,1}");
lines.add("Thanks for your reading!"); lines.add("Thanks for your reading!");
lines.add("uuid: $UUID$");
lines.add("?[click]");
lines.add("?[click]Click to see more!");
lines.add("?[hidden]This entry should be hidden!");
Map<String, List<String>> optional = new HashMap<>(); Map<String, List<String>> optional = new HashMap<>();
optional.put("guidance", Arrays.asList("To get more information for %(name), see:")); optional.put("guidance", Arrays.asList("To get more information for %(name),", " see:"));
optional.put("websites", Arrays.asList("https://www.baidu.com", "https://www.google.com")); optional.put("websites", Arrays.asList("https://www.baidu.com", "https://www.google.com"));
TextContents textContents = new TextContents(lines, optional); TextContents textContents = new TextContents(lines, optional);
@@ -31,12 +35,17 @@ public class ParseTest {
PreparedText<String, PrintStream> msg = new PreparedText<String, PrintStream>(textContents) PreparedText<String, PrintStream> msg = new PreparedText<String, PrintStream>(textContents)
.dispatcher((p, s) -> s.forEach(p::println)) .dispatcher((p, s) -> s.forEach(p::println))
.parser((p, s) -> s) .parser((p, s) -> s)
.compiler((p, s) -> s); .compiler((p, s) -> s)
.replace( // Custom replacer, replace $UUID$ with Random UUID
"$UUID$", () -> UUID.randomUUID().toString()
);
msg.placeholder("name", "Carm") msg.placeholder("name", "Carm")
.insert("guidance") .insert("guidance")
.insert("click")
.insert("websites", "Baidu", "Bilibili", "Google"); .insert("websites", "Baidu", "Bilibili", "Google");
System.out.println("----------------------------"); System.out.println("----------------------------");
msg.to(System.out); msg.to(System.out);
System.out.println("----------------------------"); System.out.println("----------------------------");
@@ -17,7 +17,8 @@ public class ConfiguredMsg extends ConfiguredText<String, PrintStream> {
return builder().defaults(text).build(); return builder().defaults(text).build();
} }
public ConfiguredMsg(@NotNull ValueManifest<TextContents> manifest, @NotNull String[] params) { public ConfiguredMsg(@NotNull ValueManifest<TextContents, TextContents> manifest,
@NotNull String[] params) {
super( super(
manifest, manifest,
(p, s) -> s, (p, s) -> s,
+51
View File
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>configured-parent</artifactId>
<version>4.1.3</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.9</version> <version>4.1.3</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.9</version> <version>4.1.3</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.9</version> <version>4.1.3</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.3</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.9</version> <version>4.1.3</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>
+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.9</version> <version>4.1.3</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,10 +75,10 @@ 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) {
+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]"
} }
``` ```
+8 -8
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.9</version> <version>4.1.3</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -17,35 +17,35 @@
<deps.yamlcommentwriter.version>1.2.1</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>
@@ -1,11 +1,11 @@
package yaml.test; package yaml.test;
import cc.carm.lib.configuration.commentable.Commentable;
import cc.carm.lib.configuration.commentable.CommentableMeta; import cc.carm.lib.configuration.commentable.CommentableMeta;
import cc.carm.lib.configuration.demo.tests.ConfigurationTest; import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.yaml.YAMLConfigFactory; import cc.carm.lib.configuration.source.yaml.YAMLConfigFactory;
import cc.carm.lib.configuration.source.yaml.YAMLSource; import cc.carm.lib.configuration.source.yaml.YAMLSource;
import cc.carm.lib.configuration.validators.Validators;
import org.junit.Test; import org.junit.Test;
import java.util.List; import java.util.List;
@@ -19,6 +19,8 @@ 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);