Skip to content

Commit eca6c16

Browse files
committed
perf: 优化测试工具代码,便于后续直接对内部验证类进行处理
1 parent 6305ac6 commit eca6c16

File tree

4 files changed

+161
-86
lines changed

4 files changed

+161
-86
lines changed

spel-validator-core/src/main/java/cn/sticki/spel/validator/core/result/ObjectValidResult.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*/
1414
public class ObjectValidResult {
1515

16-
private final ArrayList<FieldError> errors = new ArrayList<>();
16+
private final List<FieldError> errors = new ArrayList<>();
1717

1818
public boolean hasError() {
1919
return !errors.isEmpty();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package cn.sticki.spel.validator.javax.util;
2+
3+
import javax.validation.ConstraintViolation;
4+
import java.util.*;
5+
import java.util.stream.Collectors;
6+
7+
/**
8+
* 约束违反集合
9+
* <p>
10+
* 用于存储校验结果,根据字段名和期望的错误信息来获取字段约束结果
11+
*
12+
* @author 阿杆
13+
* @since 2024/10/29
14+
*/
15+
public class ConstraintViolationSet {
16+
17+
private static final ConstraintViolationSet EMPTY = new ConstraintViolationSet(Collections.emptyList());
18+
19+
private final Map<String, List<VerifyFailedField>> verifyMap;
20+
21+
public ConstraintViolationSet(Collection<VerifyFailedField> failedFields) {
22+
if (failedFields == null || failedFields.isEmpty()) {
23+
verifyMap = Collections.emptyMap();
24+
return;
25+
}
26+
27+
this.verifyMap = failedFields.stream().collect(Collectors.groupingBy(VerifyFailedField::getName));
28+
}
29+
30+
public static ConstraintViolationSet of(Set<ConstraintViolation<Object>> validate) {
31+
if (validate == null || validate.isEmpty()) {
32+
return EMPTY;
33+
}
34+
List<VerifyFailedField> list = validate.stream().map(ConstraintViolationSet::convert).collect(Collectors.toList());
35+
return new ConstraintViolationSet(list);
36+
}
37+
38+
public static ConstraintViolationSet of(List<VerifyFailedField> validate) {
39+
return new ConstraintViolationSet(validate);
40+
}
41+
42+
private static VerifyFailedField convert(ConstraintViolation<Object> violation) {
43+
return VerifyFailedField.of(violation.getPropertyPath().toString(), violation.getMessage());
44+
}
45+
46+
/**
47+
* 根据字段和期望的错误信息来获取字段约束结果
48+
*
49+
* @param fieldName 字段名
50+
* @param expectMessage 期望的错误信息
51+
* @return 字段约束结果,当 expectMessage 不为null时,会优先匹配具有相同message的数据
52+
*/
53+
public VerifyFailedField getAndRemove(String fieldName, String expectMessage) {
54+
List<VerifyFailedField> violationList = verifyMap.get(fieldName);
55+
if (violationList == null || violationList.isEmpty()) {
56+
return null;
57+
}
58+
if (violationList.size() == 1 || expectMessage == null) {
59+
VerifyFailedField violation = violationList.get(0);
60+
verifyMap.remove(fieldName);
61+
return violation;
62+
}
63+
// 当存在多个约束时,优先匹配具有相同message的数据。
64+
// 否则当一个字段有多个约束条件时,无法匹配到期望的约束。
65+
for (VerifyFailedField violation : violationList) {
66+
if (expectMessage.equals(violation.getMessage())) {
67+
violationList.remove(violation);
68+
return violation;
69+
}
70+
}
71+
72+
return violationList.remove(0);
73+
}
74+
75+
/**
76+
* 获取所有的约束违反字段
77+
*/
78+
public Set<VerifyFailedField> getAll() {
79+
return verifyMap.values().stream().flatMap(List::stream).collect(Collectors.toSet());
80+
}
81+
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package cn.sticki.spel.validator.javax.util;
2+
3+
import lombok.extern.slf4j.Slf4j;
4+
import org.slf4j.MDC;
5+
6+
/**
7+
* 日志上下文
8+
*
9+
* @author 阿杆
10+
* @since 2024/10/29
11+
*/
12+
@Slf4j
13+
public class LogContext {
14+
15+
/**
16+
* 设置验证对象日志上下文
17+
*/
18+
public static void setValidateObject(Object object) {
19+
String className = object.getClass().getSimpleName();
20+
Class<?> enclosingClass = object.getClass().getEnclosingClass();
21+
if (enclosingClass != null) {
22+
className = enclosingClass.getSimpleName() + "." + className;
23+
}
24+
25+
MDC.put("className", className);
26+
MDC.put("fullClassName", abbreviate(object.getClass().getName()));
27+
if (object instanceof ID) {
28+
MDC.put("id", String.valueOf(((ID) object).getId()));
29+
}
30+
}
31+
32+
/**
33+
* 清除验证对象日志上下文
34+
*/
35+
public static void clearValidateObject() {
36+
MDC.remove("id");
37+
MDC.remove("className");
38+
MDC.remove("fieldName");
39+
MDC.remove("fullClassName");
40+
}
41+
42+
public static void set(String key, String value) {
43+
MDC.put(key, value);
44+
}
45+
46+
public static void remove(String key) {
47+
MDC.remove(key);
48+
}
49+
50+
/**
51+
* 缩写类名
52+
*/
53+
private static String abbreviate(String className) {
54+
String[] parts = className.split("\\.");
55+
StringBuilder abbreviated = new StringBuilder();
56+
for (int i = 0; i < parts.length - 1; i++) {
57+
abbreviated.append(parts[i].charAt(0)).append(".");
58+
}
59+
abbreviated.append(parts[parts.length - 1]);
60+
return abbreviated.toString();
61+
}
62+
63+
}
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
package cn.sticki.spel.validator.javax.util;
22

33
import lombok.extern.slf4j.Slf4j;
4-
import org.slf4j.MDC;
54

65
import javax.validation.ConstraintViolation;
76
import javax.validation.Validation;
87
import javax.validation.Validator;
9-
import java.util.*;
10-
import java.util.stream.Collectors;
8+
import java.util.Collection;
9+
import java.util.List;
10+
import java.util.Set;
1111

1212
/**
1313
* 测试验证工具类
@@ -55,25 +55,14 @@ public static boolean checkConstraintResult(VerifyObject verifyObject) {
5555
boolean expectException = verifyObject.isExpectException();
5656

5757
// 设置日志上下文
58-
String className = object.getClass().getSimpleName();
59-
Class<?> enclosingClass = object.getClass().getEnclosingClass();
60-
if (enclosingClass != null) {
61-
className = enclosingClass.getSimpleName() + "." + className;
62-
}
63-
64-
MDC.put("className", className);
65-
MDC.put("fullClassName", abbreviate(object.getClass().getName()));
66-
if (object instanceof ID) {
67-
MDC.put("id", String.valueOf(((ID) object).getId()));
68-
}
69-
58+
LogContext.setValidateObject(object);
7059
log.info("Start checking object: {}", object);
7160

7261
int failCount = 0;
7362
try {
7463
// 执行约束校验
7564
Set<ConstraintViolation<Object>> validate = ValidateUtil.validate(object);
76-
failCount += calcFailCount(verifyFailedFields, ViolationSet.of(validate));
65+
failCount += processVerifyResult(verifyFailedFields, ConstraintViolationSet.of(validate));
7766
} catch (Exception e) {
7867
if (expectException) {
7968
log.info("Passed, Capture exception {}, message: {}", e.getClass(), e.getMessage());
@@ -95,30 +84,32 @@ public static boolean checkConstraintResult(VerifyObject verifyObject) {
9584
log.error("Verification end, number of failures: {}", failCount);
9685
}
9786
log.info("------------------------------------------------------------------------");
98-
MDC.clear();
87+
LogContext.clearValidateObject();
9988

10089
return failCount == 0;
10190
}
10291

10392
/**
104-
* 计算验证字段约束的失败次数
93+
* 处理验证结果
10594
*
10695
* @param verifyFailedFields 预期失败字段
10796
* @param violationSet 验证结果
97+
* @return 验证失败的次数
10898
*/
109-
private static int calcFailCount(Collection<VerifyFailedField> verifyFailedFields, ViolationSet violationSet) {
99+
private static int processVerifyResult(Collection<VerifyFailedField> verifyFailedFields, ConstraintViolationSet violationSet) {
100+
final String fieldNameLogKey = "fieldName";
110101
int failCount = 0;
111102
// 检查结果是否符合预期
112103
for (VerifyFailedField verifyFailedField : verifyFailedFields) {
113104
String fieldName = verifyFailedField.getName();
114-
MDC.put("fieldName", fieldName);
105+
LogContext.set(fieldNameLogKey, fieldName);
115106
String message = verifyFailedField.getMessage();
116107

117108
log.info("Expected exception information: {}", message == null ? "ignore" : message);
118109

119110
boolean fieldMatch = false, find = false;
120111

121-
ConstraintViolation<Object> violation = violationSet.getAndRemove(fieldName, message);
112+
VerifyFailedField violation = violationSet.getAndRemove(fieldName, message);
122113
if (violation != null) {
123114
find = true;
124115
log.info("Real exception information: {}", violation.getMessage());
@@ -141,75 +132,14 @@ private static int calcFailCount(Collection<VerifyFailedField> verifyFailedField
141132
}
142133
}
143134

144-
MDC.remove("fieldName");
135+
LogContext.remove(fieldNameLogKey);
145136
// 被忽略的字段
146-
for (ConstraintViolation<Object> violation : violationSet.getAll()) {
147-
log.error("Field [{}] is ignored", violation.getPropertyPath().toString());
137+
for (VerifyFailedField violation : violationSet.getAll()) {
138+
log.error("Field [{}] is ignored", violation.getName());
148139
failCount++;
149140
}
150141
return failCount;
151142
}
152143

153-
public static String abbreviate(String className) {
154-
String[] parts = className.split("\\.");
155-
StringBuilder abbreviated = new StringBuilder();
156-
for (int i = 0; i < parts.length - 1; i++) {
157-
abbreviated.append(parts[i].charAt(0)).append(".");
158-
}
159-
abbreviated.append(parts[parts.length - 1]);
160-
return abbreviated.toString();
161-
}
162-
163-
static class ViolationSet {
164-
165-
private final Map<String, List<ConstraintViolation<Object>>> violationMap;
166-
167-
public ViolationSet(Set<ConstraintViolation<Object>> validate) {
168-
if (validate == null || validate.isEmpty()) {
169-
violationMap = Collections.emptyMap();
170-
return;
171-
}
172-
violationMap = validate.stream().collect(
173-
Collectors.groupingBy(violation -> violation.getPropertyPath().toString())
174-
);
175-
}
176-
177-
public static ViolationSet of(Set<ConstraintViolation<Object>> validate) {
178-
return new ViolationSet(validate);
179-
}
180-
181-
/**
182-
* 根据字段和期望的错误信息来获取字段约束结果
183-
*
184-
* @param fieldName 字段名
185-
* @param expectMessage 期望的错误信息
186-
* @return 字段约束结果,当 expectMessage 不为null时,会优先匹配具有相同message的数据
187-
*/
188-
public ConstraintViolation<Object> getAndRemove(String fieldName, String expectMessage) {
189-
List<ConstraintViolation<Object>> violationList = violationMap.get(fieldName);
190-
if (violationList == null || violationList.isEmpty()) {
191-
return null;
192-
}
193-
if (violationList.size() == 1 || expectMessage == null) {
194-
ConstraintViolation<Object> violation = violationList.get(0);
195-
violationMap.remove(fieldName);
196-
return violation;
197-
}
198-
// 当存在多个约束时,优先匹配具有相同message的数据
199-
for (ConstraintViolation<Object> violation : violationList) {
200-
if (expectMessage.equals(violation.getMessage())) {
201-
violationList.remove(violation);
202-
return violation;
203-
}
204-
}
205-
206-
return violationList.remove(0);
207-
}
208-
209-
public Set<ConstraintViolation<Object>> getAll() {
210-
return violationMap.values().stream().flatMap(List::stream).collect(Collectors.toSet());
211-
}
212-
213-
}
214144

215145
}

0 commit comments

Comments
 (0)