diff --git a/CHANGELOG.md b/CHANGELOG.md
index 01e73fbc03..837246d0ae 100755
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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)
diff --git a/README-EN.md b/README-EN.md
index 8724b132c7..e402d0248c 100755
--- a/README-EN.md
+++ b/README-EN.md
@@ -135,18 +135,18 @@ Each module can be introduced individually, or all modules can be introduced by
cn.hutool
hutool-all
- 5.8.45
+ 5.8.46
```
### 🍐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.
diff --git a/README.md b/README.md
index 3c3718bef3..d61597e2ae 100755
--- a/README.md
+++ b/README.md
@@ -125,20 +125,20 @@ Hutool = Hu + tool,是原公司项目底层代码剥离后的开源库,“Hu
cn.hutool
hutool-all
- 5.8.45
+ 5.8.46
```
### 🍐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平台没有测试,不能保证所有工具类或工具方法可用。
diff --git a/bin/version.txt b/bin/version.txt
index 308d84bdbe..d09e11b30c 100755
--- a/bin/version.txt
+++ b/bin/version.txt
@@ -1 +1 @@
-5.8.45
+5.8.46
diff --git a/docs/js/version.js b/docs/js/version.js
index 1db7f384e1..25746828a4 100755
--- a/docs/js/version.js
+++ b/docs/js/version.js
@@ -1 +1 @@
-var version = '5.8.45'
\ No newline at end of file
+var version = '5.8.46'
\ No newline at end of file
diff --git a/hutool-ai/pom.xml b/hutool-ai/pom.xml
index 3e9b7a95ac..adf6ac2f32 100755
--- a/hutool-ai/pom.xml
+++ b/hutool-ai/pom.xml
@@ -6,7 +6,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-ai
diff --git a/hutool-ai/src/main/java/cn/hutool/ai/AIServiceFactory.java b/hutool-ai/src/main/java/cn/hutool/ai/AIServiceFactory.java
index 23cb874037..928bf27204 100755
--- a/hutool-ai/src/main/java/cn/hutool/ai/AIServiceFactory.java
+++ b/hutool-ai/src/main/java/cn/hutool/ai/AIServiceFactory.java
@@ -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 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);
}
}
diff --git a/hutool-ai/src/main/java/cn/hutool/ai/core/AIConfigRegistry.java b/hutool-ai/src/main/java/cn/hutool/ai/core/AIConfigRegistry.java
index 6166440495..d6070bda0b 100755
--- a/hutool-ai/src/main/java/cn/hutool/ai/core/AIConfigRegistry.java
+++ b/hutool-ai/src/main/java/cn/hutool/ai/core/AIConfigRegistry.java
@@ -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 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());
}
}
diff --git a/hutool-all/pom.xml b/hutool-all/pom.xml
index 244f7e782f..38b290a97e 100755
--- a/hutool-all/pom.xml
+++ b/hutool-all/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-all
diff --git a/hutool-aop/pom.xml b/hutool-aop/pom.xml
index ba8cc25072..1fb998dee6 100755
--- a/hutool-aop/pom.xml
+++ b/hutool-aop/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-aop
diff --git a/hutool-bloomFilter/pom.xml b/hutool-bloomFilter/pom.xml
index 2923f5b520..7acdda3975 100755
--- a/hutool-bloomFilter/pom.xml
+++ b/hutool-bloomFilter/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-bloomFilter
diff --git a/hutool-bom/pom.xml b/hutool-bom/pom.xml
index 974466963f..491c712e3d 100755
--- a/hutool-bom/pom.xml
+++ b/hutool-bom/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-bom
diff --git a/hutool-cache/pom.xml b/hutool-cache/pom.xml
index 5aee84cc39..defaa54a17 100755
--- a/hutool-cache/pom.xml
+++ b/hutool-cache/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-cache
diff --git a/hutool-captcha/pom.xml b/hutool-captcha/pom.xml
index e0c25a6d10..2eabb09e14 100755
--- a/hutool-captcha/pom.xml
+++ b/hutool-captcha/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-captcha
diff --git a/hutool-core/pom.xml b/hutool-core/pom.xml
index 6b1c9dc77a..546cfe641c 100755
--- a/hutool-core/pom.xml
+++ b/hutool-core/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-core
diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java
index 42abb70f6c..7cfd124ef2 100755
--- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java
+++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java
@@ -79,7 +79,7 @@ public class BeanConverter extends AbstractConverter {
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);
diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java
index f01a46c049..6f0f3375c8 100755
--- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java
+++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java
@@ -73,7 +73,7 @@ public class MapConverter extends AbstractConverter
*
- * @author loolY
+ * @author looly
* @since 5.7.7
*/
public class JNDIUtil {
/**
* 创建{@link InitialDirContext}
+ * 建议在应用启动时设置系统属性(禁用远程 codebase 加载)
+ * {@code
+ * System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "false");
+ * System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "false");
+ * }
*
- * @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 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}
+ * 建议在应用启动时设置系统属性(禁用远程 codebase 加载)
+ * {@code
+ * System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "false");
+ * System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "false");
+ * }
*
- * @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 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 SAFE_PROTOCOLS = Arrays.asList(
+ "java:",
+ "dns:"
+ );
+
+ /**
+ * 验证并过滤environment中的危险属性
+ *
+ * @param environment 原始环境参数
+ * @return 过滤后的环境参数
+ */
+ private static Map validateEnvironment(Map 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 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;
+ }
}
diff --git a/hutool-core/src/main/java/cn/hutool/core/util/VersionUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/VersionUtil.java
index aa666c97d3..706483f0da 100755
--- a/hutool-core/src/main/java/cn/hutool/core/util/VersionUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/util/VersionUtil.java
@@ -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 "≥":
diff --git a/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java
index c52d6c18e8..751874fa3f 100755
--- a/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java
@@ -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 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 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.
+ *
+ * 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.
+ */
+ @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 map = BeanUtil.beanToMap(item);
+ assertNotNull(map);
+ assertEquals(1L, map.get("itemId"));
+ assertEquals("aa", map.get("productName"));
+ assertEquals(1, map.get("quantity"));
+ }
}
diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/ValidatorTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/ValidatorTest.java
index c09cb77df5..125a46591b 100755
--- a/hutool-core/src/test/java/cn/hutool/core/lang/ValidatorTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/lang/ValidatorTest.java
@@ -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
diff --git a/hutool-core/src/test/java/cn/hutool/core/util/VersionUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/VersionUtilTest.java
index e89abd046b..f5a7a640a8 100755
--- a/hutool-core/src/test/java/cn/hutool/core/util/VersionUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/util/VersionUtilTest.java
@@ -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));
+ }
}
diff --git a/hutool-cron/pom.xml b/hutool-cron/pom.xml
index 893239050c..ddbbbf1483 100755
--- a/hutool-cron/pom.xml
+++ b/hutool-cron/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-cron
diff --git a/hutool-crypto/pom.xml b/hutool-crypto/pom.xml
index b2b8cfbfd8..dee72ba366 100755
--- a/hutool-crypto/pom.xml
+++ b/hutool-crypto/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-crypto
diff --git a/hutool-db/pom.xml b/hutool-db/pom.xml
index 95498dbfb3..de81d8e900 100755
--- a/hutool-db/pom.xml
+++ b/hutool-db/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-db
@@ -145,7 +145,7 @@
org.postgresql
postgresql
- 42.7.3
+ 42.7.11
test
diff --git a/hutool-dfa/pom.xml b/hutool-dfa/pom.xml
index 5b3d3d2ec7..47169504c8 100755
--- a/hutool-dfa/pom.xml
+++ b/hutool-dfa/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-dfa
diff --git a/hutool-extra/pom.xml b/hutool-extra/pom.xml
index ffdbfb6fa3..272f9f20ce 100755
--- a/hutool-extra/pom.xml
+++ b/hutool-extra/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-extra
@@ -24,7 +24,7 @@
1.4.2
2.3.32
5.1.3
- 3.1.2.RELEASE
+ 3.1.5.RELEASE
1.6.2
0.1.55
0.38.0
diff --git a/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/mvel/MvelEngine.java b/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/mvel/MvelEngine.java
index b580418818..ae85d47666 100755
--- a/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/mvel/MvelEngine.java
+++ b/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/mvel/MvelEngine.java
@@ -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 context, Collection> 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);
}
diff --git a/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/rhino/RhinoEngine.java b/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/rhino/RhinoEngine.java
index 7e2d406cb6..8adfa4a296 100755
--- a/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/rhino/RhinoEngine.java
+++ b/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/rhino/RhinoEngine.java
@@ -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 context, Collection> 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)) {
diff --git a/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/spel/SpELEngine.java b/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/spel/SpELEngine.java
index 06c647dc61..8c7766701e 100755
--- a/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/spel/SpELEngine.java
+++ b/hutool-extra/src/main/java/cn/hutool/extra/expression/engine/spel/SpELEngine.java
@@ -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 context, Collection> 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);
}
diff --git a/hutool-http/pom.xml b/hutool-http/pom.xml
index ad72070460..ae5f8d00ba 100755
--- a/hutool-http/pom.xml
+++ b/hutool-http/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-http
diff --git a/hutool-json/pom.xml b/hutool-json/pom.xml
index 35c5ac057f..9b32cf2f07 100755
--- a/hutool-json/pom.xml
+++ b/hutool-json/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-json
diff --git a/hutool-jwt/pom.xml b/hutool-jwt/pom.xml
index 560625869c..bd20f8c406 100755
--- a/hutool-jwt/pom.xml
+++ b/hutool-jwt/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-jwt
diff --git a/hutool-log/pom.xml b/hutool-log/pom.xml
index b51da6b991..40a9ddafbd 100755
--- a/hutool-log/pom.xml
+++ b/hutool-log/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-log
diff --git a/hutool-poi/pom.xml b/hutool-poi/pom.xml
index 2adaeb1584..4fc6533e6e 100755
--- a/hutool-poi/pom.xml
+++ b/hutool-poi/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-poi
diff --git a/hutool-script/pom.xml b/hutool-script/pom.xml
index a40cb66791..8cd2f0e9c6 100755
--- a/hutool-script/pom.xml
+++ b/hutool-script/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-script
diff --git a/hutool-setting/pom.xml b/hutool-setting/pom.xml
index 7d6f641a10..2f34f65826 100755
--- a/hutool-setting/pom.xml
+++ b/hutool-setting/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-setting
diff --git a/hutool-socket/pom.xml b/hutool-socket/pom.xml
index efbbe68e75..0baf650648 100755
--- a/hutool-socket/pom.xml
+++ b/hutool-socket/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-socket
diff --git a/hutool-system/pom.xml b/hutool-system/pom.xml
index 1e4c637619..720d98c4fa 100755
--- a/hutool-system/pom.xml
+++ b/hutool-system/pom.xml
@@ -9,7 +9,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool-system
diff --git a/pom.xml b/pom.xml
index 4c43e7cc7b..691c37ef38 100755
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
cn.hutool
hutool-parent
- 5.8.45
+ 5.8.46
hutool
Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。
https://github.com/chinabugotech/hutool