Skip to content

Commit

Permalink
简单编写 RollingGate api
Browse files Browse the repository at this point in the history
  • Loading branch information
Gu-ZT committed Sep 17, 2024
1 parent 1e958d0 commit 18d61af
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 0 deletions.
14 changes: 14 additions & 0 deletions src/main/java/dev/anvilcraft/rg/api/RGEnvironment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package dev.anvilcraft.rg.api;

public enum RGEnvironment {
CLIENT,
SERVER;

public boolean isClient() {
return this == CLIENT;
}

public boolean isServer() {
return this == SERVER;
}
}
125 changes: 125 additions & 0 deletions src/main/java/dev/anvilcraft/rg/api/RGRule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package dev.anvilcraft.rg.api;

import org.jetbrains.annotations.NotNull;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class RGRule<T> {
final Class<T> type;
final RGEnvironment environment;
final String serialize;
final String[] preset;
final RGValidator<T> validator;
final T defaultValue;
final Field field;

public RGRule(String namespace, Class<T> type, RGEnvironment environment, String serialize, String[] preset, RGValidator<T> validator, T defaultValue, Field field) {
this.type = type;
this.environment = environment;
this.serialize = serialize;
this.preset = preset;
this.validator = validator;
this.defaultValue = defaultValue;
this.field = field;
}

@SuppressWarnings("unchecked")
public static <T> @NotNull RGRule<T> of(String namespace, @NotNull Field field) {
if (!Modifier.isStatic(field.getModifiers())) {
throw new RuntimeException("Field %s is not static".formatted(field.getName()));
}
if (!Modifier.isPublic(field.getModifiers())) {
throw new RuntimeException("Field %s is not public".formatted(field.getName()));
}
if (!Modifier.isFinal(field.getModifiers())) {
throw new RuntimeException("Field %s can't be final".formatted(field.getName()));
}
Class<?> type = RGRule.checkType(field);
Rule rule = field.getAnnotation(Rule.class);
if (rule == null) {
throw new RuntimeException("Field %s is not annotated with @Rule".formatted(field.getName()));
}
String serialize = rule.serialize().isEmpty() ? RGRule.caseToSnake(field.getName()) : rule.serialize();
RGRule.checkSerialize(serialize);
try {
return new RGRule<>(
namespace,
(Class<T>) type,
rule.env(),
serialize,
rule.preset(),
rule.validator().getDeclaredConstructor().newInstance(),
(T) field.get(null),
field
);
} catch (Exception e) {
throw new RuntimeException("Failed to create rule for field %s".formatted(field.getName()), e);
}
}

/**
* 检查并转换字段的类型
* <p>
* 本函数的目的是根据提供的字段对象,判断其类型,并返回相应的包装类如果字段的类型是基本数据类型,
* 则返回对应的包装类(如boolean类型返回Boolean类)如果字段的类型已经是对应的包装类,则直接返回该类
* 对于不支持的类型,本函数会抛出RuntimeException异常目前支持的类型包括Boolean, Byte, Short, Integer,
* Long, Float, Double和String
*
* @param field 要检查的字段对象,不能为空
* @return 与字段类型对应的包装类,或者在不支持该类型时抛出RuntimeException异常
* @throws RuntimeException 当字段的类型不被支持时抛出
*/
public static Class<?> checkType(@NotNull Field field) {
// 检查并转换字段类型,从基本数据类型开始
if (field.getType() == boolean.class) return Boolean.class;
if (field.getType() == Boolean.class) return Boolean.class;
if (field.getType() == byte.class) return Byte.class;
if (field.getType() == Byte.class) return Byte.class;
if (field.getType() == short.class) return Short.class;
if (field.getType() == Short.class) return Short.class;
if (field.getType() == int.class) return Integer.class;
if (field.getType() == Integer.class) return Integer.class;
if (field.getType() == long.class) return Long.class;
if (field.getType() == Long.class) return Long.class;
if (field.getType() == float.class) return Float.class;
if (field.getType() == Float.class) return Float.class;
if (field.getType() == double.class) return Double.class;
if (field.getType() == Double.class) return Double.class;
// 支持String类型
if (field.getType() == String.class) return String.class;
// 对于不支持的类型,抛出异常
throw new RuntimeException("Field %s has unsupported type %s".formatted(field.getName(), field.getType()));
}


/**
* 检查序列化字符串的有效性
* <p>
* 此方法用于确保给定的字符串符合特定的格式标准,以保证其可作为序列化字符串安全使用
* 字符串必须是非空的,并且以小写字母开头,后面可以包含小写字母、数字和下划线
*
* @param str 待检查的序列化字符串
* @throws RuntimeException 如果字符串为空或不符合指定的格式,抛出此异常
*/
public static void checkSerialize(@NotNull String str) {
// 检查字符串是否为空或不符合预期的格式
if (str.isEmpty() || !str.matches("^[a-z][a-z0-9_]*$")) {
// 如果检查失败,抛出异常,说明字符串无效
throw new RuntimeException("Invalid serialize string %s".formatted(str));
}
}

/**
* 将驼峰命名法的字符串转换为蛇形命名法的字符串
* <p>
* 此方法通过识别驼峰命名法中每个单词的首字母大写,并在其前添加下划线,然后将所有字符转换为小写来实现转换
*
* @param str 驼峰命名法的字符串
* @return 转换后的蛇形命名法的字符串
*/
public static @NotNull String caseToSnake(@NotNull String str) {
// 使用正则表达式匹配驼峰命名法中的大写字母,并在其前添加下划线,然后将整个字符串转换为小写
return str.replaceAll("([a-z])([A-Z]+)", "$1_$2").toLowerCase();
}
}
22 changes: 22 additions & 0 deletions src/main/java/dev/anvilcraft/rg/api/RGRuleManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package dev.anvilcraft.rg.api;

import org.jetbrains.annotations.NotNull;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

public class RGRuleManager {
public static @NotNull List<RGRule<?>> of(String namespace, @NotNull Class<?> rules) {
List<RGRule<?>> ruleList = new ArrayList<>();
for (Field field : rules.getDeclaredFields()) {
if (!Modifier.isStatic(field.getModifiers())) continue;
if (!Modifier.isPublic(field.getModifiers())) continue;
if (Modifier.isFinal(field.getModifiers())) continue;
RGRule.checkType(field);
ruleList.add(RGRule.of(namespace, field));
}
return ruleList;
}
}
12 changes: 12 additions & 0 deletions src/main/java/dev/anvilcraft/rg/api/RGValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package dev.anvilcraft.rg.api;

public interface RGValidator<T> {
boolean validate(T oldValue, T newValue);

class DefaultValidator implements RGValidator<Object> {
@Override
public boolean validate(Object oldValue, Object newValue) {
return true;
}
}
}
20 changes: 20 additions & 0 deletions src/main/java/dev/anvilcraft/rg/api/Rule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package dev.anvilcraft.rg.api;

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 Rule {
RGEnvironment env() default RGEnvironment.SERVER;

String description() default "";

String serialize() default "";

String[] preset() default {};

Class<? extends RGValidator> validator() default RGValidator.DefaultValidator.class;
}

0 comments on commit 18d61af

Please sign in to comment.