forked from plusone/simple-jdbc
refactor!: 移除 plusone-commons 及 Guava 依赖,内化工具方法
完全移除对外部工具库 plusone-commons 和 Guava 的编译期依赖, 将所需功能内化实现,使项目成为真正的零依赖轻量级 JDBC 封装库。 - 新增 AssertTools: 断言工具(checkArgument / checkNotNull / checkState / checkCondition) - 新增 NamingTools: 命名转换(camelToSnake) - 新增 ThrowingConsumer / ThrowingPredicate: 可抛受检异常的函数式接口 - 新增 AssertToolsTests: 完整覆盖断言工具所有方法及边界场景 - pom.xml 移除 plusone-dependencies BOM,直接声明 jsr305 / test 依赖版本 - DefaultBeanRowMapper 使用 NamingTools.camelToSnake 替代 Guava CaseFormat - ParamBuilder 内联 Optional 展开逻辑,去除 OptionalTools / CollectionTools - JdbcOperationSupport 用 null/长度判断替代 ArrayTools.isEmpty/isNotEmpty - NOTICE 移除第三方依赖声明;README 移除无依赖分支说明 - 测试:新增缩写映射(URL/XML/ID/HTML/HTTP)覆盖、TransactionException 构造器测试 BREAKING CHANGE: BatchUpdateStatus 不再实现 IWithIntCode 接口; plusone-commons 和 Guava 不再作为传递依赖提供。
This commit is contained in:
24
NOTICE
24
NOTICE
@@ -5,36 +5,20 @@ This product is licensed under the Apache License, Version 2.0.
|
||||
You may obtain a copy of the License at:
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
================================================================================
|
||||
Third-Party Dependencies
|
||||
================================================================================
|
||||
|
||||
1. plusone-commons (xyz.zhouxy.plusone:plusone-commons)
|
||||
Copyright ZhouXY
|
||||
Licensed under the Apache License, Version 2.0
|
||||
|
||||
2. Google Guava (com.google.guava:guava)
|
||||
Copyright (C) The Guava Authors
|
||||
Licensed under the Apache License, Version 2.0
|
||||
|
||||
3. JSR-305 Annotations (com.google.code.findbugs:jsr305)
|
||||
Copyright (C) FindBugs
|
||||
Licensed under the Apache License, Version 2.0
|
||||
|
||||
================================================================================
|
||||
Test Dependencies (Not included in distribution)
|
||||
================================================================================
|
||||
|
||||
4. JUnit Jupiter (org.junit.jupiter:junit-jupiter)
|
||||
1. JUnit Jupiter (org.junit.jupiter:junit-jupiter)
|
||||
Copyright 2015-2026 JUnit Team
|
||||
Licensed under the Eclipse Public License 2.0
|
||||
|
||||
5. Logback (ch.qos.logback:logback-classic)
|
||||
2. Logback (ch.qos.logback:logback-classic)
|
||||
Copyright (C) 1999-2026, QOS.ch
|
||||
Licensed under the Eclipse Public License 1.0
|
||||
and GNU Lesser General Public License 2.1
|
||||
|
||||
6. H2 Database (com.h2database:h2)
|
||||
3. H2 Database (com.h2database:h2)
|
||||
Copyright 1999-2026 H2 Database Project
|
||||
Licensed under the MPL 2.0 and EPL 1.0
|
||||
|
||||
@@ -42,6 +26,6 @@ Test Dependencies (Not included in distribution)
|
||||
Notes
|
||||
================================================================================
|
||||
|
||||
- This project is a lightweight JDBC wrapper designed for legacy projects
|
||||
- This project is a lightweight JDBC wrapper designed for legacy projects
|
||||
without ORM frameworks.
|
||||
- For learning and reference purposes only.
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
> 注:本项目基于 [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) 开源协议发布。
|
||||
|
||||
> 💡 **无外部依赖说明**:主分支(`dev`)的发布版本依赖 `plusone-commons` 工具库(含 Guava)。若您的项目属于不方便引入新依赖的场景(如老项目改造),可使用 `feature/no-dependencies` 分支,直接复制源码进行使用,无需考虑依赖问题。该分支已移除所有编译期与运行期外部依赖,将所需的工具方法(如断言检查)内化实现,仅保留测试相关的依赖项。
|
||||
|
||||
---
|
||||
|
||||
## 1. ✨ 核心特性
|
||||
|
||||
28
pom.xml
28
pom.xml
@@ -16,7 +16,11 @@
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
<plusone-commons.version>1.1.0-RC2</plusone-commons.version>
|
||||
<!-- Dependency Versions -->
|
||||
<jsr305.version>3.0.2</jsr305.version>
|
||||
<junit-jupiter.version>5.14.4</junit-jupiter.version>
|
||||
<logback.version>1.3.16</logback.version>
|
||||
<h2.version>2.2.224</h2.version>
|
||||
</properties>
|
||||
|
||||
<licenses>
|
||||
@@ -40,43 +44,35 @@
|
||||
<url>https://gitea.zhouxy.xyz/plusone/simple-jdbc</url>
|
||||
</scm>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>xyz.zhouxy.plusone</groupId>
|
||||
<artifactId>plusone-dependencies</artifactId>
|
||||
<version>${plusone-commons.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>xyz.zhouxy.plusone</groupId>
|
||||
<artifactId>plusone-commons</artifactId>
|
||||
<version>${plusone-commons.version}</version>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
<version>${jsr305.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${junit-jupiter.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>${h2.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package xyz.zhouxy.jdbc;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.base.IWithIntCode;
|
||||
|
||||
/**
|
||||
* 批量更新状态
|
||||
*
|
||||
@@ -27,7 +25,7 @@ import xyz.zhouxy.plusone.commons.base.IWithIntCode;
|
||||
* @see BatchUpdateResult
|
||||
* @see BatchUpdateResult#getStatus()
|
||||
*/
|
||||
public enum BatchUpdateStatus implements IWithIntCode {
|
||||
public enum BatchUpdateStatus {
|
||||
|
||||
/**
|
||||
* 成功
|
||||
@@ -62,9 +60,10 @@ public enum BatchUpdateStatus implements IWithIntCode {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* 获取状态码
|
||||
*
|
||||
* @return 状态码
|
||||
*/
|
||||
@Override
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
@@ -34,9 +34,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.CaseFormat;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
|
||||
import xyz.zhouxy.jdbc.util.NamingTools;
|
||||
|
||||
/**
|
||||
* DefaultBeanRowMapper
|
||||
@@ -90,7 +88,6 @@ public class DefaultBeanRowMapper<T> implements RowMapper<T> {
|
||||
* @return DefaultBeanRowMapper 对象
|
||||
* @throws SQLException 创建 {@code DefaultBeanRowMapper} 出现错误的异常时抛出
|
||||
*/
|
||||
@StaticFactoryMethod(DefaultBeanRowMapper.class)
|
||||
public static <T> DefaultBeanRowMapper<T> of(Class<T> beanType) throws SQLException {
|
||||
return of(beanType, null);
|
||||
}
|
||||
@@ -104,7 +101,6 @@ public class DefaultBeanRowMapper<T> implements RowMapper<T> {
|
||||
* @return {@code DefaultBeanRowMapper} 对象
|
||||
* @throws SQLException 创建 {@code DefaultBeanRowMapper} 出现错误的异常时抛出
|
||||
*/
|
||||
@StaticFactoryMethod(DefaultBeanRowMapper.class)
|
||||
public static <T> DefaultBeanRowMapper<T> of(Class<T> beanType, @Nullable Map<String, String> propertyColMap)
|
||||
throws SQLException {
|
||||
try {
|
||||
@@ -167,14 +163,14 @@ public class DefaultBeanRowMapper<T> implements RowMapper<T> {
|
||||
// Bean 的属性名为小驼峰,对应的列名为下划线
|
||||
Function<? super PropertyDescriptor, String> keyMapper;
|
||||
if (propertyColMap == null || propertyColMap.isEmpty()) {
|
||||
keyMapper = p -> CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, p.getName());
|
||||
keyMapper = p -> NamingTools.camelToSnake(p.getName());
|
||||
}
|
||||
else {
|
||||
keyMapper = p -> {
|
||||
String propertyName = p.getName();
|
||||
String colName = propertyColMap.get(propertyName);
|
||||
return colName != null ? colName
|
||||
: CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, propertyName);
|
||||
: NamingTools.camelToSnake(propertyName);
|
||||
};
|
||||
}
|
||||
return Arrays.stream(propertyDescriptors)
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
package xyz.zhouxy.jdbc;
|
||||
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgumentNotNull;
|
||||
import static xyz.zhouxy.jdbc.util.AssertTools.checkArgument;
|
||||
import static xyz.zhouxy.jdbc.util.AssertTools.checkArgumentNotNull;
|
||||
|
||||
import java.sql.BatchUpdateException;
|
||||
import java.sql.Connection;
|
||||
@@ -37,8 +37,6 @@ import java.util.List;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.util.ArrayTools;
|
||||
|
||||
/**
|
||||
* JdbcOperationSupport
|
||||
*
|
||||
@@ -162,7 +160,7 @@ class JdbcOperationSupport {
|
||||
throws SQLException {
|
||||
assertConnectionNotNull(conn);
|
||||
assertSqlNotNull(sql);
|
||||
if (ArrayTools.isNotEmpty(params)) {
|
||||
if (params != null && params.length > 0) {
|
||||
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||
fillStatement(stmt, params);
|
||||
return stmt.executeUpdate();
|
||||
@@ -191,7 +189,7 @@ class JdbcOperationSupport {
|
||||
assertConnectionNotNull(conn);
|
||||
assertSqlNotNull(sql);
|
||||
assertRowMapperNotNull(rowMapper);
|
||||
if (ArrayTools.isNotEmpty(params)) {
|
||||
if (params != null && params.length > 0) {
|
||||
try (PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
|
||||
fillStatement(stmt, params);
|
||||
stmt.executeUpdate();
|
||||
@@ -308,7 +306,7 @@ class JdbcOperationSupport {
|
||||
@Nullable Object[] params,
|
||||
@Nonnull ResultHandler<T> resultHandler)
|
||||
throws SQLException {
|
||||
if (ArrayTools.isNotEmpty(params)) {
|
||||
if (params != null && params.length > 0) {
|
||||
try (PreparedStatement stmt = createPreparedStatementInternal(conn, sql, params);
|
||||
ResultSet rs = stmt.executeQuery()) {
|
||||
return resultHandler.handle(rs);
|
||||
|
||||
@@ -29,10 +29,7 @@ import java.util.OptionalLong;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.collection.CollectionTools;
|
||||
import xyz.zhouxy.plusone.commons.util.ArrayTools;
|
||||
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
||||
import xyz.zhouxy.plusone.commons.util.OptionalTools;
|
||||
import xyz.zhouxy.jdbc.util.AssertTools;
|
||||
|
||||
/**
|
||||
* ParamBuilder
|
||||
@@ -66,7 +63,7 @@ public class ParamBuilder {
|
||||
* @return 参数数组
|
||||
*/
|
||||
public static Object[] buildParams(final Object... params) {
|
||||
if (ArrayTools.isEmpty(params)) {
|
||||
if (params == null || params.length == 0) {
|
||||
return EMPTY_OBJECT_ARRAY;
|
||||
}
|
||||
return Arrays.stream(params)
|
||||
@@ -91,16 +88,16 @@ public class ParamBuilder {
|
||||
return param;
|
||||
}
|
||||
if (param instanceof Optional) {
|
||||
return OptionalTools.orElseNull((Optional<?>) param);
|
||||
return ((Optional<?>) param).orElse(null);
|
||||
}
|
||||
if (param instanceof OptionalInt) {
|
||||
return OptionalTools.toInteger((OptionalInt) param);
|
||||
return ((OptionalInt) param).isPresent() ? ((OptionalInt) param).getAsInt() : null;
|
||||
}
|
||||
if (param instanceof OptionalLong) {
|
||||
return OptionalTools.toLong((OptionalLong) param);
|
||||
return ((OptionalLong) param).isPresent() ? ((OptionalLong) param).getAsLong() : null;
|
||||
}
|
||||
if (param instanceof OptionalDouble) {
|
||||
return OptionalTools.toDouble((OptionalDouble) param);
|
||||
return ((OptionalDouble) param).isPresent() ? ((OptionalDouble) param).getAsDouble() : null;
|
||||
}
|
||||
return param;
|
||||
}
|
||||
@@ -121,7 +118,7 @@ public class ParamBuilder {
|
||||
public static <T> List<Object[]> buildBatchParams(final Collection<T> c, final Function<T, Object[]> func) {
|
||||
AssertTools.checkNotNull(c, "The collection can not be null.");
|
||||
AssertTools.checkNotNull(func, "The func can not be null.");
|
||||
if (CollectionTools.isEmpty(c)) {
|
||||
if (c.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return c.stream().map(func).collect(Collectors.toList());
|
||||
|
||||
@@ -26,7 +26,7 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
||||
import xyz.zhouxy.jdbc.util.AssertTools;
|
||||
|
||||
/**
|
||||
* JDBC 操作的模板类,对原生 JDBC 进行轻量封装,提供查询、更新、批量操作等便捷方法。
|
||||
|
||||
41
src/main/java/xyz/zhouxy/jdbc/ThrowingConsumer.java
Normal file
41
src/main/java/xyz/zhouxy/jdbc/ThrowingConsumer.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2026-present ZhouXY
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.jdbc;
|
||||
|
||||
/**
|
||||
* 可抛出受检异常的函数式接口。
|
||||
*
|
||||
* <p>
|
||||
* 类似于 {@link java.util.function.Consumer},但 {@code accept} 方法允许抛出受检异常。
|
||||
* </p>
|
||||
*
|
||||
* @param <T> 输入类型
|
||||
* @param <E> 允许抛出的异常类型
|
||||
* @author ZhouXY
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ThrowingConsumer<T, E extends Exception> {
|
||||
|
||||
/**
|
||||
* 对给定参数执行此操作。
|
||||
*
|
||||
* @param t 输入参数
|
||||
* @throws E 异常
|
||||
*/
|
||||
void accept(T t) throws E;
|
||||
}
|
||||
42
src/main/java/xyz/zhouxy/jdbc/ThrowingPredicate.java
Normal file
42
src/main/java/xyz/zhouxy/jdbc/ThrowingPredicate.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2026-present ZhouXY
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.jdbc;
|
||||
|
||||
/**
|
||||
* 可抛出受检异常的谓词函数式接口。
|
||||
*
|
||||
* <p>
|
||||
* 类似于 {@link java.util.function.Predicate},但 {@code test} 方法允许抛出受检异常。
|
||||
* </p>
|
||||
*
|
||||
* @param <T> 输入类型
|
||||
* @param <E> 允许抛出的异常类型
|
||||
* @author ZhouXY
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ThrowingPredicate<T, E extends Exception> {
|
||||
|
||||
/**
|
||||
* 对给定参数执行此谓词判断。
|
||||
*
|
||||
* @param t 输入参数
|
||||
* @return 谓词判断结果
|
||||
* @throws E 异常
|
||||
*/
|
||||
boolean test(T t) throws E;
|
||||
}
|
||||
@@ -26,9 +26,7 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.function.ThrowingConsumer;
|
||||
import xyz.zhouxy.plusone.commons.function.ThrowingPredicate;
|
||||
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
||||
import xyz.zhouxy.jdbc.util.AssertTools;
|
||||
|
||||
/**
|
||||
* 事务模板,提供事务执行能力。
|
||||
@@ -64,7 +62,12 @@ public class TransactionTemplate {
|
||||
@Nonnull
|
||||
private final DataSource dataSource;
|
||||
|
||||
public TransactionTemplate(@Nonnull DataSource dataSource) {
|
||||
/**
|
||||
* 构造一个 {@code TransactionTemplate} 实例
|
||||
*
|
||||
* @param dataSource 数据源,用于获取数据库连接;不可为 {@code null}
|
||||
*/
|
||||
public TransactionTemplate(DataSource dataSource) {
|
||||
AssertTools.checkNotNull(dataSource);
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
334
src/main/java/xyz/zhouxy/jdbc/util/AssertTools.java
Normal file
334
src/main/java/xyz/zhouxy/jdbc/util/AssertTools.java
Normal file
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Copyright 2024-present ZhouXY
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.jdbc.util;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* 断言工具
|
||||
*
|
||||
* <p>
|
||||
* 本工具类不封装过多判断逻辑,鼓励充分使用项目中的工具类进行逻辑判断。
|
||||
*
|
||||
* <pre>
|
||||
* checkArgument(StringUtils.hasText(str), "The argument cannot be blank.");
|
||||
* checkState(ArrayUtils.isNotEmpty(result), "The result cannot be empty.");
|
||||
* checkCondition(!CollectionUtils.isEmpty(roles),
|
||||
* () -> new InvalidInputException("The roles cannot be empty."));
|
||||
* checkCondition(RegexTools.matches(email, PatternConsts.EMAIL),
|
||||
* "must be a well-formed email address");
|
||||
* </pre>
|
||||
*
|
||||
* @author ZhouXY
|
||||
*/
|
||||
public class AssertTools {
|
||||
|
||||
// ================================
|
||||
// #region - Argument
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 检查实参
|
||||
*
|
||||
* @param condition 判断参数是否符合条件的结果
|
||||
* @throws IllegalArgumentException 当条件不满足时抛出
|
||||
*/
|
||||
public static void checkArgument(boolean condition) {
|
||||
if (!condition) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查实参
|
||||
*
|
||||
* @param condition 判断参数是否符合条件的结果
|
||||
* @param errorMessage 异常信息
|
||||
* @throws IllegalArgumentException 当条件不满足时抛出
|
||||
*/
|
||||
public static void checkArgument(boolean condition, String errorMessage) {
|
||||
if (!condition) {
|
||||
throw new IllegalArgumentException(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查实参
|
||||
*
|
||||
* @param condition 判断参数是否符合条件的结果
|
||||
* @param errorMessageSupplier 异常信息
|
||||
* @throws IllegalArgumentException 当条件不满足时抛出
|
||||
*/
|
||||
public static void checkArgument(boolean condition, Supplier<String> errorMessageSupplier) {
|
||||
if (!condition) {
|
||||
throw new IllegalArgumentException(errorMessageSupplier.get());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查实参
|
||||
*
|
||||
* @param condition 判断参数是否符合条件的结果
|
||||
* @param errorMessageTemplate 异常信息模板
|
||||
* @param errorMessageArgs 异常信息参数
|
||||
* @throws IllegalArgumentException 当条件不满足时抛出
|
||||
*/
|
||||
public static void checkArgument(boolean condition,
|
||||
String errorMessageTemplate, Object... errorMessageArgs) {
|
||||
if (!condition) {
|
||||
throw new IllegalArgumentException(String.format(errorMessageTemplate, errorMessageArgs));
|
||||
}
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion - Argument
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - ArgumentNotNull
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 判断入参不为 {@code null}
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @return 校验通过时返回入参
|
||||
* @throws IllegalArgumentException 当 {@code obj} 为 {@code null} 时抛出
|
||||
*/
|
||||
public static <T> T checkArgumentNotNull(T obj) {
|
||||
if (obj == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断入参不为 {@code null}
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @param errorMessage 异常信息
|
||||
* @return 校验通过时返回入参
|
||||
* @throws IllegalArgumentException 当 {@code obj} 为 {@code null} 时抛出
|
||||
*/
|
||||
public static <T> T checkArgumentNotNull(T obj, String errorMessage) {
|
||||
if (obj == null) {
|
||||
throw new IllegalArgumentException(errorMessage);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断入参不为 {@code null}
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @param errorMessageSupplier 异常信息
|
||||
* @return 校验通过时返回入参
|
||||
* @throws IllegalArgumentException 当 {@code obj} 为 {@code null} 时抛出
|
||||
*/
|
||||
public static <T> T checkArgumentNotNull(T obj, Supplier<String> errorMessageSupplier) {
|
||||
if (obj == null) {
|
||||
throw new IllegalArgumentException(errorMessageSupplier.get());
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断入参不为 {@code null}
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @param errorMessageTemplate 异常信息模板
|
||||
* @param errorMessageArgs 异常信息参数
|
||||
* @return 校验通过时返回入参
|
||||
* @throws IllegalArgumentException 当 {@code obj} 为 {@code null} 时抛出
|
||||
*/
|
||||
public static <T> T checkArgumentNotNull(T obj,
|
||||
String errorMessageTemplate, Object... errorMessageArgs) {
|
||||
if (obj == null) {
|
||||
throw new IllegalArgumentException(String.format(errorMessageTemplate, errorMessageArgs));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion - ArgumentNotNull
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - State
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 检查状态
|
||||
*
|
||||
* @param condition 判断状态是否符合条件的结果
|
||||
* @throws IllegalStateException 当条件不满足时抛出
|
||||
*/
|
||||
public static void checkState(boolean condition) {
|
||||
if (!condition) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查状态
|
||||
*
|
||||
* @param condition 判断状态是否符合条件的结果
|
||||
* @param errorMessage 异常信息
|
||||
* @throws IllegalStateException 当条件不满足时抛出
|
||||
*/
|
||||
public static void checkState(boolean condition, String errorMessage) {
|
||||
if (!condition) {
|
||||
throw new IllegalStateException(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查状态
|
||||
*
|
||||
* @param condition 判断状态是否符合条件的结果
|
||||
* @param errorMessageSupplier 异常信息
|
||||
* @throws IllegalStateException 当条件不满足时抛出
|
||||
*/
|
||||
public static void checkState(boolean condition, Supplier<String> errorMessageSupplier) {
|
||||
if (!condition) {
|
||||
throw new IllegalStateException(errorMessageSupplier.get());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查状态
|
||||
*
|
||||
* @param condition 判断状态是否符合条件的结果
|
||||
* @param errorMessageTemplate 异常信息模板
|
||||
* @param errorMessageArgs 异常信息参数
|
||||
* @throws IllegalStateException 当条件不满足时抛出
|
||||
*/
|
||||
public static void checkState(boolean condition,
|
||||
String errorMessageTemplate, Object... errorMessageArgs) {
|
||||
if (!condition) {
|
||||
throw new IllegalStateException(String.format(errorMessageTemplate, errorMessageArgs));
|
||||
}
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion - State
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - NotNull
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 判空
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @throws NullPointerException 当 {@code obj} 为 {@code null} 时抛出
|
||||
*/
|
||||
public static <T> void checkNotNull(T obj) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判空
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @param errorMessage 异常信息
|
||||
* @throws NullPointerException 当 {@code obj} 为 {@code null} 时抛出
|
||||
*/
|
||||
public static <T> void checkNotNull(T obj, String errorMessage) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判空
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @param errorMessageSupplier 异常信息
|
||||
* @throws NullPointerException 当 {@code obj} 为 {@code null} 时抛出
|
||||
*/
|
||||
public static <T> void checkNotNull(T obj, Supplier<String> errorMessageSupplier) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(errorMessageSupplier.get());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判空
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @param errorMessageTemplate 异常信息模板
|
||||
* @param errorMessageArgs 异常信息参数
|
||||
* @throws NullPointerException 当 {@code obj} 为 {@code null} 时抛出
|
||||
*/
|
||||
public static <T> void checkNotNull(T obj,
|
||||
String errorMessageTemplate, Object... errorMessageArgs) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(String.format(errorMessageTemplate, errorMessageArgs));
|
||||
}
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion - NotNull
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - Condition
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 当条件不满足时抛出异常。
|
||||
*
|
||||
* @param <T> 异常类型
|
||||
* @param condition 条件
|
||||
* @param e 异常
|
||||
* @throws T 当条件不满足时抛出异常
|
||||
*/
|
||||
public static <T extends Exception> void checkCondition(boolean condition, Supplier<T> e)
|
||||
throws T {
|
||||
if (!condition) {
|
||||
throw e.get();
|
||||
}
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - constructor
|
||||
// ================================
|
||||
|
||||
private AssertTools() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
}
|
||||
96
src/main/java/xyz/zhouxy/jdbc/util/NamingTools.java
Normal file
96
src/main/java/xyz/zhouxy/jdbc/util/NamingTools.java
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2026-present ZhouXY
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.jdbc.util;
|
||||
|
||||
/**
|
||||
* 字符串工具
|
||||
*
|
||||
* @author ZhouXY
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class NamingTools {
|
||||
|
||||
/**
|
||||
* 将小驼峰命名转换为小写下划线命名(snake_case)。
|
||||
*
|
||||
* <p>转换规则:
|
||||
* <ul>
|
||||
* <li>小写→大写边界插入下划线:{@code userName → user_name}</li>
|
||||
* <li>连续大写缩写视为整体,在其末尾小写边界插入下划线:{@code XMLParser → xml_parser}</li>
|
||||
* <li>纯小写保持不变:{@code username → username}</li>
|
||||
* <li>{@code null} 或空字符串返回原值</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param camelCase 小驼峰命名字符串,可空
|
||||
* @return snake_case 命名字符串;{@code null} 输入返回 {@code null}
|
||||
*/
|
||||
public static String camelToSnake(String camelCase) {
|
||||
if (camelCase == null || camelCase.isEmpty()) {
|
||||
return camelCase;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder(camelCase.length() * 2);
|
||||
int len = camelCase.length();
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = camelCase.charAt(i);
|
||||
if (isUpperCaseAscii(c)) {
|
||||
if (shouldInsertUnderscore(camelCase, i)) {
|
||||
sb.append('_');
|
||||
}
|
||||
sb.append((char) (c + 32)); // 转小写
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static boolean shouldInsertUnderscore(String str, int index) {
|
||||
if (index == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char prev = str.charAt(index - 1);
|
||||
char next = (index + 1 < str.length()) ? str.charAt(index + 1) : 0;
|
||||
|
||||
boolean prevIsBoundary = !isUpperCaseAscii(prev);
|
||||
boolean nextIsLower = isLowerCaseAscii(next);
|
||||
|
||||
return prevIsBoundary || nextIsLower;
|
||||
}
|
||||
|
||||
private static boolean isUpperCaseAscii(char c) {
|
||||
return c >= 'A' && c <= 'Z';
|
||||
}
|
||||
|
||||
private static boolean isLowerCaseAscii(char c) {
|
||||
return c >= 'a' && c <= 'z';
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #region - constructor
|
||||
// ================================
|
||||
|
||||
private NamingTools() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import static xyz.zhouxy.jdbc.ParamBuilder.*;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -16,8 +17,6 @@ import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import xyz.zhouxy.jdbc.BatchUpdateErrorInfo;
|
||||
import xyz.zhouxy.jdbc.BatchUpdateResult;
|
||||
import xyz.zhouxy.jdbc.BatchUpdateStatus;
|
||||
@@ -170,7 +169,7 @@ class BatchUpdateTest extends BaseH2Test {
|
||||
// #region - 包含错误数据
|
||||
// ================================
|
||||
|
||||
final List<User> userListContainingInvalidData = Lists.newArrayList(
|
||||
final List<User> userListContainingInvalidData = Arrays.asList(
|
||||
// batch 0
|
||||
new User("test_0001", "test_0001@example.com", 1, 1L, true),
|
||||
new User("test_0002", "test_0002@example.com", 1, 1L, true),
|
||||
|
||||
@@ -157,6 +157,63 @@ class RowMapperTest extends BaseH2Test {
|
||||
assertEquals("alice", user.get().getUsername());
|
||||
}
|
||||
|
||||
// ==================== DefaultBeanRowMapper 连续大写缩写映射 ====================
|
||||
|
||||
@Test
|
||||
@DisplayName("DefaultBeanRowMapper:连续大写缩写属性正确映射为 snake_case")
|
||||
void testDefaultBeanRowMapperAcronymMapping() throws SQLException {
|
||||
SimpleJdbcTemplate template = createTemplate();
|
||||
|
||||
// 创建测试表,列名使用 snake_case
|
||||
template.update("CREATE TABLE acronym_test ("
|
||||
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY,"
|
||||
+ "home_url VARCHAR(100),"
|
||||
+ "xml_parser VARCHAR(100),"
|
||||
+ "parse_url VARCHAR(100),"
|
||||
+ "user_id VARCHAR(100),"
|
||||
+ "parse_html VARCHAR(100),"
|
||||
+ "multi_http_client VARCHAR(100))");
|
||||
template.update(
|
||||
"INSERT INTO acronym_test (home_url, xml_parser, parse_url, user_id, parse_html, multi_http_client)"
|
||||
+ " VALUES (?, ?, ?, ?, ?, ?)",
|
||||
new Object[]{"https://example.com", "SAXParser", "/api/v1",
|
||||
"user-001", "<div>test</div>", "ApacheHttpClient"});
|
||||
|
||||
RowMapper<AcronymBean> rowMapper = RowMapper.beanRowMapper(AcronymBean.class);
|
||||
Optional<AcronymBean> result = template.queryFirst(
|
||||
"SELECT * FROM acronym_test WHERE id = ?",
|
||||
new Object[]{1L}, rowMapper);
|
||||
|
||||
assertTrue(result.isPresent());
|
||||
AcronymBean bean = result.get();
|
||||
assertEquals("https://example.com", bean.getHomeURL());
|
||||
assertEquals("SAXParser", bean.getXmlParser());
|
||||
assertEquals("/api/v1", bean.getParseURL());
|
||||
assertEquals("user-001", bean.getUserID());
|
||||
assertEquals("<div>test</div>", bean.getParseHTML());
|
||||
assertEquals("ApacheHttpClient", bean.getMultiHttpClient());
|
||||
|
||||
logger.info("缩写映射: homeURL={}, xmlParser={}, parseURL={}, userID={}, parseHTML={}, multiHttpClient={}",
|
||||
bean.getHomeURL(), bean.getXmlParser(), bean.getParseURL(),
|
||||
bean.getUserID(), bean.getParseHTML(), bean.getMultiHttpClient());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("DefaultBeanRowMapper:纯小写属性名映射为同名列")
|
||||
void testDefaultBeanRowMapperAllLowercaseMapping() throws SQLException {
|
||||
// 通过 User Bean 验证纯小写属性映射(username → username, email → email)
|
||||
SimpleJdbcTemplate template = createTemplate();
|
||||
RowMapper<User> rowMapper = RowMapper.beanRowMapper(User.class);
|
||||
|
||||
Optional<User> user = template.queryFirst(
|
||||
"SELECT username, email FROM users WHERE username = ?",
|
||||
new Object[]{"alice"}, rowMapper);
|
||||
|
||||
assertTrue(user.isPresent());
|
||||
assertEquals("alice", user.get().getUsername());
|
||||
assertEquals("alice@example.com", user.get().getEmail());
|
||||
}
|
||||
|
||||
// ==================== HASH_MAP_MAPPER ====================
|
||||
|
||||
@Test
|
||||
@@ -253,4 +310,74 @@ class RowMapperTest extends BaseH2Test {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 包含连续大写缩写属性的 Bean,用于验证 camelToSnake 的缩写处理。
|
||||
*
|
||||
* <p>覆盖场景:
|
||||
* <ul>
|
||||
* <li>homeURL — 缩写在末尾(三字母 URL)</li>
|
||||
* <li>xmlParser — 缩写在前(三字母 XML)</li>
|
||||
* <li>parseURL — 缩写在末尾</li>
|
||||
* <li>userID — 两字母缩写在末尾(ID)</li>
|
||||
* <li>parseHTML — 四字母缩写在末尾(HTML)</li>
|
||||
* <li>multiHttpClient — 缩写夹在词中(HTTP)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static class AcronymBean {
|
||||
private String homeURL;
|
||||
private String xmlParser;
|
||||
private String parseURL;
|
||||
private String userID;
|
||||
private String parseHTML;
|
||||
private String multiHttpClient;
|
||||
|
||||
public String getHomeURL() {
|
||||
return homeURL;
|
||||
}
|
||||
|
||||
public void setHomeURL(String homeURL) {
|
||||
this.homeURL = homeURL;
|
||||
}
|
||||
|
||||
public String getXmlParser() {
|
||||
return xmlParser;
|
||||
}
|
||||
|
||||
public void setXmlParser(String xmlParser) {
|
||||
this.xmlParser = xmlParser;
|
||||
}
|
||||
|
||||
public String getParseURL() {
|
||||
return parseURL;
|
||||
}
|
||||
|
||||
public void setParseURL(String parseURL) {
|
||||
this.parseURL = parseURL;
|
||||
}
|
||||
|
||||
public String getUserID() {
|
||||
return userID;
|
||||
}
|
||||
|
||||
public void setUserID(String userID) {
|
||||
this.userID = userID;
|
||||
}
|
||||
|
||||
public String getParseHTML() {
|
||||
return parseHTML;
|
||||
}
|
||||
|
||||
public void setParseHTML(String parseHTML) {
|
||||
this.parseHTML = parseHTML;
|
||||
}
|
||||
|
||||
public String getMultiHttpClient() {
|
||||
return multiHttpClient;
|
||||
}
|
||||
|
||||
public void setMultiHttpClient(String multiHttpClient) {
|
||||
this.multiHttpClient = multiHttpClient;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,6 +234,15 @@ class TransactionTest extends BaseH2Test {
|
||||
|
||||
// ==================== TransactionException ====================
|
||||
|
||||
@Test
|
||||
@DisplayName("TransactionException:单参构造器(仅 cause)")
|
||||
void testTransactionExceptionSingleArg() {
|
||||
RuntimeException cause = new RuntimeException("原始异常");
|
||||
TransactionException ex = new TransactionException(cause);
|
||||
assertEquals("Transaction failed during execution", ex.getMessage());
|
||||
assertSame(cause, ex.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("TransactionException:双参构造器")
|
||||
void testTransactionExceptionWithMessage() {
|
||||
@@ -242,4 +251,12 @@ class TransactionTest extends BaseH2Test {
|
||||
assertEquals("自定义消息", ex.getMessage());
|
||||
assertSame(cause, ex.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("TransactionException:null cause")
|
||||
void testTransactionExceptionNullCause() {
|
||||
TransactionException ex = new TransactionException(null);
|
||||
assertEquals("Transaction failed during execution", ex.getMessage());
|
||||
assertNull(ex.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
522
src/test/java/xyz/zhouxy/jdbc/test/util/AssertToolsTests.java
Normal file
522
src/test/java/xyz/zhouxy/jdbc/test/util/AssertToolsTests.java
Normal file
@@ -0,0 +1,522 @@
|
||||
/*
|
||||
* Copyright 2024-2025 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.jdbc.test.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static xyz.zhouxy.jdbc.util.AssertTools.*;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import xyz.zhouxy.jdbc.util.AssertTools;
|
||||
|
||||
class AssertToolsTests {
|
||||
|
||||
// #region - Argument
|
||||
|
||||
@Test
|
||||
void testCheckArgument_true() {
|
||||
checkArgument(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgument_true_withMessage() {
|
||||
final String IGNORE_ME = "IGNORE_ME"; // NOSONAR
|
||||
checkArgument(true, IGNORE_ME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgument_true_withNullMessage() {
|
||||
final String IGNORE_ME = null; // NOSONAR
|
||||
checkArgument(true, IGNORE_ME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgument_true_withMessageSupplier() {
|
||||
checkArgument(true, () -> "Error message: " + LocalDate.now());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgument_true_withNullMessageSupplier() {
|
||||
final Supplier<String> IGNORE_ME = null; // NOSONAR
|
||||
checkArgument(true, IGNORE_ME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgument_true_withMessageFormat() {
|
||||
LocalDate today = LocalDate.now();
|
||||
checkArgument(true, "String format: %s", today);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgument_true_withNullMessageFormat() {
|
||||
checkArgument(true, null, LocalDate.now());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgument_false() {
|
||||
final IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
|
||||
() -> checkArgument(false));
|
||||
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgument_false_withMessage() {
|
||||
final String message = "testCheckArgument_false_withMessage";
|
||||
|
||||
final IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
|
||||
() -> checkArgument(false, message));
|
||||
|
||||
assertEquals(message, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgument_false_withNullMessage() {
|
||||
final String message = null;
|
||||
|
||||
final IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
|
||||
() -> checkArgument(false, message));
|
||||
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgument_false_withMessageSupplier() {
|
||||
final LocalDate today = LocalDate.now();
|
||||
final IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
|
||||
() -> checkArgument(false, () -> "Error message: " + today));
|
||||
|
||||
assertEquals("Error message: " + today, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgument_false_withNullMessageSupplier() {
|
||||
Supplier<String> messageSupplier = null;
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> checkArgument(false, messageSupplier));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgument_false_withMessageFormat() {
|
||||
LocalDate today = LocalDate.now();
|
||||
final IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
|
||||
() -> checkArgument(false, "String format: %s", today));
|
||||
assertEquals(String.format("String format: %s", today), e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgument_false_withNullMessageFormat() {
|
||||
LocalDate today = LocalDate.now();
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> checkArgument(false, null, today));
|
||||
}
|
||||
|
||||
// #endregion - Argument
|
||||
|
||||
// #region - ArgumentNotNull
|
||||
|
||||
@Test
|
||||
void testCheckArgumentNotNull_notNull() {
|
||||
final Object object = new Object();
|
||||
assertEquals(object, checkArgumentNotNull(object));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgumentNotNull_notNull_withMessage() {
|
||||
final Object object = new Object();
|
||||
final String IGNORE_ME = "IGNORE_ME"; // NOSONAR
|
||||
assertEquals(object, checkArgumentNotNull(object, IGNORE_ME));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgumentNotNull_notNull_withNullMessage() {
|
||||
final Object object = new Object();
|
||||
final String IGNORE_ME = null; // NOSONAR
|
||||
assertEquals(object, checkArgumentNotNull(object, IGNORE_ME));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgumentNotNull_notNull_withMessageSupplier() {
|
||||
final Object object = new Object();
|
||||
assertEquals(object, checkArgumentNotNull(object, () -> "Error message: " + LocalDate.now()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgumentNotNull_notNull_withNullMessageSupplier() {
|
||||
final Object object = new Object();
|
||||
final Supplier<String> IGNORE_ME = null; // NOSONAR
|
||||
assertEquals(object, checkArgumentNotNull(object, IGNORE_ME));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgumentNotNull_notNull_withMessageFormat() {
|
||||
final Object object = new Object();
|
||||
LocalDate today = LocalDate.now();
|
||||
assertEquals(object, checkArgumentNotNull(object, "String format: %s", today));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgumentNotNull_notNull_withNullMessageFormat() {
|
||||
final Object object = new Object();
|
||||
assertEquals(object, checkArgumentNotNull(object, null, LocalDate.now()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgumentNotNull_null() {
|
||||
final Object object = null;
|
||||
final IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
|
||||
() -> checkArgumentNotNull(object));
|
||||
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgumentNotNull_null_withMessage() {
|
||||
final Object object = null;
|
||||
final String message = "testCheckArgumentNotNull_null_withMessage";
|
||||
|
||||
final IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
|
||||
() -> checkArgumentNotNull(object, message));
|
||||
|
||||
assertEquals(message, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgumentNotNull_null_withNullMessage() {
|
||||
final Object object = null;
|
||||
final String message = null;
|
||||
|
||||
final IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
|
||||
() -> checkArgumentNotNull(object, message));
|
||||
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgumentNotNull_null_withMessageSupplier() {
|
||||
final Object object = null;
|
||||
final LocalDate today = LocalDate.now();
|
||||
final IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
|
||||
() -> checkArgumentNotNull(object, () -> "Error message: " + today));
|
||||
|
||||
assertEquals("Error message: " + today, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgumentNotNull_null_withNullMessageSupplier() {
|
||||
final Object object = null;
|
||||
Supplier<String> messageSupplier = null;
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> checkArgumentNotNull(object, messageSupplier));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgumentNotNull_null_withMessageFormat() {
|
||||
final Object object = null;
|
||||
LocalDate today = LocalDate.now();
|
||||
final IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
|
||||
() -> checkArgumentNotNull(object, "String format: %s", today));
|
||||
assertEquals(String.format("String format: %s", today), e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckArgumentNotNull_null_withNullMessageFormat() {
|
||||
final Object object = null;
|
||||
LocalDate today = LocalDate.now();
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> checkArgumentNotNull(object, null, today));
|
||||
}
|
||||
|
||||
// #endregion - ArgumentNotNull
|
||||
|
||||
// #region - State
|
||||
|
||||
@Test
|
||||
void testCheckState_true() {
|
||||
checkState(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckState_true_withMessage() {
|
||||
final String IGNORE_ME = "IGNORE_ME"; // NOSONAR
|
||||
checkState(true, IGNORE_ME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckState_true_withNullMessage() {
|
||||
final String IGNORE_ME = null; // NOSONAR
|
||||
checkState(true, IGNORE_ME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckState_true_withMessageSupplier() {
|
||||
checkState(true, () -> "Error message: " + LocalDate.now());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckState_true_withNullMessageSupplier() {
|
||||
final Supplier<String> IGNORE_ME = null; // NOSONAR
|
||||
checkState(true, IGNORE_ME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckState_true_withMessageFormat() {
|
||||
LocalDate today = LocalDate.now();
|
||||
checkState(true, "String format: %s", today);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckState_true_withNullMessageFormat() {
|
||||
checkState(true, null, LocalDate.now());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckState_false() {
|
||||
final IllegalStateException e = assertThrows(IllegalStateException.class,
|
||||
() -> checkState(false));
|
||||
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckState_false_withMessage() {
|
||||
final String message = "testCheckState_false_withMessage";
|
||||
|
||||
final IllegalStateException e = assertThrows(IllegalStateException.class,
|
||||
() -> checkState(false, message));
|
||||
|
||||
assertEquals(message, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckState_false_withNullMessage() {
|
||||
final String message = null;
|
||||
|
||||
final IllegalStateException e = assertThrows(IllegalStateException.class,
|
||||
() -> checkState(false, message));
|
||||
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckState_false_withMessageSupplier() {
|
||||
final LocalDate today = LocalDate.now();
|
||||
final IllegalStateException e = assertThrows(IllegalStateException.class,
|
||||
() -> checkState(false, () -> "Error message: " + today));
|
||||
|
||||
assertEquals("Error message: " + today, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckState_false_withNullMessageSupplier() {
|
||||
Supplier<String> messageSupplier = null;
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> checkState(false, messageSupplier));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckState_false_withMessageFormat() {
|
||||
LocalDate today = LocalDate.now();
|
||||
final IllegalStateException e = assertThrows(IllegalStateException.class,
|
||||
() -> checkState(false, "String format: %s", today));
|
||||
assertEquals(String.format("String format: %s", today), e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckState_false_withNullMessageFormat() {
|
||||
LocalDate today = LocalDate.now();
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> checkState(false, null, today));
|
||||
}
|
||||
|
||||
// #endregion - State
|
||||
|
||||
// #region - NotNull
|
||||
|
||||
@Test
|
||||
void testCheckNotNull_notNull() {
|
||||
final Object object = new Object();
|
||||
checkNotNull(object);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckNotNull_notNull_withMessage() {
|
||||
final Object object = new Object();
|
||||
final String IGNORE_ME = "IGNORE_ME"; // NOSONAR
|
||||
checkNotNull(object, IGNORE_ME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckNotNull_notNull_withNullMessage() {
|
||||
final Object object = new Object();
|
||||
final String IGNORE_ME = null; // NOSONAR
|
||||
checkNotNull(object, IGNORE_ME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckNotNull_notNull_withMessageSupplier() {
|
||||
final Object object = new Object();
|
||||
checkNotNull(object, () -> "Error message: " + LocalDate.now());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckNotNull_notNull_withNullMessageSupplier() {
|
||||
final Object object = new Object();
|
||||
final Supplier<String> IGNORE_ME = null; // NOSONAR
|
||||
checkNotNull(object, IGNORE_ME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckNotNull_notNull_withMessageFormat() {
|
||||
final Object object = new Object();
|
||||
LocalDate today = LocalDate.now();
|
||||
checkNotNull(object, "String format: %s", today);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckNotNull_notNull_withNullMessageFormat() {
|
||||
final Object object = new Object();
|
||||
checkNotNull(object, null, LocalDate.now());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckNotNull_null() {
|
||||
final Object object = null;
|
||||
final NullPointerException e = assertThrows(NullPointerException.class,
|
||||
() -> checkNotNull(object));
|
||||
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckNotNull_null_withMessage() {
|
||||
final Object object = null;
|
||||
final String message = "testCheckNotNull_null_withMessage";
|
||||
|
||||
final NullPointerException e = assertThrows(NullPointerException.class,
|
||||
() -> checkNotNull(object, message));
|
||||
|
||||
assertEquals(message, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckNotNull_null_withNullMessage() {
|
||||
final Object object = null;
|
||||
final String message = null;
|
||||
|
||||
final NullPointerException e = assertThrows(NullPointerException.class,
|
||||
() -> checkNotNull(object, message));
|
||||
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckNotNull_null_withMessageSupplier() {
|
||||
final Object object = null;
|
||||
final LocalDate today = LocalDate.now();
|
||||
final NullPointerException e = assertThrows(NullPointerException.class,
|
||||
() -> checkNotNull(object, () -> "Error message: " + today));
|
||||
|
||||
assertEquals("Error message: " + today, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckNotNull_null_withNullMessageSupplier() {
|
||||
final Object object = null;
|
||||
Supplier<String> messageSupplier = null;
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> checkNotNull(object, messageSupplier));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckNotNull_null_withMessageFormat() {
|
||||
final Object object = null;
|
||||
LocalDate today = LocalDate.now();
|
||||
final NullPointerException e = assertThrows(NullPointerException.class,
|
||||
() -> checkNotNull(object, "String format: %s", today));
|
||||
assertEquals(String.format("String format: %s", today), e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckNotNull_null_withNullMessageFormat() {
|
||||
final Object object = null;
|
||||
LocalDate today = LocalDate.now();
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> checkNotNull(object, null, today));
|
||||
}
|
||||
|
||||
// #endregion - NotNull
|
||||
|
||||
// #region - Condition
|
||||
|
||||
static final class MyException extends RuntimeException {}
|
||||
|
||||
@Test
|
||||
void testCheckCondition() {
|
||||
|
||||
checkCondition(true, MyException::new);
|
||||
|
||||
final MyException me = new MyException();
|
||||
MyException e = assertThrows(MyException.class, () -> checkCondition(false, () -> me));
|
||||
assertEquals(me, e);
|
||||
}
|
||||
|
||||
// #endregion - Condition
|
||||
|
||||
// ================================
|
||||
// #region - invoke constructor
|
||||
// ================================
|
||||
|
||||
@Test
|
||||
void test_constructor_isNotAccessible_ThrowsIllegalStateException() {
|
||||
Constructor<?>[] constructors = AssertTools.class.getDeclaredConstructors();
|
||||
Arrays.stream(constructors)
|
||||
.forEach(constructor -> {
|
||||
assertFalse(constructor.isAccessible());
|
||||
constructor.setAccessible(true);
|
||||
Throwable cause = assertThrows(Exception.class, constructor::newInstance)
|
||||
.getCause();
|
||||
assertInstanceOf(IllegalStateException.class, cause);
|
||||
assertEquals("Utility class", cause.getMessage());
|
||||
});
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion - invoke constructor
|
||||
// ================================
|
||||
}
|
||||
Reference in New Issue
Block a user