Prepare release

This commit is contained in:
chinabugotech
2026-05-25 17:07:04 +08:00
42 changed files with 289 additions and 60 deletions

View File

@@ -1,12 +1,24 @@
# 🚀Changelog
-------------------------------------------------------------------------------------------------------------
# 5.8.45(2026-03-20)
# 5.8.46(2026-05-25)
### 🐣新特性
* 【core 】 `AnnotationUtil`新增两级缓存架构提升高频注解解析性能pr#1434@Gitee
* 【core 】 `RegexPool.PLATE_NUMBER`新增粤AP号段支持issue#IJNDJR@Gitee
### 🐞Bug修复
* 【db 】 修复`Page``PageResult`首页调用问题issue#IH7A18@Gitee
* 【ai 】 修复AI SPI classloader找不到实现问题issue#4241@Github
* 【extra 】 修复`ExpressionEngine`中SpELEngine、MVEL白名单无效问题issue#4249@Github
* 【core 】 修复`JNDIUtil`远程加载漏洞issue#4249@Github
* 【core 】 修复`ValidateObjectInputStream`白名单规则问题issue#4249@Github
* 【core 】 修复`VersionUtil`比对null时结果异常问题issue#IJNFQZ@Gitee
* 【core 】 修复`BeanConverter``MapConverter`源Bean判断问题pr#4252@Github
# 5.8.45(2026-05-19)
### 🐣新特性
* 此版本发布出现问题,跳过!
### 🐞Bug修复
-------------------------------------------------------------------------------------------------------------
# 5.8.44(2026-03-11)

View File

@@ -135,18 +135,18 @@ Each module can be introduced individually, or all modules can be introduced by
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</dependency>
```
### 🍐Gradle
```
implementation 'cn.hutool:hutool-all:5.8.45'
implementation 'cn.hutool:hutool-all:5.8.46'
```
## 📥Download
- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.8.45/)
- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.8.46/)
> 🔔note:
> Hutool 5.x supports JDK8+ and is not tested on Android platforms, and cannot guarantee that all tool classes or tool methods are available.

View File

@@ -125,20 +125,20 @@ Hutool = Hu + tool是原公司项目底层代码剥离后的开源库“Hu
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</dependency>
```
### 🍐Gradle
```
implementation 'cn.hutool:hutool-all:5.8.45'
implementation 'cn.hutool:hutool-all:5.8.46'
```
### 📥下载jar
点击以下链接,下载`hutool-all-X.X.X.jar`即可:
- [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.8.45/)
- [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.8.46/)
> 🔔️注意
> Hutool 5.x支持JDK8+对Android平台没有测试不能保证所有工具类或工具方法可用。

View File

@@ -1 +1 @@
5.8.45
5.8.46

View File

@@ -1 +1 @@
var version = '5.8.45'
var version = '5.8.46'

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-ai</artifactId>

View File

