mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
Prepare release
This commit is contained in:
commit
acfb7bcdba
23
CHANGELOG.md
23
CHANGELOG.md
@ -3,6 +3,27 @@
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# 5.8.2 (2022-05-27)
|
||||
|
||||
### 🐣新特性
|
||||
* 【core 】 BeanUtil拷贝对象增加空检查(issue#I58CJ3@Gitee)
|
||||
* 【db 】 Column#size改为long
|
||||
* 【core 】 ClassUtil增加isInterface等方法(pr#623@Gitee)
|
||||
* 【socket 】 增加ChannelUtil
|
||||
|
||||
### 🐞Bug修复
|
||||
* 【extra 】 修复SshjSftp初始化未能代入端口配置问题(issue#2333@Github)
|
||||
* 【core 】 修复Convert.numberToSimple转换问题(issue#2334@Github)
|
||||
* 【core 】 修复TemporalAccessorConverter导致的转换问题(issue#2341@Github)
|
||||
* 【core 】 修复NumberUtil除法空指针问题(issue#I58XKE@Gitee)
|
||||
* 【core 】 修复CAR_VIN正则(pr#624@Gitee)
|
||||
* 【db 】 修复count查询别名问题(issue#I590YB@Gitee)
|
||||
* 【json 】 修复json中byte[]无法转换问题(issue#I59LW4@Gitee)
|
||||
* 【core 】 修复NumberUtil.isXXX未判空问题(issue#2350@Github)
|
||||
* 【core 】 修复Singleton中ConcurrentHashMap在JDK8下的bug引起的可能的死循环问题(issue#2349@Github)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# 5.8.1 (2022-05-16)
|
||||
|
||||
### 🐣新特性
|
||||
@ -13,7 +34,7 @@
|
||||
* 【core 】 ByteUtil新增bytesToShort重载(issue#I57FA7@Gitee)
|
||||
* 【core 】 ReflectUtil.invoke方法抛出运行时异常增加InvocationTargetRuntimeException(issue#I57GI2@Gitee)
|
||||
* 【core 】 NumberUtil.parseNumber支持16进制(issue#2328@Github)
|
||||
*
|
||||
|
||||
### 🐞Bug修复
|
||||
* 【core 】 MapUtil.map对null友好,且修复了测试用例中分组问题(pr#614@Gitee)
|
||||
* 【core 】 修复BeanUtil.beanToMap中properties为null的空指针问题(issue#2303@Github)
|
||||
|
@ -144,18 +144,18 @@ We provide the T-Shirt and Sweater with Hutool Logo, please visit the shop:
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### 🍐Gradle
|
||||
```
|
||||
implementation 'cn.hutool:hutool-all:5.8.1'
|
||||
implementation 'cn.hutool:hutool-all:5.8.2'
|
||||
```
|
||||
|
||||
## 📥Download
|
||||
|
||||
- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.8.1/)
|
||||
- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.8.2/)
|
||||
|
||||
> 🔔️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.
|
||||
|
@ -144,20 +144,20 @@ Hutool的存在就是为了减少代码搜索成本,避免网络上参差不
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### 🍐Gradle
|
||||
```
|
||||
implementation 'cn.hutool:hutool-all:5.8.1'
|
||||
implementation 'cn.hutool:hutool-all:5.8.2'
|
||||
```
|
||||
|
||||
### 📥下载jar
|
||||
|
||||
点击以下链接,下载`hutool-all-X.X.X.jar`即可:
|
||||
|
||||
- [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.8.1/)
|
||||
- [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.8.2/)
|
||||
|
||||
> 🔔️注意
|
||||
> Hutool 5.x支持JDK8+,对Android平台没有测试,不能保证所有工具类或工具方法可用。
|
||||
|
@ -1 +1 @@
|
||||
5.8.1
|
||||
5.8.2
|
||||
|
@ -1 +1 @@
|
||||
var version = '5.8.1'
|
||||
var version = '5.8.2'
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-all</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-aop</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-bloomFilter</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-bom</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-cache</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-captcha</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-core</artifactId>
|
||||
|
@ -728,6 +728,9 @@ public class BeanUtil {
|
||||
* @return 目标对象
|
||||
*/
|
||||
public static <T> T copyProperties(Object source, Class<T> tClass, String... ignoreProperties) {
|
||||
if(null == source){
|
||||
return null;
|
||||
}
|
||||
T target = ReflectUtil.newInstanceIfPossible(tClass);
|
||||
copyProperties(source, target, CopyOptions.create().setIgnoreProperties(ignoreProperties));
|
||||
return target;
|
||||
@ -765,6 +768,9 @@ public class BeanUtil {
|
||||
* @param copyOptions 拷贝选项,见 {@link CopyOptions}
|
||||
*/
|
||||
public static void copyProperties(Object source, Object target, CopyOptions copyOptions) {
|
||||
if(null == source){
|
||||
return;
|
||||
}
|
||||
BeanCopier.create(source, target, ObjectUtil.defaultIfNull(copyOptions, CopyOptions::create)).copy();
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package cn.hutool.core.bean.copier;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.lang.copier.Copier;
|
||||
|
||||
import java.io.Serializable;
|
||||
@ -62,6 +63,8 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
|
||||
* @param copyOptions 拷贝属性选项
|
||||
*/
|
||||
public BeanCopier(Object source, T target, Type targetType, CopyOptions copyOptions) {
|
||||
Assert.notNull(source, "Source bean must be not null!");
|
||||
Assert.notNull(target, "Target bean must be not null!");
|
||||
Copier<T> copier;
|
||||
if (source instanceof Map) {
|
||||
if (target instanceof Map) {
|
||||
|
@ -63,7 +63,7 @@ public class NumberWordFormatter {
|
||||
int index = -1;
|
||||
double res = value;
|
||||
while (res > 10 && (false == isTwo || index < 1)) {
|
||||
if (res > 1000) {
|
||||
if (res >= 1000) {
|
||||
res = res / 1000;
|
||||
index++;
|
||||
}
|
||||
|
@ -84,6 +84,12 @@ public class TemporalAccessorConverter extends AbstractConverter<TemporalAccesso
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Class<TemporalAccessor> getTargetType() {
|
||||
return (Class<TemporalAccessor>) this.targetType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TemporalAccessor convertInternal(Object value) {
|
||||
if (value instanceof Long) {
|
||||
|
@ -168,7 +168,7 @@ public interface RegexPool {
|
||||
* 十七位码、车架号
|
||||
* 车辆的唯一标示
|
||||
*/
|
||||
String CAR_VIN = "^[A-Za-z0-9]{17}$";
|
||||
String CAR_VIN = "^[A-HJ-NPR-Z0-9]{8}[0-9X][A-HJ-NPR-Z0-9]{2}\\d{6}$";
|
||||
/**
|
||||
* 驾驶证 别名:驾驶证档案编号、行驶证编号
|
||||
* eg:430101758218
|
||||
|
@ -52,7 +52,15 @@ public final class Singleton {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T get(String key, Func0<T> supplier) {
|
||||
return (T) POOL.computeIfAbsent(key, (k)-> supplier.callWithRuntimeException());
|
||||
//return (T) POOL.computeIfAbsent(key, (k)-> supplier.callWithRuntimeException());
|
||||
// issues#2349
|
||||
// ConcurrentHashMap.computeIfAbsent在某些情况下会导致死循环问题,此处采用Dubbo的解决方案
|
||||
Object value = POOL.get(key);
|
||||
if(null == value){
|
||||
POOL.putIfAbsent(key, supplier.callWithRuntimeException());
|
||||
value = POOL.get(key);
|
||||
}
|
||||
return (T) value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1110,4 +1110,26 @@ public class ClassUtil {
|
||||
}
|
||||
return location.getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为抽象类或接口
|
||||
*
|
||||
* @param clazz 类
|
||||
* @return 是否为抽象类或接口
|
||||
* @since 5.8.2
|
||||
*/
|
||||
public static boolean isAbstractOrInterface(Class<?> clazz) {
|
||||
return isAbstract(clazz) || isInterface(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为接口
|
||||
*
|
||||
* @param clazz 类
|
||||
* @return 是否为接口
|
||||
* @since 5.8.2
|
||||
*/
|
||||
public static boolean isInterface(Class<?> clazz) {
|
||||
return clazz.isInterface();
|
||||
}
|
||||
}
|
||||
|
@ -719,7 +719,7 @@ public class NumberUtil {
|
||||
if (v1 instanceof BigDecimal && v2 instanceof BigDecimal) {
|
||||
return div((BigDecimal) v1, (BigDecimal) v2, scale, roundingMode);
|
||||
}
|
||||
return div(v1.toString(), v2.toString(), scale, roundingMode);
|
||||
return div(StrUtil.toStringOrNull(v1), StrUtil.toStringOrNull(v2), scale, roundingMode);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1238,10 +1238,12 @@ public class NumberUtil {
|
||||
* @return 是否为整数
|
||||
*/
|
||||
public static boolean isInteger(String s) {
|
||||
try {
|
||||
Integer.parseInt(s);
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
if(StrUtil.isNotBlank(s)) {
|
||||
try {
|
||||
Integer.parseInt(s);
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1255,10 +1257,12 @@ public class NumberUtil {
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public static boolean isLong(String s) {
|
||||
try {
|
||||
Long.parseLong(s);
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
if(StrUtil.isNotBlank(s)) {
|
||||
try {
|
||||
Long.parseLong(s);
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1270,11 +1274,13 @@ public class NumberUtil {
|
||||
* @return 是否为{@link Double}类型
|
||||
*/
|
||||
public static boolean isDouble(String s) {
|
||||
try {
|
||||
Double.parseDouble(s);
|
||||
return s.contains(".");
|
||||
} catch (NumberFormatException ignore) {
|
||||
// ignore
|
||||
if(StrUtil.isNotBlank(s)) {
|
||||
try {
|
||||
Double.parseDouble(s);
|
||||
return s.contains(".");
|
||||
} catch (NumberFormatException ignore) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -567,6 +567,11 @@ public class BeanUtilTest {
|
||||
Assert.assertNull(newFood.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyNullTest() {
|
||||
Assert.assertNull(BeanUtil.copyProperties(null, Food.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyBeanPropertiesFilterTest() {
|
||||
Food info = new Food();
|
||||
|
@ -15,6 +15,8 @@ import org.junit.Test;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
@ -383,4 +385,11 @@ public class ConvertTest {
|
||||
float b = Convert.toFloat(a);
|
||||
Assert.assertEquals(a, b, 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void localDateTimeToLocalDateTest(){
|
||||
final LocalDateTime localDateTime = LocalDateTime.now();
|
||||
final LocalDate convert = Convert.convert(LocalDate.class, localDateTime);
|
||||
Assert.assertEquals(localDateTime.toLocalDate(), convert);
|
||||
}
|
||||
}
|
||||
|
@ -31,4 +31,10 @@ public class NumberWordFormatTest {
|
||||
String format5 = NumberWordFormatter.formatSimple(438);
|
||||
Assert.assertEquals("438", format5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formatSimpleTest2(){
|
||||
final String s = NumberWordFormatter.formatSimple(1000);
|
||||
Assert.assertEquals("1k", s);
|
||||
}
|
||||
}
|
||||
|
@ -221,6 +221,7 @@ public class ValidatorTest {
|
||||
public void isCarVinTest(){
|
||||
Assert.assertTrue(Validator.isCarVin("LSJA24U62JG269225"));
|
||||
Assert.assertTrue(Validator.isCarVin("LDC613P23A1305189"));
|
||||
Assert.assertFalse(Validator.isCarVin("LOC613P23A1305189"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -439,6 +439,16 @@ public class NumberUtilTest {
|
||||
Assert.assertFalse(NumberUtil.isEven(a[4]));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void divIntegerTest(){
|
||||
Assert.assertEquals(1001013, NumberUtil.div(100101300, (Number) 100).intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isDoubleTest(){
|
||||
Assert.assertFalse(NumberUtil.isDouble(null));
|
||||
Assert.assertFalse(NumberUtil.isDouble(""));
|
||||
Assert.assertFalse(NumberUtil.isDouble(" "));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-cron</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-db</artifactId>
|
||||
@ -22,12 +22,12 @@
|
||||
<dbcp2.version>2.9.0</dbcp2.version>
|
||||
<tomcat-jdbc.version>10.0.20</tomcat-jdbc.version>
|
||||
<druid.version>1.2.9</druid.version>
|
||||
<hikariCP.version>2.4.13</hikariCP.version>
|
||||
<hikariCP.version>4.0.3</hikariCP.version>
|
||||
<mongo4.version>4.6.0</mongo4.version>
|
||||
<sqlite.version>3.36.0.3</sqlite.version>
|
||||
<!-- 此处固定2.5.x,支持到JDK8 -->
|
||||
<hsqldb.version>2.5.2</hsqldb.version>
|
||||
<jedis.version>4.2.2</jedis.version>
|
||||
<jedis.version>4.2.3</jedis.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@ -62,7 +62,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP-java7</artifactId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
<version>${hikariCP.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@ -156,7 +156,7 @@
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>mssql-jdbc</artifactId>
|
||||
<version>10.2.0.jre8</version>
|
||||
<version>10.2.1.jre8</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -1,6 +1,5 @@
|
||||
package cn.hutool.db.dialect;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.db.Entity;
|
||||
import cn.hutool.db.Page;
|
||||
import cn.hutool.db.sql.Order;
|
||||
@ -134,8 +133,7 @@ public interface Dialect extends Serializable {
|
||||
* @throws SQLException SQL执行异常
|
||||
*/
|
||||
default PreparedStatement psForCount(Connection conn, Query query) throws SQLException {
|
||||
query.setFields(ListUtil.toList("count(1)"));
|
||||
return psForFind(conn, query);
|
||||
return psForCount(conn, SqlBuilder.create().query(query));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,7 +37,7 @@ public class Column implements Serializable, Cloneable {
|
||||
/**
|
||||
* 大小或数据长度
|
||||
*/
|
||||
private int size;
|
||||
private long size;
|
||||
private Integer digit;
|
||||
/**
|
||||
* 是否为可空
|
||||
@ -118,7 +118,7 @@ public class Column implements Serializable, Cloneable {
|
||||
typeName = ReUtil.delLast("\\(\\d+\\)", typeName);
|
||||
this.typeName = typeName;
|
||||
|
||||
this.size = columnMetaRs.getInt("COLUMN_SIZE");
|
||||
this.size = columnMetaRs.getLong("COLUMN_SIZE");
|
||||
this.isNullable = columnMetaRs.getBoolean("NULLABLE");
|
||||
this.comment = columnMetaRs.getString("REMARKS");
|
||||
this.columnDef = columnMetaRs.getString("COLUMN_DEF");
|
||||
@ -238,7 +238,7 @@ public class Column implements Serializable, Cloneable {
|
||||
*
|
||||
* @return 大小或数据长度
|
||||
*/
|
||||
public int getSize() {
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,12 @@ public class DbTest {
|
||||
Assert.assertEquals(4, count);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void countByQueryTest() throws SQLException {
|
||||
final long count = Db.use().count(Entity.create("user"));
|
||||
Assert.assertEquals(4, count);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void countTest2() throws SQLException {
|
||||
final long count = Db.use().count("select * from user order by name DESC");
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-dfa</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-extra</artifactId>
|
||||
|
@ -102,7 +102,7 @@ public class SshjSftp extends AbstractFtp {
|
||||
this.ssh = new SSHClient();
|
||||
ssh.addHostKeyVerifier(new PromiscuousVerifier());
|
||||
try {
|
||||
ssh.connect(ftpConfig.getHost());
|
||||
ssh.connect(ftpConfig.getHost(), ftpConfig.getPort());
|
||||
ssh.authPassword(ftpConfig.getUser(), ftpConfig.getPassword());
|
||||
ssh.setRemoteCharset(ftpConfig.getCharset());
|
||||
this.sftp = ssh.newSFTPClient();
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-http</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-json</artifactId>
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cn.hutool.json;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.convert.ConvertException;
|
||||
import cn.hutool.core.convert.Converter;
|
||||
@ -85,6 +86,9 @@ public class JSONConverter implements Converter<JSON> {
|
||||
}
|
||||
target.parse(value);
|
||||
return (T) target;
|
||||
} else if(targetType == byte[].class && value instanceof CharSequence){
|
||||
// issue#I59LW4
|
||||
return (T) Base64.decode((CharSequence) value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,6 +190,17 @@ public interface JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K> {
|
||||
return Convert.toLocalDateTime(obj, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取byte[]数据
|
||||
*
|
||||
* @param key 键
|
||||
* @return 值
|
||||
* @since 5.8.2
|
||||
*/
|
||||
default byte[] getBytes(K key) {
|
||||
return get(key, byte[].class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定类型的对象<br>
|
||||
* 转换失败或抛出异常
|
||||
|
@ -1,5 +1,6 @@
|
||||
package cn.hutool.json;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.file.FileReader;
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
@ -784,6 +785,12 @@ public class JSONUtil {
|
||||
|
||||
// JSONArray
|
||||
if (object instanceof Iterable || ArrayUtil.isArray(object)) {
|
||||
if(object instanceof byte[]){
|
||||
// issue#I59LW4
|
||||
// json内容中的bytes默认转为Base64
|
||||
return Base64.encode((byte[]) object);
|
||||
}
|
||||
|
||||
return new JSONArray(object, jsonConfig);
|
||||
}
|
||||
// JSONObject
|
||||
|
@ -144,6 +144,7 @@ public class ObjectMapper {
|
||||
} else if (source instanceof InputStream) {
|
||||
mapFromTokener(new JSONTokener((InputStream) source, jsonArray.getConfig()), jsonArray, filter);
|
||||
} else if (source instanceof byte[]) {
|
||||
// bytes按照JSON的二进制流对待
|
||||
mapFromTokener(new JSONTokener(IoUtil.toStream((byte[]) source), jsonArray.getConfig()), jsonArray, filter);
|
||||
} else if (source instanceof JSONTokener) {
|
||||
mapFromTokener((JSONTokener) source, jsonArray, filter);
|
||||
|
@ -1,5 +1,6 @@
|
||||
package cn.hutool.json.serialize;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.date.TemporalAccessorUtil;
|
||||
@ -167,7 +168,6 @@ public class JSONWriter extends Writer {
|
||||
if(JSONUtil.isNull(value) && config.isIgnoreNullValue()){
|
||||
return this;
|
||||
}
|
||||
|
||||
return writeKey(key).writeValueDirect(value);
|
||||
}
|
||||
|
||||
@ -226,7 +226,13 @@ public class JSONWriter extends Writer {
|
||||
} else if (value instanceof Map || value instanceof Map.Entry) {
|
||||
new JSONObject(value).write(writer, indentFactor, indent);
|
||||
} else if (value instanceof Iterable || value instanceof Iterator || ArrayUtil.isArray(value)) {
|
||||
new JSONArray(value).write(writer, indentFactor, indent);
|
||||
if(value instanceof byte[]){
|
||||
// issue#I59LW4
|
||||
// json内容中的bytes默认转为Base64
|
||||
writeStrValue(Base64.encode((byte[]) value));
|
||||
}else{
|
||||
new JSONArray(value).write(writer, indentFactor, indent);
|
||||
}
|
||||
} else if (value instanceof Number) {
|
||||
writeNumberValue((Number) value);
|
||||
} else if (value instanceof Date || value instanceof Calendar || value instanceof TemporalAccessor) {
|
||||
|
@ -0,0 +1,25 @@
|
||||
package cn.hutool.json;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class IssueI59LW4Test {
|
||||
|
||||
@Test
|
||||
public void bytesTest(){
|
||||
final JSONObject jsonObject = JSONUtil.createObj().set("bytes", new byte[]{1});
|
||||
Assert.assertEquals("{\"bytes\":\"AQ==\"}", jsonObject.toString());
|
||||
|
||||
final byte[] bytes = jsonObject.getBytes("bytes");
|
||||
Assert.assertArrayEquals(new byte[]{1}, bytes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bytesInJSONArrayTest(){
|
||||
final JSONArray jsonArray = JSONUtil.createArray().set(new byte[]{1});
|
||||
Assert.assertEquals("[\"AQ==\"]", jsonArray.toString());
|
||||
|
||||
final byte[] bytes = jsonArray.getBytes(0);
|
||||
Assert.assertArrayEquals(new byte[]{1}, bytes);
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-jwt</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-log</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-poi</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-script</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-setting</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-socket</artifactId>
|
||||
|
@ -0,0 +1,62 @@
|
||||
package cn.hutool.socket;
|
||||
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.thread.ThreadFactoryBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.channels.AsynchronousChannelGroup;
|
||||
import java.nio.channels.AsynchronousSocketChannel;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* Channel相关封装
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.8.2
|
||||
*/
|
||||
public class ChannelUtil {
|
||||
|
||||
/**
|
||||
* 创建{@link AsynchronousChannelGroup}
|
||||
*
|
||||
* @param poolSize 线程池大小
|
||||
* @return {@link AsynchronousChannelGroup}
|
||||
*/
|
||||
public static AsynchronousChannelGroup createFixedGroup(int poolSize) {
|
||||
|
||||
try {
|
||||
return AsynchronousChannelGroup.withFixedThreadPool(//
|
||||
poolSize, // 默认线程池大小
|
||||
ThreadFactoryBuilder.create().setNamePrefix("Huool-socket-").build()//
|
||||
);
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接到指定地址
|
||||
*
|
||||
* @param group {@link AsynchronousChannelGroup}
|
||||
* @param address 地址信息,包括地址和端口
|
||||
* @return {@link AsynchronousSocketChannel}
|
||||
*/
|
||||
public static AsynchronousSocketChannel connect(AsynchronousChannelGroup group, InetSocketAddress address) {
|
||||
AsynchronousSocketChannel channel;
|
||||
try {
|
||||
channel = AsynchronousSocketChannel.open(group);
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
|
||||
try {
|
||||
channel.connect(address).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
IoUtil.close(channel);
|
||||
throw new SocketRuntimeException(e);
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
}
|
@ -1,19 +1,14 @@
|
||||
package cn.hutool.socket.aio;
|
||||
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.thread.ThreadFactoryBuilder;
|
||||
import cn.hutool.socket.ChannelUtil;
|
||||
import cn.hutool.socket.SocketConfig;
|
||||
import cn.hutool.socket.SocketRuntimeException;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketOption;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.AsynchronousChannelGroup;
|
||||
import java.nio.channels.AsynchronousSocketChannel;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* Aio Socket客户端
|
||||
@ -120,25 +115,7 @@ public class AioClient implements Closeable{
|
||||
* @return this
|
||||
*/
|
||||
private static AsynchronousSocketChannel createChannel(InetSocketAddress address, int poolSize) {
|
||||
|
||||
AsynchronousSocketChannel channel;
|
||||
try {
|
||||
AsynchronousChannelGroup group = AsynchronousChannelGroup.withFixedThreadPool(//
|
||||
poolSize, // 默认线程池大小
|
||||
ThreadFactoryBuilder.create().setNamePrefix("Huool-socket-").build()//
|
||||
);
|
||||
channel = AsynchronousSocketChannel.open(group);
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
|
||||
try {
|
||||
channel.connect(address).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
IoUtil.close(channel);
|
||||
throw new SocketRuntimeException(e);
|
||||
}
|
||||
return channel;
|
||||
return ChannelUtil.connect(ChannelUtil.createFixedGroup(poolSize), address);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------- Private method end
|
||||
}
|
||||
|
@ -1,15 +1,23 @@
|
||||
package cn.hutool.socket.aio;
|
||||
|
||||
import cn.hutool.core.lang.Console;
|
||||
import cn.hutool.core.thread.ThreadFactoryBuilder;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.AsynchronousChannelGroup;
|
||||
|
||||
public class AioClientTest {
|
||||
public static void main(String[] args) {
|
||||
public static void main(String[] args) throws IOException {
|
||||
final AsynchronousChannelGroup GROUP = AsynchronousChannelGroup.withFixedThreadPool(//
|
||||
Runtime.getRuntime().availableProcessors(), // 默认线程池大小
|
||||
ThreadFactoryBuilder.create().setNamePrefix("Huool-socket-").build()//
|
||||
);
|
||||
|
||||
AioClient client = new AioClient(new InetSocketAddress("localhost", 8899), new SimpleIoAction() {
|
||||
|
||||
|
||||
@Override
|
||||
public void doAction(AioSession session, ByteBuffer data) {
|
||||
if(data.hasRemaining()) {
|
||||
@ -19,10 +27,10 @@ public class AioClientTest {
|
||||
Console.log("OK");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
client.write(ByteBuffer.wrap("Hello".getBytes()));
|
||||
client.read();
|
||||
|
||||
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-system</artifactId>
|
||||
|
2
pom.xml
2
pom.xml
@ -8,7 +8,7 @@
|
||||
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<version>5.8.2</version>
|
||||
<name>hutool</name>
|
||||
<description>Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。</description>
|
||||
<url>https://github.com/dromara/hutool</url>
|
||||
|
Loading…
x
Reference in New Issue
Block a user