Skip to content

Commit

Permalink
feat: 升级到 0.3.0-beta (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
stick-i authored Oct 13, 2024
2 parents a982eba + 13eba51 commit 3a1b422
Show file tree
Hide file tree
Showing 32 changed files with 1,471 additions and 58 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/mvn-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: run mvn test

on: [ push, pull_request, workflow_dispatch ]

jobs:
run-mvn-test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: '8'
cache: maven

- run: |
java -version
mvn -v
- run: mvn verify
- run: mvn clean test jacoco:report coveralls:report -DrepoToken="${{secrets.COVERALLS_TOKEN}}"
46 changes: 46 additions & 0 deletions .run/jacoco_report.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="jacoco:report" type="MavenRunConfiguration" factoryName="Maven">
<MavenSettings>
<option name="myGeneralSettings"/>
<option name="myRunnerSettings"/>
<option name="myRunnerParameters">
<MavenRunnerParameters>
<option name="cmdOptions"/>
<option name="profiles">
<set/>
</option>
<option name="goals">
<list>
<option value="clean"/>
<option value="test"/>
<option value="jacoco:report"/>
</list>
</option>
<option name="multimoduleDir"/>
<option name="pomFileName" value="pom.xml"/>
<option name="profilesMap">
<map>
<entry key="release" value="false"/>
</map>
</option>
<option name="projectsCmdOptionValues">
<list/>
</option>
<option name="resolveToWorkspace" value="false"/>
<option name="workingDirPath" value="$PROJECT_DIR$"/>
</MavenRunnerParameters>
</option>
</MavenSettings>
<extension name="net.ashald.envfile">
<option name="IS_ENABLED" value="false"/>
<option name="IS_SUBST" value="false"/>
<option name="IS_PATH_MACRO_SUPPORTED" value="false"/>
<option name="IS_IGNORE_MISSING_FILES" value="false"/>
<option name="IS_ENABLE_EXPERIMENTAL_INTEGRATIONS" value="false"/>
<ENTRIES>
<ENTRY IS_ENABLED="true" PARSER="runconfig"/>
</ENTRIES>
</extension>
<method v="2"/>
</configuration>
</component>
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# SpEL Validator

[![Coverage Status](https://coveralls.io/repos/github/stick-i/spel-validator/badge.svg?branch=main)](https://coveralls.io/github/stick-i/spel-validator?branch=main)
[![Maven Central](https://img.shields.io/maven-central/v/cn.sticki/spel-validator.svg)](https://central.sonatype.com/search?q=g:cn.sticki%20a:spel-validator)
[![license](https://img.shields.io/github/license/stick-i/spel-validator)](https://github.com/stick-i/spel-validator/blob/main/LICENSE)

一个强大的 Java 参数校验包,基于 SpEL 实现,扩展自 javax.validation 包,用于简化参数校验,几乎支持所有场景下的参数校验。


## 项目地址

- GitHub:https://github.com/stick-i/spel-validator
Expand Down
21 changes: 13 additions & 8 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<groupId>cn.sticki</groupId>
<artifactId>spel-validator</artifactId>
<version>0.2.0-beta</version>
<version>0.3.0-beta</version>
<packaging>jar</packaging>
<name>Spel Validator</name>
<url>https://github.com/stick-i/spel-validator</url>
Expand Down Expand Up @@ -139,6 +139,12 @@
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<!-- 若要在GitHub Actions上执行mvn test,则必须添加此插件才能成功执行 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>
<!-- Source -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
Expand Down Expand Up @@ -169,15 +175,14 @@
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 测试报告上传Coveralls -->
<plugin>
<groupId>com.github.hazendaz.maven</groupId>
<artifactId>coveralls-maven-plugin</artifactId>
<version>4.5.0-M2</version>
</plugin>
</plugins>
</build>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ private static <A extends Annotation> FieldValidResult doValidate(
// noinspection unchecked
result = ((SpelConstraintValidator<A>) validator).isValid(annotation, verifiedObject, verifiedField);
} catch (SpelValidatorException e) {
log.error("Spel validate error: {} ;Located in the annotation [{}] of class [{}] field [{}]",
log.error("Spel validate error: {}; Located in the annotation [{}] of class [{}] field [{}]",
e.getMessage(), annotation.annotationType().getName(), verifiedObject.getClass().getName(), verifiedField.getName());
throw e;
} catch (IllegalAccessException e) {
Expand Down
74 changes: 74 additions & 0 deletions src/main/java/cn/sticki/validator/spel/constrain/SpelMax.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package cn.sticki.validator.spel.constrain;

import cn.sticki.validator.spel.SpelConstraint;
import cn.sticki.validator.spel.SpelValid;
import cn.sticki.validator.spel.constraintvalidator.SpelMaxValidator;
import org.intellij.lang.annotations.Language;

import java.lang.annotation.Documented;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
* 被标记的元素值必须小于或等于指定的最小值。{@code null} 元素被认为是有效的。
* <p>
* 支持所有 {@link Number} 类型及它们的基本数据类型。
*
* @author 阿杆
* @version 1.0
* @since 2024/9/29
*/
@Documented
@Retention(RUNTIME)
@Target(FIELD)
@Repeatable(SpelMax.List.class)
@SpelConstraint(validatedBy = SpelMaxValidator.class)
public @interface SpelMax {

/**
* 校验失败时的错误消息。
*/
String message() default "必须小于或等于 {value}";

/**
* 约束开启条件,必须为合法的SpEL表达式,计算结果必须为boolean类型。
* <p>
* 当 表达式为空 或 计算结果为true 时,会对带注解的元素进行校验。
* <p>
* 默认情况下,开启校验。
*/
@Language("SpEL")
String condition() default "";

/**
* 分组条件,必须为合法的SpEL表达式。
* <p>
* 当分组信息不为空时,只有当 {@link SpelValid#spelGroups()} 中的分组信息与此处的分组信息有交集时,才会对带注解的元素进行校验。
* <p>
* 其计算结果可以是任何类型,但只有两个计算结果完全相等时,才被认为是相等的。
*/
@Language("SpEL")
String[] group() default {};

/**
* 指定元素最大值。必须为合法的SpEL表达式,
* <p>
* 表达式的计算结果必须为 {@link Number} 类型。
*/
@Language("SpEL")
String value() default "0";

@Documented
@Target(FIELD)
@Retention(RUNTIME)
@interface List {

SpelMax[] value();

}

}
73 changes: 73 additions & 0 deletions src/main/java/cn/sticki/validator/spel/constrain/SpelMin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package cn.sticki.validator.spel.constrain;

import cn.sticki.validator.spel.SpelConstraint;
import cn.sticki.validator.spel.SpelValid;
import cn.sticki.validator.spel.constraintvalidator.SpelMinValidator;
import org.intellij.lang.annotations.Language;

import java.lang.annotation.Documented;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
* 被标记的元素值必须大于或等于指定的最小值。{@code null} 元素被认为是有效的。
* <p>
* 支持所有 {@link Number} 类型及它们的基本数据类型。
*
* @author oddfar、阿杆
* @version 1.0
* @since 2024/8/25
*/
@Documented
@Retention(RUNTIME)
@Target(FIELD)
@Repeatable(SpelMin.List.class)
@SpelConstraint(validatedBy = SpelMinValidator.class)
public @interface SpelMin {

/**
* 校验失败时的错误消息。
*/
String message() default "必须大于或等于 {value}";

/**
* 约束开启条件,必须为合法的SpEL表达式,计算结果必须为boolean类型。
* <p>
* 当 表达式为空 或 计算结果为true 时,会对带注解的元素进行校验。
* <p>
* 默认情况下,开启校验。
*/
@Language("SpEL")
String condition() default "";

/**
* 分组条件,必须为合法的SpEL表达式。
* <p>
* 当分组信息不为空时,只有当 {@link SpelValid#spelGroups()} 中的分组信息与此处的分组信息有交集时,才会对带注解的元素进行校验。
* <p>
* 其计算结果可以是任何类型,但只有两个计算结果完全相等时,才被认为是相等的。
*/
@Language("SpEL")
String[] group() default {};

/**
* 指定元素最小值。必须为合法的SpEL表达式,
* <p>
* 表达式的计算结果必须为 {@link Number} 类型。
*/
@Language("SpEL")
String value() default "0";

@Documented
@Target(FIELD)
@Retention(RUNTIME)
@interface List {

SpelMin[] value();

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package cn.sticki.validator.spel.constraintvalidator;

import cn.sticki.validator.spel.SpelConstraintValidator;
import cn.sticki.validator.spel.exception.SpelParserException;
import cn.sticki.validator.spel.parse.SpelParser;
import cn.sticki.validator.spel.result.FieldValidResult;

import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
* 约束注解 Max、Min 的抽象校验器。
*
* @author oddfar、阿杆
* @version 1.0
* @since 2024/8/25
*/
public abstract class AbstractSpelNumberCompareValidator<T extends Annotation> implements SpelConstraintValidator<T> {

public FieldValidResult isValid(Number fieldValue, String spel, String errorMessage, Object obj) {
// 元素为null是被允许的
if (fieldValue == null) {
return FieldValidResult.success();
}
// 计算表达式的值,基本数据类型会自动装箱
Object minValue = SpelParser.parse(spel, obj);
if (!(minValue instanceof Number)) {
throw new SpelParserException("Expression [" + spel + "] calculate result must be Number.");
}
// 比较大小,其中一个是Not-a-Number (NaN)默认失败
if (!this.compare(fieldValue, (Number) minValue)) {
// todo 目前对Double的边界值处理不太友好,message的展示类似为:不能小于等于 NaN。后续考虑去掉对Double Float类型的支持,或者对边界值抛出异常。
// 构建错误信息
String replacedMessage = errorMessage.replace("{value}", String.valueOf(minValue));
return new FieldValidResult(false, replacedMessage);
}

return FieldValidResult.success();
}

/**
* 比较两个数值的大小,返回比较结果。
*
* @param fieldValue 当前元素的值
* @param compareValue 比较的值,最大值或最小值
* @return 成功时返回true,失败时返回false
*/
protected abstract boolean compare(Number fieldValue, Number compareValue);

static final Set<Class<?>> SUPPORT_TYPE;

static {
HashSet<Class<?>> hashSet = new HashSet<>();
hashSet.add(Number.class);
hashSet.add(int.class);
hashSet.add(long.class);
hashSet.add(float.class);
hashSet.add(double.class);
hashSet.add(short.class);
hashSet.add(byte.class);
SUPPORT_TYPE = Collections.unmodifiableSet(hashSet);
}

@Override
public Set<Class<?>> supportType() {
return SUPPORT_TYPE;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package cn.sticki.validator.spel.constraintvalidator;

import cn.sticki.validator.spel.constrain.SpelMax;
import cn.sticki.validator.spel.result.FieldValidResult;
import cn.sticki.validator.spel.util.NumberComparatorUtil;

import java.lang.reflect.Field;

/**
* {@link SpelMax} 注解校验器。
*
* @author 阿杆
* @version 1.0
* @since 2024/9/29
*/
public class SpelMaxValidator extends AbstractSpelNumberCompareValidator<SpelMax> {

@Override
protected boolean compare(Number fieldValue, Number compareValue) {
return NumberComparatorUtil.compare(fieldValue, compareValue, NumberComparatorUtil.GREATER_THAN) <= 0;
}

@Override
public FieldValidResult isValid(SpelMax annotation, Object obj, Field field) throws IllegalAccessException {
return super.isValid((Number) field.get(obj), annotation.value(), annotation.message(), obj);
}

}
Loading

0 comments on commit 3a1b422

Please sign in to comment.