@@ -22,7 +22,6 @@ import cn.hutool.ai.core.AIServiceProvider;
import cn.hutool.core.util.ServiceLoaderUtil;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -37,9 +36,12 @@ public class AIServiceFactory {
// 加载所有 AIModelProvider 实现类
static {
final ServiceLoader<AIServiceProvider> loader = ServiceLoaderUtil.load(AIServiceProvider.class);
for (final AIServiceProvider provider : loader) {
providers.put(provider.getServiceName().toLowerCase(), provider);
for (final AIServiceProvider provider : ServiceLoaderUtil.load(AIServiceProvider.class)) {
providers.putIfAbsent(provider.getServiceName().toLowerCase(), provider);
}
// issue#4241@github多线程和Spring环境下可能导致SPI文件找不到问题
for (final AIServiceProvider provider : ServiceLoaderUtil.load(AIServiceProvider.class, AIServiceProvider.class.getClassLoader())) {
providers.putIfAbsent(provider.getServiceName().toLowerCase(), provider);
}
}

View File

@@ -19,7 +19,6 @@ package cn.hutool.ai.core;
import cn.hutool.core.util.ServiceLoaderUtil;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -34,9 +33,12 @@ public class AIConfigRegistry {
// 加载所有 AIConfig 实现类
static {
final ServiceLoader<AIConfig> loader = ServiceLoaderUtil.load(AIConfig.class);
for (final AIConfig config : loader) {
configClasses.put(config.getModelName().toLowerCase(), config.getClass());
for (final AIConfig config : ServiceLoaderUtil.load(AIConfig.class)) {
configClasses.putIfAbsent(config.getModelName().toLowerCase(), config.getClass());
}
// issue#4241@github多线程和Spring环境下可能导致SPI文件找不到问题
for (final AIConfig config : ServiceLoaderUtil.load(AIConfig.class, AIConfig.class.getClassLoader())) {
configClasses.putIfAbsent(config.getModelName().toLowerCase(), config.getClass());
}
}

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-all</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-aop</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-bloomFilter</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-bom</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-cache</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-captcha</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-core</artifactId>

View File

@@ -79,7 +79,7 @@ public class BeanConverter<T> extends AbstractConverter<T> {
if(value instanceof Map ||
value instanceof ValueProvider ||
BeanUtil.isBean(value.getClass())) {
BeanUtil.isReadableBean(value.getClass())) {
if(value instanceof Map && this.beanClass.isInterface()) {
// 将Map动态代理为Bean
return MapProxy.create((Map<?, ?>)value).toProxyBean(this.beanClass);

View File

@@ -73,7 +73,7 @@ public class MapConverter extends AbstractConverter<Map<?, ?>> {
map = MapUtil.createMap(mapClass);
}
convertMapToMap((Map) value, map);
} else if (BeanUtil.isBean(value.getClass())) {
} else if (BeanUtil.isReadableBean(value.getClass())) {
if(value.getClass().getName().equals("cn.hutool.json.JSONArray")){
// issue#3795 增加JSONArray转Map错误检查
throw new UnsupportedOperationException(StrUtil.format("Unsupported {} to Map.", value.getClass().getName()));

View File

@@ -85,14 +85,7 @@ public class ValidateObjectInputStream extends ObjectInputStream {
}
}
if(CollUtil.isEmpty(this.whiteClassSet)){
return;
}
if(className.startsWith("java.")){
// java中的类默认在白名单中
return;
}
if(this.whiteClassSet.contains(className)){
if(CollUtil.isEmpty(this.whiteClassSet) || this.whiteClassSet.contains(className)){
return;
}

View File

@@ -145,7 +145,7 @@ public interface RegexPool {
*/
String PLATE_NUMBER =
//https://gitee.com/chinabugotech/hutool/issues/I1B77H?from=project-issue
"^(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[ABCDEFGHJK])|([ABCDEFGHJK]([A-HJ-NP-Z0-9])[0-9]{4})))|" +
"^(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[ABCDEFGHJK])|([ABCDEFGHJKP]([A-HJ-NP-Z0-9])[0-9]{4})))|" +
//https://gitee.com/chinabugotech/hutool/issues/I1BJHE?from=project-issue
"([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领]\\d{3}\\d{1,3}[领])|" +
"([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))$";

View File

@@ -8,7 +8,9 @@ import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.InitialDirContext;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
/**
@@ -20,15 +22,20 @@ import java.util.Map;
* 见https://blog.csdn.net/u010430304/article/details/54601302
* </p>
*
* @author loolY
* @author looly
* @since 5.7.7
*/
public class JNDIUtil {
/**
* 创建{@link InitialDirContext}
* 建议在应用启动时设置系统属性(禁用远程 codebase 加载)
* <pre>{@code
* System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "false");
* System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "false");
* }</pre>
*
* @param environment 环境参数,{@code null}表示无参数
* @param environment 环境参数,如@{code java.naming.factory.initial}和{@code java.naming.provider.url}{@code null}表示无参数
* @return {@link InitialDirContext}
*/
public static InitialDirContext createInitialDirContext(Map<String, String> environment) {
@@ -36,6 +43,10 @@ public class JNDIUtil {
if (MapUtil.isEmpty(environment)) {
return new InitialDirContext();
}
// issue#4249 修复JNDI注入漏洞
validateEnvironment(environment);
return new InitialDirContext(Convert.convert(Hashtable.class, environment));
} catch (NamingException e) {
throw new UtilException(e);
@@ -43,9 +54,14 @@ public class JNDIUtil {
}
/**
* 创建{@link InitialContext}
* 创建{@link InitialContext}<br>
* 建议在应用启动时设置系统属性(禁用远程 codebase 加载)
* <pre>{@code
* System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "false");
* System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "false");
* }</pre>
*
* @param environment 环境参数,{@code null}表示无参数
* @param environment 环境参数,如@{code java.naming.factory.initial}和{@code java.naming.provider.url}{@code null}表示无参数
* @return {@link InitialContext}
*/
public static InitialContext createInitialContext(Map<String, String> environment) {
@@ -53,6 +69,10 @@ public class JNDIUtil {
if (MapUtil.isEmpty(environment)) {
return new InitialContext();
}
// issue#4249 修复JNDI注入漏洞
validateEnvironment(environment);
return new InitialContext(Convert.convert(Hashtable.class, environment));
} catch (NamingException e) {
throw new UtilException(e);
@@ -74,4 +94,63 @@ public class JNDIUtil {
throw new UtilException(e);
}
}
private static final List<String> SAFE_PROTOCOLS = Arrays.asList(
"java:",
"dns:"
);
/**
* 验证并过滤environment中的危险属性
*
* @param environment 原始环境参数
* @return 过滤后的环境参数
*/
private static Map<String, String> validateEnvironment(Map<String, String> environment) {
if (MapUtil.isNotEmpty(environment)) {
// 检查 PROVIDER_URL
String providerUrl = environment.get("java.naming.provider.url");
if (StrUtil.isNotBlank(providerUrl) && !isSafeProtocol(providerUrl)) {
throw new UtilException("JNDI protocol not allowed: " + providerUrl);
}
// 检查 INITIAL_CONTEXT_FACTORY
String factory = environment.get("java.naming.factory.initial");
if (StrUtil.isNotBlank(factory)) {
// 只允许安全的工厂类
if (!factory.startsWith("com.sun.jndi.dns.") &&
!factory.startsWith("com.sun.jndi.ldap.") &&
!factory.startsWith("com.sun.jndi.rmi.")) {
throw new UtilException("JNDI factory not allowed: " + factory);
}
}
}
return environment;
}
/**
* 检查URL是否在协议白名单内
*
* @param url 要检查的URL
* @param allowedProtocols 允许的协议列表,{@code null}或空表示使用默认安全协议
* @return 是否安全
*/
private static boolean isSafeProtocol(String url, String... allowedProtocols) {
if (StrUtil.isBlank(url)) {
return false;
}
List<String> protocols = (allowedProtocols != null && allowedProtocols.length > 0)
? Arrays.asList(allowedProtocols)
: SAFE_PROTOCOLS;
String lowerUrl = url.toLowerCase();
for (String protocol : protocols) {
if (lowerUrl.startsWith(protocol.toLowerCase())) {
return true;
}
}
return false;
}
}

View File

@@ -142,7 +142,7 @@ public class VersionUtil {
throw new UtilException("非法的版本分隔符:" + versionsDelimiter);
}
if (StrUtil.isBlank(versionEl) || StrUtil.isBlank(currentVersion)) {
if (StrUtil.isBlank(versionEl)) {
return false;
}
String trimmedVersion = StrUtil.trim(currentVersion);
@@ -158,6 +158,9 @@ public class VersionUtil {
if (matcher.find()) {
String op = matcher.group();
String ver = StrUtil.removePrefix(el, op);
if("null".equalsIgnoreCase( ver)){
ver = null;
}
switch (op) {
case ">=":
case "":

View File

@@ -974,4 +974,85 @@ public class BeanUtilTest {
final boolean bean = BeanUtil.isBean(Dict.class);
assertFalse(bean);
}
// ============ Test for GitHub issue #4245 ============
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Order4245 {
private Long orderId;
private String orderNo;
private List<OrderItem4245> orderItemList;
}
@Getter
@Setter(AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor
public static class OrderItem4245 {
private Long itemId;
private String productName;
private Integer quantity;
}
@Data
public static class OrderDto4245 {
private Long orderId;
private String orderNo;
private List<OrderItemDto4245> orderItemList;
}
@Data
public static class OrderItemDto4245 {
private Long itemId;
private String productName;
private Integer quantity;
}
/**
* GitHub issue#4245: BeanUtil.copyProperties throws ConvertException
* when source list element has protected setters.
*
* <p>Root cause: BeanConverter used isBean() (which checks for public setters)
* on the SOURCE object instead of isReadableBean() (which checks for public getters).
* A source bean only needs to be readable, not writable.</p>
*/
@Test
public void issue4245Test() {
final Order4245 order = new Order4245(
1L,
"01",
new ArrayList<>()
);
order.getOrderItemList().add(
new OrderItem4245(1L, "aa", 1)
);
// This should not throw ConvertException
final OrderDto4245 dto = BeanUtil.copyProperties(order, OrderDto4245.class);
assertNotNull(dto);
assertEquals(order.getOrderId(), dto.getOrderId());
assertEquals(order.getOrderNo(), dto.getOrderNo());
assertNotNull(dto.getOrderItemList());
assertEquals(1, dto.getOrderItemList().size());
assertEquals(Long.valueOf(1L), dto.getOrderItemList().get(0).getItemId());
assertEquals("aa", dto.getOrderItemList().get(0).getProductName());
assertEquals(Integer.valueOf(1), dto.getOrderItemList().get(0).getQuantity());
}
/**
* Test map conversion with protected setter bean
*/
@Test
public void issue4245MapConvertTest() {
final OrderItem4245 item = new OrderItem4245(1L, "aa", 1);
// Should not throw UnsupportedOperationException
final Map<String, Object> map = BeanUtil.beanToMap(item);
assertNotNull(map);
assertEquals(1L, map.get("itemId"));
assertEquals("aa", map.get("productName"));
assertEquals(1, map.get("quantity"));
}
}

View File

@@ -167,6 +167,15 @@ public class ValidatorTest {
assertTrue(Validator.isPlateNumber("闽20401领"));
//issue#3979
assertTrue(Validator.isPlateNumber("沪AE22075"));
// issue#IJNDJR
assertTrue(Validator.isPlateNumber("粤AP00000"));
assertTrue(Validator.isPlateNumber("粤AP00001"));
assertTrue(Validator.isPlateNumber("粤AP10000"));
assertTrue(Validator.isPlateNumber("粤AP20000"));
assertTrue(Validator.isPlateNumber("粤AP30000"));
assertTrue(Validator.isPlateNumber("粤AP40000"));
assertTrue(Validator.isPlateNumber("粤AP50000"));
}
@Test

View File

@@ -1,6 +1,7 @@
package cn.hutool.core.util;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.comparator.VersionComparator;
import cn.hutool.core.exceptions.UtilException;
import org.junit.jupiter.api.Test;
@@ -104,4 +105,10 @@ class VersionUtilTest {
assertTrue(VersionUtil.matchEl("999.999.999", "-"));
}
@Test
void issueIJNFQZTest(){
assertEquals(1, VersionComparator.INSTANCE.compare("1.0", null));
assertEquals(1, StrUtil.compareVersion("1.0", null));
assertTrue(VersionUtil.isGreaterThan("1.0", null));
}
}

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-cron</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-crypto</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-db</artifactId>
@@ -145,7 +145,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.3</version>
<version>42.7.11</version>
<scope>test</scope>
</dependency>
<dependency>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-dfa</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-extra</artifactId>
@@ -24,7 +24,7 @@
<rythm.version>1.4.2</rythm.version>
<freemarker.version>2.3.32</freemarker.version>
<enjoy.version>5.1.3</enjoy.version>
<thymeleaf.version>3.1.2.RELEASE</thymeleaf.version>
<thymeleaf.version>3.1.5.RELEASE</thymeleaf.version>
<mail.version>1.6.2</mail.version>
<jsch.version>0.1.55</jsch.version>
<sshj.version>0.38.0</sshj.version>

View File

@@ -1,6 +1,8 @@
package cn.hutool.extra.expression.engine.mvel;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.extra.expression.ExpressionEngine;
import cn.hutool.extra.expression.ExpressionException;
import org.mvel2.MVEL;
import java.util.Collection;
@@ -27,6 +29,16 @@ public class MvelEngine implements ExpressionEngine {
@Override
public Object eval(String expression, Map<String, Object> context, Collection<Class<?>> allowClassSet) {
// issue#4249 检查context的value类型是否在白名单中不在则抛出异常
if(CollUtil.isNotEmpty(allowClassSet)){
context.values().forEach(value -> {
if(!allowClassSet.contains(value.getClass())){
throw new ExpressionException("Value type [{}] is not in allowClassSet [{}]", value.getClass(), allowClassSet);
}
});
}
return MVEL.eval(expression, context);
}

View File

@@ -1,7 +1,9 @@
package cn.hutool.extra.expression.engine.rhino;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.extra.expression.ExpressionEngine;
import cn.hutool.extra.expression.ExpressionException;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
@@ -24,6 +26,16 @@ public class RhinoEngine implements ExpressionEngine {
@Override
public Object eval(String expression, Map<String, Object> context, Collection<Class<?>> allowClassSet) {
// issue#4249 检查context的value类型是否在白名单中不在则抛出异常
if(CollUtil.isNotEmpty(allowClassSet)){
context.values().forEach(value -> {
if(!allowClassSet.contains(value.getClass())){
throw new ExpressionException("Value type [{}] is not in allowClassSet [{}]", value.getClass(), allowClassSet);
}
});
}
final Context ctx = Context.enter();
final Scriptable scope = ctx.initStandardObjects();
if (MapUtil.isNotEmpty(context)) {

View File

@@ -1,10 +1,12 @@
package cn.hutool.extra.expression.engine.spel;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.extra.expression.ExpressionEngine;
import cn.hutool.extra.expression.ExpressionException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import java.util.Collection;
import java.util.Map;
@@ -29,7 +31,22 @@ public class SpELEngine implements ExpressionEngine {
@Override
public Object eval(String expression, Map<String, Object> context, Collection<Class<?>> allowClassSet) {
final EvaluationContext evaluationContext = new StandardEvaluationContext();
// final EvaluationContext evaluationContext = new StandardEvaluationContext();
// issue#4249 检查context的value类型是否在白名单中不在则抛出异常
if(CollUtil.isNotEmpty(allowClassSet)){
context.values().forEach(value -> {
if(!allowClassSet.contains(value.getClass())){
throw new ExpressionException("Value type [{}] is not in allowClassSet [{}]", value.getClass(), allowClassSet);
}
});
}
EvaluationContext evaluationContext = SimpleEvaluationContext
.forReadOnlyDataBinding()
.withInstanceMethods() // 仅允许调用白名单类的实例方法
.build();
context.forEach(evaluationContext::setVariable);
return parser.parseExpression(expression).getValue(evaluationContext);
}

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-http</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-json</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-jwt</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-log</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-poi</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-script</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-setting</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-socket</artifactId>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
</parent>
<artifactId>hutool-system</artifactId>

View File

@@ -8,7 +8,7 @@
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.45</version>
<version>5.8.46</version>
<name>hutool</name>
<description>Hutool是一个小而全的Java工具类库通过静态方法封装降低相关API的学习成本提高工作效率使Java拥有函数式语言般的优雅让Java语言也可以“甜甜的”。</description>
<url>https://github.com/chinabugotech/hutool</url>