diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c1cdbeac..188c3828b 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ # 🚀Changelog ------------------------------------------------------------------------------------------------------------- -# 5.8.22(2023-08-16) +# 5.8.22(2023-09-05) ### 🐣新特性 * 【core 】 NumberUtil.nullToZero增加重载(issue#I7PPD2@Gitee) @@ -22,6 +22,15 @@ * 【core 】 去除默认的ACCEPT_LANGUAGE(issue#3258@Github) * 【core 】 修复FieldsComparator比较结果不正确问题(issue#3259@Github) * 【core 】 修复Db.findAll全局忽略大小写无效问题(issue#I7T30Y@Gitee) +* 【core 】 修复Ipv4Util.getEndIpLong 取反符号导致数据越界(issue#I7U1OQ@Gitee) +* 【http 】 修复302重定向时,Location中的问号被转义问题(issue#3265@Github) +* 【core 】 修复CombinationAnnotationElement判断循环问题(pr#3267@Github) +* 【core 】 修复StrUtil#containsAny NPE问题(pr#1063@Gitee) +* 【all 】 修复SONArray的add()方法抛出OutOfMemory异常问题(issue#3286@Github) +* 【core 】 修复fillColumns空指针问题(issue#3284@Github) +* 【core 】 修复Convert不能转换Optional和Opt问题(issue#I7WJHH@Gitee) +* 【core 】 修复DateUtil.age年龄计算问题(issue#I7XMYW@Gitee) +* 【core 】 修复JSONUtil.parse()溢出问题(issue#3289@Github) ------------------------------------------------------------------------------------------------------------- # 5.8.21(2023-07-29) diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/CombinationAnnotationElement.java b/hutool-core/src/main/java/cn/hutool/core/annotation/CombinationAnnotationElement.java index 780dc681e..bfe8b8598 100755 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/CombinationAnnotationElement.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/CombinationAnnotationElement.java @@ -143,7 +143,7 @@ public class CombinationAnnotationElement implements AnnotatedElement, Serializa annotationType = annotation.annotationType(); // issue#I5FQGW@Gitee:跳过元注解和已经处理过的注解,防止递归调用 if (AnnotationUtil.isNotJdkMateAnnotation(annotationType) - && false == declaredAnnotationMap.containsKey(annotationType)) { + && false == annotationMap.containsKey(annotationType)) { if(test(annotation)){ annotationMap.put(annotationType, annotation); } diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java index dcc4064d6..829a5b147 100755 --- a/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java @@ -2,8 +2,10 @@ package cn.hutool.core.collection; import cn.hutool.core.comparator.PinyinComparator; import cn.hutool.core.comparator.PropertyComparator; +import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Matcher; +import cn.hutool.core.lang.Validator; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.PageUtil; @@ -431,6 +433,8 @@ public class ListUtil { if (index < size) { list.set(index, element); } else { + // issue#3286, 增加安全检查,最多增加10倍 + Validator.checkIndexLimit(index, list.size()); for (int i = size; i < index; i++) { list.add(paddingElement); } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java b/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java index 0a755c4fe..16cb2e9c9 100755 --- a/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java @@ -193,6 +193,20 @@ public class ConverterRegistry implements Serializable { type = defaultValue.getClass(); } + // issue#I7WJHH,Opt和Optional处理 + if (value instanceof Opt) { + value = ((Opt) value).get(); + if (ObjUtil.isNull(value)) { + return defaultValue; + } + } + if (value instanceof Optional) { + value = ((Optional) value).orElse(null); + if (ObjUtil.isNull(value)) { + return defaultValue; + } + } + if (type instanceof TypeReference) { type = ((TypeReference) type).getType(); } diff --git a/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java index 4a0f6ae91..d98cd0b3a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java @@ -629,7 +629,12 @@ public class CalendarUtil { } /** - * 计算相对于dateToCompare的年龄,常用于计算指定生日在某年的年龄 + * 计算相对于dateToCompare的年龄,常用于计算指定生日在某年的年龄
+ * 按照《最高人民法院关于审理未成年人刑事案件具体应用法律若干问题的解释》第二条规定刑法第十七条规定的“周岁”,按照公历的年、月、日计算,从周岁生日的第二天起算。 + * * * @param birthday 生日 * @param dateToCompare 需要对比的日期 @@ -646,22 +651,22 @@ public class CalendarUtil { final int year = cal.get(Calendar.YEAR); final int month = cal.get(Calendar.MONTH); final int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH); - final boolean isLastDayOfMonth = dayOfMonth == cal.getActualMaximum(Calendar.DAY_OF_MONTH); + // 复用cal cal.setTimeInMillis(birthday); int age = year - cal.get(Calendar.YEAR); - final int monthBirth = cal.get(Calendar.MONTH); - //当前日期,则为0岁 if (age == 0){ return 0; - } else if (month == monthBirth) { + } + final int monthBirth = cal.get(Calendar.MONTH); + if (month == monthBirth) { final int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH); - final boolean isLastDayOfMonthBirth = dayOfMonthBirth == cal.getActualMaximum(Calendar.DAY_OF_MONTH); - if ((false == isLastDayOfMonth || false == isLastDayOfMonthBirth) && dayOfMonth <= dayOfMonthBirth) { - // 如果生日在当月,但是未超过生日当天的日期,年龄减一 + // issue#I6E6ZG,法定生日当天不算年龄,从第二天开始计算 + if (dayOfMonth <= dayOfMonthBirth) { + // 如果生日在当月,但是未达到生日当天的日期,年龄减一 age--; } } else if (month < monthBirth) { diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/ConsoleTable.java b/hutool-core/src/main/java/cn/hutool/core/lang/ConsoleTable.java index 380a839ba..c2986c93d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/ConsoleTable.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/ConsoleTable.java @@ -97,7 +97,7 @@ public class ConsoleTable { */ private void fillColumns(List l, String[] columns) { for (int i = 0; i < columns.length; i++) { - String column = columns[i]; + String column = StrUtil.toString(columns[i]); if (isSBCMode) { column = Convert.toSBC(column); } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/Validator.java b/hutool-core/src/main/java/cn/hutool/core/lang/Validator.java index 54f39209f..5551832ff 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/Validator.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/Validator.java @@ -1257,4 +1257,23 @@ public class Validator { } return value; } + + /** + * 检查给定的index是否超出长度限制,默认检查超出倍数(10倍),此方法主要用于内部,检查包括: + *
    + *
  • 数组调用setOrPadding时,最多允许padding的长度
  • + *
  • List调用setOrPadding时,最多允许padding的长度
  • + *
  • JSONArray调用setOrPadding时,最多允许padding的长度
  • + *
