• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stick-i / spel-validator / #94

09 Feb 2026 09:03AM UTC coverage: 97.133%. First build
#94

push

web-flow
Merge 52eeeee6d into 92c946c9c

266 of 280 branches covered (95.0%)

Branch coverage included in aggregate %.

52 of 56 new or added lines in 4 files covered. (92.86%)

581 of 592 relevant lines covered (98.14%)

0.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.59
/spel-validator-core/src/main/java/cn/sticki/spel/validator/core/parse/SpelParser.java
1
package cn.sticki.spel.validator.core.parse;
2

3
import cn.sticki.spel.validator.core.exception.SpelParserException;
4
import lombok.extern.slf4j.Slf4j;
5
import org.intellij.lang.annotations.Language;
6
import org.jetbrains.annotations.NotNull;
7
import org.jetbrains.annotations.Nullable;
8
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
9
import org.springframework.context.ApplicationContext;
10
import org.springframework.context.expression.BeanFactoryResolver;
11
import org.springframework.expression.Expression;
12
import org.springframework.expression.spel.standard.SpelExpressionParser;
13
import org.springframework.expression.spel.support.StandardEvaluationContext;
14

15
import java.util.Map;
16
import java.util.concurrent.ConcurrentHashMap;
17

18
/**
19
 * Spel表达式解析工具
20
 *
21
 * @author 阿杆
22
 * @version 1.0
23
 * @since 2024/4/29
24
 */
25
@SuppressWarnings("AlibabaConstantFieldShouldBeUpperCase")
26
@Slf4j
1✔
27
public class SpelParser {
28

29
    private SpelParser() {
30
    }
31

32
    private static final SpelExpressionParser parser = new SpelExpressionParser();
1✔
33

34
    private static final StandardEvaluationContext context = new StandardEvaluationContext();
1✔
35

36
    private static final Map<String, Expression> expressionCache = new ConcurrentHashMap<>();
1✔
37

38
    // 静态初始化仅输出一次启动日志,BeanResolver 绑定由 SpelValidatorBeanRegistrar 主动触发。
39
    static {
40
        logInitInfo();
1✔
41
    }
1✔
42

43
    private static void logInitInfo() {
44
        if (context.getBeanResolver() == null) {
1!
45
            log.info("SpelParser initialized without BeanResolver, spring bean reference is temporarily unavailable");
1✔
46
            log.info("If you want to use spring bean reference in SpelParser, please use @EnableSpelValidatorBeanRegistrar to enable ApplicationContext support");
1✔
47
        } else {
NEW
48
            log.debug("SpelParser initialized with BeanResolver");
×
49
        }
50
        log.debug("SpelParser init log complete");
1✔
51
    }
1✔
52

53
    /**
54
     * 绑定 Spring BeanResolver。
55
     * 该方法由 {@link SpelValidatorBeanRegistrar} 在 ApplicationContext 注入后主动调用。
56
     */
57
    static void bindBeanResolver(@NotNull ApplicationContext applicationContext) {
58
        synchronized (context) {
1✔
59
            AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
1✔
60
            context.setBeanResolver(new BeanFactoryResolver(beanFactory));
1✔
61
            log.debug("SpelParser bind bean resolver success");
1✔
62
        }
1✔
63
    }
1✔
64

65
    /**
66
     * 解析表达式
67
     *
68
     * @param expression 表达式
69
     * @param rootObject 用于计算表达式的根对象
70
     * @return 表达式计算结果。若为基本数据类型,则会自动转为包装类型。
71
     */
72
    @Nullable
73
    public static Object parse(@Language("spel") String expression, Object rootObject) {
74
        try {
75
            log.debug("======> Parse expression [{}]", expression);
1✔
76
            Expression parsed = expressionCache.computeIfAbsent(expression, parser::parseExpression);
1✔
77
            Object value = parsed.getValue(context, rootObject, Object.class);
1✔
78
            log.debug("======> Parse result [{}]", value);
1✔
79
            return value;
1✔
80
        } catch (RuntimeException e) {
1✔
81
            throw new SpelParserException("Parse expression error, expression [" + expression + "], message [" + e.getMessage() + "]", e);
1✔
82
        }
83
    }
84

85
    /**
86
     * 解析表达式
87
     *
88
     * @param <T>          返回值类型
89
     * @param expression   表达式
90
     * @param rootObject   用于计算表达式的根对象
91
     * @param requiredType 指定返回值的类型
92
     * @return 表达式计算结果。若为基本数据类型,则会自动转为包装类型。
93
     * @throws SpelParserException 当表达式计算结果为null或者不是指定类型时抛出
94
     */
95
    @NotNull
96
    public static <T> T parse(@Language("spel") String expression, Object rootObject, Class<T> requiredType) {
97
        Object any = parse(expression, rootObject);
1✔
98
        if (any == null) {
1✔
99
            throw new SpelParserException("Expression [" + expression + "] calculate result can not be null");
1✔
100
        }
101
        if (!requiredType.isInstance(any)) {
1✔
102
            throw new SpelParserException("Expression [" + expression + "] calculate result must be [" + requiredType.getName() + "]");
1✔
103
        }
104
        //noinspection unchecked
105
        return (T) any;
1✔
106
    }
107

108
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc