Compare commits

...

14 Commits

Author SHA1 Message Date
Looly
1a102f9359 分流收集器收集方式从固定Collection改为自定义收集器,可以自定义如何收集元素 2025-04-26 13:38:51 +08:00
Looly
51b9bfd8bb fix resource 2025-04-26 13:15:37 +08:00
Looly
f8bf24aa0c fix resource 2025-04-26 13:08:44 +08:00
Looly
05dfc221a5 add rename 2025-04-26 11:45:33 +08:00
Looly
8b3e6c99c4 TemplateConfig增加setUseCache方法(issue#IC3JRY@Gitee) 2025-04-26 11:37:06 +08:00
Looly
80eccf98bb Merge branch 'v7-dev' of gitcode.com:chinabugotech/hutool into v7-dev 2025-04-24 08:59:06 +08:00
Looly
6d493b2fc9 Merge branch 'v7-dev' of github.com:chinabugotech/hutool into v7-dev 2025-04-24 08:59:01 +08:00
choweli
eb68f61a18 fix test 2025-04-22 10:33:05 +08:00
choweli
9cbeea018d fix test 2025-04-22 10:32:02 +08:00
choweli
74738b67ca fix test 2025-04-22 10:18:28 +08:00
Looly
c8199504fc fix test 2025-04-21 19:20:20 +08:00
Looly
861b961b6f fix test 2025-04-21 18:22:48 +08:00
choweli
49093afcd4 添加 modul-info.java 剩余extra模块 2025-04-21 15:38:18 +08:00
choweli
2a90c4b7b5 添加 modul-info.java 暂未完成 2025-04-18 17:22:55 +08:00
54 changed files with 1400 additions and 181 deletions

View File

@@ -18,6 +18,27 @@
<properties>
<Automatic-Module-Name>cn.hutool.v7.ai</Automatic-Module-Name>
<moshi.version>1.15.2</moshi.version>
<jackson.version>2.18.1</jackson.version>
<fastjson2.version>2.0.53</fastjson2.version>
<gson.version>2.13.0</gson.version>
<jetty.version>12.0.19</jetty.version>
<jakarta.xml.soap-api.version>3.0.2</jakarta.xml.soap-api.version>
<httpclient5.version>5.4.3</httpclient5.version>
<httpclient4.version>4.5.14</httpclient4.version>
<okhttp.version>5.0.0-alpha.14</okhttp.version>
<undertow.version>2.3.18.Final</undertow.version>
<tomcat.version>11.0.6</tomcat.version>
<smartboot.version>1.4.3</smartboot.version>
<slf4j.version>2.0.9</slf4j.version>
<log4j.version>1.2.17</log4j.version>
<log4j2.version>2.20.0</log4j2.version>
<tinylog.version>1.3.6</tinylog.version>
<tinylog2.version>2.7.0</tinylog2.version>
<commons-logging.version>1.3.4</commons-logging.version>
</properties>
<dependencies>
@@ -43,12 +64,154 @@
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.hutool.v7</groupId>
<artifactId>hutool-crypto</artifactId>
<version>${project.parent.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool.v7</groupId>
<artifactId>hutool-swing</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.moshi</groupId>
<artifactId>moshi</artifactId>
<version>${moshi.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>${fastjson2.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>${bouncycastle.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.xml.soap</groupId>
<artifactId>jakarta.xml.soap-api</artifactId>
<version>${jakarta.xml.soap-api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.smartboot.http</groupId>
<artifactId>smart-http-server</artifactId>
<version>${smartboot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.smartboot.socket</groupId>
<artifactId>aio-core</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>org.smartboot.socket</groupId>
<artifactId>aio-pro</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>${httpclient5.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient4.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp.version}</version>
<scope>provided</scope>
</dependency>
<!-- 第三方HTTP服务器库 -->
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-core</artifactId>
<version>${undertow.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>${tomcat.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j2.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog</artifactId>
<version>${tinylog.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog-api</artifactId>
<version>${tinylog2.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>${commons-logging.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2025 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @author choweli
*/
module hutool.ai {
exports cn.hutool.v7.ai;
exports cn.hutool.v7.ai.core;
exports cn.hutool.v7.ai.model.deepseek;
exports cn.hutool.v7.ai.model.doubao;
exports cn.hutool.v7.ai.model.grok;
exports cn.hutool.v7.ai.model.openai;
requires hutool.json;
requires hutool.core;
requires hutool.crypto;
requires hutool.http;
}

View File

@@ -82,6 +82,6 @@ class AIUtilTest {
messages.add(new Message("system","你是财神爷,只会说“我是财神”"));
messages.add(new Message("user","你是谁啊?"));
final String chat = AIUtil.chat(new AIConfigBuilder(ModelName.DEEPSEEK.getValue()).setApiKey(key).build(), messages);
System.out.println(chat);
assertNotNull(chat);
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2025 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @author choweli
*/
module hutool.all {
requires hutool.core;
}

View File

@@ -55,6 +55,11 @@ public class PropDesc {
*/
protected Invoker setter;
private Boolean hasTransientForGetter;
private Boolean hasTransientForSetter;
private Boolean isReadable;
private Boolean isWritable;
/**
* 构造<br>
* Getter和Setter方法设置为默认可访问
@@ -181,27 +186,12 @@ public class PropDesc {
* @since 5.4.2
*/
public boolean isReadable(final boolean checkTransient) {
Field field = null;
if (this.fieldInvoker instanceof FieldInvoker) {
field = ((FieldInvoker) this.fieldInvoker).getField();
}
Method getterMethod = null;
if (this.getter instanceof MethodInvoker) {
getterMethod = ((MethodInvoker) this.getter).getMethod();
}
cacheReadable();
// 检查transient关键字和@Transient注解
if (checkTransient && isTransientForGet(field, getterMethod)) {
if(checkTransient && this.hasTransientForGetter){
return false;
}
// 检查@PropIgnore注解
if (isIgnoreGet(field, getterMethod)) {
return false;
}
// 检查是否有getter方法或是否为public修饰
return null != getterMethod || ModifierUtil.isPublic(field);
return this.isReadable;
}
/**
@@ -260,27 +250,12 @@ public class PropDesc {
* @since 5.4.2
*/
public boolean isWritable(final boolean checkTransient) {
Field field = null;
if (this.fieldInvoker instanceof FieldInvoker) {
field = ((FieldInvoker) this.fieldInvoker).getField();
}
Method setterMethod = null;
if (this.setter instanceof MethodInvoker) {
setterMethod = ((MethodInvoker) this.setter).getMethod();
}
cacheWritable();
// 检查transient关键字和@Transient注解
if (checkTransient && isTransientForSet(field, setterMethod)) {
if(checkTransient && this.hasTransientForSetter){
return false;
}
// 检查@PropIgnore注解
if(isIgnoreSet(field, setterMethod)){
return false;
}
// 检查是否有setter方法或是否为public修饰
return null != setterMethod || ModifierUtil.isPublic(field);
return this.isWritable;
}
/**
@@ -373,6 +348,66 @@ public class PropDesc {
// region ----- private methods
/**
* 缓存读取属性的可读性如果已经检查过直接返回true
*/
private void cacheReadable(){
if(null != this.isReadable){
return;
}
Field field = null;
if (this.fieldInvoker instanceof FieldInvoker) {
field = ((FieldInvoker) this.fieldInvoker).getField();
}
Method getterMethod = null;
if (this.getter instanceof MethodInvoker) {
getterMethod = ((MethodInvoker) this.getter).getMethod();
}
// 检查transient关键字和@Transient注解
this.hasTransientForGetter = isTransientForGet(field, getterMethod);
// 检查@PropIgnore注解
if (isIgnoreGet(field, getterMethod)) {
this.isReadable = false;
return;
}
// 检查是否有getter方法或是否为public修饰
this.isReadable = null != getterMethod || ModifierUtil.isPublic(field);
}
/**
* 缓存写入属性的可写性如果已经检查过直接返回true
*/
private void cacheWritable(){
if(null != this.isWritable){
return;
}
Field field = null;
if (this.fieldInvoker instanceof FieldInvoker) {
field = ((FieldInvoker) this.fieldInvoker).getField();
}
Method setterMethod = null;
if (this.setter instanceof MethodInvoker) {
setterMethod = ((MethodInvoker) this.setter).getMethod();
}
// 检查transient关键字和@Transient注解
this.hasTransientForSetter = isTransientForSet(field, setterMethod);
// 检查@PropIgnore注解
if(isIgnoreSet(field, setterMethod)){
this.isWritable = false;
return;
}
// 检查是否有setter方法或是否为public修饰
this.isWritable = null != setterMethod || ModifierUtil.isPublic(field);
}
/**
* 通过Getter和Setter方法中找到属性类型
*

View File

@@ -22,6 +22,7 @@ import cn.hutool.v7.core.reflect.method.MethodNameUtil;
import cn.hutool.v7.core.reflect.method.MethodUtil;
import cn.hutool.v7.core.util.BooleanUtil;
import java.io.Serial;
import java.lang.reflect.Method;
import java.util.Map;
@@ -37,6 +38,7 @@ import java.util.Map;
* @since 6.0.0
*/
public class SimpleBeanDesc extends AbstractBeanDesc {
@Serial
private static final long serialVersionUID = 1L;
/**

View File

@@ -25,6 +25,7 @@ import cn.hutool.v7.core.reflect.method.MethodUtil;
import cn.hutool.v7.core.text.StrUtil;
import cn.hutool.v7.core.util.BooleanUtil;
import java.io.Serial;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
@@ -44,6 +45,7 @@ import java.util.Map;
* @since 3.1.2
*/
public class StrictBeanDesc extends AbstractBeanDesc {
@Serial
private static final long serialVersionUID = 1L;
/**

View File

@@ -21,6 +21,7 @@ import cn.hutool.v7.core.bean.PropDesc;
import cn.hutool.v7.core.lang.Assert;
import cn.hutool.v7.core.map.CaseInsensitiveMap;
import java.io.Serial;
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -32,6 +33,7 @@ import java.util.Map;
* @since 6.0.0
*/
public abstract class AbstractBeanDesc implements BeanDesc {
@Serial
private static final long serialVersionUID = 1L;
/**

View File

@@ -314,8 +314,8 @@ public class FileUtil {
}
// 如果用户需要相对项目路径则使用project:前缀
if (path.startsWith("project:")) {
return new File(path);
if (path.startsWith(UrlUtil.PROJECT_URL_PREFIX)) {
return new File(StrUtil.subSuf(path, UrlUtil.PROJECT_URL_PREFIX.length()));
}
return new File(getAbsolutePath(path));

View File

@@ -24,6 +24,7 @@ import cn.hutool.v7.core.net.url.UrlUtil;
import cn.hutool.v7.core.text.StrUtil;
import cn.hutool.v7.core.util.ObjUtil;
import java.io.Serial;
import java.net.URL;
/**
@@ -35,6 +36,7 @@ import java.net.URL;
*
*/
public class ClassPathResource extends UrlResource {
@Serial
private static final long serialVersionUID = 1L;
private final String path;

View File

@@ -23,6 +23,7 @@ import cn.hutool.v7.core.util.ObjUtil;
import java.io.File;
import java.io.InputStream;
import java.io.Serial;
import java.io.Serializable;
import java.net.URL;
import java.nio.file.Path;
@@ -33,6 +34,7 @@ import java.nio.file.Path;
* @author Looly
*/
public class FileResource implements Resource, Serializable {
@Serial
private static final long serialVersionUID = 1L;
private final File file;
@@ -75,7 +77,7 @@ public class FileResource implements Resource, Serializable {
* @param fileName 文件名带扩展名如果为null获取文件本身的文件名
*/
public FileResource(final File file, final String fileName) {
this.file = Assert.notNull(file, "File must be not null !");;
this.file = Assert.notNull(file, "File must be not null !");
this.lastModified = file.lastModified();
this.name = ObjUtil.defaultIfNull(fileName, file::getName);
}

View File

@@ -243,7 +243,7 @@ public class ResourceUtil {
*/
public static Resource getResource(final String path) {
if (StrUtil.isNotBlank(path)) {
if (path.startsWith(UrlUtil.FILE_URL_PREFIX) || FileUtil.isAbsolutePath(path)) {
if (StrUtil.startWithAny(path, UrlUtil.FILE_URL_PREFIX, UrlUtil.PROJECT_URL_PREFIX) || FileUtil.isAbsolutePath(path)) {
return new FileResource(path);
}
}

View File

@@ -55,6 +55,10 @@ public class UrlUtil {
* 针对ClassPath路径的伪协议前缀兼容Spring: "classpath:"
*/
public static final String CLASSPATH_URL_PREFIX = "classpath:";
/**
* 针对project路径的伪协议前缀: "project:"
*/
public static final String PROJECT_URL_PREFIX = "project:";
/**
* URL 前缀表示文件: "file:"
*/

View File

@@ -472,7 +472,7 @@ public class CollectorUtil {
}
/**
* 将一个{@code Collection<T>}两个属性分流至两个ArrayList,并使用Pair收集。
* 将一个{@code Collection<T>}两个属性分流至两个List,并使用Pair收集。
*
* @param lMapper 左属性收集方法
* @param rMapper 右属性收集方法
@@ -482,53 +482,69 @@ public class CollectorUtil {
* @return {@code Pair<List<L>,List<R>>} Pair收集的两个List
* @author Tanglt
*/
public static <T, L, R> Collector<T, Pair<List<L>, List<R>>, Pair<List<L>, List<R>>> toPairList(final Function<T, L> lMapper,
final Function<T, R> rMapper) {
return toPairCollection(lMapper, rMapper, ArrayList::new, ArrayList::new);
public static <T, L, R> Collector<T, ?, Pair<List<L>, List<R>>> toPairList(final Function<? super T, ? extends L> lMapper,
final Function<? super T, ? extends R> rMapper) {
return toPair(lMapper, rMapper, Collectors.toList(), Collectors.toList());
}
/**
* 将一个{@code Collection<T>}两个属性分流至两个Collection,并使用Pair收集。需要指定Collection类型
* 将一个{@code Collection<T>}两个属性分流至两个Collection,并使用Pair收集。
*
* @param lMapper 左属性收集方法
* @param rMapper 右属性收集方法
* @param newCollectionL 左属性Collection创建方法
* @param newCollectionR 右属性Collection创建方法
* @param lDownstream 左属性下游操作
* @param rDownstream 右属性下游操作
* @param <T> 元素类型
* @param <L> 左属性类型
* @param <R> 右属性类型
* @param <LC> 左分流Collection类型
* @param <RC> 右分流Collection类型
* @return {@code Pair<C<L>,C<R>>} Pair收集的两个List
* @param <LU> 左属性类型
* @param <LA> 左属性收集类型
* @param <LR> 左属性收集最终类型
* @param <RU> 左属性类型
* @param <RA> 左属性收集类型
* @param <RR> 左属性收集最终类型
* @return {@code Pair<LR,RR>} Pair收集的结果
* @author Tanglt
*/
public static <T, L, R, LC extends Collection<L>, RC extends Collection<R>>
Collector<T, Pair<LC, RC>, Pair<LC, RC>> toPairCollection(final Function<T, L> lMapper,
final Function<T, R> rMapper,
final Supplier<LC> newCollectionL,
final Supplier<RC> newCollectionR) {
return new SimpleCollector<>(() -> Pair.of(newCollectionL.get(), newCollectionR.get()),
@SuppressWarnings("unchecked")
public static <T, LU, LA, LR, RU, RA, RR>
Collector<T, ?, Pair<LR, RR>> toPair(final Function<? super T, ? extends LU> lMapper,
final Function<? super T, ? extends RU> rMapper,
final Collector<? super LU, LA, LR> lDownstream,
final Collector<? super RU, RA, RR> rDownstream
) {
return new SimpleCollector<>(
() -> Pair.of(lDownstream.supplier().get(), rDownstream.supplier().get()),
(listPair, element) -> {
final L lValue = lMapper.apply(element);
if (lValue != null) {
listPair.getLeft().add(lValue);
}
final R rValue = rMapper.apply(element);
if (rValue != null) {
listPair.getRight().add(rValue);
}
lDownstream.accumulator().accept(listPair.getLeft(), lMapper.apply(element));
rDownstream.accumulator().accept(listPair.getRight(), rMapper.apply(element));
},
(listPair1, listPair2) -> {
listPair1.getLeft().addAll(listPair2.getLeft());
listPair1.getRight().addAll(listPair2.getRight());
return listPair1;
(listPair1, listPair2) ->
Pair.of(lDownstream.combiner().apply(listPair1.getLeft(), listPair2.getLeft()),
rDownstream.combiner().apply(listPair1.getRight(), listPair2.getRight())),
finisherPair -> {
final LR finisherLeftValue;
if (lDownstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
finisherLeftValue = (LR) finisherPair.getLeft();
} else {
finisherLeftValue = lDownstream.finisher().apply(finisherPair.getLeft());
}
final RR finisherRightValue;
if (lDownstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
finisherRightValue = (RR) finisherPair.getRight();
} else {
finisherRightValue = rDownstream.finisher().apply(finisherPair.getRight());
}
return Pair.of(finisherLeftValue, finisherRightValue);
},
CH_ID);
CH_NOID);
}
/**
* 将一个{@code Collection<T>}三个属性分流至三个ArrayList,并使用Triple收集。
* 将一个{@code Collection<T>}三个属性分流至三个List,并使用Triple收集。
*
* @param lMapper 左属性收集方法
* @param mMapper 中属性收集方法
@@ -541,64 +557,82 @@ public class CollectorUtil {
* @author Tanglt
*/
public static <T, L, M, R>
Collector<T, Triple<List<L>, List<M>, List<R>>, Triple<List<L>, List<M>, List<R>>> toTripleList(final Function<T, L> lMapper,
final Function<T, M> mMapper,
final Function<T, R> rMapper) {
return toTripleCollection(lMapper, mMapper, rMapper, ArrayList::new, ArrayList::new, ArrayList::new);
Collector<T, ?, Triple<List<L>, List<M>, List<R>>> toTripleList(final Function<? super T, ? extends L> lMapper,
final Function<? super T, ? extends M> mMapper,
final Function<? super T, ? extends R> rMapper) {
return toTriple(lMapper, mMapper, rMapper, Collectors.toList(), Collectors.toList(), Collectors.toList());
}
/**
* 将一个{@code Collection<T>}两个属性分流至两个Collection,并使用Triple收集。需要指定Collection类型
* 将一个{@code Collection<T>}两个属性分流至两个Collection,并使用Pair收集。
*
* @param lMapper 左属性收集方法
* @param mMapper 中属性收集方法
* @param rMapper 右属性收集方法
* @param newCollectionL 左属性Collection创建方法
* @param newCollectionM 中属性Collection创建方法
* @param newCollectionR 右属性Collection创建方法
* @param lMapper 左元素收集方法
* @param mMapper 中元素收集方法
* @param rMapper 右元素收集方法
* @param lDownstream 左元素下游操作
* @param mDownstream 中元素下游操作
* @param rDownstream 右元素下游操作
* @param <T> 元素类型
* @param <L> 左属性类型
* @param <M> 中属性类型
* @param <R> 右属性类型
* @param <LC> 左分流Collection类型
* @param <MC> 分流Collection类型
* @param <RC> 右分流Collection类型
* @return {@code Triple<LC<L>,MC<M>,RC<R>>} Triple收集的三个List
* @param <LU> 左属性类型
* @param <LA> 左属性收集类型
* @param <LR> 左属性收集最终类型
* @param <MU> 中属性类型
* @param <MA>属性收集类型
* @param <MR> 中属性收集最终类型
* @param <RU> 左属性类型
* @param <RA> 左属性收集类型
* @param <RR> 左属性收集最终类型
* @return {@code Triple<LR,MR,RR>} Triple收集的结果
* @author Tanglt
*/
public static <T, L, M, R,
LC extends Collection<L>,
MC extends Collection<M>,
RC extends Collection<R>>
Collector<T, Triple<LC, MC, RC>, Triple<LC, MC, RC>> toTripleCollection(final Function<T, L> lMapper,
final Function<T, M> mMapper,
final Function<T, R> rMapper,
final Supplier<LC> newCollectionL,
final Supplier<MC> newCollectionM,
final Supplier<RC> newCollectionR) {
@SuppressWarnings("unchecked")
public static <T, LU, LA, LR, MU, MA, MR, RU, RA, RR>
Collector<T, ?, Triple<LR, MR, RR>> toTriple(final Function<? super T, ? extends LU> lMapper,
final Function<? super T, ? extends MU> mMapper,
final Function<? super T, ? extends RU> rMapper,
final Collector<? super LU, LA, LR> lDownstream,
final Collector<? super MU, MA, MR> mDownstream,
final Collector<? super RU, RA, RR> rDownstream
) {
return new SimpleCollector<>(
() -> Triple.of(newCollectionL.get(), newCollectionM.get(), newCollectionR.get()),
() -> Triple.of(lDownstream.supplier().get(), mDownstream.supplier().get(), rDownstream.supplier().get()),
(listTriple, element) -> {
final L lValue = lMapper.apply(element);
if (lValue != null) {
listTriple.getLeft().add(lValue);
}
final M mValue = mMapper.apply(element);
if (mValue != null) {
listTriple.getMiddle().add(mValue);
}
final R rValue = rMapper.apply(element);
if (rValue != null) {
listTriple.getRight().add(rValue);
}
lDownstream.accumulator().accept(listTriple.getLeft(), lMapper.apply(element));
mDownstream.accumulator().accept(listTriple.getMiddle(), mMapper.apply(element));
rDownstream.accumulator().accept(listTriple.getRight(), rMapper.apply(element));
},
(listTriple1, listTriple2) -> {
listTriple1.getLeft().addAll(listTriple2.getLeft());
listTriple1.getMiddle().addAll(listTriple2.getMiddle());
listTriple1.getRight().addAll(listTriple2.getRight());
return listTriple1;
},
CH_ID);
(listTriple1, listTriple2) ->
Triple.of(lDownstream.combiner().apply(listTriple1.getLeft(), listTriple2.getLeft()),
mDownstream.combiner().apply(listTriple1.getMiddle(), listTriple2.getMiddle()),
rDownstream.combiner().apply(listTriple1.getRight(), listTriple2.getRight())),
finisherTriple -> {
final LR finisherLeftValue;
if (lDownstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
finisherLeftValue = (LR) finisherTriple.getLeft();
} else {
finisherLeftValue = lDownstream.finisher().apply(finisherTriple.getLeft());
}
final MR finisherMiddleValue;
if (mDownstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
finisherMiddleValue = (MR) finisherTriple.getMiddle();
} else {
finisherMiddleValue = mDownstream.finisher().apply(finisherTriple.getMiddle());
}
final RR finisherRightValue;
if (lDownstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
finisherRightValue = (RR) finisherTriple.getRight();
} else {
finisherRightValue = rDownstream.finisher().apply(finisherTriple.getRight());
}
return Triple.of(finisherLeftValue, finisherMiddleValue, finisherRightValue);
},
CH_NOID);
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 2025 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @author choweli
*/
module hutool.core {
exports cn.hutool.v7.core.exception;
exports cn.hutool.v7.core.lang;
exports cn.hutool.v7.core.lang.wrapper;
exports cn.hutool.v7.core.text;
exports cn.hutool.v7.core.io;
exports cn.hutool.v7.core.io.file;
exports cn.hutool.v7.core.io.stream;
exports cn.hutool.v7.core.io.resource;
exports cn.hutool.v7.core.util;
exports cn.hutool.v7.core.array;
exports cn.hutool.v7.core.codec.binary;
exports cn.hutool.v7.core.thread;
exports cn.hutool.v7.core.thread.lock;
exports cn.hutool.v7.core.map;
exports cn.hutool.v7.core.collection;
exports cn.hutool.v7.core.spi;
exports cn.hutool.v7.core.func;
exports cn.hutool.v7.core.lang.caller;
exports cn.hutool.v7.core.reflect;
exports cn.hutool.v7.core.lang.ansi;
exports cn.hutool.v7.core.date;
exports cn.hutool.v7.core.lang.getter;
exports cn.hutool.v7.core.text.split;
exports cn.hutool.v7.core.bean.copier;
exports cn.hutool.v7.core.bean.path;
exports cn.hutool.v7.core.bean;
exports cn.hutool.v7.core.net.url;
exports cn.hutool.v7.core.io.watch;
exports cn.hutool.v7.core.io.watch.watchers;
exports cn.hutool.v7.core.convert;
exports cn.hutool.v7.core.regex;
exports cn.hutool.v7.core.map.concurrent;
exports cn.hutool.v7.core.math;
exports cn.hutool.v7.core.collection.set;
exports cn.hutool.v7.core.collection.iter;
exports cn.hutool.v7.core.reflect.method;
exports cn.hutool.v7.core.lang.builder;
exports cn.hutool.v7.core.lang.range;
exports cn.hutool.v7.core.lang.page;
exports cn.hutool.v7.core.classloader;
exports cn.hutool.v7.core.pool;
exports cn.hutool.v7.core.pool.partition;
exports cn.hutool.v7.core.stream;
exports cn.hutool.v7.core.lang.tuple;
exports cn.hutool.v7.core.codec;
exports cn.hutool.v7.core.net;
exports cn.hutool.v7.core.map.reference;
exports cn.hutool.v7.core.lang.mutable;
exports cn.hutool.v7.core.lang.loader;
exports cn.hutool.v7.core.comparator;
exports cn.hutool.v7.core.date.format;
exports cn.hutool.v7.core.lang.copier;
exports cn.hutool.v7.core.convert.impl;
exports cn.hutool.v7.core.bean.path.node;
exports cn.hutool.v7.core.xml;
exports cn.hutool.v7.core.reflect.kotlin;
exports cn.hutool.v7.core.text.escape;
exports cn.hutool.v7.core.annotation;
exports cn.hutool.v7.core.map.multi;
exports cn.hutool.v7.core.data.id;
exports cn.hutool.v7.core.io.buffer;
exports cn.hutool.v7.core.reflect.creator;
exports cn.hutool.v7.core.compress;
exports cn.hutool.v7.core.net.ssl;
requires java.desktop;
requires java.sql;
requires java.management;
requires java.compiler;
requires java.naming;
}

View File

@@ -59,6 +59,6 @@ public class ResourceUtilTest {
@Test
void getResourceTest2() {
// project:开头表示基于项目的相对路径,此处无文件报错
Assertions.assertThrows(NoResourceException.class, () -> ResourceUtil.getResource("project:test.xml"));
Assertions.assertThrows(NoResourceException.class, () -> ResourceUtil.getResource("project:test.xml").getStream());
}
}

View File

@@ -147,8 +147,8 @@ public class CollectorUtilTest {
Assertions.assertEquals(pairList.getLeft().size(),list.size());
Assertions.assertEquals(pairList.getRight().size(),list.size());
final Pair<HashSet<Integer>, ArrayList<String>> pairMixed = list.stream()
.collect(CollectorUtil.toPairCollection(Pair::getLeft, Pair::getRight, HashSet::new, ArrayList::new));
final Pair<Set<Integer>, List<String>> pairMixed = list.stream()
.collect(CollectorUtil.toPair(Pair::getLeft, Pair::getRight, Collectors.toSet(), Collectors.toList()));
Assertions.assertEquals(pairMixed.getLeft().size(),list.size());
Assertions.assertEquals(pairMixed.getRight().size(),list.size());
@@ -167,12 +167,13 @@ public class CollectorUtilTest {
Assertions.assertEquals(tripleList.getMiddle().size(),list.size());
Assertions.assertEquals(tripleList.getRight().size(),list.size());
final Triple<HashSet<Integer>, HashSet<Long>, ArrayList<String>> tripleMixed = list.stream()
.collect(CollectorUtil.toTripleCollection(Triple::getLeft, Triple::getMiddle, Triple::getRight, HashSet::new, HashSet::new, ArrayList::new));
final Triple<Integer, List<Long>, String> tripleMixed = list.stream()
.collect(CollectorUtil.toTriple(Triple::getLeft, Triple::getMiddle, Triple::getRight,
Collectors.summingInt(s->s), Collectors.toList(), Collectors.joining()));
Assertions.assertEquals(tripleMixed.getLeft().size(),list.size());
Assertions.assertEquals(tripleMixed.getMiddle().size(),list.size());
Assertions.assertEquals(tripleMixed.getRight().size(),list.size());
Assertions.assertEquals(3,tripleMixed.getLeft());
Assertions.assertEquals(list.size(),tripleMixed.getMiddle().size());
Assertions.assertEquals(6,tripleMixed.getRight().length());
}

View File

@@ -24,6 +24,7 @@ public class IssueI96LWHTest {
@Test
public void replaceByCodePointTest() {
final String str = "\uD83D\uDC46最上方点击蓝字";
Assertions.assertArrayEquals(new int[]{128070, 26368, 19978, 26041, 28857, 20987, 34013, 23383}, str.codePoints().toArray());
// 这个方法里\uD83D\uDC46表示一个emoji表情使用codePoint之后一个表情表示一个字符因此按照一个字符对
Assertions.assertEquals("\uD83D\uDC46最上下点击蓝字", StrUtil.replaceByCodePoint(str, 3, 4, ""));

View File

@@ -34,6 +34,15 @@
<properties>
<Automatic-Module-Name>cn.hutool.v7.cron</Automatic-Module-Name>
<snakeyaml.version>2.3</snakeyaml.version>
<!-- 固定3.4.x支持到jdk8 -->
<jboss-logging.version>3.4.3.Final</jboss-logging.version>
<slf4j.version>2.0.9</slf4j.version>
<log4j.version>1.2.17</log4j.version>
<log4j2.version>2.20.0</log4j2.version>
<tinylog.version>1.3.6</tinylog.version>
<tinylog2.version>2.7.0</tinylog2.version>
<commons-logging.version>1.3.4</commons-logging.version>
</properties>
<dependencies>
@@ -53,5 +62,54 @@
<version>2.4.0</version>
<scope>test</scope>
</dependency>
<!-- YAML支持 -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${snakeyaml.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss-logging.version}</version>
</dependency>
<!-- 仅用于测试 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog</artifactId>
<version>${tinylog.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog-api</artifactId>
<version>${tinylog2.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>${commons-logging.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2025 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @author choweli
*/
module hutool.cron {
requires hutool.setting;
requires hutool.log;
requires hutool.core;
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2025 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @author choweli
*/
module hutool.crypto {
exports cn.hutool.v7.crypto;
exports cn.hutool.v7.crypto.provider;
exports cn.hutool.v7.crypto.digest.mac;
exports cn.hutool.v7.crypto.asymmetric;
requires hutool.core;
requires org.bouncycastle.provider;
requires java.security.sasl;
requires org.bouncycastle.pkix;
}

View File

@@ -42,6 +42,15 @@
<hikariCP.version>6.3.0</hikariCP.version>
<sqlite.version>3.46.0.0</sqlite.version>
<hsqldb.version>2.7.4</hsqldb.version>
<!--log-->
<snakeyaml.version>2.3</snakeyaml.version>
<jboss-logging.version>3.4.3.Final</jboss-logging.version>
<slf4j.version>2.0.9</slf4j.version>
<log4j.version>1.2.17</log4j.version>
<log4j2.version>2.20.0</log4j2.version>
<tinylog.version>1.3.6</tinylog.version>
<tinylog2.version>2.7.0</tinylog2.version>
<commons-logging.version>1.3.4</commons-logging.version>
</properties>
<dependencies>
@@ -167,5 +176,53 @@
<version>2.24.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${snakeyaml.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss-logging.version}</version>
</dependency>
<!-- 仅用于测试 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog</artifactId>
<version>${tinylog.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog-api</artifactId>
<version>${tinylog2.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>${commons-logging.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,8 @@
package cn.hutool.v7.db.pojo;
/**
* 为了通过test进行占位
* @author choweli
*/
public class Test {
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 2025 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @author choweli
*/
module hutool.db {
exports cn.hutool.v7.db;
exports cn.hutool.v7.db.config;
exports cn.hutool.v7.db.ds;
exports cn.hutool.v7.db.ds.bee;
exports cn.hutool.v7.db.ds.c3p0;
exports cn.hutool.v7.db.ds.dbcp;
exports cn.hutool.v7.db.ds.druid;
exports cn.hutool.v7.db.ds.hikari;
exports cn.hutool.v7.db.ds.jndi;
exports cn.hutool.v7.db.ds.pooled;
exports cn.hutool.v7.db.ds.simple;
exports cn.hutool.v7.db.ds.tomcat;
requires hutool.setting;
requires hutool.log;
requires hutool.core;
requires beecp;
requires com.mchange.v2.c3p0;
requires java.desktop;
requires org.apache.commons.dbcp2;
requires druid;
requires com.zaxxer.hikari;
requires java.sql;
requires java.naming;
requires tomcat.jdbc;
opens cn.hutool.v7.db;
opens cn.hutool.v7.db.config;
opens cn.hutool.v7.db.pojo;
}

View File

@@ -268,6 +268,17 @@
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-core</artifactId>
<version>${sshd.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-common</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-common</artifactId>
<version>${sshd.version}</version>
</dependency>
<!-- FTP工具 -->
<dependency>
@@ -337,10 +348,9 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.janeluo</groupId>
<artifactId>ikanalyzer</artifactId>
<version>2012_u6</version>
<optional>true</optional>
<groupId>com.jianggujin</groupId>
<artifactId>IKAnalyzer-lucene</artifactId>
<version>8.0.0</version>
<exclusions>
<exclusion>
<groupId>org.apache.lucene</groupId>

View File

@@ -403,6 +403,15 @@ public class CommonsFtp extends AbstractFtp {
return ftpFiles;
}
@Override
public boolean rename(String oldPath, String newPath) {
try {
return this.client.rename(oldPath, newPath);
} catch (final IOException e) {
throw new IORuntimeException(e);
}
}
@Override
public boolean mkdir(final String dir) throws IORuntimeException {
try {

View File

@@ -127,6 +127,15 @@ public interface Ftp extends Closeable {
*/
List<String> ls(String path);
/**
* 重命名文件
*
* @param oldPath 旧文件名(或路径)
* @param newPath 新文件名(或路径)
* @return 是否重命名成功
*/
boolean rename(String oldPath, String newPath);
/**
* 删除指定目录下的指定文件
*

View File

@@ -328,6 +328,16 @@ public class JschSftp extends AbstractFtp {
return entryList;
}
@Override
public boolean rename(String oldPath, String newPath) {
try {
getClient().rename(oldPath, newPath);
} catch (final SftpException e) {
throw new SshException(e);
}
return true;
}
@Override
public boolean mkdir(final String dir) {
if (isDir(dir)) {

View File

@@ -188,6 +188,16 @@ public class SshjSftp extends AbstractFtp {
return null;
}
@Override
public boolean rename(String oldPath, String newPath) {
try {
sftp.rename(oldPath, newPath);
return containsFile(newPath);
} catch (final IOException e) {
throw new FtpException(e);
}
}
@Override
public boolean delFile(final String path) {
try {

View File

@@ -16,13 +16,14 @@
package cn.hutool.v7.extra.template;
import cn.hutool.v7.core.util.CharsetUtil;
import cn.hutool.v7.extra.template.engine.TemplateEngine;
import java.io.Serial;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.Objects;
import cn.hutool.v7.core.util.CharsetUtil;
import cn.hutool.v7.extra.template.engine.TemplateEngine;
/**
* 模板配置
*
@@ -30,6 +31,7 @@ import cn.hutool.v7.extra.template.engine.TemplateEngine;
* @since 4.1.0
*/
public class TemplateConfig implements Serializable {
@Serial
private static final long serialVersionUID = 2933113779920339523L;
/**
@@ -53,6 +55,10 @@ public class TemplateConfig implements Serializable {
* 自定义引擎当多个jar包引入时可以自定使用的默认引擎
*/
private Class<? extends TemplateEngine> customEngine;
/**
* 是否使用缓存
*/
private boolean useCache = true;
/**
* 默认构造使用UTF8编码默认从ClassPath获取模板
@@ -119,9 +125,11 @@ public class TemplateConfig implements Serializable {
* 设置编码
*
* @param charset 编码
* @return this
*/
public void setCharset(final Charset charset) {
public TemplateConfig setCharset(final Charset charset) {
this.charset = charset;
return this;
}
/**
@@ -137,9 +145,11 @@ public class TemplateConfig implements Serializable {
* 设置模板路径如果ClassPath或者WebRoot模式则表示相对路径
*
* @param path 模板路径
* @return this
*/
public void setPath(final String path) {
public TemplateConfig setPath(final String path) {
this.path = path;
return this;
}
/**
@@ -155,9 +165,11 @@ public class TemplateConfig implements Serializable {
* 设置模板资源加载方式
*
* @param resourceMode 模板资源加载方式
* @return this
*/
public void setResourceMode(final ResourceMode resourceMode) {
public TemplateConfig setResourceMode(final ResourceMode resourceMode) {
this.resourceMode = resourceMode;
return this;
}
/**
@@ -183,6 +195,28 @@ public class TemplateConfig implements Serializable {
return this;
}
/**
* 是否使用缓存
*
* @return 是否使用缓存
* @since 5.8.38
*/
public boolean isUseCache() {
return useCache;
}
/**
* 设置是否使用缓存
*
* @param useCache 是否使用缓存
* @return this
* @since 5.8.38
*/
public TemplateConfig setUseCache(boolean useCache) {
this.useCache = useCache;
return this;
}
/**
* 资源加载方式枚举
*

View File

@@ -126,6 +126,7 @@ public class ThymeleafEngine implements TemplateEngine {
classLoaderResolver.setCharacterEncoding(config.getCharsetStr());
classLoaderResolver.setTemplateMode(TemplateMode.HTML);
classLoaderResolver.setPrefix(StrUtil.addSuffixIfNot(config.getPath(), "/"));
classLoaderResolver.setCacheable(config.isUseCache());
resolver = classLoaderResolver;
break;
case FILE:
@@ -133,6 +134,7 @@ public class ThymeleafEngine implements TemplateEngine {
fileResolver.setCharacterEncoding(config.getCharsetStr());
fileResolver.setTemplateMode(TemplateMode.HTML);
fileResolver.setPrefix(StrUtil.addSuffixIfNot(config.getPath(), "/"));
fileResolver.setCacheable(config.isUseCache());
resolver = fileResolver;
break;
case WEB_ROOT:
@@ -140,6 +142,7 @@ public class ThymeleafEngine implements TemplateEngine {
webRootResolver.setCharacterEncoding(config.getCharsetStr());
webRootResolver.setTemplateMode(TemplateMode.HTML);
webRootResolver.setPrefix(StrUtil.addSuffixIfNot(FileUtil.getAbsolutePath(FileUtil.file(FileUtil.getWebRoot(), config.getPath())), "/"));
webRootResolver.setCacheable(config.isUseCache());
resolver = webRootResolver;
break;
case STRING:

View File

@@ -136,7 +136,10 @@ public class VelocityEngine implements TemplateEngine {
final String charsetStr = config.getCharset().toString();
ve.setProperty(Velocity.INPUT_ENCODING, charsetStr);
// ve.setProperty(Velocity.OUTPUT_ENCODING, charsetStr);
if(config.isUseCache()){
// issue#IC3JRY 可定制是否使用缓存
ve.setProperty(Velocity.FILE_RESOURCE_LOADER_CACHE, true); // 使用缓存
}
// loader
switch (config.getResourceMode()) {

View File

@@ -58,7 +58,8 @@ public class TokenizerUtilTest {
final TokenizerEngine engine = TokenizerUtil.createEngine("IKAnalyzer");
final Result result = engine.parse(text);
final String resultStr = IterUtil.join(result, " ");
Assertions.assertEquals("这两个 方法 的 区别 在于 返回值", resultStr);
//Assertions.assertEquals("这两个 方法 的 区别 在于 返回值", resultStr);
Assertions.assertEquals("这两个 方法 区别 在于 返回值", resultStr);
}
@Test

View File

@@ -36,7 +36,7 @@
<Automatic-Module-Name>cn.hutool.v7.http</Automatic-Module-Name>
<httpclient5.version>5.4.3</httpclient5.version>
<httpclient4.version>4.5.14</httpclient4.version>
<okhttp.version>4.12.0</okhttp.version>
<okhttp.version>5.0.0-alpha.14</okhttp.version>
<undertow.version>2.3.18.Final</undertow.version>
<jetty.version>12.0.19</jetty.version>
<tomcat.version>11.0.6</tomcat.version>
@@ -44,6 +44,13 @@
<jakarta.servlet-api.version>6.1.0</jakarta.servlet-api.version>
<jakarta.xml.soap-api.version>3.0.2</jakarta.xml.soap-api.version>
<saaj-impl.version>3.0.4</saaj-impl.version>
<slf4j.version>2.0.9</slf4j.version>
<log4j.version>1.2.17</log4j.version>
<log4j2.version>2.20.0</log4j2.version>
<tinylog.version>1.3.6</tinylog.version>
<tinylog2.version>2.7.0</tinylog2.version>
<commons-logging.version>1.3.4</commons-logging.version>
</properties>
<dependencies>
@@ -123,12 +130,24 @@
<artifactId>tomcat-embed-core</artifactId>
<version>${tomcat.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.smartboot.http</groupId>
<artifactId>smart-http-server</artifactId>
<version>${smartboot.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.smartboot.socket</groupId>
<artifactId>aio-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 仅用于测试 -->
<dependency>
@@ -149,5 +168,48 @@
<version>1.7.36</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j2.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog</artifactId>
<version>${tinylog.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog-api</artifactId>
<version>${tinylog2.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>${commons-logging.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -21,10 +21,10 @@ import cn.hutool.v7.http.HttpException;
import cn.hutool.v7.http.server.ServerConfig;
import cn.hutool.v7.http.server.engine.AbstractServerEngine;
import org.smartboot.http.server.*;
import org.smartboot.http.server.impl.Request;
import org.smartboot.socket.extension.plugins.SslPlugin;
import javax.net.ssl.SSLContext;
import java.lang.reflect.Method;
import java.util.function.Supplier;
/**
* smart-http-server引擎
@@ -79,13 +79,16 @@ public class SmartHttpServerEngine extends AbstractServerEngine {
// SSL
final SSLContext sslContext = config.getSslContext();
if(null != sslContext){
final SslPlugin<Request> sslPlugin;
try {
sslPlugin = new SslPlugin<>(() -> sslContext);
// 使用反射创建SslPlugin
Class<?> sslPluginClass = Class.forName("org.smartboot.socket.extension.plugins.SslPlugin");
Object sslPlugin = sslPluginClass.getConstructor(Supplier.class).newInstance((Supplier<SSLContext>) () -> sslContext);
// 使用反射调用addPlugin方法
Method addPlugin = configuration.getClass().getMethod("addPlugin", Object.class);
addPlugin.invoke(configuration, sslPlugin);
} catch (final Exception e) {
throw new HttpException(e);
}
configuration.addPlugin(sslPlugin);
}
// 选项

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2025 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @author choweli
*/
module hutool.http {
exports cn.hutool.v7.http.meta;
exports cn.hutool.v7.http.client;
exports cn.hutool.v7.http;
requires jdk.httpserver;
requires hutool.log;
requires org.apache.httpcomponents.httpclient;
requires org.apache.httpcomponents.httpcore;
requires hutool.core;
requires org.apache.httpcomponents.core5.httpcore5;
requires org.apache.httpcomponents.client5.httpclient5;
requires okhttp3;
requires org.eclipse.jetty.server;
requires smart.http.server;
requires undertow.core;
requires jakarta.xml.soap;
requires okio;
requires smart.http.common;
requires org.apache.tomcat.embed.core;
requires aio.pro;
opens cn.hutool.v7.http.client.engine;
opens cn.hutool.v7.http.client.engine.httpclient5;
opens cn.hutool.v7.http.client.engine.httpclient4;
opens cn.hutool.v7.http.client.engine.okhttp;
opens cn.hutool.v7.http.client.engine.jdk;
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2025 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @author choweli
*/
module hutool.jmh {
}

View File

@@ -0,0 +1,8 @@
package cn.hutool.v7.json.issues;
/**
* 为了通过test进行占位
* @author choweli
*/
public class Test {
}

View File

@@ -0,0 +1,8 @@
package cn.hutool.v7.json.issues.issueIVMD5;
/**
* 为了通过test进行占位
* @author choweli
*/
public class Test {
}

View File

@@ -0,0 +1,8 @@
package cn.hutool.v7.json.test.bean;
/**
* 为了通过test进行占位
* @author choweli
*/
public class Test {
}

View File

@@ -0,0 +1,8 @@
package cn.hutool.v7.json.test.bean.report;
/**
* 为了通过test进行占位
* @author choweli
*/
public class Test {
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (c) 2025 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @author choweli
*/
module hutool.json {
exports cn.hutool.v7.json;
exports cn.hutool.v7.json.jwt;
exports cn.hutool.v7.json.writer;
exports cn.hutool.v7.json.engine;
exports cn.hutool.v7.json.engine.gson;
exports cn.hutool.v7.json.engine.moshi;
exports cn.hutool.v7.json.engine.jackson;
exports cn.hutool.v7.json.engine.fastjson;
exports cn.hutool.v7.json.test.bean;
exports cn.hutool.v7.json.test.bean.report;
requires hutool.core;
requires hutool.crypto;
requires com.alibaba.fastjson2;
requires com.google.gson;
requires com.fasterxml.jackson.databind;
requires com.squareup.moshi;
requires okio;
requires java.sql;
opens cn.hutool.v7.json;
opens cn.hutool.v7.json.jwt;
opens cn.hutool.v7.json.engine;
opens cn.hutool.v7.json.issues;
opens cn.hutool.v7.json.issues.issueIVMD5;
}

View File

@@ -16,10 +16,9 @@
package cn.hutool.v7.log.engine.commons;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.impl.Log4JLogger;
import cn.hutool.v7.log.engine.log4j.Log4jLog;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Apache Commons Logging for Log4j
@@ -36,8 +35,8 @@ public class ApacheCommonsLog4JLog extends Log4jLog {
*
* @param logger Logger
*/
public ApacheCommonsLog4JLog(final Log logger) {
super(((Log4JLogger) logger).getLogger());
public ApacheCommonsLog4JLog(final Logger logger) {
super(logger);
}
/**
@@ -46,7 +45,7 @@ public class ApacheCommonsLog4JLog extends Log4jLog {
* @param clazz 类
*/
public ApacheCommonsLog4JLog(final Class<?> clazz) {
super(clazz);
super(LogManager.getLogger(clazz));
}
/**
@@ -55,6 +54,6 @@ public class ApacheCommonsLog4JLog extends Log4jLog {
* @param name 名称
*/
public ApacheCommonsLog4JLog(final String name) {
super(name);
super(LogManager.getLogger(name));
}
}

View File

@@ -16,11 +16,11 @@
package cn.hutool.v7.log.engine.log4j;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import cn.hutool.v7.core.text.StrUtil;
import cn.hutool.v7.log.AbstractLog;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* <a href="http://logging.apache.org/log4j/1.2/index.html">Apache Log4J</a> log.<br>
@@ -49,7 +49,7 @@ public class Log4jLog extends AbstractLog {
* @param name 日志标识
*/
public Log4jLog(final String name) {
this(Logger.getLogger(name));
this(LogManager.getLogger(name));
}
/**
@@ -101,7 +101,7 @@ public class Log4jLog extends AbstractLog {
// ------------------------------------------------------------------------- Warn
@Override
public boolean isWarnEnabled() {
return logger.isEnabledFor(Level.WARN);
return logger.isEnabled(Level.WARN);
}
@Override
@@ -112,7 +112,7 @@ public class Log4jLog extends AbstractLog {
// ------------------------------------------------------------------------- Error
@Override
public boolean isErrorEnabled() {
return logger.isEnabledFor(Level.ERROR);
return logger.isEnabled(Level.ERROR);
}
@Override
@@ -144,8 +144,9 @@ public class Log4jLog extends AbstractLog {
throw new Error(StrUtil.format("Can not identify level: {}", level));
}
if(logger.isEnabledFor(log4jLevel)) {
logger.log(fqcn, log4jLevel, StrUtil.format(format, arguments), t);
if(logger.isEnabled(log4jLevel)) {
//Log4j2的API设计已内置类名自动获取能力
logger.log(log4jLevel, StrUtil.format(format, arguments), t);
}
}
}

View File

@@ -16,13 +16,15 @@
package cn.hutool.v7.log.engine.tinylog;
import cn.hutool.v7.log.AbstractLog;
import org.pmw.tinylog.Level;
import org.pmw.tinylog.LogEntryForwarder;
import org.pmw.tinylog.Logger;
import cn.hutool.v7.core.array.ArrayUtil;
import cn.hutool.v7.core.text.StrUtil;
import cn.hutool.v7.log.AbstractLog;
import org.tinylog.Level;
import org.tinylog.configuration.Configuration;
import org.tinylog.format.AdvancedMessageFormatter;
import org.tinylog.format.MessageFormatter;
import org.tinylog.provider.LoggingProvider;
import org.tinylog.provider.ProviderRegistry;
/**
* <a href="http://www.tinylog.org/">tinylog</a> log.<br>
@@ -39,6 +41,12 @@ public class TinyLog extends AbstractLog {
private final int level;
private final String name;
private static final LoggingProvider provider = ProviderRegistry.getLoggingProvider();
private static final MessageFormatter formatter = new AdvancedMessageFormatter(
Configuration.getLocale(),
Configuration.isEscapingEnabled()
);
/**
* 构造
@@ -57,7 +65,7 @@ public class TinyLog extends AbstractLog {
*/
public TinyLog(final String name) {
this.name = name;
this.level = Logger.getLevel(name).ordinal();
this.level = provider.getMinimumLevel().ordinal();
}
@Override
@@ -101,12 +109,12 @@ public class TinyLog extends AbstractLog {
// ------------------------------------------------------------------------- Warn
@Override
public boolean isWarnEnabled() {
return this.level <= org.pmw.tinylog.Level.WARNING.ordinal();
return this.level <= Level.WARN.ordinal();
}
@Override
public void warn(final String fqcn, final Throwable t, final String format, final Object... arguments) {
logIfEnabled(fqcn, Level.WARNING, t, format, arguments);
logIfEnabled(fqcn, Level.WARN, t, format, arguments);
}
// ------------------------------------------------------------------------- Error
@@ -145,7 +153,7 @@ public class TinyLog extends AbstractLog {
if (null == t) {
t = getLastArgumentIfThrowable(arguments);
}
LogEntryForwarder.forward(DEPTH, level, t, StrUtil.toString(format), arguments);
provider.log(DEPTH, null, level, t, formatter, StrUtil.toString(format), arguments);
}
/**
@@ -168,7 +176,7 @@ public class TinyLog extends AbstractLog {
tinyLevel = Level.INFO;
break;
case WARN:
tinyLevel = Level.WARNING;
tinyLevel = Level.WARN;
break;
case ERROR:
tinyLevel = Level.ERROR;

View File

@@ -32,7 +32,7 @@ public class TinyLogEngine extends AbsLogEngine {
*/
public TinyLogEngine() {
super("TinyLog");
checkLogExist(org.pmw.tinylog.Logger.class);
checkLogExist(org.tinylog.Logger.class);
}
@Override

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2025 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @author choweli
*/
module hutool.log {
exports cn.hutool.v7.log;
exports cn.hutool.v7.log.level;
exports cn.hutool.v7.log.engine.console;
exports cn.hutool.v7.log.engine.log4j2;
requires hutool.core;
requires org.jboss.logging;
requires org.apache.commons.logging;
requires org.apache.logging.log4j;
requires org.slf4j;
requires tinylog;
requires org.tinylog.api;
requires java.logging;
requires log4j;
}

View File

@@ -37,6 +37,7 @@
<!-- versions -->
<poi.version>5.4.1</poi.version>
<log4j2.version>2.20.0</log4j2.version>
<hierynomus.version>0.39.0</hierynomus.version>
</properties>
<dependencies>
@@ -69,6 +70,14 @@
<artifactId>bcprov-jdk15on</artifactId>
<groupId>org.bouncycastle</groupId>
</exclusion>
<exclusion>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>xmlgraphics-commons</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-transcoder</artifactId>
</exclusion>
</exclusions>
<optional>true</optional>
</dependency>
@@ -79,5 +88,11 @@
<version>${log4j2.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.hierynomus</groupId>
<artifactId>sshj</artifactId>
<version>${hierynomus.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2025 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @author choweli
*/
module hutool.poi {
exports cn.hutool.v7.poi.excel.reader;
requires org.apache.poi.ooxml;
requires hutool.core;
requires java.desktop;
requires ofdrw.layout;
requires ofdrw.font;
requires ofdrw.reader;
requires ofdrw.converter;
requires java.sql;
opens cn.hutool.v7.poi.excel.writer;
opens cn.hutool.v7.poi.csv;
}

View File

@@ -35,6 +35,14 @@
<properties>
<Automatic-Module-Name>cn.hutool.v7.setting</Automatic-Module-Name>
<snakeyaml.version>2.3</snakeyaml.version>
<!-- 固定3.4.x支持到jdk8 -->
<jboss-logging.version>3.4.3.Final</jboss-logging.version>
<slf4j.version>2.0.9</slf4j.version>
<log4j.version>1.2.17</log4j.version>
<log4j2.version>2.20.0</log4j2.version>
<tinylog.version>1.3.6</tinylog.version>
<tinylog2.version>2.7.0</tinylog2.version>
<commons-logging.version>1.3.4</commons-logging.version>
</properties>
<dependencies>
@@ -55,5 +63,47 @@
<version>${snakeyaml.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss-logging.version}</version>
</dependency>
<!-- 仅用于测试 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog</artifactId>
<version>${tinylog.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog-api</artifactId>
<version>${tinylog2.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>${commons-logging.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2025 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @author choweli
*/
module hutool.setting {
exports cn.hutool.v7.setting;
exports cn.hutool.v7.setting.props;
requires hutool.log;
requires hutool.core;
requires org.yaml.snakeyaml;
opens cn.hutool.v7.setting.toml;
}

View File

@@ -34,6 +34,14 @@
<properties>
<Automatic-Module-Name>cn.hutool.v7.socket</Automatic-Module-Name>
<!-- 固定3.4.x支持到jdk8 -->
<jboss-logging.version>3.4.3.Final</jboss-logging.version>
<slf4j.version>2.0.9</slf4j.version>
<log4j.version>1.2.17</log4j.version>
<log4j2.version>2.20.0</log4j2.version>
<tinylog.version>1.3.6</tinylog.version>
<tinylog2.version>2.7.0</tinylog2.version>
<commons-logging.version>1.3.4</commons-logging.version>
</properties>
<dependencies>
@@ -47,5 +55,47 @@
<artifactId>hutool-log</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss-logging.version}</version>
</dependency>
<!-- 仅用于测试 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog</artifactId>
<version>${tinylog.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog-api</artifactId>
<version>${tinylog2.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>${commons-logging.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2025 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @author choweli
*/
module hutool.socket {
requires hutool.log;
requires hutool.core;
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2025 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @author choweli
*/
module hutool.swing {
requires hutool.core;
requires java.desktop;
requires animated.gif.lib;
requires metadata.extractor;
requires com.google.zxing;
}