+ * + * @param index 索引 + * @param size 数组、列表长度 + * @since 5.8.22 + */ + public static void checkIndexLimit(final int index, final int size) { + // issue#3286, 增加安全检查,最多增加10倍 + if (index > (size + 1) * 10) { + throw new ValidateException("Index [{}] is too large for size: [{}]", index, size); + } + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/net/Ipv4Util.java b/hutool-core/src/main/java/cn/hutool/core/net/Ipv4Util.java index ed990e71a..ba0251f95 100755 --- a/hutool-core/src/main/java/cn/hutool/core/net/Ipv4Util.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/Ipv4Util.java @@ -407,7 +407,7 @@ public class Ipv4Util { */ public static Long getEndIpLong(String ip, int maskBit) { return getBeginIpLong(ip, maskBit) - + ~ipv4ToLong(getMaskByMaskBit(maskBit)); + + (0xffffffffL & ~ipv4ToLong(getMaskByMaskBit(maskBit))); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java index 9e1c38c9d..495fcc9e6 100755 --- a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java @@ -1064,7 +1064,7 @@ public class CharSequenceUtil { return null; } for (CharSequence checkStr : testStrs) { - if (str.toString().contains(checkStr)) { + if (null != checkStr && str.toString().contains(checkStr)) { return checkStr.toString(); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java index f79ac9e00..33f908261 100755 --- a/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java @@ -2948,10 +2948,10 @@ public class NumberUtil { /** * 检查是否为有效的数字
* 检查Double和Float是否为无限大,或者Not a Number
- * 非数字类型和Null将返回true + * 非数字类型和Null将返回false * * @param number 被检查类型 - * @return 检查结果,非数字类型和Null将返回true + * @return 检查结果,非数字类型和Null将返回false * @since 4.6.7 */ public static boolean isValidNumber(Number number) { diff --git a/hutool-core/src/test/java/cn/hutool/core/convert/IssueI7WJHHTest.java b/hutool-core/src/test/java/cn/hutool/core/convert/IssueI7WJHHTest.java new file mode 100755 index 000000000..d3068a3a0 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/convert/IssueI7WJHHTest.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package cn.hutool.core.convert; + +import cn.hutool.core.lang.Opt; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Optional; + +public class IssueI7WJHHTest { + + @Test + public void toIntTest() { + final Optional optional = Optional.of(1); + final Integer integer = Convert.toInt(optional); + + Assert.assertEquals(Integer.valueOf(1), integer); + } + + @Test + public void toIntTest2() { + final Opt optional = Opt.of(1); + final Integer integer = Convert.toInt(optional); + + Assert.assertEquals(Integer.valueOf(1), integer); + } +} diff --git a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java index 9a9ed5a13..776615120 100755 --- a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java @@ -868,7 +868,9 @@ public class DateUtilTest { final String d1 = "2000-02-29"; final String d2 = "2018-02-28"; final int age = DateUtil.age(DateUtil.parseDate(d1), DateUtil.parseDate(d2)); - Assert.assertEquals(18, age); + + // issue#I6E6ZG,法定生日当天不算年龄,从第二天开始计算 + Assert.assertEquals(17, age); } @Test(expected = IllegalArgumentException.class) @@ -878,6 +880,28 @@ public class DateUtilTest { DateUtil.age(DateUtil.parseDate(d1), DateUtil.parseDate(d2)); } + @Test + public void ageTest3() { + // 按照《最高人民法院关于审理未成年人刑事案件具体应用法律若干问题的解释》第二条规定刑法第十七条规定的“周岁”,按照公历的年、月、日计算,从周岁生日的第二天起算。 + // 那我们认为就算当年是闰年,29日也算周岁生日的第二天,可以算作一岁 + final String d1 = "1998-02-28"; + final String d2 = "2000-02-29"; + final int age = DateUtil.age(DateUtil.parse(d1), DateUtil.parse(d2)); + // issue#I6E6ZG,法定生日当天不算年龄,从第二天开始计算 + Assert.assertEquals(2, age); + } + + @Test + public void ageTest4() { + // 按照《最高人民法院关于审理未成年人刑事案件具体应用法律若干问题的解释》第二条规定刑法第十七条规定的“周岁”,按照公历的年、月、日计算,从周岁生日的第二天起算。 + // 那我们认为就算当年是闰年,29日也算周岁生日的第二天,可以算作一岁 + final String d1 = "1999-02-28"; + final String d2 = "2000-02-29"; + final int age = DateUtil.age(DateUtil.parse(d1), DateUtil.parse(d2)); + // issue#I6E6ZG,法定生日当天不算年龄,从第二天开始计算 + Assert.assertEquals(1, age); + } + @Test public void isExpiredTest() { final DateTime startDate = DateUtil.parse("2019-12-01 17:02:30"); diff --git a/hutool-core/src/test/java/cn/hutool/core/date/IssueI7XMYWTest.java b/hutool-core/src/test/java/cn/hutool/core/date/IssueI7XMYWTest.java new file mode 100755 index 000000000..a5645f818 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/date/IssueI7XMYWTest.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package cn.hutool.core.date; + +import org.junit.Assert; +import org.junit.Test; + +public class IssueI7XMYWTest { + @Test + public void ageTest() { + DateTime date1 = DateUtil.parse("2023-08-31"); + Assert.assertEquals(49, DateUtil.age(DateUtil.parse("1973-08-31"), date1)); + + date1 = DateUtil.parse("2023-08-30"); + Assert.assertEquals(49, DateUtil.age(DateUtil.parse("1973-08-30"), date1)); + } +} diff --git a/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java index 93177aaf2..f86bf884b 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java @@ -220,6 +220,12 @@ public class NumberUtilTest { Assert.assertEquals("467.81", format); } + @Test + public void isValidNumberTest() { + boolean validNumber = NumberUtil.isValidNumber(1); + Assert.assertTrue(validNumber); + } + @Test public void decimalFormatMoneyTest() { final double c = 299792400.543534534; diff --git a/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java index 03c4d1bae..558ae6b24 100755 --- a/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java @@ -412,6 +412,10 @@ public class StrUtilTest { Assert.assertFalse(containsAny); containsAny = StrUtil.containsAny("aaabbbccc", "d", "c"); Assert.assertTrue(containsAny); + + // https://gitee.com/dromara/hutool/issues/I7WSYD + containsAny = StrUtil.containsAny("你好啊", "嗯", null); + Assert.assertFalse(containsAny); } @Test diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PartParser.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PartParser.java index 1f0107df0..263b64135 100644 --- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PartParser.java +++ b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PartParser.java @@ -130,7 +130,8 @@ public class PartParser { if (size == 1) {// 普通形式 results = parseRange(value, -1); } else if (size == 2) {// 间隔形式 - final int step = parseNumber(parts.get(1)); + // issue#I7SMP7,步进不检查范围 + final int step = parseNumber(parts.get(1), false); if (step < 1) { throw new CronException("Non positive divisor for field: [{}]", value); } @@ -163,7 +164,7 @@ public class PartParser { //根据步进的第一个数字确定起始时间,类似于 12/3则从12(秒、分等)开始 int minValue = part.getMin(); if (false == isMatchAllStr(value)) { - minValue = Math.max(minValue, parseNumber(value)); + minValue = Math.max(minValue, parseNumber(value, true)); } else { //在全匹配模式下,如果步进不存在,表示步进为1 if (step < 1) { @@ -190,15 +191,15 @@ public class PartParser { List parts = StrUtil.split(value, '-'); int size = parts.size(); if (size == 1) {// 普通值 - final int v1 = parseNumber(value); + final int v1 = parseNumber(value, true); if (step > 0) {//类似 20/2的形式 NumberUtil.appendRange(v1, part.getMax(), step, results); } else { results.add(v1); } } else if (size == 2) {// range值 - final int v1 = parseNumber(parts.get(0)); - final int v2 = parseNumber(parts.get(1)); + final int v1 = parseNumber(parts.get(0), true); + final int v2 = parseNumber(parts.get(1), true); if (step < 1) { //在range模式下,如果步进不存在,表示步进为1 step = 1; @@ -233,10 +234,11 @@ public class PartParser { * 解析单个int值,支持别名 * * @param value 被解析的值 + * @param checkValue 是否检查值在有效范围内 * @return 解析结果 * @throws CronException 当无效数字或无效别名时抛出 */ - private int parseNumber(String value) throws CronException { + private int parseNumber(String value, boolean checkValue) throws CronException { int i; try { i = Integer.parseInt(value); @@ -254,13 +256,7 @@ public class PartParser { i = Week.SUNDAY.ordinal(); } - // issue#I7SMP7 - // 年的形式中,如果类似于*/2,不做范围检查 - if(Part.YEAR.equals(this.part)){ - return i; - } - - return part.checkValue(i); + return checkValue ? part.checkValue(i) : i; } /** diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java index c46df6120..9c9f8ed2b 100755 --- a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java @@ -1293,13 +1293,23 @@ public class HttpRequest extends HttpBase { final UrlBuilder redirectUrl; String location = httpConnection.header(Header.LOCATION); if (false == HttpUtil.isHttp(location) && false == HttpUtil.isHttps(location)) { - // issue#I5TPSY - // location可能为相对路径 + // issue#I5TPSY, location可能为相对路径 if (false == location.startsWith("/")) { location = StrUtil.addSuffixIfNot(this.url.getPathStr(), "/") + location; } + + // issue#3265, 相对路径中可能存在参数,单独处理参数 + final String query; + final List split = StrUtil.split(location, '?', 2); + if (split.size() == 2) { + // 存在参数 + location = split.get(0); + query = split.get(1); + } else { + query = null; + } redirectUrl = UrlBuilder.of(this.url.getScheme(), this.url.getHost(), this.url.getPort() - , location, null, null, this.charset); + , location, query, null, this.charset); } else { redirectUrl = UrlBuilder.ofHttpWithoutEncode(location); } diff --git a/hutool-http/src/test/java/cn/hutool/http/IssueI7WZEOTest.java b/hutool-http/src/test/java/cn/hutool/http/IssueI7WZEOTest.java new file mode 100755 index 000000000..5f142a284 --- /dev/null +++ b/hutool-http/src/test/java/cn/hutool/http/IssueI7WZEOTest.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package cn.hutool.http; + +import cn.hutool.core.lang.Console; +import org.junit.Test; + +public class IssueI7WZEOTest { + @Test + public void postTest() { + final String post = HttpUtil.post("https://tenapi.cn/v2/video", "url=https://v.douyin.com/ie1EX3LH/"); + Console.log(post); + } +} diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONArray.java b/hutool-json/src/main/java/cn/hutool/json/JSONArray.java index a97bedd83..f567b043d 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSONArray.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONArray.java @@ -3,6 +3,7 @@ package cn.hutool.json; import cn.hutool.core.bean.BeanPath; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Filter; +import cn.hutool.core.lang.Validator; import cn.hutool.core.lang.mutable.Mutable; import cn.hutool.core.lang.mutable.MutableObj; import cn.hutool.core.lang.mutable.MutablePair; @@ -457,6 +458,8 @@ public class JSONArray implements JSON, JSONGetter, List, Rando InternalJSONUtil.testValidity(element); this.rawList.add(index, JSONUtil.wrap(element, this.config)); } else { + // issue#3286, 增加安全检查,最多增加10倍 + Validator.checkIndexLimit(index, this.size()); while (index != this.size()) { this.add(JSONNull.NULL); } diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONParser.java b/hutool-json/src/main/java/cn/hutool/json/JSONParser.java index fef631bfa..3b1becd3a 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSONParser.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONParser.java @@ -1,5 +1,6 @@ package cn.hutool.json; +import cn.hutool.core.lang.Console; import cn.hutool.core.lang.Filter; import cn.hutool.core.lang.mutable.Mutable; import cn.hutool.core.lang.mutable.MutablePair; @@ -66,7 +67,7 @@ public class JSONParser { } default: tokener.back(); - key = tokener.nextValue().toString(); + key = tokener.nextStringValue(); } // The key is followed by ':'. diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java b/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java index 2b8caf7b7..effbbcb0c 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java @@ -322,6 +322,43 @@ public class JSONTokener { } } + /** + * 获取下一个String格式的值,用户获取key + * @return String格式的值 + * @since 5.8.22 + */ + public String nextStringValue(){ + char c = this.nextClean(); + + switch (c) { + case '"': + case '\'': + return this.nextString(c); + case '{': + case '[': + throw this.syntaxError("Sting value must be not begin with a '{' or '['"); + } + + /* + * Handle unquoted text. This could be the values true, false, or null, or it can be a number. + * An implementation (such as this one) is allowed to also accept non-standard forms. Accumulate + * characters until we reach the end of the text or a formatting character. + */ + + final StringBuilder sb = new StringBuilder(); + while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) { + sb.append(c); + c = this.next(); + } + this.back(); + + final String string = sb.toString().trim(); + if (string.isEmpty()) { + throw this.syntaxError("Missing value"); + } + return string; + } + /** * 获得下一个值,值类型可以是Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the JSONObject.NULL * @@ -366,7 +403,7 @@ public class JSONTokener { this.back(); string = sb.toString().trim(); - if (0 == string.length()) { + if (string.isEmpty()) { throw this.syntaxError("Missing value"); } return InternalJSONUtil.stringToValue(string); diff --git a/hutool-json/src/test/java/cn/hutool/json/Issue3274Test.java b/hutool-json/src/test/java/cn/hutool/json/Issue3274Test.java new file mode 100755 index 000000000..a5191d273 --- /dev/null +++ b/hutool-json/src/test/java/cn/hutool/json/Issue3274Test.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package cn.hutool.json; + +import lombok.Data; +import lombok.Getter; +import org.junit.Assert; +import org.junit.Test; + +public class Issue3274Test { + @Test + public void toBeanTest(){ + final JSONObject entries = new JSONObject("{\n" + + " \n" + + " \"age\": 36,\n" + + " \"gender\": \"\",\n" + + " \"id\": \"123123123\"\n" + + "}", JSONConfig.create().setIgnoreError(true)); + final LarkCoreHrPersonal larkCoreHrPersonal = entries.toBean(LarkCoreHrPersonal.class); + Assert.assertNotNull(larkCoreHrPersonal); + } + + @Data + static class LarkCoreHrPersonal { + private String id; + private String age=""; + private Gender gender; + } + + @Getter + enum Gender { + male("male","Male","男"), + female("female","Female","女"), + other("other","Other","其他"); + private JSONArray display; + private String enum_name; + Gender(final String enum_name, final String en_Us, final String zh_CN){ + this.enum_name=enum_name; + this.display=new JSONArray("[{\"lang\": \"en-US\",\"value\": \""+en_Us+"\"},{\"lang\": \"zh-CN\",\"value\": \""+zh_CN+"\"}]"); + } + } +} diff --git a/hutool-json/src/test/java/cn/hutool/json/Issue3289Test.java b/hutool-json/src/test/java/cn/hutool/json/Issue3289Test.java new file mode 100755 index 000000000..cd938dc92 --- /dev/null +++ b/hutool-json/src/test/java/cn/hutool/json/Issue3289Test.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package cn.hutool.json; + +import org.junit.Test; + +public class Issue3289Test { + @Test(expected = JSONException.class) + public void parseTest() { + final String s = "{\"a\":1,[6E962756779]}"; + JSONUtil.parse(s); + } +}