mirror of
https://github.com/CarmJos/EasyConfiguration.git
synced 2026-06-04 18:48:20 +08:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c32a941906 | |||
| 8b597d10f9 | |||
| cedfcfd262 | |||
| 12add75232 | |||
| 4d29a24768 | |||
| 8626b86961 | |||
| 754dc1de1f | |||
| 3d1d4ca609 | |||
| 990b10b6f0 | |||
| 7462cd720e | |||
| 6bc83eb3b3 | |||
| dbec551c84 | |||
| 82cca5eca2 | |||
| 65f3cc1b3d | |||
| fae048dd69 | |||
| 854e3df49f | |||
| f6167c3b5e | |||
| ffe3e88b3b | |||
| caa3077f48 | |||
| 05dbf0b504 | |||
| 810e95198e | |||
| 10004f16b4 | |||
| 8e19748c7c | |||
| 17762a2e70 | |||
| 7dbd607a3f | |||
| 035e8a227e | |||
| 04eaf6606d | |||
| e558e93410 | |||
| e55fe3a8d5 | |||
| 8f075b99b5 | |||
| 09a0b3c373 | |||
| 4df4977733 | |||
| 6434feb980 |
@@ -1,9 +1,3 @@
|
||||
# EasyConfiguration Javadoc
|
||||
# configured Javadoc
|
||||
|
||||
基于 [Github Pages](https://pages.github.com/) 搭建,请访问 [JavaDoc](https://carmjos.github.io/EasyConfiguration) 。
|
||||
|
||||
## 如何实现?
|
||||
|
||||
若您也想通过 [Github Actions](https://docs.github.com/en/actions/learn-github-actions)
|
||||
自动部署项目的Javadoc到 [Github Pages](https://pages.github.com/) ,
|
||||
可以参考我的文章 [《自动部署Javadoc到Github Pages》](https://pages.carm.cc/doc/javadoc-in-github.html) 。
|
||||
Based on [Github Pages](https://pages.github.com/), please see [JavaDoc](https://carmjos.github.io/configured) 。
|
||||
+1
-16
@@ -1,16 +1 @@
|
||||
# 欢迎使用 EasyConfiguration !
|
||||
|
||||
这个项目刚刚创建,详细的Javadoc与开发指南还在补充,请给我一点时间~
|
||||
|
||||
|
||||
## 基本定义
|
||||
|
||||
Value: 实际配置的单例值。
|
||||
|
||||
Manifest: 用于描述值基本配置的对象。
|
||||
|
||||
Provider: 用于提供配置文件的接口。
|
||||
|
||||
Wrapper: 用于包装配置文件的接口。
|
||||
|
||||
Initializer: 用于初始化的接口
|
||||
# Documentation
|
||||
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 |
@@ -47,7 +47,7 @@ jobs:
|
||||
id: sitemap
|
||||
uses: cicirello/generate-sitemap@v1
|
||||
with:
|
||||
base-url-path: https://CarmJos.github.io/EasyConfiguration
|
||||
base-url-path: https://CarmJos.github.io/configured
|
||||
path-to-root: docs
|
||||
|
||||
- name: "Output stats"
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
run: |
|
||||
cd docs
|
||||
git init
|
||||
git remote add origin git@github.com:CarmJos/EasyConfiguration.git
|
||||
git remote add origin git@github.com:CarmJos/configured.git
|
||||
git checkout -b gh-pages
|
||||
git add -A
|
||||
git commit -m "API Document generated."
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
.idea/
|
||||
.idea/*
|
||||
!.idea/icon.svg
|
||||
**/target/
|
||||
**.iml
|
||||
Generated
+36
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 23 KiB |
@@ -1,6 +1,7 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
```text
|
||||
____ _____ ____ __ _
|
||||
/ __/__ ____ __ __ / ___/__ ___ / _(_)__ ___ _________ _/ /_(_)__ ___
|
||||
/ _// _ `(_-</ // / / /__/ _ \/ _ \/ _/ / _ `/ // / __/ _ `/ __/ / _ \/ _ \
|
||||
/___/\_,_/___/\_, / \___/\___/_//_/_//_/\_, /\_,_/_/ \_,_/\__/_/\___/_//_/
|
||||
/___/ /___/
|
||||
```
|
||||
<div align=center>
|
||||
<img src=".doc/images/banner.png" alt="Banner"/>
|
||||
|
||||
[](https://github.com/CarmJos/configured/releases)
|
||||
[](https://www.gnu.org/licenses/lgpl-3.0.html)
|
||||
[](https://github.com/CarmJos/configured/actions/workflows/maven.yml)
|
||||
[](https://www.codefactor.io/repository/github/carmjos/configured)
|
||||

|
||||

|
||||
|
||||
README LANGUAGES [ [**English**](README.md) | [中文](README_CN.md) ]
|
||||
</div>
|
||||
|
||||
# EasyConfiguration
|
||||
# configured _(config framework)_
|
||||
|
||||
[](https://github.com/CarmJos/EasyConfiguration/releases)
|
||||
[](https://www.gnu.org/licenses/lgpl-3.0.html)
|
||||
[](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml)
|
||||
[](https://www.codefactor.io/repository/github/carmjos/easyconfiguration)
|
||||

|
||||

|
||||
<img src=".doc/images/logo-bg.svg" width="150px" alt="logo" align="right" style="float: right"/>
|
||||
|
||||
**Easy _(to make)_ Configurations!**
|
||||
_**"Once set, Simple get."**_
|
||||
|
||||
A simple, easy-to-use and universal solution for managing configuration files.
|
||||
Enjoy the ease of use with customizable formats for loading, reading, and updating your configuration files.
|
||||
A simple, easy-to-use and universal solution for managing, loading, reading,
|
||||
and updating configuration files.
|
||||
|
||||
Supported **JSON**, **YAML**, **Hocon**, **TOML**, **SQL**, **MongoDB**... and much more!
|
||||
|
||||
## Features & Advantages
|
||||
|
||||
@@ -35,13 +35,14 @@ format.
|
||||
|
||||
## 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).
|
||||
|
||||
### Code Samples
|
||||
### Preview
|
||||
|
||||
To quickly demonstrate the applicability of the project, here are a few practical demonstrations:
|
||||
|
||||
- [Database configuration.](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java)
|
||||
- [Demonstration of all types of configuration instance classes.](demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java)
|
||||
|
||||
@@ -49,6 +50,7 @@ Check out all code demonstrations [HERE](demo/src/main/java/cc/carm/lib/configur
|
||||
For more examples, see the [Development Guide](.doc/README.md).
|
||||
|
||||
```java
|
||||
|
||||
@ConfigPath(root = true)
|
||||
@HeaderComments("Configurations for sample")
|
||||
public interface SampleConfig extends Configuration {
|
||||
@@ -95,9 +97,9 @@ public class Sample {
|
||||
// 2. Initialize the configuration classes or instances.
|
||||
holder.initialize(SampleConfig.class);
|
||||
// 3. Enjoy using the configuration!
|
||||
System.out.println("Enabled? -> " + SampleConfig.ENABLED.resolve());
|
||||
System.out.println("Enabled? -> " + SampleConfig.ENABLED.resolve()); // true
|
||||
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.
|
||||
|
||||
System.out.println("Your name is " + SampleConfig.INFO.NAME.resolve() + " (age=" + SampleConfig.INFO.AGE.resolve() + ")!");
|
||||
@@ -148,9 +150,9 @@ info:
|
||||
|
||||
<repository>
|
||||
<!-- Using GitHub dependencies for real-time updates, configuration required (recommended). -->
|
||||
<id>EasyConfiguration</id>
|
||||
<id>configured</id>
|
||||
<name>GitHub Packages</name>
|
||||
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url>
|
||||
<url>https://maven.pkg.github.com/CarmJos/configured</url>
|
||||
</repository>
|
||||
|
||||
</repositories>
|
||||
@@ -169,7 +171,7 @@ info:
|
||||
<!-- Basic implementation part, requiring custom implementation of “Provider” and “Wrapper”. -->
|
||||
<dependency>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-core</artifactId>
|
||||
<artifactId>configured-core</artifactId>
|
||||
<version>[LATEST RELEASE]</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
@@ -177,7 +179,7 @@ info:
|
||||
<!-- YAML file-based implementation, compatible with all Java environments. -->
|
||||
<dependency>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-yaml</artifactId>
|
||||
<artifactId>configured-yaml</artifactId>
|
||||
<version>[LATEST RELEASE]</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
@@ -185,7 +187,7 @@ info:
|
||||
<!-- JSON file-based implementation, compatible with all Java environments. -->
|
||||
<dependency>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-gson</artifactId>
|
||||
<artifactId>configured-gson</artifactId>
|
||||
<version>[LATEST RELEASE]</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
@@ -208,7 +210,7 @@ repositories {
|
||||
mavenCentral()
|
||||
|
||||
// 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 {
|
||||
|
||||
// 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.
|
||||
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.
|
||||
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)
|
||||
|
||||
EasyConfiguration for MineCraft!
|
||||
configured for MineCraft!
|
||||
Easily manage configurations on MineCraft-related server platforms.
|
||||
|
||||
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.
|
||||
|
||||
[](https://www.jetbrains.com/?from=https://github.com/CarmJos/EasyConfiguration)
|
||||
[](https://www.jetbrains.com/?from=https://github.com/CarmJos/configured)
|
||||
|
||||
Many thanks to [ArtformGames](https://github.com/ArtformGames) for their
|
||||
strong support and active contribution to this project!
|
||||
|
||||
+31
-32
@@ -1,29 +1,28 @@
|
||||
```text
|
||||
____ _____ ____ __ _
|
||||
/ __/__ ____ __ __ / ___/__ ___ / _(_)__ ___ _________ _/ /_(_)__ ___
|
||||
/ _// _ `(_-</ // / / /__/ _ \/ _ \/ _/ / _ `/ // / __/ _ `/ __/ / _ \/ _ \
|
||||
/___/\_,_/___/\_, / \___/\___/_//_/_//_/\_, /\_,_/_/ \_,_/\__/_/\___/_//_/
|
||||
/___/ /___/
|
||||
```
|
||||
<div align=center>
|
||||
<img src=".doc/images/banner.png" alt="Banner"/>
|
||||
|
||||
[](https://github.com/CarmJos/configured/releases)
|
||||
[](https://www.gnu.org/licenses/lgpl-3.0.html)
|
||||
[](https://github.com/CarmJos/configured/actions/workflows/maven.yml)
|
||||
[](https://www.codefactor.io/repository/github/carmjos/configured)
|
||||

|
||||

|
||||
|
||||
README LANGUAGES [ [English](README.md) | [**中文**](README_CN.md) ]
|
||||
|
||||
# EasyConfiguration
|
||||
</div>
|
||||
|
||||
[](https://github.com/CarmJos/EasyConfiguration/releases)
|
||||
[](https://www.gnu.org/licenses/lgpl-3.0.html)
|
||||
[](https://github.com/CarmJos/EasyConfiguration/actions/workflows/maven.yml)
|
||||
[](https://www.codefactor.io/repository/github/carmjos/easyconfiguration)
|
||||

|
||||

|
||||
# configured _(配置文件框架)_
|
||||
|
||||
**轻松(做)配置!**
|
||||
<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)
|
||||
请 [点击这里](https://CarmJos.github.io/EasyConfiguration) 。
|
||||
请 [点击这里](https://CarmJos.github.io/configured) 。
|
||||
|
||||
### 示例代码
|
||||
|
||||
@@ -142,9 +141,9 @@ info:
|
||||
|
||||
<repository>
|
||||
<!--采用github依赖库,实时更新,但需要配置 (推荐) -->
|
||||
<id>EasyConfiguration</id>
|
||||
<id>configured</id>
|
||||
<name>GitHub Packages</name>
|
||||
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url>
|
||||
<url>https://maven.pkg.github.com/CarmJos/configured</url>
|
||||
</repository>
|
||||
|
||||
<repository>
|
||||
@@ -170,7 +169,7 @@ info:
|
||||
<!--基础实现部分,需要自行实现“Provider”与“Wrapper”。-->
|
||||
<dependency>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-core</artifactId>
|
||||
<artifactId>configured-core</artifactId>
|
||||
<version>[LATEST RELEASE]</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
@@ -178,7 +177,7 @@ info:
|
||||
<!--基于YAML文件的实现版本,可用于全部Java环境。-->
|
||||
<dependency>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-yaml</artifactId>
|
||||
<artifactId>configured-yaml</artifactId>
|
||||
<version>[LATEST RELEASE]</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
@@ -187,21 +186,21 @@ info:
|
||||
<!--需要注意的是,JSON不支持文件注释。-->
|
||||
<dependency>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-gson</artifactId>
|
||||
<artifactId>configured-gson</artifactId>
|
||||
<version>[LATEST RELEASE]</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-hocon</artifactId>
|
||||
<artifactId>configured-hocon</artifactId>
|
||||
<version>[LATEST RELEASE]</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-sql</artifactId>
|
||||
<artifactId>configured-sql</artifactId>
|
||||
<version>[LATEST RELEASE]</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
@@ -224,7 +223,7 @@ repositories {
|
||||
mavenCentral()
|
||||
|
||||
// 采用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/' }
|
||||
@@ -241,18 +240,18 @@ repositories {
|
||||
dependencies {
|
||||
|
||||
//基础实现部分,需要自行实现“Provider”与“Wrapper”。
|
||||
api "cc.carm.lib:easyconfiguration-core:[LATEST RELEASE]"
|
||||
api "cc.carm.lib:configured-core:[LATEST RELEASE]"
|
||||
|
||||
//基于YAML文件的实现版本,可用于全部Java环境。
|
||||
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]"
|
||||
api "cc.carm.lib:configured-yaml:[LATEST RELEASE]"
|
||||
|
||||
//基于JSON文件的实现版本,可用于全部Java环境。
|
||||
//需要注意的是,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 )
|
||||
|
||||
EasyConfiguration for MineCraft!
|
||||
configured for MineCraft!
|
||||
开始在 MineCraft 相关服务器平台上轻松(做)配置吧!
|
||||
|
||||
目前支持 BungeeCord, Bukkit(Spigot) 服务端,后续将支持更多平台。
|
||||
@@ -276,7 +275,7 @@ EasyConfiguration for MineCraft!
|
||||
|
||||
万分感谢 Jetbrains 为我们提供了从事此项目和其他开源项目的许可!
|
||||
|
||||
[](https://www.jetbrains.com/?from=https://github.com/CarmJos/EasyConfiguration)
|
||||
[](https://www.jetbrains.com/?from=https://github.com/CarmJos/configured)
|
||||
|
||||
万分感谢来自 [ArtformGames](https://github.com/ArtformGames) 对本项目的大力支持与积极贡献!
|
||||
|
||||
|
||||
+3
-3
@@ -3,9 +3,9 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<artifactId>configured-parent</artifactId>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<version>4.0.9</version>
|
||||
<version>4.1.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<properties>
|
||||
@@ -15,7 +15,7 @@
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
</properties>
|
||||
|
||||
<artifactId>easyconfiguration-core</artifactId>
|
||||
<artifactId>configured-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -15,6 +15,7 @@ public class ValueAdapter<TYPE>
|
||||
implements ValueSerializer<TYPE>, ValueParser<TYPE> {
|
||||
|
||||
protected final @NotNull ValueType<TYPE> type;
|
||||
|
||||
protected @Nullable ValueSerializer<TYPE> serializer;
|
||||
protected @Nullable ValueParser<TYPE> deserializer;
|
||||
|
||||
@@ -53,13 +54,21 @@ public class ValueAdapter<TYPE>
|
||||
}
|
||||
|
||||
@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");
|
||||
return serializer.serialize(holder, type, value);
|
||||
}
|
||||
|
||||
@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");
|
||||
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.source.ConfigurationHolder;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
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;
|
||||
ValueAdapter<T> existing = adapterOf(type);
|
||||
if (existing != null) {
|
||||
@@ -82,7 +83,9 @@ public class ValueAdapterRegistry {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> @Nullable ValueAdapter<T> adapterOf(@NotNull ValueType<T> type) {
|
||||
ValueAdapter<?> matched = adapters.stream().filter(adapter -> adapter.type().equals(type)).findFirst().orElse(null);
|
||||
ValueAdapter<?> matched = adapters.stream()
|
||||
.filter(adapter -> adapter.type().equals(type))
|
||||
.findFirst().orElse(null);
|
||||
if (matched != null) return (ValueAdapter<T>) matched;
|
||||
|
||||
// If no adapter found, try to find the adapter for the super type
|
||||
@@ -99,12 +102,10 @@ public class ValueAdapterRegistry {
|
||||
return adapterOf(ValueType.of(type));
|
||||
}
|
||||
|
||||
@Contract("_,_,null -> null")
|
||||
public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull Class<T> type, @Nullable Object source) throws Exception {
|
||||
return deserialize(holder, ValueType.of(type), source);
|
||||
}
|
||||
|
||||
@Contract("_,_,null -> null")
|
||||
public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<T> type, @Nullable Object source) throws Exception {
|
||||
if (source == null) return null; // Null check
|
||||
if (type.isInstance(source)) return type.cast(source); // Not required to deserialize
|
||||
@@ -113,7 +114,7 @@ public class ValueAdapterRegistry {
|
||||
return adapter.parse(holder, type, source);
|
||||
}
|
||||
|
||||
@Contract("_,null -> null")
|
||||
@Nullable
|
||||
public <T> Object serialize(@NotNull ConfigurationHolder<?> holder, @Nullable T value) throws Exception {
|
||||
if (value == null) return null; // Null check
|
||||
ValueType<T> type = ValueType.of(value);
|
||||
|
||||
@@ -2,6 +2,7 @@ package cc.carm.lib.configuration.adapter;
|
||||
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Value deserializer, convert base data to target value.
|
||||
@@ -11,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
@FunctionalInterface
|
||||
public interface ValueParser<TYPE> {
|
||||
|
||||
TYPE parse(
|
||||
@Nullable TYPE parse(
|
||||
@NotNull ConfigurationHolder<?> holder,
|
||||
@NotNull ValueType<? super TYPE> type, @NotNull Object data
|
||||
) throws Exception;
|
||||
|
||||
@@ -2,6 +2,7 @@ package cc.carm.lib.configuration.adapter;
|
||||
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Value serializer, convert target value to base data.
|
||||
@@ -11,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
@FunctionalInterface
|
||||
public interface ValueSerializer<TYPE> {
|
||||
|
||||
Object serialize(
|
||||
@Nullable Object serialize(
|
||||
@NotNull ConfigurationHolder<?> holder,
|
||||
@NotNull ValueType<? super TYPE> type, @NotNull TYPE value
|
||||
) throws Exception;
|
||||
|
||||
@@ -5,7 +5,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
|
||||
@@ -5,6 +5,8 @@ import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.source.section.ConfigureSection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapter.*;
|
||||
|
||||
public interface StandardAdapters {
|
||||
@@ -17,6 +19,12 @@ public interface StandardAdapters {
|
||||
|
||||
@NotNull ValueAdapter<Enum<?>> ENUMS = PrimitiveAdapter.ofEnum();
|
||||
|
||||
@NotNull ValueAdapter<UUID> UUID = new ValueAdapter<>(
|
||||
ValueType.of(UUID.class),
|
||||
(provider, type, value) -> value.toString(),
|
||||
(provider, type, value) -> java.util.UUID.fromString(value.toString())
|
||||
);
|
||||
|
||||
@NotNull ValueAdapter<ConfigureSection> SECTIONS = new ValueAdapter<>(
|
||||
ValueType.of(ConfigureSection.class),
|
||||
(provider, type, value) -> value,
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
package cc.carm.lib.configuration.builder;
|
||||
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.function.DataValidator;
|
||||
import cc.carm.lib.configuration.function.ValueValidator;
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
|
||||
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
|
||||
import cc.carm.lib.configuration.value.ConfigValue;
|
||||
import cc.carm.lib.configuration.value.ValueManifest;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.NotNullByDefault;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@NotNullByDefault
|
||||
public abstract class AbstractConfigBuilder<
|
||||
TYPE, RESULT extends ConfigValue<TYPE>, HOLDER extends ConfigurationHolder<?>,
|
||||
SELF extends AbstractConfigBuilder<TYPE, RESULT, HOLDER, SELF>
|
||||
TYPE, UNIT, RESULT extends ConfigValue<TYPE, UNIT>, HOLDER extends ConfigurationHolder<?>,
|
||||
SELF extends AbstractConfigBuilder<TYPE, UNIT, RESULT, HOLDER, SELF>
|
||||
> {
|
||||
|
||||
protected final Class<? super HOLDER> providerClass;
|
||||
@@ -24,6 +29,7 @@ public abstract class AbstractConfigBuilder<
|
||||
protected @Nullable HOLDER holder;
|
||||
protected @Nullable String path;
|
||||
|
||||
protected @NotNull ValueValidator<UNIT> valueValidator = ValueValidator.none();
|
||||
protected @NotNull Supplier<@Nullable TYPE> defaultValueSupplier = () -> null;
|
||||
protected @NotNull BiConsumer<ConfigurationHolder<?>, String> initializer = (h, p) -> {
|
||||
};
|
||||
@@ -37,54 +43,121 @@ public abstract class AbstractConfigBuilder<
|
||||
return type;
|
||||
}
|
||||
|
||||
protected abstract @NotNull SELF self();
|
||||
protected abstract SELF self();
|
||||
|
||||
public abstract @NotNull RESULT build();
|
||||
|
||||
public @NotNull SELF holder(@Nullable HOLDER holder) {
|
||||
public SELF holder(@Nullable HOLDER holder) {
|
||||
this.holder = holder;
|
||||
return self();
|
||||
}
|
||||
|
||||
public @NotNull SELF path(@Nullable String path) {
|
||||
public SELF path(@Nullable String path) {
|
||||
this.path = path;
|
||||
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;
|
||||
return self();
|
||||
}
|
||||
|
||||
public @NotNull SELF append(@NotNull BiConsumer<ConfigurationHolder<?>, String> initializer) {
|
||||
public SELF append(@NotNull BiConsumer<ConfigurationHolder<?>, String> 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));
|
||||
}
|
||||
|
||||
public @NotNull SELF defaults(@Nullable TYPE defaultValue) {
|
||||
public SELF defaults(@Nullable TYPE defaultValue) {
|
||||
return defaults(() -> defaultValue);
|
||||
}
|
||||
|
||||
public @NotNull SELF defaults(@NotNull Supplier<@Nullable TYPE> supplier) {
|
||||
public SELF defaults(@NotNull Supplier<@Nullable TYPE> supplier) {
|
||||
this.defaultValueSupplier = supplier;
|
||||
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)));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
protected @NotNull ValueManifest<TYPE> buildManifest() {
|
||||
protected @NotNull ValueManifest<TYPE, UNIT> buildManifest() {
|
||||
return new ValueManifest<>(
|
||||
type(), this.defaultValueSupplier, this.initializer,
|
||||
this.holder, this.path
|
||||
type(), this.defaultValueSupplier, this.valueValidator,
|
||||
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.value.ConfigValue;
|
||||
|
||||
public abstract class CommonConfigBuilder<TYPE, RESULT extends ConfigValue<TYPE>, SELF extends CommonConfigBuilder<TYPE, RESULT, SELF>>
|
||||
extends AbstractConfigBuilder<TYPE, RESULT, ConfigurationHolder<?>, SELF> {
|
||||
public abstract class CommonConfigBuilder<
|
||||
TYPE, UNIT,
|
||||
RESULT extends ConfigValue<TYPE, UNIT>,
|
||||
SELF extends CommonConfigBuilder<TYPE, UNIT, RESULT, SELF>
|
||||
> extends AbstractConfigBuilder<TYPE, UNIT, RESULT, ConfigurationHolder<?>, SELF> {
|
||||
|
||||
protected CommonConfigBuilder(ValueType<TYPE> type) {
|
||||
super(ConfigurationHolder.class, type);
|
||||
|
||||
+18
-20
@@ -4,7 +4,7 @@ import cc.carm.lib.configuration.adapter.ValueAdapter;
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.builder.CommonConfigBuilder;
|
||||
import cc.carm.lib.configuration.function.DataFunction;
|
||||
import cc.carm.lib.configuration.function.ValueConsumer;
|
||||
import cc.carm.lib.configuration.function.ValueComposer;
|
||||
import cc.carm.lib.configuration.function.ValueHandler;
|
||||
import cc.carm.lib.configuration.source.section.ConfigureSection;
|
||||
import cc.carm.lib.configuration.value.ConfigValue;
|
||||
@@ -14,47 +14,45 @@ import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class AbstractSectionBuilder<
|
||||
TYPE, PARAM,
|
||||
RESULT extends ConfigValue<TYPE>,
|
||||
SELF extends AbstractSectionBuilder<TYPE, PARAM, RESULT, SELF>
|
||||
> extends CommonConfigBuilder<TYPE, RESULT, SELF> {
|
||||
TYPE, UNIT,
|
||||
RESULT extends ConfigValue<TYPE, UNIT>,
|
||||
SELF extends AbstractSectionBuilder<TYPE, UNIT, 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<PARAM, ? extends Map<String, Object>> serializer;
|
||||
protected @NotNull ValueHandler<ConfigureSection, UNIT> parser;
|
||||
protected @NotNull ValueHandler<UNIT, ? extends Map<String, Object>> serializer;
|
||||
|
||||
protected AbstractSectionBuilder(@NotNull ValueType<TYPE> type, @NotNull ValueType<PARAM> paramType,
|
||||
@NotNull ValueHandler<ConfigureSection, PARAM> parser,
|
||||
@NotNull ValueHandler<PARAM, ? extends Map<String, Object>> serializer) {
|
||||
protected AbstractSectionBuilder(@NotNull ValueType<TYPE> type, @NotNull ValueType<UNIT> paramType,
|
||||
@NotNull ValueHandler<ConfigureSection, UNIT> parser,
|
||||
@NotNull ValueHandler<UNIT, ? extends Map<String, Object>> serializer) {
|
||||
super(type);
|
||||
this.paramType = paramType;
|
||||
this.parser = parser;
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
public @NotNull SELF parse(@NotNull DataFunction<ConfigureSection, PARAM> valueParser) {
|
||||
public @NotNull SELF parse(@NotNull DataFunction<ConfigureSection, UNIT> valueParser) {
|
||||
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;
|
||||
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;
|
||||
return self();
|
||||
}
|
||||
|
||||
public @NotNull SELF serialize(@NotNull DataFunction<PARAM, ? extends Map<String, Object>> serializer) {
|
||||
return serialize((p, value) -> {
|
||||
return serializer.handle(value);
|
||||
});
|
||||
public @NotNull SELF serialize(@NotNull DataFunction<UNIT, ? extends Map<String, Object>> serializer) {
|
||||
return serialize((p, value) -> 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) -> {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
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)
|
||||
.parser((p, type, data) -> {
|
||||
ConfigureSection section = p.deserialize(ConfigureSection.class, data);
|
||||
|
||||
+14
-14
@@ -9,19 +9,19 @@ import cc.carm.lib.configuration.value.ConfigValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class AbstractSourceBuilder<
|
||||
V, SOURCE, PARAM, RESULT extends ConfigValue<V>,
|
||||
SELF extends AbstractSourceBuilder<V, SOURCE, PARAM, RESULT, SELF>
|
||||
> extends CommonConfigBuilder<V, RESULT, SELF> {
|
||||
V, SOURCE, UNIT, RESULT extends ConfigValue<V, UNIT>,
|
||||
SELF extends AbstractSourceBuilder<V, SOURCE, UNIT, RESULT, SELF>
|
||||
> extends CommonConfigBuilder<V, UNIT, RESULT, SELF> {
|
||||
|
||||
protected final @NotNull ValueType<SOURCE> sourceType;
|
||||
protected final @NotNull ValueType<PARAM> paramType;
|
||||
protected @NotNull ValueHandler<SOURCE, PARAM> valueParser;
|
||||
protected @NotNull ValueHandler<PARAM, SOURCE> valueSerializer;
|
||||
protected final @NotNull ValueType<UNIT> paramType;
|
||||
protected @NotNull ValueHandler<SOURCE, UNIT> valueParser;
|
||||
protected @NotNull ValueHandler<UNIT, SOURCE> valueSerializer;
|
||||
|
||||
protected AbstractSourceBuilder(@NotNull ValueType<V> type,
|
||||
@NotNull ValueType<SOURCE> sourceType, @NotNull ValueType<PARAM> paramType,
|
||||
@NotNull ValueHandler<SOURCE, PARAM> parser,
|
||||
@NotNull ValueHandler<PARAM, SOURCE> serializer) {
|
||||
@NotNull ValueType<SOURCE> sourceType, @NotNull ValueType<UNIT> paramType,
|
||||
@NotNull ValueHandler<SOURCE, UNIT> parser,
|
||||
@NotNull ValueHandler<UNIT, SOURCE> serializer) {
|
||||
super(type);
|
||||
this.sourceType = sourceType;
|
||||
this.paramType = paramType;
|
||||
@@ -29,25 +29,25 @@ public abstract class AbstractSourceBuilder<
|
||||
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));
|
||||
}
|
||||
|
||||
public @NotNull SELF parse(@NotNull ValueHandler<SOURCE, PARAM> parser) {
|
||||
public @NotNull SELF parse(@NotNull ValueHandler<SOURCE, UNIT> parser) {
|
||||
this.valueParser = parser;
|
||||
return self();
|
||||
}
|
||||
|
||||
public @NotNull SELF serialize(@NotNull ValueHandler<PARAM, SOURCE> serializer) {
|
||||
public @NotNull SELF serialize(@NotNull ValueHandler<UNIT, SOURCE> serializer) {
|
||||
this.valueSerializer = serializer;
|
||||
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));
|
||||
}
|
||||
|
||||
protected ValueAdapter<PARAM> buildAdapter() {
|
||||
protected ValueAdapter<UNIT> buildAdapter() {
|
||||
return new ValueAdapter<>(this.paramType)
|
||||
.parser((holder, type, 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 java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
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;
|
||||
|
||||
@@ -32,6 +34,14 @@ public class SectionListBuilder<V> extends AbstractSectionBuilder<List<V>, V, Co
|
||||
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) {
|
||||
this.constructor = constructor;
|
||||
return this;
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class SourceListBuilder<SOURCE, V>
|
||||
@@ -34,6 +35,23 @@ public class SourceListBuilder<SOURCE, V>
|
||||
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
|
||||
protected @NotNull SourceListBuilder<SOURCE, V> self() {
|
||||
return this;
|
||||
|
||||
@@ -3,10 +3,7 @@ package cc.carm.lib.configuration.builder.map;
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ConfigMapCreator<K, V> {
|
||||
@@ -45,4 +42,8 @@ public class ConfigMapCreator<K, V> {
|
||||
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;
|
||||
|
||||
public class SectionMapBuilder<MAP extends Map<K, V>, K, V>
|
||||
extends AbstractSectionBuilder<
|
||||
Map<K, V>, V, ConfiguredMap<K, V>,
|
||||
SectionMapBuilder<MAP, K, V>
|
||||
> {
|
||||
extends AbstractSectionBuilder<Map<K, V>, V, ConfiguredMap<K, V>, SectionMapBuilder<MAP, K, V>> {
|
||||
|
||||
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() {
|
||||
return new ValueAdapter<>(this.keyType)
|
||||
.parser((holder, type, data) -> {
|
||||
|
||||
@@ -13,10 +13,7 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class SourceMapBuilder<MAP extends Map<K, V>, SOURCE, K, V>
|
||||
extends AbstractSourceBuilder<
|
||||
Map<K, V>, SOURCE, V, ConfiguredMap<K, V>,
|
||||
SourceMapBuilder<MAP, SOURCE, K, V>
|
||||
> {
|
||||
extends AbstractSourceBuilder<Map<K, V>, SOURCE, V, ConfiguredMap<K, V>, SourceMapBuilder<MAP, SOURCE, K, V>> {
|
||||
|
||||
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) {
|
||||
return parseKey((holder, data) -> keyParser.handle(data));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package cc.carm.lib.configuration.builder.value;
|
||||
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.builder.impl.AbstractSectionBuilder;
|
||||
import cc.carm.lib.configuration.function.ValueHandler;
|
||||
import cc.carm.lib.configuration.source.section.ConfigureSection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -6,7 +6,8 @@ import cc.carm.lib.configuration.function.ValueHandler;
|
||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class SourceValueBuilder<S, V> extends AbstractSourceBuilder<V, S, V, ConfiguredValue<V>, SourceValueBuilder<S, V>> {
|
||||
public class SourceValueBuilder<S, V>
|
||||
extends AbstractSourceBuilder<V, S, V, ConfiguredValue<V>, SourceValueBuilder<S, V>> {
|
||||
|
||||
|
||||
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.strandard.StandardAdapters;
|
||||
import cc.carm.lib.configuration.function.ConfigExceptionHandler;
|
||||
import cc.carm.lib.configuration.function.DataFunction;
|
||||
import cc.carm.lib.configuration.function.ValueValidator;
|
||||
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
|
||||
import cc.carm.lib.configuration.source.loader.PathGenerator;
|
||||
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
|
||||
@@ -33,15 +35,17 @@ public abstract class ConfigurationFactory<
|
||||
SELF
|
||||
> {
|
||||
|
||||
protected ValueAdapterRegistry adapters = new ValueAdapterRegistry();
|
||||
protected ConfigurationOptionHolder options = new ConfigurationOptionHolder();
|
||||
protected @NotNull ValueAdapterRegistry adapters = new ValueAdapterRegistry();
|
||||
protected @NotNull ConfigurationOptionHolder options = new ConfigurationOptionHolder();
|
||||
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.SECTIONS);
|
||||
this.adapters.register(StandardAdapters.ENUMS);
|
||||
this.adapters.register(StandardAdapters.UUID);
|
||||
}
|
||||
|
||||
protected abstract SELF self();
|
||||
@@ -146,6 +150,11 @@ public abstract class ConfigurationFactory<
|
||||
return self();
|
||||
}
|
||||
|
||||
public SELF exceptionally(@NotNull ConfigExceptionHandler handler) {
|
||||
this.exceptionHandler = handler;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Supply the base path generator for this configuration holder
|
||||
*
|
||||
@@ -153,9 +162,7 @@ public abstract class ConfigurationFactory<
|
||||
* @return this
|
||||
*/
|
||||
public SELF pathGenerator(PathGenerator generator) {
|
||||
return initializer(loader -> {
|
||||
loader.pathGenerator(generator);
|
||||
});
|
||||
return initializer(loader -> loader.pathGenerator(generator));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,6 +181,19 @@ public abstract class ConfigurationFactory<
|
||||
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.
|
||||
*
|
||||
|
||||
@@ -3,6 +3,7 @@ package cc.carm.lib.configuration.source;
|
||||
import cc.carm.lib.configuration.Configuration;
|
||||
import cc.carm.lib.configuration.adapter.ValueAdapterRegistry;
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.function.ConfigExceptionHandler;
|
||||
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
|
||||
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
|
||||
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
|
||||
@@ -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.value.ConfigValue;
|
||||
import cc.carm.lib.configuration.value.ValueManifest;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnmodifiableView;
|
||||
@@ -31,14 +31,25 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
|
||||
|
||||
protected final @NotNull ConfigurationInitializer initializer;
|
||||
|
||||
protected @NotNull ConfigExceptionHandler exceptionHandler;
|
||||
|
||||
public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters,
|
||||
@NotNull ConfigurationOptionHolder options,
|
||||
@NotNull Map<String, ConfigurationMetaHolder> metadata,
|
||||
@NotNull ConfigurationInitializer initializer) {
|
||||
this(adapters, options, metadata, initializer, ConfigExceptionHandler.print());
|
||||
}
|
||||
|
||||
public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters,
|
||||
@NotNull ConfigurationOptionHolder options,
|
||||
@NotNull Map<String, ConfigurationMetaHolder> metadata,
|
||||
@NotNull ConfigurationInitializer initializer,
|
||||
@NotNull ConfigExceptionHandler exceptionHandler) {
|
||||
this.initializer = initializer;
|
||||
this.adapters = adapters;
|
||||
this.options = options;
|
||||
this.metadata = metadata;
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
public abstract @NotNull SOURCE config();
|
||||
@@ -75,7 +86,7 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
|
||||
|
||||
@NotNull
|
||||
@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<>();
|
||||
for (Map.Entry<String, ConfigurationMetaHolder> entry : this.metadata.entrySet()) {
|
||||
M data = entry.getValue().get(type);
|
||||
@@ -86,7 +97,7 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
|
||||
|
||||
@NotNull
|
||||
@UnmodifiableView
|
||||
public Map<String, ConfigValue<?>> registeredValues() {
|
||||
public Map<String, ConfigValue<?, ?>> registeredValues() {
|
||||
return extractMetadata(StandardMeta.VALUE);
|
||||
}
|
||||
|
||||
@@ -98,17 +109,17 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
|
||||
return initializer;
|
||||
}
|
||||
|
||||
@Contract("_,null -> null")
|
||||
@Nullable
|
||||
public <T> T deserialize(@NotNull Class<T> type, @Nullable Object source) throws Exception {
|
||||
return adapters().deserialize(this, type, source);
|
||||
}
|
||||
|
||||
@Contract("_,null -> null")
|
||||
@Nullable
|
||||
public <T> T deserialize(@NotNull ValueType<T> type, @Nullable Object source) throws Exception {
|
||||
return adapters().deserialize(this, type, source);
|
||||
}
|
||||
|
||||
@Contract("null -> null")
|
||||
@Nullable
|
||||
public <T> Object serialize(@Nullable T value) throws Exception {
|
||||
return adapters().serialize(this, value);
|
||||
}
|
||||
@@ -117,7 +128,7 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
|
||||
try {
|
||||
initializer.initialize(this, configClass);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throwing(configClass.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,12 +136,20 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
|
||||
try {
|
||||
initializer.initialize(this, config);
|
||||
} 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);
|
||||
}
|
||||
|
||||
public void throwing(@NotNull String path, @NotNull Throwable e) {
|
||||
this.exceptionHandler.handle(path, e);
|
||||
}
|
||||
|
||||
public void exceptionally(@NotNull ConfigExceptionHandler handler) {
|
||||
this.exceptionHandler = handler;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
public interface ConfigInitializeHandler<T, V> {
|
||||
|
||||
static <T, V> ConfigInitializeHandler<T, V> start() {
|
||||
return (provider, path, value, instace) -> {
|
||||
return (provider, path, value, instance) -> {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+19
-10
@@ -1,6 +1,7 @@
|
||||
package cc.carm.lib.configuration.source.loader;
|
||||
|
||||
import cc.carm.lib.configuration.Configuration;
|
||||
import cc.carm.lib.configuration.function.ValueValidator;
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
|
||||
import cc.carm.lib.configuration.source.meta.StandardMeta;
|
||||
@@ -21,7 +22,7 @@ import java.util.function.Function;
|
||||
public class ConfigurationInitializer {
|
||||
|
||||
protected @NotNull PathGenerator pathGenerator;
|
||||
protected @NotNull ConfigInitializeHandler<Field, ConfigValue<?>> valueInitializer;
|
||||
protected @NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> valueInitializer;
|
||||
protected @NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer;
|
||||
|
||||
public ConfigurationInitializer() {
|
||||
@@ -29,7 +30,7 @@ public class ConfigurationInitializer {
|
||||
}
|
||||
|
||||
public ConfigurationInitializer(@NotNull PathGenerator pathGenerator,
|
||||
@NotNull ConfigInitializeHandler<Field, ConfigValue<?>> valueInitializer,
|
||||
@NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> valueInitializer,
|
||||
@NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer) {
|
||||
this.pathGenerator = pathGenerator;
|
||||
this.valueInitializer = valueInitializer;
|
||||
@@ -44,11 +45,11 @@ public class ConfigurationInitializer {
|
||||
return pathGenerator;
|
||||
}
|
||||
|
||||
public ConfigInitializeHandler<Field, ConfigValue<?>> fieldInitializer() {
|
||||
public ConfigInitializeHandler<Field, ConfigValue<?, ?>> fieldInitializer() {
|
||||
return valueInitializer;
|
||||
}
|
||||
|
||||
public void fieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?>> fieldInitializer) {
|
||||
public void fieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?, ?>> fieldInitializer) {
|
||||
this.valueInitializer = fieldInitializer;
|
||||
}
|
||||
|
||||
@@ -60,7 +61,7 @@ public class ConfigurationInitializer {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -95,6 +96,14 @@ public class ConfigurationInitializer {
|
||||
registerFieldAnnotation(annotation, metadata, extractor);
|
||||
}
|
||||
|
||||
public <A extends Annotation> void registerValidAnnotation(@NotNull Class<A> annotation,
|
||||
@NotNull Function<A, ValueValidator<Object>> builder) {
|
||||
appendFieldInitializer((holder, path, field, instance) -> {
|
||||
A data = field.getAnnotation(annotation);
|
||||
if (data == null) return;
|
||||
instance.validate((h, t) -> builder.apply(data).validate(h, t));
|
||||
});
|
||||
}
|
||||
|
||||
public @Nullable String getFieldPath(@NotNull ConfigurationHolder<?> holder, @Nullable String parentPath, @NotNull Field field) {
|
||||
return pathGenerator.getFieldPath(holder, parentPath, field);
|
||||
@@ -125,7 +134,7 @@ public class ConfigurationInitializer {
|
||||
try {
|
||||
this.classInitializer.whenInitialize(holder, path, root.getClass(), root);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
holder.throwing(path, e);
|
||||
}
|
||||
Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(holder, root, field, path));
|
||||
}
|
||||
@@ -142,7 +151,7 @@ public class ConfigurationInitializer {
|
||||
try {
|
||||
this.classInitializer.whenInitialize(holder, path, (Class<? extends Configuration>) clazz, configField);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
holder.throwing(path, e);
|
||||
}
|
||||
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
@@ -163,9 +172,9 @@ public class ConfigurationInitializer {
|
||||
field.setAccessible(true);
|
||||
Object object = field.get(source);
|
||||
//
|
||||
if (object instanceof ConfigValue<?>) {
|
||||
if (object instanceof ConfigValue<?, ?>) {
|
||||
// 目标是 ConfigValue 实例,进行具体的初始化注入
|
||||
ConfigValue<?> value = (ConfigValue<?>) object;
|
||||
ConfigValue<?, ?> value = (ConfigValue<?, ?>) object;
|
||||
String path = getFieldPath(holder, parent, field);
|
||||
if (path == null) return;
|
||||
value.initialize(holder, path);
|
||||
@@ -176,7 +185,7 @@ public class ConfigurationInitializer {
|
||||
try {
|
||||
this.valueInitializer.whenInitialize(holder, path, field, value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
holder.throwing(path, e);
|
||||
}
|
||||
if (holder.option(StandardOptions.PRELOAD)) {
|
||||
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.
|
||||
*/
|
||||
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 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cc.carm.lib.configuration.value;
|
||||
|
||||
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.meta.ConfigurationMetaHolder;
|
||||
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.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 @Nullable ConfigurationHolder<?> holder;
|
||||
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) {
|
||||
this(type, () -> null, EMPTY_INITIALIZER, null, null);
|
||||
public ValueManifest(@NotNull ValueType<TYPE> type) {
|
||||
this(type, () -> null, ValueValidator.none(), EMPTY_INITIALIZER, null, null);
|
||||
}
|
||||
|
||||
public ValueManifest(@NotNull T defaultValue) {
|
||||
public ValueManifest(@NotNull TYPE defaultValue) {
|
||||
this(ValueType.of(defaultValue), () -> defaultValue);
|
||||
}
|
||||
|
||||
public ValueManifest(@NotNull ValueType<T> type, @NotNull Supplier<@Nullable T> defaultSupplier) {
|
||||
this(type, defaultSupplier, EMPTY_INITIALIZER, null, null);
|
||||
public ValueManifest(@NotNull ValueType<TYPE> type, @NotNull Supplier<@Nullable TYPE> defaultSupplier) {
|
||||
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) {
|
||||
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,
|
||||
@Nullable ConfigurationHolder<?> holder, @Nullable String path) {
|
||||
this.type = type;
|
||||
this.validator = validator;
|
||||
this.initializer = initializer;
|
||||
this.defaultSupplier = defaultSupplier;
|
||||
this.holder = holder;
|
||||
@@ -49,8 +61,8 @@ public class ValueManifest<T> {
|
||||
initialize();
|
||||
}
|
||||
|
||||
protected ValueManifest(@NotNull ValueManifest<T> manifest) {
|
||||
this(manifest.type, manifest.defaultSupplier, manifest.initializer, manifest.holder, manifest.path);
|
||||
protected ValueManifest(@NotNull ValueManifest<TYPE, UNIT> manifest) {
|
||||
this(manifest.type, manifest.defaultSupplier, manifest.validator, manifest.initializer, manifest.holder, manifest.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);
|
||||
}
|
||||
|
||||
public @NotNull ValueType<T> type() {
|
||||
public @NotNull ValueType<TYPE> type() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
@@ -75,20 +87,37 @@ public class ValueManifest<T> {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public @Nullable T defaults() {
|
||||
public @Nullable TYPE defaults() {
|
||||
return this.defaultSupplier.get();
|
||||
}
|
||||
|
||||
public void defaults(@Nullable T defaultValue) {
|
||||
public void defaults(@Nullable TYPE defaultValue) {
|
||||
defaults(() -> defaultValue);
|
||||
}
|
||||
|
||||
public void defaults(@NotNull Supplier<@Nullable T> defaultValue) {
|
||||
public void defaults(@NotNull Supplier<@Nullable TYPE> defaultValue) {
|
||||
this.defaultSupplier = defaultValue;
|
||||
}
|
||||
|
||||
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() {
|
||||
@@ -105,12 +134,12 @@ public class ValueManifest<T> {
|
||||
return holder().config();
|
||||
}
|
||||
|
||||
public ConfigurationMetaHolder metadata() {
|
||||
public @NotNull ConfigurationMetaHolder metadata() {
|
||||
return holder().metadata(path());
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
protected Object getData() {
|
||||
protected @Nullable Object getData() {
|
||||
return config().get(path());
|
||||
}
|
||||
|
||||
@@ -119,6 +148,15 @@ public class ValueManifest<T> {
|
||||
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) -> {
|
||||
};
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@ import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
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 long parsedTime = -1;
|
||||
|
||||
protected CachedConfigValue(@NotNull ValueManifest<T> manifest) {
|
||||
protected CachedConfigValue(@NotNull ValueManifest<T, U> 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.ValueType;
|
||||
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.impl.CachedConfigValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -15,7 +16,7 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements List<V> {
|
||||
public class ConfiguredList<V> extends CachedConfigValue<List<V>, V> implements List<V> {
|
||||
|
||||
public static <T> @NotNull ConfigListBuilder<T> builderOf(@NotNull Class<T> type) {
|
||||
return builderOf(ValueType.of(type));
|
||||
@@ -25,10 +26,26 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements Lis
|
||||
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 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 ValueAdapter<V> paramAdapter) {
|
||||
super(manifest);
|
||||
@@ -70,40 +87,46 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements Lis
|
||||
if (!cacheExpired()) return getCachedOrDefault(createList());
|
||||
// Data that is outdated and needs to be parsed again.
|
||||
List<V> list = createList();
|
||||
try {
|
||||
List<?> data = config().contains(path()) ? config().getList(path()) : null;
|
||||
if (data == null) return getDefaultFirst(list);
|
||||
|
||||
ValueParser<V> parser = parser();
|
||||
if (parser == null) return getDefaultFirst(list);
|
||||
|
||||
int i = 0;
|
||||
for (Object dataVal : data) {
|
||||
if (dataVal == null) continue;
|
||||
try {
|
||||
list.add(parser.parse(holder(), paramType(), dataVal));
|
||||
list.add(withValidated(parser.parse(holder(), paramType(), dataVal)));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throwing(path + "[" + i + "]", e);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throwing(ex);
|
||||
}
|
||||
return updateCache(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(@Nullable List<V> value) {
|
||||
updateCache(value);
|
||||
if (value == null) {
|
||||
public void set(@Nullable List<V> list) {
|
||||
updateCache(list);
|
||||
if (list == null) {
|
||||
setData(null);
|
||||
return;
|
||||
}
|
||||
|
||||
ValueSerializer<V> serializer = serializer();
|
||||
if (serializer == null) return;
|
||||
|
||||
List<Object> data = new ArrayList<>();
|
||||
for (V val : value) {
|
||||
for (V val : list) {
|
||||
if (val == null) continue;
|
||||
try {
|
||||
data.add(serializer.serialize(holder(), paramType(), val));
|
||||
data.add(serializer.serialize(holder(), paramType(), withValidated(val)));
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
throwing(ex);
|
||||
}
|
||||
}
|
||||
setData(data);
|
||||
|
||||
@@ -17,7 +17,11 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements Map<K, V> {
|
||||
public 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) {
|
||||
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<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 ValueAdapter<K> keyAdapter, @NotNull ValueAdapter<V> valueAdapter) {
|
||||
super(manifest);
|
||||
@@ -73,6 +77,7 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
|
||||
// If the value is expired, we need to update it
|
||||
Map<K, V> map = createMap();
|
||||
|
||||
try {
|
||||
ConfigureSection section = config().getSection(path());
|
||||
if (section == null) return getDefaultFirst(map);
|
||||
|
||||
@@ -80,8 +85,9 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
|
||||
if (keys.isEmpty()) return getDefaultFirst(map);
|
||||
|
||||
ValueParser<K> keyParser = parserFor(keyAdapter);
|
||||
if (keyParser == null) return getDefaultFirst(map);
|
||||
ValueParser<V> valueParser = parserFor(valueAdapter);
|
||||
if (keyParser == null || valueParser == null) return getDefaultFirst(map);
|
||||
if (valueParser == null) return getDefaultFirst(map);
|
||||
|
||||
for (String dataKey : keys) {
|
||||
Object dataVal = section.get(dataKey);
|
||||
@@ -89,11 +95,14 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
|
||||
try {
|
||||
K key = keyParser.parse(holder(), keyType(), dataKey);
|
||||
V value = valueParser.parse(holder(), valueType(), dataVal);
|
||||
map.put(key, value);
|
||||
map.put(key, withValidated(value));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throwing(path + "." + dataKey, e);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throwing(ex);
|
||||
}
|
||||
|
||||
return updateCache(map);
|
||||
}
|
||||
@@ -115,9 +124,11 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ValueSerializer<K> keySerializer = serializerFor(keyAdapter);
|
||||
if (keySerializer == null) return;
|
||||
ValueSerializer<V> valueSerializer = serializerFor(valueAdapter);
|
||||
if (keySerializer == null || valueSerializer == null) return;
|
||||
if (valueSerializer == null) return;
|
||||
|
||||
Map<Object, Object> data = new LinkedHashMap<>();
|
||||
|
||||
@@ -125,13 +136,16 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
|
||||
try {
|
||||
data.put(
|
||||
keySerializer.serialize(holder(), keyType(), entry.getKey()),
|
||||
valueSerializer.serialize(holder(), valueType(), entry.getValue())
|
||||
valueSerializer.serialize(holder(), valueType(), withValidated(entry.getValue()))
|
||||
);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throwing(path + "." + entry.getKey(), e);
|
||||
}
|
||||
}
|
||||
setData(data);
|
||||
} catch (Exception ex) {
|
||||
throwing(ex);
|
||||
}
|
||||
}
|
||||
|
||||
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.ValueType;
|
||||
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.impl.CachedConfigValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -12,16 +14,54 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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 ValueSerializer<V> serializer) {
|
||||
ValueAdapter<V> adapter = new ValueAdapter<>(manifest.type());
|
||||
@@ -60,13 +100,13 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
this.adapter = adapter;
|
||||
}
|
||||
@@ -97,18 +137,19 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
||||
if (!cacheExpired()) return getCachedOrDefault();
|
||||
// Data that is outdated and needs to be parsed again.
|
||||
|
||||
try {
|
||||
Object data = getData();
|
||||
if (data == null) return defaults();
|
||||
|
||||
ValueParser<V> parser = parser();
|
||||
if (parser == null) return defaults(); // No parser, return default value.
|
||||
|
||||
try {
|
||||
// If there are no errors, update the cache and return.
|
||||
return updateCache(parser.parse(holder(), type(), data));
|
||||
V parsed = parser.parse(holder(), type(), data);
|
||||
return updateCache(withValidated(parsed));
|
||||
} catch (Exception e) {
|
||||
// There was a parsing error, prompted and returned the default value.
|
||||
e.printStackTrace();
|
||||
// There was a validate or parsing error, prompted and returned the default value.
|
||||
throwing(e);
|
||||
return defaults();
|
||||
}
|
||||
|
||||
@@ -121,20 +162,20 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
||||
* @param value The value to be set
|
||||
*/
|
||||
@Override
|
||||
public void set(V value) {
|
||||
public void set(@Nullable V value) {
|
||||
updateCache(value); // Update cache
|
||||
if (value == null) {
|
||||
setData(null);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ValueSerializer<V> serializer = serializer();
|
||||
if (serializer == null) return; // No serializer, do nothing.
|
||||
|
||||
try {
|
||||
setData(serializer.serialize(holder(), type(), value));
|
||||
setData(serializer.serialize(holder(), type(), withValidated(value)));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throwing(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-9
@@ -3,9 +3,9 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<artifactId>configured-parent</artifactId>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<version>4.0.9</version>
|
||||
<version>4.1.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<properties>
|
||||
@@ -13,36 +13,38 @@
|
||||
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
|
||||
</properties>
|
||||
<artifactId>easyconfiguration-demo</artifactId>
|
||||
<artifactId>configured-demo</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-core</artifactId>
|
||||
<artifactId>configured-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-feature-commentable</artifactId>
|
||||
<artifactId>configured-feature-commentable</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-feature-versioned</artifactId>
|
||||
<artifactId>configured-feature-versioned</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-feature-versioned</artifactId>
|
||||
<version>4.0.8</version>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>configured-feature-validators</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package cc.carm.lib.configuration.demo;
|
||||
import cc.carm.lib.configuration.Configuration;
|
||||
import cc.carm.lib.configuration.annotation.ConfigPath;
|
||||
import cc.carm.lib.configuration.annotation.HeaderComments;
|
||||
import cc.carm.lib.configuration.value.ConfigValue;
|
||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||
|
||||
@HeaderComments({"", "数据库配置", " 用于提供数据库连接,进行数据库操作。"})
|
||||
@@ -16,17 +15,17 @@ public interface DatabaseConfiguration extends Configuration {
|
||||
"- MySQL(新): com.mysql.cj.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"
|
||||
);
|
||||
|
||||
ConfigValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1");
|
||||
ConfigValue<Integer> PORT = ConfiguredValue.of(Integer.class, 3306);
|
||||
ConfigValue<String> DATABASE = ConfiguredValue.of(String.class, "minecraft");
|
||||
ConfigValue<String> USERNAME = ConfiguredValue.of(String.class, "root");
|
||||
ConfigValue<String> PASSWORD = ConfiguredValue.of(String.class, "password");
|
||||
ConfiguredValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1");
|
||||
ConfiguredValue<Integer> PORT = ConfiguredValue.of(Integer.class, 3306);
|
||||
ConfiguredValue<String> DATABASE = ConfiguredValue.of(String.class, "minecraft");
|
||||
ConfiguredValue<String> USERNAME = ConfiguredValue.of(String.class, "root");
|
||||
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() {
|
||||
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.demo.tests.model.ItemStack;
|
||||
import cc.carm.lib.configuration.demo.tests.model.UserRecord;
|
||||
import cc.carm.lib.configuration.value.ConfigValue;
|
||||
import cc.carm.lib.configuration.value.standard.ConfiguredList;
|
||||
import cc.carm.lib.configuration.value.standard.ConfiguredMap;
|
||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||
@@ -20,21 +19,21 @@ import java.util.UUID;
|
||||
"------------------------------------------------",
|
||||
"此处内容将显示在配置文件的最下方",
|
||||
"可用于显示版权信息等",
|
||||
"感谢您使用 https://github.com/CarmJos/EasyConfiguration !"
|
||||
"感谢您使用 https://github.com/CarmJos/configured !"
|
||||
})
|
||||
public interface DemoConfiguration extends Configuration {
|
||||
|
||||
@ConfigPath(root = true)
|
||||
@ConfigVersion(2)
|
||||
ConfigValue<Double> VERSION = ConfiguredValue.of(Double.class, 2.0D);
|
||||
ConfiguredValue<Double> VERSION = ConfiguredValue.of(Double.class, 2.0D);
|
||||
|
||||
@ConfigPath(root = true)
|
||||
@FooterComments({"此处内容将显示在配置条目的下方", "可用于补充说明,但一般不建议使用"})
|
||||
ConfigValue<Long> TEST_NUMBER = ConfiguredValue.of(1000000L);
|
||||
ConfiguredValue<Long> TEST_NUMBER = ConfiguredValue.with(Long.class).defaults(123456789L).build();
|
||||
|
||||
@HeaderComments({"枚举类型测试"})
|
||||
@FooterComments({"上述的枚举内容本质上是通过STRING解析的"})
|
||||
ConfigValue<ChronoUnit> TEST_ENUM = ConfiguredValue.of(ChronoUnit.class, ChronoUnit.DAYS);
|
||||
ConfiguredValue<ChronoUnit> TEST_ENUM = ConfiguredValue.of(ChronoUnit.class, ChronoUnit.DAYS);
|
||||
|
||||
@HeaderComments({"空值测试"})
|
||||
@InlineComment("空值Inline注释")
|
||||
@@ -72,7 +71,7 @@ public interface DemoConfiguration extends Configuration {
|
||||
class SUB implements Configuration {
|
||||
|
||||
@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()
|
||||
.parse((holder, data) -> UUID.fromString(data))
|
||||
.build();
|
||||
|
||||
@@ -2,12 +2,13 @@ package cc.carm.lib.configuration.demo.tests.conf;
|
||||
|
||||
import cc.carm.lib.configuration.Configuration;
|
||||
import cc.carm.lib.configuration.annotation.HeaderComments;
|
||||
import cc.carm.lib.configuration.value.ConfigValue;
|
||||
import cc.carm.lib.configuration.annotation.ValueRange;
|
||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||
|
||||
@HeaderComments("Inner Test")
|
||||
@HeaderComments("service")
|
||||
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.InlineComment;
|
||||
import cc.carm.lib.configuration.demo.tests.model.UserRecord;
|
||||
import cc.carm.lib.configuration.value.ConfigValue;
|
||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||
|
||||
import java.util.UUID;
|
||||
@@ -20,7 +19,7 @@ public class RegistryConfig implements Configuration {
|
||||
@FooterComments({"12313213212"})
|
||||
@InlineComment(value = "用户名(匹配注释)", regex = "name") // 通过注解给配置添加注释。
|
||||
@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()))
|
||||
.parse((holder, section) -> UserRecord.deserialize(section))
|
||||
.serialize((holder, data) -> data.serialize()).build();
|
||||
|
||||
@@ -33,11 +33,11 @@ public class ItemStack {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
public @Nullable String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<String> getLore() {
|
||||
public @Nullable List<String> getLore() {
|
||||
return lore;
|
||||
}
|
||||
|
||||
@@ -49,11 +49,11 @@ public class ItemStack {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
public void setName(@Nullable String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setLore(List<String> lore) {
|
||||
public void setLore(@Nullable List<String> lore) {
|
||||
this.lore = lore;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<version>4.0.9</version>
|
||||
<artifactId>configured-parent</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
@@ -16,13 +16,13 @@
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
</properties>
|
||||
|
||||
<artifactId>easyconfiguration-feature-commentable</artifactId>
|
||||
<artifactId>configured-feature-commentable</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-core</artifactId>
|
||||
<artifactId>configured-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<version>4.0.9</version>
|
||||
<artifactId>configured-parent</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
@@ -16,13 +16,13 @@
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
</properties>
|
||||
|
||||
<artifactId>easyconfiguration-feature-file</artifactId>
|
||||
<artifactId>configured-feature-file</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-core</artifactId>
|
||||
<artifactId>configured-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<version>4.0.9</version>
|
||||
<artifactId>configured-parent</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
@@ -16,13 +16,13 @@
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
</properties>
|
||||
|
||||
<artifactId>easyconfiguration-feature-section</artifactId>
|
||||
<artifactId>configured-feature-section</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-core</artifactId>
|
||||
<artifactId>configured-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
+2
-2
@@ -166,12 +166,12 @@ public class ImmutableSection implements ConfigureSection {
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<version>4.0.9</version>
|
||||
<artifactId>configured-parent</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
@@ -16,20 +16,20 @@
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
</properties>
|
||||
|
||||
<artifactId>easyconfiguration-feature-text</artifactId>
|
||||
<artifactId>configured-feature-text</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-core</artifactId>
|
||||
<artifactId>configured-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-yaml</artifactId>
|
||||
<artifactId>configured-gson</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
+4
-5
@@ -7,7 +7,6 @@ import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import cc.carm.lib.configuration.value.ValueManifest;
|
||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||
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.Nullable;
|
||||
|
||||
@@ -22,7 +21,7 @@ import java.util.function.Consumer;
|
||||
*/
|
||||
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<>();
|
||||
}
|
||||
|
||||
@@ -38,7 +37,7 @@ public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents>
|
||||
|
||||
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, MSG> compiler,
|
||||
@NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher,
|
||||
@@ -50,7 +49,7 @@ public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents>
|
||||
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)
|
||||
.parser(this.parser).compiler(this.compiler)
|
||||
.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>>
|
||||
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 String[] params = new String[0];
|
||||
|
||||
|
||||
+95
-95
@@ -1,36 +1,27 @@
|
||||
package cc.carm.lib.configuration.value.text.function;
|
||||
|
||||
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.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.Consumer;
|
||||
import java.util.function.Function;
|
||||
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>> {
|
||||
|
||||
/**
|
||||
* 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 + ")";
|
||||
public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEIVER, SELF>>
|
||||
implements Replaceable<RECEIVER, SELF>, Insertable<RECEIVER, SELF> {
|
||||
|
||||
protected BiFunction<RECEIVER, String, String> parser = (receiver, value) -> value;
|
||||
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
|
||||
*/
|
||||
protected @NotNull Map<String, Object> placeholders = new HashMap<>();
|
||||
protected @NotNull UnaryOperator<String> paramFormatter = DEFAULT_PARAM_BUILDER;
|
||||
protected @NotNull ParamReplacer<RECEIVER> paramReplacer = ParamReplacer.defaults();
|
||||
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
|
||||
*/
|
||||
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;
|
||||
|
||||
public ContentHandler() {
|
||||
inserters.add(new AppendLineInserter<>(0));
|
||||
inserters.add(new OptionalLineInserter<>(0));
|
||||
}
|
||||
|
||||
|
||||
public abstract SELF self();
|
||||
|
||||
/**
|
||||
@@ -71,6 +70,11 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean noneInsertion() {
|
||||
return this.insertion.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public SELF placeholders(@NotNull Map<String, Object> placeholders) {
|
||||
this.placeholders = placeholders;
|
||||
this.paramReplacer.set(placeholders);
|
||||
return self();
|
||||
}
|
||||
|
||||
@@ -101,7 +105,7 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
|
||||
* @return the current {@link ContentHandler} instance
|
||||
*/
|
||||
public SELF placeholders(@NotNull Consumer<Map<String, Object>> consumer) {
|
||||
consumer.accept(this.placeholders);
|
||||
consumer.accept(this.paramReplacer.placeholders());
|
||||
return self();
|
||||
}
|
||||
|
||||
@@ -112,7 +116,8 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
|
||||
* @return the current {@link ContentHandler} instance
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public SELF placeholder(@NotNull String key, @Nullable Object value) {
|
||||
this.placeholders.put(paramFormatter.apply(key), value);
|
||||
this.paramReplacer.put(key, value);
|
||||
return self();
|
||||
}
|
||||
|
||||
@@ -139,38 +144,52 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the specific contents by the id.
|
||||
*
|
||||
* @param id the id of the insertion text
|
||||
* @param linesSupplier to supply the lines to insert
|
||||
* @return the current {@link ContentHandler} instance
|
||||
*/
|
||||
public SELF insert(@NotNull String id, @NotNull Function<RECEIVER, List<String>> linesSupplier) {
|
||||
this.insertion.put(id, linesSupplier);
|
||||
@Override
|
||||
public List<ContentReplacer<RECEIVER>> replacers() {
|
||||
return this.replacers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SELF replacer(@NotNull ContentReplacer<RECEIVER> replacer) {
|
||||
this.replacers.add(replacer);
|
||||
this.replacers.sort(ContentReplacer::compareTo);
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the specific contents by the id.
|
||||
*
|
||||
* @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
|
||||
public List<ContentInserter<RECEIVER>> inserters() {
|
||||
return this.inserters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the specific contents by the id.
|
||||
*
|
||||
* @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 List<String> lines) {
|
||||
return insert(id, receiver -> lines);
|
||||
@Override
|
||||
public SELF inserter(@NotNull ContentInserter<RECEIVER> inserter) {
|
||||
this.inserters.add(inserter);
|
||||
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,58 +211,39 @@ public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEI
|
||||
* @return the parsed 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,
|
||||
@NotNull Consumer<String> lineConsumer) {
|
||||
if (contents.isEmpty()) return; // Nothing to parse
|
||||
|
||||
if (this.disableInsertion) {
|
||||
if (this.disableInsertion || noneInsertion()) {
|
||||
contents.lines().forEach(line -> lineConsumer.accept(parse(receiver, line)));
|
||||
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()) {
|
||||
Matcher matcher = INSERT_PATTERN.matcher(line);
|
||||
if (!matcher.matches()) {
|
||||
for (ContentInserter<RECEIVER> inserter : inserters) {
|
||||
List<String> inserted = inserter.handle(receiver, line, this);
|
||||
if (inserted != null) { // Found the insertion
|
||||
inserted.forEach(l -> lineConsumer.accept(parse(receiver, l)));
|
||||
continue lines; // Go to the next line
|
||||
}
|
||||
}
|
||||
lineConsumer.accept(parse(receiver, line));
|
||||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public static String setPlaceholders(@NotNull String messages,
|
||||
@NotNull Map<String, Object> placeholders) {
|
||||
if (messages.isEmpty()) return messages;
|
||||
String parsed = messages;
|
||||
for (Map.Entry<String, Object> entry : placeholders.entrySet()) {
|
||||
parsed = parsed.replace(entry.getKey(), entry.getValue() == null ? "" : entry.getValue().toString());
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
public static Map<String, Object> buildParams(@NotNull UnaryOperator<String> paramBuilder,
|
||||
|
||||
+67
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+46
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+71
@@ -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();
|
||||
}
|
||||
}
|
||||
+51
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+66
@@ -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);
|
||||
|
||||
}
|
||||
+105
@@ -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>> {
|
||||
}
|
||||
|
||||
}
|
||||
+63
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
+7
-6
@@ -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.yaml.YAMLConfigFactory;
|
||||
import cc.carm.lib.configuration.source.json.JSONConfigFactory;
|
||||
import cc.carm.lib.configuration.value.text.tests.conf.AppMessages;
|
||||
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[]{
|
||||
"https://carm.cc",
|
||||
@@ -15,21 +17,20 @@ public class ConfigTest {
|
||||
"https://www.google.com"
|
||||
};
|
||||
|
||||
|
||||
@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);
|
||||
|
||||
System.out.println("--------------------------");
|
||||
|
||||
AppMessages.WELCOME.prepare()
|
||||
List<String> str = AppMessages.WELCOME.prepare()
|
||||
.placeholders("Carm")
|
||||
.insert("guidance")
|
||||
.insert("websites", WEBSITES)
|
||||
.to(System.out);
|
||||
.compile(System.out);
|
||||
|
||||
System.out.println("--------------------------");
|
||||
|
||||
|
||||
+13
-4
@@ -7,6 +7,7 @@ import org.junit.Test;
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public class ParseTest {
|
||||
|
||||
|
||||
@@ -18,12 +19,15 @@ public class ParseTest {
|
||||
lines.add("#more-creating#{1}");
|
||||
lines.add("This is a test message");
|
||||
lines.add("#guidance#");
|
||||
lines.add("{- }#websites#{0,1}");
|
||||
lines.add("{ - }#websites#{0,1}");
|
||||
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<>();
|
||||
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"));
|
||||
|
||||
TextContents textContents = new TextContents(lines, optional);
|
||||
@@ -31,12 +35,17 @@ public class ParseTest {
|
||||
PreparedText<String, PrintStream> msg = new PreparedText<String, PrintStream>(textContents)
|
||||
.dispatcher((p, s) -> s.forEach(p::println))
|
||||
.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")
|
||||
.insert("guidance")
|
||||
.insert("click")
|
||||
.insert("websites", "Baidu", "Bilibili", "Google");
|
||||
|
||||
|
||||
System.out.println("----------------------------");
|
||||
msg.to(System.out);
|
||||
System.out.println("----------------------------");
|
||||
|
||||
+2
-1
@@ -17,7 +17,8 @@ public class ConfiguredMsg extends ConfiguredText<String, PrintStream> {
|
||||
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(
|
||||
manifest,
|
||||
(p, s) -> s,
|
||||
|
||||
@@ -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.2</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>
|
||||
+16
@@ -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!";
|
||||
|
||||
}
|
||||
+18
@@ -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.";
|
||||
|
||||
}
|
||||
+44
@@ -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());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,8 +5,8 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<version>4.0.9</version>
|
||||
<artifactId>configured-parent</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
@@ -16,13 +16,13 @@
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
</properties>
|
||||
|
||||
<artifactId>easyconfiguration-feature-versioned</artifactId>
|
||||
<artifactId>configured-feature-versioned</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-core</artifactId>
|
||||
<artifactId>configured-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -13,29 +13,30 @@
|
||||
</properties>
|
||||
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<artifactId>configured-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>4.0.9</version>
|
||||
<version>4.1.2</version>
|
||||
<modules>
|
||||
<module>core</module>
|
||||
<module>features/section</module>
|
||||
<module>features/file</module>
|
||||
<module>features/commentable</module>
|
||||
<module>features/versioned</module>
|
||||
<module>features/validators</module>
|
||||
<module>features/text</module>
|
||||
|
||||
<module>providers/yaml</module>
|
||||
<module>providers/gson</module>
|
||||
<!-- <module>providers/hocon</module>-->
|
||||
<module>providers/hocon</module>
|
||||
<module>providers/sql</module>
|
||||
<module>providers/mongodb</module>
|
||||
|
||||
<module>demo</module>
|
||||
</modules>
|
||||
|
||||
<name>EasyConfiguration</name>
|
||||
<name>configured</name>
|
||||
<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>
|
||||
<developer>
|
||||
@@ -48,9 +49,9 @@
|
||||
</developers>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:git@github.com:CarmJos/Easy.EasyConfiguration</connection>
|
||||
<developerConnection>scm:git:git@github.com:CarmJos/EasyConfiguration.git</developerConnection>
|
||||
<url>https://github.com/CarmJos/EasyConfiguration</url>
|
||||
<connection>scm:git:git@github.com:CarmJos/Easy.configured</connection>
|
||||
<developerConnection>scm:git:git@github.com:CarmJos/configured.git</developerConnection>
|
||||
<url>https://github.com/CarmJos/configured</url>
|
||||
<tag>HEAD</tag>
|
||||
</scm>
|
||||
|
||||
@@ -63,12 +64,12 @@
|
||||
|
||||
<issueManagement>
|
||||
<system>GitHub Issues</system>
|
||||
<url>https://github.com/CarmJos/EasyConfiguration/issues</url>
|
||||
<url>https://github.com/CarmJos/configured/issues</url>
|
||||
</issueManagement>
|
||||
|
||||
<ciManagement>
|
||||
<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>
|
||||
|
||||
<repositories>
|
||||
@@ -92,11 +93,11 @@
|
||||
</repositories>
|
||||
|
||||
<distributionManagement>
|
||||
<downloadUrl>https://github.com/CarmJos/EasyConfiguration/releases</downloadUrl>
|
||||
<downloadUrl>https://github.com/CarmJos/configured/releases</downloadUrl>
|
||||
<site>
|
||||
<id>javadoc</id>
|
||||
<name>EasyConfiguration JavaDoc (on GitHub Pages)</name>
|
||||
<url>https://CarmJos.github.io/EasyConfiguration</url>
|
||||
<name>configured JavaDoc (on GitHub Pages)</name>
|
||||
<url>https://CarmJos.github.io/configured</url>
|
||||
</site>
|
||||
</distributionManagement>
|
||||
|
||||
@@ -292,7 +293,7 @@
|
||||
<repository>
|
||||
<id>github</id>
|
||||
<name>GitHub Packages</name>
|
||||
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url>
|
||||
<url>https://maven.pkg.github.com/CarmJos/configured</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
</profile>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# EasyConfiguration-JSON
|
||||
# configured-JSON
|
||||
|
||||
JSON file-based implementation, compatible with all Java environments.
|
||||
|
||||
@@ -22,9 +22,9 @@ JSON file-based implementation, compatible with all Java environments.
|
||||
|
||||
<repository>
|
||||
<!-- Using GitHub dependencies for real-time updates, configuration required (recommended). -->
|
||||
<id>EasyConfiguration</id>
|
||||
<id>configured</id>
|
||||
<name>GitHub Packages</name>
|
||||
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url>
|
||||
<url>https://maven.pkg.github.com/CarmJos/configured</url>
|
||||
</repository>
|
||||
|
||||
</repositories>
|
||||
@@ -37,7 +37,7 @@ JSON file-based implementation, compatible with all Java environments.
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-json</artifactId>
|
||||
<artifactId>configured-json</artifactId>
|
||||
<version>[LATEST RELEASE]</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
@@ -54,14 +54,14 @@ repositories {
|
||||
mavenCentral()
|
||||
|
||||
// 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
|
||||
dependencies {
|
||||
api "cc.carm.lib:easyconfiguration-json:[LATEST RELEASE]"
|
||||
api "cc.carm.lib:configured-json:[LATEST RELEASE]"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<artifactId>configured-parent</artifactId>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<version>4.0.9</version>
|
||||
<version>4.1.2</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -15,35 +15,35 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
</properties>
|
||||
<artifactId>easyconfiguration-gson</artifactId>
|
||||
<artifactId>configured-gson</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-core</artifactId>
|
||||
<artifactId>configured-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-feature-file</artifactId>
|
||||
<artifactId>configured-feature-file</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-feature-section</artifactId>
|
||||
<artifactId>configured-feature-section</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-demo</artifactId>
|
||||
<artifactId>configured-demo</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package config;
|
||||
|
||||
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.value.ConfigValue;
|
||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||
import cc.carm.lib.configuration.source.json.JSONConfigFactory;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
@@ -18,12 +16,6 @@ public class JSONConfigTest {
|
||||
|
||||
@Test
|
||||
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.testInner(this.holder);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# EasyConfiguration-HOCON
|
||||
# configured-HOCON
|
||||
|
||||
HOCON file-based implementation, compatible with all Java environments.
|
||||
|
||||
@@ -20,9 +20,9 @@ HOCON file-based implementation, compatible with all Java environments.
|
||||
|
||||
<repository>
|
||||
<!-- Using GitHub dependencies for real-time updates, configuration required (recommended). -->
|
||||
<id>EasyConfiguration</id>
|
||||
<id>configured</id>
|
||||
<name>GitHub Packages</name>
|
||||
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url>
|
||||
<url>https://maven.pkg.github.com/CarmJos/configured</url>
|
||||
</repository>
|
||||
|
||||
</repositories>
|
||||
@@ -35,7 +35,7 @@ HOCON file-based implementation, compatible with all Java environments.
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-hocon</artifactId>
|
||||
<artifactId>configured-hocon</artifactId>
|
||||
<version>[LATEST RELEASE]</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
@@ -52,14 +52,14 @@ repositories {
|
||||
mavenCentral()
|
||||
|
||||
// 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
|
||||
dependencies {
|
||||
api "cc.carm.lib:easyconfiguration-hocon:[LATEST RELEASE]"
|
||||
api "cc.carm.lib:configured-hocon:[LATEST RELEASE]"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<?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">
|
||||
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>
|
||||
<parent>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<version>4.0.0</version>
|
||||
<artifactId>configured-parent</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
@@ -15,38 +15,38 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
</properties>
|
||||
<artifactId>easyconfiguration-hocon</artifactId>
|
||||
<artifactId>configured-hocon</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-core</artifactId>
|
||||
<artifactId>configured-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-feature-commentable</artifactId>
|
||||
<artifactId>configured-feature-commentable</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-feature-file</artifactId>
|
||||
<artifactId>configured-feature-file</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-feature-section</artifactId>
|
||||
<artifactId>configured-feature-section</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-demo</artifactId>
|
||||
<artifactId>configured-demo</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</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;
|
||||
}
|
||||
}
|
||||
+48
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
-69
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+74
-14
@@ -1,44 +1,104 @@
|
||||
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.section.ConfigureSource;
|
||||
import com.typesafe.config.Config;
|
||||
import cc.carm.lib.configuration.source.file.FileConfigSource;
|
||||
import cc.carm.lib.configuration.source.section.SourcedSection;
|
||||
import com.typesafe.config.*;
|
||||
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) {
|
||||
super(holder, lastUpdateMillis);
|
||||
public void initialize() {
|
||||
try {
|
||||
this.initializeFile();
|
||||
this.onReload();
|
||||
} catch (Exception e) {
|
||||
//noinspection CallToPrintStackTrace
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HOCONSource self() {
|
||||
protected @NotNull HOCONSource self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Config original() {
|
||||
return section().data();
|
||||
public @NotNull Map<String, Object> original() {
|
||||
return this.section().data();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HOCONSection section() {
|
||||
return Objects.requireNonNull(rootSection, "RootSection is not initialized");
|
||||
public @NotNull SourcedSection section() {
|
||||
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
|
||||
public void save() throws Exception {
|
||||
|
||||
this.fileWriter(w -> w.write(HOCONSource.this.saveToString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
-18
@@ -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
|
||||
@@ -3,9 +3,9 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<artifactId>configured-parent</artifactId>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<version>4.0.9</version>
|
||||
<version>4.1.2</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -18,20 +18,20 @@
|
||||
<deps.mongodb.version>5.3.1</deps.mongodb.version>
|
||||
<log4j.version>2.24.3</log4j.version>
|
||||
</properties>
|
||||
<artifactId>easyconfiguration-mongodb</artifactId>
|
||||
<artifactId>configured-mongodb</artifactId>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-core</artifactId>
|
||||
<artifactId>configured-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-feature-section</artifactId>
|
||||
<artifactId>configured-feature-section</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
@@ -65,14 +65,14 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-demo</artifactId>
|
||||
<artifactId>configured-demo</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-gson</artifactId>
|
||||
<artifactId>configured-gson</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# EasyConfiguration-SQL
|
||||
# configured-SQL
|
||||
|
||||
SQL database implementation, support for MySQL or MariaDB.
|
||||
|
||||
@@ -39,9 +39,9 @@ CREATE TABLE IF NOT EXISTS conf
|
||||
|
||||
<repository>
|
||||
<!-- Using GitHub dependencies for real-time updates, configuration required (recommended). -->
|
||||
<id>EasyConfiguration</id>
|
||||
<id>configured</id>
|
||||
<name>GitHub Packages</name>
|
||||
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url>
|
||||
<url>https://maven.pkg.github.com/CarmJos/configured</url>
|
||||
</repository>
|
||||
|
||||
</repositories>
|
||||
@@ -54,7 +54,7 @@ CREATE TABLE IF NOT EXISTS conf
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-sql</artifactId>
|
||||
<artifactId>configured-sql</artifactId>
|
||||
<version>[LATEST RELEASE]</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
@@ -71,13 +71,13 @@ repositories {
|
||||
mavenCentral()
|
||||
|
||||
// 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
|
||||
dependencies {
|
||||
api "cc.carm.lib:easyconfiguration-sql:[LATEST RELEASE]"
|
||||
api "cc.carm.lib:configured-sql:[LATEST RELEASE]"
|
||||
}
|
||||
```
|
||||
@@ -4,9 +4,9 @@
|
||||
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>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<artifactId>configured-parent</artifactId>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<version>4.0.9</version>
|
||||
<version>4.1.2</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
@@ -18,33 +18,33 @@
|
||||
<deps.mysql-driver.version>8.0.33</deps.mysql-driver.version>
|
||||
<deps.log4j.version>2.24.3</deps.log4j.version>
|
||||
</properties>
|
||||
<artifactId>easyconfiguration-sql</artifactId>
|
||||
<artifactId>configured-sql</artifactId>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-core</artifactId>
|
||||
<artifactId>configured-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-feature-commentable</artifactId>
|
||||
<artifactId>configured-feature-commentable</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-feature-section</artifactId>
|
||||
<artifactId>configured-feature-section</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-feature-versioned</artifactId>
|
||||
<artifactId>configured-feature-versioned</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
@@ -70,7 +70,7 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-demo</artifactId>
|
||||
<artifactId>configured-demo</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
@@ -98,7 +98,7 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-gson</artifactId>
|
||||
<artifactId>configured-gson</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
+49
-4
@@ -7,12 +7,17 @@ import cc.carm.lib.configuration.source.ConfigurationFactory;
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import cc.carm.lib.configuration.versioned.VersionedMetaTypes;
|
||||
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.GsonBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -26,11 +31,43 @@ public class SQLConfigFactory extends ConfigurationFactory<SQLSource, Configurat
|
||||
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 Supplier<Gson> gsonSupplier = () -> SQLSource.DEFAULT_GSON;
|
||||
protected Supplier<Gson> gsonSupplier = () -> DEFAULT_GSON;
|
||||
|
||||
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";
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
public SQLConfigFactory tableName(@NotNull String tableName) {
|
||||
this.tableName = tableName;
|
||||
public SQLConfigFactory table(@NotNull SQLTable table) {
|
||||
this.tableName = table;
|
||||
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) {
|
||||
this.namespace = namespace;
|
||||
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.SQLQuery;
|
||||
import cc.carm.lib.easysql.api.SQLTable;
|
||||
import cc.carm.lib.easysql.api.enums.IndexType;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -21,9 +19,6 @@ import java.util.*;
|
||||
|
||||
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 SQLManager sqlManager;
|
||||
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,
|
||||
@NotNull Gson gson, @NotNull SQLManager sqlManager,
|
||||
@NotNull Map<Integer, SQLValueResolver<?>> resolvers,
|
||||
@NotNull String tableName, @NotNull String namespace) {
|
||||
@NotNull SQLTable table, @NotNull String namespace) {
|
||||
super(holder, lastUpdateMillis);
|
||||
this.gson = gson;
|
||||
this.sqlManager = sqlManager;
|
||||
this.resolvers = resolvers;
|
||||
this.namespace = namespace;
|
||||
this.table = SQLTable.of(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");
|
||||
builder.addColumn("update_time", "TIMESTAMP NOT NULL");
|
||||
|
||||
builder.setIndex(
|
||||
IndexType.PRIMARY_KEY, "pk_" + tableName.toLowerCase(),
|
||||
"namespace", "path"
|
||||
);
|
||||
builder.setTableSettings("ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
|
||||
});
|
||||
this.table = table;
|
||||
|
||||
try {
|
||||
this.table.create(this.sqlManager);
|
||||
@@ -102,10 +75,10 @@ public class SQLSource extends ConfigureSource<SourcedSection, Map<String, Objec
|
||||
List<Object[]> dataValues = new ArrayList<>();
|
||||
|
||||
SourcedSection section = section();
|
||||
Map<String, ConfigValue<?>> values = holder().registeredValues();
|
||||
for (Map.Entry<String, ConfigValue<?>> entry : values.entrySet()) {
|
||||
Map<String, ConfigValue<?, ?>> values = holder().registeredValues();
|
||||
for (Map.Entry<String, ConfigValue<?, ?>> entry : values.entrySet()) {
|
||||
@NotNull String path = entry.getKey();
|
||||
@NotNull ConfigValue<?> config = entry.getValue();
|
||||
@NotNull ConfigValue<?, ?> config = entry.getValue();
|
||||
@Nullable Object value = section.get(path);
|
||||
|
||||
if (value instanceof SourcedSection) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# EasyConfiguration-YAML
|
||||
# configured-YAML
|
||||
|
||||
YAML file-based implementation, compatible with all Java environments.
|
||||
|
||||
@@ -20,9 +20,9 @@ YAML file-based implementation, compatible with all Java environments.
|
||||
|
||||
<repository>
|
||||
<!-- Using GitHub dependencies for real-time updates, configuration required (recommended). -->
|
||||
<id>EasyConfiguration</id>
|
||||
<id>configured</id>
|
||||
<name>GitHub Packages</name>
|
||||
<url>https://maven.pkg.github.com/CarmJos/EasyConfiguration</url>
|
||||
<url>https://maven.pkg.github.com/CarmJos/configured</url>
|
||||
</repository>
|
||||
|
||||
</repositories>
|
||||
@@ -35,7 +35,7 @@ YAML file-based implementation, compatible with all Java environments.
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-yaml</artifactId>
|
||||
<artifactId>configured-yaml</artifactId>
|
||||
<version>[LATEST RELEASE]</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
@@ -52,13 +52,13 @@ repositories {
|
||||
mavenCentral()
|
||||
|
||||
// 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
|
||||
dependencies {
|
||||
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]"
|
||||
api "cc.carm.lib:configured-yaml:[LATEST RELEASE]"
|
||||
}
|
||||
```
|
||||
@@ -4,9 +4,9 @@
|
||||
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>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<artifactId>configured-parent</artifactId>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<version>4.0.9</version>
|
||||
<version>4.1.2</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
@@ -17,35 +17,35 @@
|
||||
<deps.yamlcommentwriter.version>1.2.1</deps.yamlcommentwriter.version>
|
||||
</properties>
|
||||
|
||||
<artifactId>easyconfiguration-yaml</artifactId>
|
||||
<artifactId>configured-yaml</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-core</artifactId>
|
||||
<artifactId>configured-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-feature-file</artifactId>
|
||||
<artifactId>configured-feature-file</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-feature-section</artifactId>
|
||||
<artifactId>configured-feature-section</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-feature-commentable</artifactId>
|
||||
<artifactId>configured-feature-commentable</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
@@ -66,7 +66,7 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-demo</artifactId>
|
||||
<artifactId>configured-demo</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package yaml.test;
|
||||
|
||||
import cc.carm.lib.configuration.commentable.Commentable;
|
||||
import cc.carm.lib.configuration.commentable.CommentableMeta;
|
||||
import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import cc.carm.lib.configuration.source.yaml.YAMLConfigFactory;
|
||||
import cc.carm.lib.configuration.source.yaml.YAMLSource;
|
||||
import cc.carm.lib.configuration.validators.Validators;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
@@ -19,6 +19,8 @@ public class YamlTests {
|
||||
ConfigurationHolder<YAMLSource> holder = YAMLConfigFactory.from("target/tests.yml")
|
||||
.resourcePath("configs/sample.yml").build();
|
||||
|
||||
Validators.activate(holder);
|
||||
|
||||
ConfigurationTest.testDemo(holder);
|
||||
ConfigurationTest.testInner(holder);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user