@@ -0,0 +1,16 @@
|
||||
# Module `devkit-utils`
|
||||
|
||||
## Introduction
|
||||
|
||||
This module provides a set of utilities to streamline Java codes.
|
||||
|
||||
## Features
|
||||
|
||||
- AES encryption and decryption;
|
||||
- Base64 encode and decode;
|
||||
- Boolean calculation;
|
||||
- Reduce `if...else...` with **lambdas**;
|
||||
- Hash calculation for strings;
|
||||
- Convert Java beans to map and map to Java beans;
|
||||
- Simplified range generator.
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 OnixByte.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
import java.net.URI
|
||||
|
||||
plugins {
|
||||
java
|
||||
id("java-library")
|
||||
id("maven-publish")
|
||||
id("signing")
|
||||
}
|
||||
|
||||
val artefactVersion: String by project
|
||||
val projectUrl: String by project
|
||||
val projectGithubUrl: String by project
|
||||
val licenseName: String by project
|
||||
val licenseUrl: String by project
|
||||
|
||||
group = "com.onixbyte"
|
||||
version = artefactVersion
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
tasks.withType<Jar> {
|
||||
exclude("logback.xml")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.slf4j)
|
||||
implementation(libs.logback)
|
||||
testImplementation(platform(libs.junit.bom))
|
||||
testImplementation(libs.junit.jupiter)
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("commonToolbox") {
|
||||
groupId = group.toString()
|
||||
artifactId = "common-toolbox"
|
||||
version = artefactVersion
|
||||
|
||||
pom {
|
||||
name = "OnixByte Common Toolbox"
|
||||
description = "The utils module of OnixByte toolbox."
|
||||
url = projectUrl
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name = licenseName
|
||||
url = licenseUrl
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
connection = "scm:git:git://github.com:OnixByte/JDevKit.git"
|
||||
developerConnection = "scm:git:git://github.com:OnixByte/JDevKit.git"
|
||||
url = projectGithubUrl
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id = "zihluwang"
|
||||
name = "Zihlu Wang"
|
||||
email = "really@zihlu.wang"
|
||||
timezone = "Asia/Hong_Kong"
|
||||
}
|
||||
|
||||
developer {
|
||||
id = "siujamo"
|
||||
name = "Siu Jam'o"
|
||||
email = "jamo.siu@outlook.com"
|
||||
timezone = "Asia/Shanghai"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
from(components["java"])
|
||||
|
||||
signing {
|
||||
sign(publishing.publications["commonToolbox"])
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
name = "sonatypeNexus"
|
||||
url = URI(providers.gradleProperty("repo.maven-central.host").get())
|
||||
credentials {
|
||||
username = providers.gradleProperty("repo.maven-central.username").get()
|
||||
password = providers.gradleProperty("repo.maven-central.password").get()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 OnixByte.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.onixbyte.devkit.utils;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Base64;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* The {@link AesUtil} class provides utility methods for encrypting and decrypting data using the
|
||||
* AES algorithm. This class supports both byte array and string data, and uses a specified secret
|
||||
* key for encryption and decryption.
|
||||
* <p>
|
||||
* The utility methods in this class are useful for scenarios where data needs to be securely
|
||||
* encrypted and decrypted.
|
||||
* </p>
|
||||
*
|
||||
* <p><b>Example usage:</b></p>
|
||||
* <pre>{@code
|
||||
* // Encrypting and decrypting byte array data
|
||||
* byte[] secretKey = "43f72073956d4c81".getBytes(StandardCharsets.UTF_8);
|
||||
* byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8);
|
||||
* byte[] encryptedData = AesUtil.encrypt(data, secretKey);
|
||||
* byte[] decryptedData = AesUtil.decrypt(encryptedData, secretKey);
|
||||
* System.out.println(new String(decryptedData, StandardCharsets.UTF_8)); // Output: Hello World
|
||||
*
|
||||
* // Encrypting and decrypting string data
|
||||
* String secret = "43f72073956d4c81";
|
||||
* String encryptedString = AesUtil.encrypt("Hello World", secret);
|
||||
* String decryptedString = AesUtil.decrypt(encryptedString, secret);
|
||||
* System.out.println(decryptedString); // Output: Hello World
|
||||
*
|
||||
* // Generating a random secret key
|
||||
* String randomSecret = AesUtil.generateRandomSecret();
|
||||
* System.out.println(randomSecret); // Output: A randomly generated 16-character long secret
|
||||
* }</pre>
|
||||
*
|
||||
* @author hubin@baomidou
|
||||
* @version 1.1.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public final class AesUtil {
|
||||
|
||||
/**
|
||||
* Encrypts the specified data using the AES algorithm with the provided secret key.
|
||||
*
|
||||
* @param data the data to be encrypted
|
||||
* @param secret the secret key used for encryption
|
||||
* @return the encrypted data as a byte array
|
||||
* @throws GeneralSecurityException if any cryptographic error occurs during encryption
|
||||
*/
|
||||
public static byte[] encrypt(byte[] data, byte[] secret) throws GeneralSecurityException {
|
||||
var secretKeySpec = new SecretKeySpec(new SecretKeySpec(secret, AES).getEncoded(), AES);
|
||||
var cipher = Cipher.getInstance(AES_CBC_CIPHER);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(secret));
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts the specified data using the AES algorithm with the provided secret key.
|
||||
*
|
||||
* @param data the data to be decrypted
|
||||
* @param secret the secret key used for decryption
|
||||
* @return the decrypted data as a byte array
|
||||
* @throws GeneralSecurityException if any cryptographic error occurs during decryption
|
||||
*/
|
||||
public static byte[] decrypt(byte[] data, byte[] secret) throws GeneralSecurityException {
|
||||
var secretKeySpec = new SecretKeySpec(new SecretKeySpec(secret, AES).getEncoded(), AES);
|
||||
var cipher = Cipher.getInstance(AES_CBC_CIPHER);
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(secret));
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts the specified string data using the AES algorithm with the provided secret key.
|
||||
*
|
||||
* @param data the string data to be encrypted
|
||||
* @param secret the secret key used for encryption
|
||||
* @return the encrypted data encoded in Base64
|
||||
* @throws GeneralSecurityException if any cryptographic error occurs during encryption
|
||||
*/
|
||||
public static String encrypt(String data, String secret) throws GeneralSecurityException {
|
||||
return Base64.getEncoder().encodeToString(encrypt(data.getBytes(StandardCharsets.UTF_8),
|
||||
secret.getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts the specified Base64-encoded string data using the AES algorithm with the provided secret key.
|
||||
*
|
||||
* @param data the Base64-encoded string data to be decrypted
|
||||
* @param secret the secret key used for decryption
|
||||
* @return the decrypted string data
|
||||
* @throws GeneralSecurityException if any cryptographic error occurs during decryption
|
||||
*/
|
||||
public static String decrypt(String data, String secret) throws GeneralSecurityException {
|
||||
var decrypted = decrypt(Base64.getDecoder().decode(data.getBytes(StandardCharsets.UTF_8)),
|
||||
secret.getBytes(StandardCharsets.UTF_8));
|
||||
return new String(decrypted, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates 16-character random secret.
|
||||
*
|
||||
* @return the generated secure secret
|
||||
*/
|
||||
public static String generateRandomSecret() {
|
||||
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor to prevent instantiation of this utility class.
|
||||
*/
|
||||
private AesUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The algorithm AES.
|
||||
*/
|
||||
private static final String AES = "AES";
|
||||
|
||||
/**
|
||||
* The algorithm AES/CBC/PKCS5Padding.
|
||||
*/
|
||||
private static final String AES_CBC_CIPHER = "AES/CBC/PKCS5Padding";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 OnixByte.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.onixbyte.devkit.utils;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The {@link Base64Util} class provides static methods to encode and decode strings with Base64
|
||||
* encoding. It utilizes the {@link Base64} class from the Java standard library for performing the
|
||||
* encoding and decoding operations. This utility class offers convenient methods to encode and
|
||||
* decode strings with different character sets.
|
||||
* <p>
|
||||
* This class is designed as a final class with a private constructor to prevent instantiation.
|
||||
* All methods in this class are static, allowing easy access to the Base64 encoding and
|
||||
* decoding functionality.
|
||||
* <p>
|
||||
* Example usage:
|
||||
* <pre>
|
||||
* String original = "Hello, World!";
|
||||
*
|
||||
* // Encode the string using UTF-8 charset
|
||||
* String encoded = Base64Util.encode(original);
|
||||
* System.out.println("Encoded string: " + encoded);
|
||||
*
|
||||
* // Decode the encoded string using UTF-8 charset
|
||||
* String decoded = Base64Util.decode(encoded);
|
||||
* System.out.println("Decoded string: " + decoded);
|
||||
* </pre>
|
||||
* <p>
|
||||
* <b>Note:</b> This utility class uses the default charset (UTF-8) if no specific charset is
|
||||
* provided. It is recommended to specify the charset explicitly to ensure consistent
|
||||
* encoding and decoding.
|
||||
*
|
||||
* @author zihluwang
|
||||
* @version 1.1.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public final class Base64Util {
|
||||
|
||||
/**
|
||||
* Ensure that there is only one Base64 Encoder.
|
||||
*
|
||||
* @return the {@link Base64.Encoder} instance
|
||||
*/
|
||||
private static Base64.Encoder getEncoder() {
|
||||
if (Objects.isNull(encoder)) {
|
||||
encoder = Base64.getEncoder();
|
||||
}
|
||||
return encoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that there is only one Base64 Encoder.
|
||||
*
|
||||
* @return the {@link Base64.Encoder} instance
|
||||
*/
|
||||
private static Base64.Decoder getDecoder() {
|
||||
if (Objects.isNull(decoder)) {
|
||||
decoder = Base64.getDecoder();
|
||||
}
|
||||
return decoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that there is only one Base64 URL Encoder.
|
||||
*
|
||||
* @return the {@link Base64.Encoder} instance
|
||||
*/
|
||||
private static Base64.Encoder getUrlEncoder() {
|
||||
if (Objects.isNull(urlEncoder)) {
|
||||
urlEncoder = Base64.getUrlEncoder();
|
||||
}
|
||||
return urlEncoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that there is only one Base64 URL Decoder.
|
||||
*
|
||||
* @return the {@link Base64.Encoder} instance
|
||||
*/
|
||||
public static Base64.Decoder getUrlDecoder() {
|
||||
if (Objects.isNull(urlDecoder)) {
|
||||
urlDecoder = Base64.getUrlDecoder();
|
||||
}
|
||||
return urlDecoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor to prevent instantiation of this utility class.
|
||||
*/
|
||||
private Base64Util() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given string using the specified charset.
|
||||
*
|
||||
* @param value the string to be encoded
|
||||
* @param charset the charset to be used for encoding
|
||||
* @return the Base64 encoded string
|
||||
*/
|
||||
public static String encode(String value, Charset charset) {
|
||||
var encoded = getEncoder().encode(value.getBytes(charset));
|
||||
|
||||
return new String(encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given string using the default UTF-8 charset.
|
||||
*
|
||||
* @param value the string to be encoded
|
||||
* @return the Base64 encoded string
|
||||
*/
|
||||
public static String encode(String value) {
|
||||
return encode(value, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the given Base64 encoded string using the specified charset.
|
||||
*
|
||||
* @param value the Base64 encoded string to be decoded
|
||||
* @param charset the charset to be used for decoding
|
||||
* @return the decoded string
|
||||
*/
|
||||
public static String decode(String value, Charset charset) {
|
||||
var decoded = getDecoder().decode(value.getBytes(charset));
|
||||
|
||||
return new String(decoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the given Base64 encoded string using the default UTF-8 charset.
|
||||
*
|
||||
* @param value the Base64 encoded string to be decoded
|
||||
* @return the decoded string
|
||||
*/
|
||||
public static String decode(String value) {
|
||||
return decode(value, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given string using the specified charset.
|
||||
*
|
||||
* @param value the string to be encoded
|
||||
* @param charset the charset to be used for encoding
|
||||
* @return the Base64 encoded string
|
||||
*/
|
||||
public static String encodeUrlComponents(String value, Charset charset) {
|
||||
var encoded = getUrlEncoder().encode(value.getBytes(charset));
|
||||
|
||||
return new String(encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given string using the default UTF-8 charset.
|
||||
*
|
||||
* @param value the string to be encoded
|
||||
* @return the Base64 encoded string
|
||||
*/
|
||||
public static String encodeUrlComponents(String value) {
|
||||
return encodeUrlComponents(value, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the given Base64 encoded string using the specified charset.
|
||||
*
|
||||
* @param value the Base64 encoded string to be decoded
|
||||
* @param charset the charset to be used for decoding
|
||||
* @return the decoded string
|
||||
*/
|
||||
public static String decodeUrlComponents(String value, Charset charset) {
|
||||
var decoded = getUrlDecoder().decode(value.getBytes(charset));
|
||||
|
||||
return new String(decoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the given Base64 encoded string using the default UTF-8 charset.
|
||||
*
|
||||
* @param value the Base64 encoded string to be decoded
|
||||
* @return the decoded string
|
||||
*/
|
||||
public static String decodeUrlComponents(String value) {
|
||||
return decodeUrlComponents(value, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static Base64.Encoder encoder;
|
||||
|
||||
private static Base64.Decoder decoder;
|
||||
|
||||
private static Base64.Encoder urlEncoder;
|
||||
|
||||
private static Base64.Decoder urlDecoder;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 OnixByte.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.onixbyte.devkit.utils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
/**
|
||||
* The {@link BoolUtil} class provides utility methods for boolean calculations.
|
||||
* This class offers methods to perform logical operations such as AND, OR, and NOT on boolean values.
|
||||
* <p>
|
||||
* The utility methods in this class are useful for scenarios where multiple boolean values need to be
|
||||
* evaluated together, and for simplifying complex boolean expressions.
|
||||
* </p>
|
||||
*
|
||||
* <p><b>Example usage:</b></p>
|
||||
* <pre>
|
||||
* {@code
|
||||
* boolean result1 = BoolUtil.and(true, true, false); // false
|
||||
* boolean result2 = BoolUtil.or(true, false, false); // true
|
||||
* boolean result3 = BoolUtil.not(false); // true
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author zihluwang
|
||||
* @version 1.6.2
|
||||
* @since 1.6.2
|
||||
*/
|
||||
public final class BoolUtil {
|
||||
|
||||
/**
|
||||
* Logical and calculation.
|
||||
*
|
||||
* @param values the values to be calculated
|
||||
* @return {@code true} if all value in values is {@code true}, otherwise {@code false}
|
||||
*/
|
||||
public static boolean and(Boolean... values) {
|
||||
return Arrays.stream(values)
|
||||
.filter(Objects::nonNull)
|
||||
.allMatch(Boolean::booleanValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical and calculation.
|
||||
*
|
||||
* @param valueSuppliers the suppliers of value to be calculated
|
||||
* @return {@code true} if all value in values is {@code true}, otherwise {@code false}
|
||||
*/
|
||||
public static boolean and(BooleanSupplier... valueSuppliers) {
|
||||
return Arrays.stream(valueSuppliers)
|
||||
.filter(Objects::nonNull)
|
||||
.allMatch(BooleanSupplier::getAsBoolean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical or calculation.
|
||||
*
|
||||
* @param values the values to be calculated
|
||||
* @return {@code true} if any value in values is {@code true}, otherwise {@code false}
|
||||
*/
|
||||
public static boolean or(Boolean... values) {
|
||||
return Arrays.stream(values)
|
||||
.filter(Objects::nonNull)
|
||||
.anyMatch(Boolean::booleanValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical or calculation.
|
||||
*
|
||||
* @param valueSuppliers the suppliers of value to be calculated
|
||||
* @return {@code true} if any value in values is {@code true}, otherwise {@code false}
|
||||
*/
|
||||
public static boolean or(BooleanSupplier... valueSuppliers) {
|
||||
return Arrays.stream(valueSuppliers)
|
||||
.filter(Objects::nonNull)
|
||||
.anyMatch(BooleanSupplier::getAsBoolean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor to prevent instantiation of this utility class.
|
||||
*/
|
||||
private BoolUtil() {}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 OnixByte.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.onixbyte.devkit.utils;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* The {@link BranchUtil} class provides static methods to simplify conditional logic in Java
|
||||
* development by leveraging lambda expressions. It offers convenient methods to replace verbose
|
||||
* {@code if...else} statements with more concise and expressive functional constructs.
|
||||
* <p>
|
||||
* Developers can use methods in this utility class to streamline their code, enhance readability,
|
||||
* and promote a more functional style of programming when dealing with branching logic and
|
||||
* conditional statements.
|
||||
* <p>
|
||||
* <b>Example:</b>
|
||||
* <pre>
|
||||
* // If you want to simplify an if (exp1 || exp2), you can use the following code:
|
||||
* String r1 = BranchUtil.or(1 == 1, 2 == 1)
|
||||
* .handle(() -> "1 is equal to 1 or 2 is equal to 1.");
|
||||
*
|
||||
* // If you have an else branch, you can use the following code:
|
||||
* String r2 = BranchUtil.or(1 == 1, 2 == 1)
|
||||
* .handle(() -> "1 is equal to 1 or 2 is equal to 1.",
|
||||
* () -> "1 is not equal to 1 and 2 is not equal to 1.");
|
||||
*
|
||||
* // If you only need to execute code without a return value:
|
||||
* BranchUtil.or(1 == 1, 2 == 1)
|
||||
* .handle(() -> {
|
||||
* // do something
|
||||
* }, () -> {
|
||||
* // do something
|
||||
* });
|
||||
* // If you only need an if branch, you can remove the second Supplier instance.
|
||||
*
|
||||
* // To check if all boolean expressions are true, use the 'and' method:
|
||||
* BranchUtil.and(1 == 1, 2 == 1)
|
||||
* .handle(() -> {
|
||||
* // do something
|
||||
* }, () -> {
|
||||
* // do something
|
||||
* });
|
||||
* </pre>
|
||||
* <p>
|
||||
* <b>Note:</b>
|
||||
* The {@link #and(Boolean...)} and {@link #or(Boolean...)} methods accept any number of boolean
|
||||
* expressions.
|
||||
*
|
||||
* @author zihluwang
|
||||
* @version 2.1.3
|
||||
* @see java.util.function.Supplier
|
||||
* @see java.util.function.BooleanSupplier
|
||||
* @see java.lang.Runnable
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public final class BranchUtil {
|
||||
|
||||
/**
|
||||
* The final result of the boolean expression.
|
||||
*/
|
||||
private final boolean result;
|
||||
|
||||
/**
|
||||
* Create a {@code BranchUtil} instance.
|
||||
*
|
||||
* @param result the result of the boolean expressions.
|
||||
*/
|
||||
private BranchUtil(boolean result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code BranchUtil} instance to evaluate a logical OR operation on the provided
|
||||
* boolean expressions.
|
||||
*
|
||||
* @param values the boolean expressions to be evaluated
|
||||
* @return a {@code BranchUtil} instance representing the result of the logical OR operation
|
||||
*/
|
||||
public static BranchUtil or(Boolean... values) {
|
||||
return new BranchUtil(BoolUtil.or(values));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code BranchUtil} instance to evaluate a logical AND operation on the provided
|
||||
* boolean expressions.
|
||||
*
|
||||
* @param values the boolean expressions to be evaluated
|
||||
* @return a {@code BranchUtil} instance representing the result of the logical AND operation
|
||||
*/
|
||||
public static BranchUtil and(Boolean... values) {
|
||||
return new BranchUtil(BoolUtil.and(values));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code BranchUtil} instance to evaluate a logical OR operation on the provided
|
||||
* boolean suppliers.
|
||||
*
|
||||
* @param valueSuppliers the boolean suppliers to be evaluated
|
||||
* @return a {@code BranchUtil} instance representing the result of the
|
||||
* logical OR operation
|
||||
*/
|
||||
public static BranchUtil or(BooleanSupplier... valueSuppliers) {
|
||||
return new BranchUtil(BoolUtil.or(valueSuppliers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code BranchUtil} instance to evaluate a logical AND operation on the provided
|
||||
* boolean suppliers.
|
||||
*
|
||||
* @param valueSuppliers the boolean suppliers to be evaluated
|
||||
* @return a {@code BranchUtil} instance representing the result of the
|
||||
* logical AND operation
|
||||
*/
|
||||
public static BranchUtil and(BooleanSupplier... valueSuppliers) {
|
||||
return new BranchUtil(BoolUtil.and(valueSuppliers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the result of the boolean expressions by executing the appropriate handler based
|
||||
* on the result.
|
||||
* <p>
|
||||
* If the result is {@code true}, the {@code trueSupplier} is executed. If the result is
|
||||
* {@code false} and an {@code falseSupplier} is provided, it is executed.
|
||||
* <p>
|
||||
* Returns the result of the executed supplier.
|
||||
*
|
||||
* @param <T> the type of the result to be handled by the methods
|
||||
* @param trueSupplier the supplier to be executed if the result is {@code true}
|
||||
* @param falseSupplier the supplier to be executed if the result is {@code false} (optional)
|
||||
* @return the result of the executed supplier, or {@code null} if no {@code falseSupplier} is
|
||||
* provided and the result of the evaluation is {@code false}
|
||||
*/
|
||||
public <T> T thenSupply(Supplier<T> trueSupplier, Supplier<T> falseSupplier) {
|
||||
if (this.result && Objects.nonNull(trueSupplier)) {
|
||||
return trueSupplier.get();
|
||||
}
|
||||
|
||||
if (Objects.isNull(falseSupplier)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return falseSupplier.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the result of the boolean expressions by executing the provided handler if the
|
||||
* result is {@code true}.
|
||||
* <p>
|
||||
* Returns the result of the executed handler.
|
||||
*
|
||||
* @param <T> the type of the result to be handled by the methods
|
||||
* @param trueSupplier the supplier to be executed if the result is {@code true}
|
||||
* @return the result of the executed handler, or {@code null} if result of evaluation is {@code false}
|
||||
*/
|
||||
public <T> T thenSupply(Supplier<T> trueSupplier) {
|
||||
return thenSupply(trueSupplier, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the result of the boolean expressions by executing the appropriate handler based
|
||||
* on the result.
|
||||
* <p>
|
||||
* If the result is {@code true}, the {@code ifHandler} is executed. If the result is
|
||||
* {@code false} and an {@code elseHandler} is provided, it is executed.
|
||||
*
|
||||
* @param trueHandler the handler to be executed if the result is {@code true}
|
||||
* @param falseHandler the handler to be executed if the result is {@code false} (optional)
|
||||
*/
|
||||
public void then(Runnable trueHandler, Runnable falseHandler) {
|
||||
if (this.result && Objects.nonNull(trueHandler)) {
|
||||
trueHandler.run();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Objects.isNull(falseHandler)) {
|
||||
return;
|
||||
}
|
||||
|
||||
falseHandler.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the result of the boolean expressions by executing the provided handler if the
|
||||
* result is {@code true}.
|
||||
*
|
||||
* @param trueHandler the handler to be executed if the result is {@code true}
|
||||
*/
|
||||
public void then(Runnable trueHandler) {
|
||||
then(trueHandler, null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 OnixByte.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.onixbyte.devkit.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A utility class providing static methods for manipulating collections.
|
||||
*
|
||||
* @author zihluwang
|
||||
*/
|
||||
public final class CollectionUtil {
|
||||
|
||||
/**
|
||||
* Private constructor to prevent instantiation of this utility class.
|
||||
*/
|
||||
private CollectionUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits a collection into a list of sub-collections, each with a maximum size specified by
|
||||
* the caller.
|
||||
* <p>
|
||||
* This method takes an original collection and divides it into smaller sub-collections,
|
||||
* ensuring that each sub-collection contains no more than the specified maximum size. If the
|
||||
* original collection's size is less than or equal to the maximum size, it is returned as a
|
||||
* single sub-collection. The sub-collections are created using the provided collection factory.
|
||||
*
|
||||
* @param <T> the type of elements in the collection
|
||||
* @param <C> the type of the collection, which must extend {@link Collection}
|
||||
* @param originalCollection the collection to be split into sub-collections
|
||||
* @param maxSize the maximum number of elements allowed in each sub-collection
|
||||
* @param collectionFactory a supplier that creates new instances of the sub-collection type
|
||||
* @return a list of sub-collections, each containing up to {@code maxSize} elements
|
||||
* @throws IllegalArgumentException if {@code originalCollection} is {@code null},
|
||||
* {@code maxSize} is less than zero, or
|
||||
* {@code collectionFactory} is {@code null}
|
||||
*/
|
||||
public static <T, C extends Collection<T>> List<C> chunk(C originalCollection,
|
||||
int maxSize,
|
||||
Supplier<C> collectionFactory) {
|
||||
// check inputs
|
||||
if (Objects.isNull(originalCollection)) {
|
||||
throw new IllegalArgumentException("Collection must not be null.");
|
||||
}
|
||||
|
||||
if (maxSize <= 0) {
|
||||
throw new IllegalArgumentException("maxSize must greater than 0.");
|
||||
}
|
||||
|
||||
if (Objects.isNull(collectionFactory)) {
|
||||
throw new IllegalArgumentException("Factory method cannot be null.");
|
||||
}
|
||||
|
||||
var result = new ArrayList<C>();
|
||||
var size = originalCollection.size();
|
||||
|
||||
// if original collection is empty or the size less than maxSize, return it as a single
|
||||
// sub collection
|
||||
if (size <= maxSize) {
|
||||
var singleCollection = collectionFactory.get();
|
||||
singleCollection.addAll(originalCollection);
|
||||
result.add(singleCollection);
|
||||
return result;
|
||||
}
|
||||
|
||||
// use iterator to split the given collection
|
||||
var iter = originalCollection.iterator();
|
||||
var count = 0;
|
||||
var currentSubCollection = collectionFactory.get();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
var element = iter.next();
|
||||
currentSubCollection.add(element);
|
||||
count++;
|
||||
|
||||
// add sub collection to result when current sub collection reached maxSize or
|
||||
// collection traverse is completed
|
||||
if (count % maxSize == 0 || !iter.hasNext()) {
|
||||
result.add(currentSubCollection);
|
||||
currentSubCollection = collectionFactory.get();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 OnixByte.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.onixbyte.devkit.utils;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* The {@code HashUtil} class provides convenient methods for calculating various hash functions on
|
||||
* strings, including MD2, MD5, SHA-1, SHA-224, SHA-256, SHA-384, and SHA-512. It allows developers
|
||||
* to easily obtain the hash value of a given string using different algorithms.
|
||||
* <p>
|
||||
* Example usage:
|
||||
* <pre>
|
||||
* // Perform MD2 hash operation
|
||||
* String md2Hash = HashUtil.md2("someString");
|
||||
*
|
||||
* // Perform MD5 hash operation
|
||||
* String md5Hash = HashUtil.md5("someString");
|
||||
*
|
||||
* // Perform SHA-1 hash operation
|
||||
* String sha1Hash = HashUtil.sha1("someString");
|
||||
*
|
||||
* // Perform SHA-224 hash operation
|
||||
* String sha224Hash = HashUtil.sha224("someString");
|
||||
*
|
||||
* // Perform SHA-256 hash operation
|
||||
* String sha256Hash = HashUtil.sha256("someString");
|
||||
*
|
||||
* // Perform SHA-384 hash operation
|
||||
* String sha384Hash = HashUtil.sha384("someString");
|
||||
*
|
||||
* // Perform SHA-512 hash operation
|
||||
* String sha512Hash = HashUtil.sha512("someString");
|
||||
* </pre>
|
||||
* The above examples demonstrate how to use the {@code HashUtil} class to calculate hash values
|
||||
* for a given string using different algorithms.
|
||||
* <p>
|
||||
* The hash functions provided by the {@link HashUtil} are one-way hash functions, meaning the
|
||||
* original data cannot be retrieved from the hash value. These hash functions are commonly used
|
||||
* for data integrity checks and password storage, but they should not be used for
|
||||
* encryption purposes.
|
||||
*
|
||||
* @author zihluwang
|
||||
* @version 1.1.0
|
||||
* @see java.security.MessageDigest
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public final class HashUtil {
|
||||
|
||||
/**
|
||||
* Calculates the MD2 hash value of the specified string using the given charset.
|
||||
*
|
||||
* @param value the string to calculate with the MD2 algorithm
|
||||
* @param charset the charset to use for encoding the string (default is UTF-8 if null)
|
||||
* @return the MD2 hash value as a hexadecimal string
|
||||
*/
|
||||
public static String md2(String value, Charset charset) {
|
||||
charset = Optional.ofNullable(charset).orElse(StandardCharsets.UTF_8);
|
||||
return hash("MD2", value, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the MD2 hash value of the specified string using the UTF-8 charset.
|
||||
*
|
||||
* @param value the string to calculate with the MD2 algorithm
|
||||
* @return the MD2 hash value as a hexadecimal string
|
||||
*/
|
||||
public static String md2(String value) {
|
||||
return hash("MD2", value, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the MD5 hash value of the specified string using the given charset.
|
||||
*
|
||||
* @param value the string to calculate with the MD5 algorithm
|
||||
* @param charset the charset to use for encoding the string (default is UTF-8 if null)
|
||||
* @return the MD5 hash value as a hexadecimal string
|
||||
*/
|
||||
public static String md5(String value, Charset charset) {
|
||||
charset = Optional.ofNullable(charset).orElse(StandardCharsets.UTF_8);
|
||||
return hash("MD5", value, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the MD5 hash value of the specified string using the UTF-8 charset.
|
||||
*
|
||||
* @param value the string to calculate with the MD5 algorithm
|
||||
* @return the MD5 hash value as a hexadecimal string
|
||||
*/
|
||||
public static String md5(String value) {
|
||||
return hash("MD5", value, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-1 hash value of the specified string using the given charset.
|
||||
*
|
||||
* @param value the string to calculate with the SHA-1 algorithm
|
||||
* @param charset the charset to use for encoding the string (default is UTF-8 if null)
|
||||
* @return the SHA-1 hash value as a hexadecimal string
|
||||
*/
|
||||
public static String sha1(String value, Charset charset) {
|
||||
charset = Optional.ofNullable(charset).orElse(StandardCharsets.UTF_8);
|
||||
return hash("SHA-1", value, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-1 hash value of the specified string using the UTF-8 charset.
|
||||
*
|
||||
* @param value the string to calculate with the SHA-1 algorithm
|
||||
* @return the SHA-1 hash value as a hexadecimal string
|
||||
*/
|
||||
public static String sha1(String value) {
|
||||
return hash("SHA-1", value, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-224 hash value of the specified string using the given charset.
|
||||
*
|
||||
* @param value the string to calculate with the SHA-225 algorithm
|
||||
* @param charset the charset to use for encoding the string (default is UTF-8 if null)
|
||||
* @return the SHA-224 hash value as a hexadecimal string
|
||||
*/
|
||||
public static String sha224(String value, Charset charset) {
|
||||
charset = Optional.ofNullable(charset).orElse(StandardCharsets.UTF_8);
|
||||
return hash("SHA-224", value, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-224 hash value of the specified string using the
|
||||
* UTF-8 charset.
|
||||
*
|
||||
* @param value the string to calculate with the SHA-224 algorithm
|
||||
* @return the SHA-224 hash value as a hexadecimal string
|
||||
*/
|
||||
public static String sha224(String value) {
|
||||
return hash("SHA-224", value, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-256 hash value of the specified string using the
|
||||
* given charset.
|
||||
*
|
||||
* @param value the string to calculate with the SHA-256 algorithm
|
||||
* @param charset the charset to use for encoding the string (default is UTF-8 if null)
|
||||
* @return the SHA-256 hash value as a hexadecimal string
|
||||
*/
|
||||
public static String sha256(String value, Charset charset) {
|
||||
charset = Optional.ofNullable(charset).orElse(StandardCharsets.UTF_8);
|
||||
return hash("SHA-256", value, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-256 hash value of the specified string using the UTF-8 charset.
|
||||
*
|
||||
* @param value the string to calculate with the SHA-256 algorithm
|
||||
* @return the SHA-256 hash value as a hexadecimal string
|
||||
*/
|
||||
public static String sha256(String value) {
|
||||
return hash("SHA-256", value, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-384 hash value of the specified string using the given charset.
|
||||
*
|
||||
* @param value the string to calculate with the SHA-384 algorithm
|
||||
* @param charset the charset to use for encoding the string (default is UTF-8 if null)
|
||||
* @return the SHA-384 hash value as a hexadecimal string
|
||||
*/
|
||||
public static String sha384(String value, Charset charset) {
|
||||
charset = Optional.ofNullable(charset).orElse(StandardCharsets.UTF_8);
|
||||
return hash("SHA-384", value, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-384 hash value of the specified string using the UTF-8 charset.
|
||||
*
|
||||
* @param value the string to calculate with the SHA-384 algorithm
|
||||
* @return the SHA-384 hash value as a hexadecimal string
|
||||
*/
|
||||
public static String sha384(String value) {
|
||||
return hash("SHA-384", value, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-512 hash value of the specified string using the given charset.
|
||||
*
|
||||
* @param value the string to calculate with the SHA-512 algorithm
|
||||
* @param charset the charset to use for encoding the string (default is UTF-8 if null)
|
||||
* @return the SHA-512 hash value as a hexadecimal string
|
||||
*/
|
||||
public static String sha512(String value, Charset charset) {
|
||||
charset = Optional.ofNullable(charset).orElse(StandardCharsets.UTF_8);
|
||||
return hash("SHA-512", value, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA-512 hash value of the specified string using the UTF-8 charset.
|
||||
*
|
||||
* @param value the string to calculate with the SHA-512 algorithm
|
||||
* @return the SHA-512 hash value as a hexadecimal string
|
||||
*/
|
||||
public static String sha512(String value) {
|
||||
return hash("SHA-512", value, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor to prevent instantiation of this utility class.
|
||||
*/
|
||||
private HashUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the hash value of the specified string using the specified
|
||||
* algorithm and charset.
|
||||
*
|
||||
* @param method the hash algorithm to use
|
||||
* @param value the string to calculate the hash value for
|
||||
* @param charset the charset to use for encoding the string (default is UTF-8 if null)
|
||||
* @return the hash value as a hexadecimal string, or an empty string if the algorithm is
|
||||
* not available
|
||||
* @throws RuntimeException if an unknown algorithm name is provided (should not occur under
|
||||
* controlled usage)
|
||||
*/
|
||||
private static String hash(String method, String value, Charset charset) {
|
||||
try {
|
||||
var messageDigest = MessageDigest.getInstance(method);
|
||||
messageDigest.update(value.getBytes(charset));
|
||||
var bytes = messageDigest.digest();
|
||||
var builder = new StringBuilder();
|
||||
|
||||
for (var b : bytes) {
|
||||
var str = Integer.toHexString(b & 0xff);
|
||||
if (str.length() == 1) {
|
||||
builder.append(0);
|
||||
}
|
||||
builder.append(str);
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
} catch (NoSuchAlgorithmException ignored) {
|
||||
// This should not occur under controlled usage
|
||||
// Only trusted algorithms are allowed
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 OnixByte.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.onixbyte.devkit.utils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The {@link MapUtil} class provides utility methods for converting between objects and maps.
|
||||
* This class leverages the {@link ObjectMapAdapter} interface to perform the conversions.
|
||||
* <p>
|
||||
* The utility methods in this class are useful for scenarios where objects need to be represented
|
||||
* as maps for serialization, deserialization, or other purposes.
|
||||
* </p>
|
||||
*
|
||||
* <p><b>Example usage:</b></p>
|
||||
* <pre>
|
||||
* {@code
|
||||
* public class User {
|
||||
* private String name;
|
||||
* private int age;
|
||||
*
|
||||
* // getters and setters
|
||||
* }
|
||||
*
|
||||
* public class UserMapAdapter implements ObjectMapAdapter<User> {
|
||||
* @Override
|
||||
* public Map<String, Object> toMap(User user) {
|
||||
* Map<String, Object> map = new HashMap<>();
|
||||
* map.put("name", user.getName());
|
||||
* map.put("age", user.getAge());
|
||||
* return map;
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public User fromMap(Map<String, Object> map) {
|
||||
* User user = new User();
|
||||
* user.setName((String) map.get("name"));
|
||||
* user.setAge((Integer) map.get("age"));
|
||||
* return user;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* public class Example {
|
||||
* public static void main(String[] args) {
|
||||
* User user = new User();
|
||||
* user.setName("John");
|
||||
* user.setAge(30);
|
||||
*
|
||||
* UserMapAdapter adapter = new UserMapAdapter();
|
||||
*
|
||||
* // Convert object to map
|
||||
* Map<String, Object> userMap = MapUtil.objectToMap(user, adapter);
|
||||
* System.out.println(userMap); // Output: {name=John, age=30}
|
||||
*
|
||||
* // Convert map to object
|
||||
* User newUser = MapUtil.mapToObject(userMap, adapter);
|
||||
* System.out.println(newUser.getName()); // Output: John
|
||||
* System.out.println(newUser.getAge()); // Output: 30
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author zihluwang
|
||||
* @version 1.7.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public final class MapUtil {
|
||||
|
||||
/**
|
||||
* Converts an object to a map by mapping the field names to their corresponding values.
|
||||
*
|
||||
* @param <T> the type of the object
|
||||
* @param entity the object to be converted to a map
|
||||
* @param adapter adapts the entity for mapping to a map
|
||||
* @return a map representing the fields and their values of the object
|
||||
*/
|
||||
public static <T> Map<String, Object> objectToMap(T entity, ObjectMapAdapter<T> adapter) {
|
||||
return adapter.toMap(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a map to an object of the specified type by setting the field values using the
|
||||
* map entries.
|
||||
*
|
||||
* @param objectMap the map representing the fields and their values
|
||||
* @param adapter the adapter to execute the setter for the entity
|
||||
* @param <T> the type of the object to be created
|
||||
* @return an object of the specified type with the field values set from the map
|
||||
*/
|
||||
public static <T> T mapToObject(Map<String, Object> objectMap, ObjectMapAdapter<T> adapter) {
|
||||
return adapter.toObject(objectMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor to prevent instantiation of this utility class.
|
||||
*/
|
||||
private MapUtil() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 OnixByte.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.onixbyte.devkit.utils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The {@link ObjectMapAdapter} interface provides methods to convert between objects and maps.
|
||||
* This interface is useful for scenarios where objects need to be represented as maps for
|
||||
* serialization, deserialization, or other purposes.
|
||||
*
|
||||
* <p>Implementations of this interface should provide the logic to convert an object of type
|
||||
* {@code T} to a {@link Map} and vice versa.</p>
|
||||
*
|
||||
* <p><b>Example usage:</b></p>
|
||||
* <pre>
|
||||
* {@code
|
||||
* public class User {
|
||||
* private String name;
|
||||
* private int age;
|
||||
*
|
||||
* // getters and setters
|
||||
* }
|
||||
*
|
||||
* public class UserMapAdapter implements ObjectMapAdapter<User> {
|
||||
* @Override
|
||||
* public Map<String, Object> toMap(User user) {
|
||||
* Map<String, Object> map = new HashMap<>();
|
||||
* map.put("name", user.getName());
|
||||
* map.put("age", user.getAge());
|
||||
* return map;
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public User fromMap(Map<String, Object> map) {
|
||||
* User user = new User();
|
||||
* user.setName((String) map.get("name"));
|
||||
* user.setAge((Integer) map.get("age"));
|
||||
* return user;
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> the type of the object to be converted
|
||||
* @author zihluwang
|
||||
* @version 1.7.0
|
||||
* @since 1.4.2
|
||||
*/
|
||||
public interface ObjectMapAdapter<T> {
|
||||
|
||||
/**
|
||||
* Convert an object to a map.
|
||||
*
|
||||
* @param element the element that will be converted to Map
|
||||
* @return a Map that is converted from the element
|
||||
*/
|
||||
Map<String, Object> toMap(T element);
|
||||
|
||||
/**
|
||||
* Convert a Map to an object.
|
||||
*
|
||||
* @param map the map that will be converted to an object
|
||||
* @return the object that is converted from the Map
|
||||
*/
|
||||
T toObject(Map<String, Object> map);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 OnixByte.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.onixbyte.devkit.utils;
|
||||
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* {@code RangeUtil} is a utility class providing methods for generating streams of integers that
|
||||
* emulate the behaviour of Python's {@code range} function.
|
||||
* <p>
|
||||
* This class offers static methods to create ranges with various configurations. These methods
|
||||
* leverage the {@link IntStream} to provide efficient and versatile integer sequences.
|
||||
*
|
||||
* @author zihluwang
|
||||
* @see IntStream
|
||||
*/
|
||||
public final class RangeUtil {
|
||||
|
||||
/**
|
||||
* Private constructor to prevent instantiation of this utility class.
|
||||
*/
|
||||
private RangeUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a stream of integers starting from {@code 0} up to the specified {@code end} value.
|
||||
* <p>
|
||||
* It creates a sequential, ordered {@code IntStream} that can be used for iteration or
|
||||
* further processing.
|
||||
* <p>
|
||||
* <b>Example Usage:</b>
|
||||
* <pre>{@code
|
||||
* RangeUtil.range(5).forEach(System.out::println);
|
||||
*
|
||||
* // Output:
|
||||
* // 0
|
||||
* // 1
|
||||
* // 2
|
||||
* // 3
|
||||
* // 4
|
||||
* }</pre>
|
||||
*
|
||||
* @param end upper-bound of the range (exclusive)
|
||||
* @return an {@code IntStream} of integers from {@code 0} (inclusive) to
|
||||
* {@code end} (exclusive)
|
||||
* @throws IllegalArgumentException if the given {@code end} value is less equal to 0
|
||||
* @see IntStream
|
||||
*/
|
||||
public static IntStream range(int end) {
|
||||
if (end <= 0) {
|
||||
throw new IllegalArgumentException("Parameter [end] should not be less than or equal to 0, provided: " +
|
||||
end);
|
||||
}
|
||||
return IntStream.range(0, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a stream of integers starting from the specified {@code start} value up to the
|
||||
* specified {@code end} value.
|
||||
* <p>
|
||||
* It creates a sequential, ordered {@code IntStream} that can be used for iteration or
|
||||
* further processing.
|
||||
* <p>
|
||||
* If {@code start} is less than {@code end}, an ascending range (exclusive of {@code end})
|
||||
* is generated. If {@code start} is greater than {@code end}, a descending range (exclusive of {@code end})
|
||||
* is generated. If {@code start} equals {@code end}, an empty stream is returned.
|
||||
* <p>
|
||||
* <b>Example Usage:</b>
|
||||
* <pre>{@code
|
||||
* RangeUtil.range(3, 8).forEach(System.out::println);
|
||||
*
|
||||
* // Output:
|
||||
* // 3
|
||||
* // 4
|
||||
* // 5
|
||||
* // 6
|
||||
* // 7
|
||||
*
|
||||
* RangeUtil.range(8, 3).forEach(System.out::println);
|
||||
*
|
||||
* // Output:
|
||||
* // 8
|
||||
* // 7
|
||||
* // 6
|
||||
* // 5
|
||||
* // 4
|
||||
* }</pre>
|
||||
*
|
||||
* @param start the starting value of the range (inclusive)
|
||||
* @param end upper-bound of the range (exclusive)
|
||||
* @return an {@code IntStream} of integers in ascending or descending order, exclusive of {@code end}
|
||||
* @see IntStream
|
||||
*/
|
||||
public static IntStream range(int start, int end) {
|
||||
if (start == end) {
|
||||
return IntStream.empty();
|
||||
}
|
||||
if (start < end) {
|
||||
return IntStream.range(start, end);
|
||||
} else {
|
||||
// Descending range (exclusive of end)
|
||||
return IntStream.iterate(start, n -> n > end, n -> n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a stream of integers starting from the specified {@code start} value up to the
|
||||
* specified {@code end} value.
|
||||
* <p>
|
||||
* It creates a sequential, ordered {@code IntStream} that can be used for iteration or
|
||||
* further processing.
|
||||
* <p>
|
||||
* The range includes both {@code start} and {@code end}.
|
||||
* <p>
|
||||
* <b>Example Usage:</b>
|
||||
* <pre>{@code
|
||||
* RangeUtil.rangeClosed(3, 8).forEach(System.out::println);
|
||||
*
|
||||
* // Output:
|
||||
* // 3
|
||||
* // 4
|
||||
* // 5
|
||||
* // 6
|
||||
* // 7
|
||||
* // 8
|
||||
* }</pre>
|
||||
*
|
||||
* @param start the starting value of the range (inclusive)
|
||||
* @param end upper-bound of the range (inclusive)
|
||||
* @return an {@code IntStream} of integers from {@code start} to {@code end} inclusive
|
||||
* @see IntStream
|
||||
*/
|
||||
public static IntStream rangeClosed(int start, int end) {
|
||||
return IntStream.rangeClosed(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a stream of integers starting from the specified {@code start} value, incremented by
|
||||
* the specified {@code step}, up to the specified {@code end} value.
|
||||
* <p>
|
||||
* It creates a sequential, ordered {@code IntStream} that can be used for iteration or
|
||||
* further processing.
|
||||
* <p>
|
||||
* The stream excludes the {@code end} value.
|
||||
* <p>
|
||||
* <b>Example Usage:</b>
|
||||
* <pre>{@code
|
||||
* RangeUtil.range(3, 10, 2).forEach(System.out::println);
|
||||
*
|
||||
* // Output:
|
||||
* // 3
|
||||
* // 5
|
||||
* // 7
|
||||
* // 9
|
||||
*
|
||||
* RangeUtil.range(10, 3, -2).forEach(System.out::println);
|
||||
*
|
||||
* // Output:
|
||||
* // 10
|
||||
* // 8
|
||||
* // 6
|
||||
* // 4
|
||||
* }</pre>
|
||||
*
|
||||
* @param start the starting value of the range (inclusive)
|
||||
* @param end upper-bound of the range (exclusive)
|
||||
* @param step the increment or decrement between each value (non-zero)
|
||||
* @return an {@code IntStream} of integers from {@code start} to {@code end} exclusive stepping by {@code step}
|
||||
* @throws IllegalArgumentException if {@code step} is zero or if {@code start} and {@code end} are inconsistent
|
||||
* with the direction imposed by {@code step}
|
||||
* @see IntStream
|
||||
*/
|
||||
public static IntStream range(int start, int end, int step) {
|
||||
if (step == 0) {
|
||||
throw new IllegalArgumentException("Step value must not be zero.");
|
||||
}
|
||||
if ((step > 0 && start >= end) || (step < 0 && start <= end)) {
|
||||
throw new IllegalArgumentException("Range parameters are inconsistent with the step value.");
|
||||
}
|
||||
return IntStream.iterate(start, (n) -> step > 0 ? n < end : n > end, (n) -> n + step);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2024-2025 OnixByte.
|
||||
~
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<configuration>
|
||||
<property name="COLOURFUL_OUTPUT"
|
||||
value="%black(%date{'dd MMM, yyyy HH:mm:ss', Asia/Hong_Kong, en-UK}) %highlight(%-5level) %black(---) %black([%10.10t]) %cyan(%-20.20logger{20}) %black(:) %msg%n"/>
|
||||
<property name="STANDARD_OUTPUT"
|
||||
value="%date{'dd MMM, yyyy HH:mm:ss', Asia/Hong_Kong, en-UK} %-5level %black(---) [%10.10t] %-20.20logger{20} : %msg%n"/>
|
||||
|
||||
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>${COLOURFUL_OUTPUT}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 OnixByte.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.onixbyte.devkit.utils;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class AesUtilTest {
|
||||
|
||||
@Test
|
||||
void testEncryptAndDecryptByte() throws GeneralSecurityException {
|
||||
byte[] secretKey = "43f72073956d4c81".getBytes(StandardCharsets.UTF_8);
|
||||
byte[] originalData = "Hello World".getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
byte[] encryptedData = AesUtil.encrypt(originalData, secretKey);
|
||||
assertNotNull(encryptedData);
|
||||
|
||||
byte[] decryptedData = AesUtil.decrypt(encryptedData, secretKey);
|
||||
assertNotNull(decryptedData);
|
||||
|
||||
assertArrayEquals(originalData, decryptedData);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEncryptAndDecryptString() throws GeneralSecurityException {
|
||||
var secret = "43f72073956d4c81";
|
||||
var originalData = "Hello World";
|
||||
|
||||
var encryptedData = AesUtil.encrypt(originalData, secret);
|
||||
assertNotNull(encryptedData);
|
||||
assertNotEquals(originalData, encryptedData);
|
||||
|
||||
var decryptedData = AesUtil.decrypt(encryptedData, secret);
|
||||
assertNotNull(decryptedData);
|
||||
assertEquals(originalData, decryptedData);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEncryptWithWrongKeyFails() throws GeneralSecurityException {
|
||||
var secret = "43f72073956d4c81";
|
||||
var wrongSecret = "0000000000000000";
|
||||
var originalData = "Hello World";
|
||||
|
||||
var encryptedData = AesUtil.encrypt(originalData.getBytes(StandardCharsets.UTF_8),
|
||||
secret.getBytes(StandardCharsets.UTF_8));
|
||||
assertNotNull(encryptedData);
|
||||
|
||||
// When decrypting with the wrong key, a BadPaddingException or IllegalBlockSizeException is expected to be thrown
|
||||
assertThrows(GeneralSecurityException.class, () -> {
|
||||
AesUtil.decrypt(encryptedData, wrongSecret.getBytes(StandardCharsets.UTF_8));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGenerateRandomSecret() {
|
||||
var randomSecret = AesUtil.generateRandomSecret();
|
||||
assertNotNull(randomSecret);
|
||||
assertEquals(16, randomSecret.length());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 OnixByte.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.onixbyte.devkit.utils;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class Base64UtilTest {
|
||||
|
||||
@Test
|
||||
void testEncodeAndDecodeWithUtf8() {
|
||||
var original = "Hello, Base64!";
|
||||
var encoded = Base64Util.encode(original);
|
||||
assertNotNull(encoded);
|
||||
assertNotEquals(original, encoded);
|
||||
|
||||
var decoded = Base64Util.decode(encoded);
|
||||
assertNotNull(decoded);
|
||||
assertEquals(original, decoded);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEncodeAndDecodeWithCharset() {
|
||||
var original = "编码测试"; // Some unicode characters (Chinese)
|
||||
var charset = StandardCharsets.UTF_8;
|
||||
|
||||
var encoded = Base64Util.encode(original, charset);
|
||||
assertNotNull(encoded);
|
||||
assertNotEquals(original, encoded);
|
||||
|
||||
var decoded = Base64Util.decode(encoded, charset);
|
||||
assertNotNull(decoded);
|
||||
assertEquals(original, decoded);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEncodeUrlComponentsAndDecodeWithUtf8() {
|
||||
var original = "This is a test for URL-safe Base64 encoding+!";
|
||||
|
||||
var encodedUrl = Base64Util.encodeUrlComponents(original);
|
||||
assertNotNull(encodedUrl);
|
||||
assertNotEquals(original, encodedUrl);
|
||||
// URL-safe encoding should not contain '+' or '/' characters
|
||||
assertFalse(encodedUrl.contains("+"));
|
||||
assertFalse(encodedUrl.contains("/"));
|
||||
|
||||
var decodedUrl = Base64Util.decodeUrlComponents(encodedUrl);
|
||||
assertNotNull(decodedUrl);
|
||||
assertEquals(original, decodedUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEncodeUrlComponentsAndDecodeWithCharset() {
|
||||
var original = "测试 URL 安全编码"; // Unicode string
|
||||
var charset = StandardCharsets.UTF_8;
|
||||
|
||||
var encodedUrl = Base64Util.encodeUrlComponents(original, charset);
|
||||
assertNotNull(encodedUrl);
|
||||
assertNotEquals(original, encodedUrl);
|
||||
|
||||
var decodedUrl = Base64Util.decodeUrlComponents(encodedUrl, charset);
|
||||
assertNotNull(decodedUrl);
|
||||
assertEquals(original, decodedUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEncodeAndDecodeEmptyString() {
|
||||
var original = "";
|
||||
|
||||
var encoded = Base64Util.encode(original);
|
||||
assertNotNull(encoded);
|
||||
assertEquals("", Base64Util.decode(encoded));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEncodeAndDecodeNullSafety() {
|
||||
// Since Base64Util does not explicitly handle null, the test expects NPE if null is input
|
||||
assertThrows(NullPointerException.class, () -> Base64Util.encode(null));
|
||||
assertThrows(NullPointerException.class, () -> Base64Util.decode(null));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 OnixByte.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.onixbyte.devkit.utils;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class BoolUtilTest {
|
||||
|
||||
// Tests for and(Boolean... values)
|
||||
|
||||
@Test
|
||||
void and_AllTrueValues_ReturnsTrue() {
|
||||
assertTrue(BoolUtil.and(true, true, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void and_SomeFalseValues_ReturnsFalse() {
|
||||
assertFalse(BoolUtil.and(true, false, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void and_AllFalseValues_ReturnsFalse() {
|
||||
assertFalse(BoolUtil.and(false, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void and_WithNullValues_IgnoresNulls() {
|
||||
assertTrue(BoolUtil.and(true, null, true));
|
||||
assertFalse(BoolUtil.and(true, null, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void and_AllNullValues_ReturnsTrue() {
|
||||
// Stream after filtering null is empty, allMatch on empty returns true
|
||||
assertTrue(BoolUtil.and((Boolean) null, null));
|
||||
}
|
||||
|
||||
// Tests for and(BooleanSupplier... valueSuppliers)
|
||||
|
||||
@Test
|
||||
void and_AllSuppliersTrue_ReturnsTrue() {
|
||||
BooleanSupplier trueSupplier = () -> true;
|
||||
BooleanSupplier falseSupplier = () -> false;
|
||||
|
||||
assertTrue(BoolUtil.and(trueSupplier, trueSupplier));
|
||||
assertFalse(BoolUtil.and(trueSupplier, falseSupplier));
|
||||
}
|
||||
|
||||
@Test
|
||||
void and_WithNullSuppliers_IgnoresNull() {
|
||||
BooleanSupplier trueSupplier = () -> true;
|
||||
|
||||
assertTrue(BoolUtil.and(trueSupplier, null, trueSupplier));
|
||||
assertFalse(BoolUtil.and(trueSupplier, null, () -> false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void and_AllNullSuppliers_ReturnsTrue() {
|
||||
assertTrue(BoolUtil.and((BooleanSupplier) null, null));
|
||||
}
|
||||
|
||||
|
||||
// Tests for or(Boolean... values)
|
||||
|
||||
@Test
|
||||
void or_AllTrueValues_ReturnsTrue() {
|
||||
assertTrue(BoolUtil.or(true, true, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void or_SomeTrueValues_ReturnsTrue() {
|
||||
assertTrue(BoolUtil.or(false, true, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void or_AllFalseValues_ReturnsFalse() {
|
||||
assertFalse(BoolUtil.or(false, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void or_WithNullValues_IgnoresNull() {
|
||||
assertTrue(BoolUtil.or(false, null, true));
|
||||
assertFalse(BoolUtil.or(false, null, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void or_AllNullValues_ReturnsFalse() {
|
||||
// Stream after filtering null is empty, anyMatch on empty returns false
|
||||
assertFalse(BoolUtil.or((Boolean) null, null));
|
||||
}
|
||||
|
||||
// Tests for or(BooleanSupplier... valueSuppliers)
|
||||
|
||||
@Test
|
||||
void or_AllSuppliersTrue_ReturnsTrue() {
|
||||
BooleanSupplier trueSupplier = () -> true;
|
||||
BooleanSupplier falseSupplier = () -> false;
|
||||
|
||||
assertTrue(BoolUtil.or(trueSupplier, trueSupplier));
|
||||
assertTrue(BoolUtil.or(falseSupplier, trueSupplier));
|
||||
assertFalse(BoolUtil.or(falseSupplier, falseSupplier));
|
||||
}
|
||||
|
||||
@Test
|
||||
void or_WithNullSuppliers_IgnoresNull() {
|
||||
BooleanSupplier trueSupplier = () -> true;
|
||||
BooleanSupplier falseSupplier = () -> false;
|
||||
|
||||
assertTrue(BoolUtil.or(falseSupplier, null, trueSupplier));
|
||||
assertFalse(BoolUtil.or(falseSupplier, null, falseSupplier));
|
||||
}
|
||||
|
||||
@Test
|
||||
void or_AllNullSuppliers_ReturnsFalse() {
|
||||
assertFalse(BoolUtil.or((BooleanSupplier) null, null));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 OnixByte.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.onixbyte.devkit.utils;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class BranchUtilTest {
|
||||
|
||||
// Test the static methods or(Boolean... values) and and(Boolean... values)
|
||||
@Test
|
||||
void testOrWithBooleanValues() {
|
||||
BranchUtil trueResult = BranchUtil.or(true, false, false);
|
||||
assertNotNull(trueResult);
|
||||
|
||||
BranchUtil falseResult = BranchUtil.or(false, false, false);
|
||||
assertNotNull(falseResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAndWithBooleanValues() {
|
||||
BranchUtil trueResult = BranchUtil.and(true, true, true);
|
||||
assertNotNull(trueResult);
|
||||
|
||||
BranchUtil falseResult = BranchUtil.and(true, false, true);
|
||||
assertNotNull(falseResult);
|
||||
}
|
||||
|
||||
// Test the static methods or(BooleanSupplier... valueSuppliers) and and(BooleanSupplier... valueSuppliers)
|
||||
@Test
|
||||
void testOrWithBooleanSuppliers() {
|
||||
BooleanSupplier trueSupplier = () -> true;
|
||||
BooleanSupplier falseSupplier = () -> false;
|
||||
|
||||
BranchUtil trueResult = BranchUtil.or(falseSupplier, trueSupplier);
|
||||
|
||||
BranchUtil falseResult = BranchUtil.or(falseSupplier, falseSupplier);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAndWithBooleanSuppliers() {
|
||||
BooleanSupplier trueSupplier = () -> true;
|
||||
BooleanSupplier falseSupplier = () -> false;
|
||||
|
||||
BranchUtil trueResult = BranchUtil.and(trueSupplier, trueSupplier);
|
||||
|
||||
BranchUtil falseResult = BranchUtil.and(trueSupplier, falseSupplier);
|
||||
}
|
||||
|
||||
// Test thenSupply(T, T)
|
||||
@Test
|
||||
void testThenSupplyBothSuppliers_ResultTrue() {
|
||||
BranchUtil b = BranchUtil.and(true);
|
||||
String trueVal = "yes";
|
||||
String falseVal = "no";
|
||||
|
||||
String result = b.thenSupply(() -> trueVal, () -> falseVal);
|
||||
assertEquals(trueVal, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testThenSupplyBothSuppliers_ResultFalse_WithFalseSupplier() {
|
||||
BranchUtil b = BranchUtil.and(false);
|
||||
String trueVal = "yes";
|
||||
String falseVal = "no";
|
||||
|
||||
String result = b.thenSupply(() -> trueVal, () -> falseVal);
|
||||
assertEquals(falseVal, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testThenSupplyBothSuppliers_ResultFalse_NoFalseSupplier() {
|
||||
BranchUtil b = BranchUtil.and(false);
|
||||
String trueVal = "yes";
|
||||
|
||||
String result = b.thenSupply(() -> trueVal, null);
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testThenSupplySingleTrueSupplier_ResultTrue() {
|
||||
BranchUtil b = BranchUtil.and(true);
|
||||
String trueVal = "success";
|
||||
|
||||
String result = b.thenSupply(() -> trueVal);
|
||||
assertEquals(trueVal, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testThenSupplySingleTrueSupplier_ResultFalse() {
|
||||
BranchUtil b = BranchUtil.and(false);
|
||||
String trueVal = "success";
|
||||
|
||||
String result = b.thenSupply(() -> trueVal);
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
// Test then(Runnable, Runnable)
|
||||
@Test
|
||||
void testThenWithBothHandlers_ResultTrue() {
|
||||
BranchUtil b = BranchUtil.and(true);
|
||||
AtomicBoolean trueRun = new AtomicBoolean(false);
|
||||
AtomicBoolean falseRun = new AtomicBoolean(false);
|
||||
|
||||
b.then(() -> trueRun.set(true), () -> falseRun.set(true));
|
||||
|
||||
assertTrue(trueRun.get());
|
||||
assertFalse(falseRun.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testThenWithBothHandlers_ResultFalse() {
|
||||
BranchUtil b = BranchUtil.and(false);
|
||||
AtomicBoolean trueRun = new AtomicBoolean(false);
|
||||
AtomicBoolean falseRun = new AtomicBoolean(false);
|
||||
|
||||
b.then(() -> trueRun.set(true), () -> falseRun.set(true));
|
||||
|
||||
assertFalse(trueRun.get());
|
||||
assertTrue(falseRun.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testThenWithOnlyTrueHandler_ResultTrue() {
|
||||
BranchUtil b = BranchUtil.and(true);
|
||||
AtomicBoolean trueRun = new AtomicBoolean(false);
|
||||
|
||||
b.then(() -> trueRun.set(true));
|
||||
|
||||
assertTrue(trueRun.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testThenWithOnlyTrueHandler_ResultFalse() {
|
||||
BranchUtil b = BranchUtil.and(false);
|
||||
AtomicBoolean trueRun = new AtomicBoolean(false);
|
||||
|
||||
b.then(() -> trueRun.set(true));
|
||||
|
||||
assertFalse(trueRun.get());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 OnixByte.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.onixbyte.devkit.utils;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class CollectionUtilTest {
|
||||
|
||||
@Test
|
||||
void chunk_NullOriginalCollection_ThrowsException() {
|
||||
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||
() -> CollectionUtil.chunk(null, 3, ArrayList::new));
|
||||
assertEquals("Collection must not be null.", ex.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void chunk_NegativeMaxSize_ThrowsException() {
|
||||
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||
() -> CollectionUtil.chunk(List.of(1, 2), -1, ArrayList::new));
|
||||
assertEquals("maxSize must greater than 0.", ex.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void chunk_NullCollectionFactory_ThrowsException() {
|
||||
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||
() -> CollectionUtil.chunk(List.of(1, 2), 2, null));
|
||||
assertEquals("Factory method cannot be null.", ex.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void chunk_EmptyCollection_ReturnsOneEmptySubCollection() {
|
||||
List<List<Integer>> chunks = CollectionUtil.chunk(Collections.emptyList(), 3, ArrayList::new);
|
||||
assertEquals(1, chunks.size());
|
||||
assertTrue(chunks.get(0).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void chunk_CollectionSizeLessThanMaxSize_ReturnsOneSubCollectionWithAllElements() {
|
||||
List<Integer> list = List.of(1, 2);
|
||||
List<List<Integer>> chunks = CollectionUtil.chunk(list, 5, ArrayList::new);
|
||||
assertEquals(1, chunks.size());
|
||||
assertEquals(list, chunks.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void chunk_CollectionSizeEqualMaxSize_ReturnsOneSubCollectionWithAllElements() {
|
||||
List<Integer> list = List.of(1, 2, 3);
|
||||
List<List<Integer>> chunks = CollectionUtil.chunk(list, 3, ArrayList::new);
|
||||
assertEquals(1, chunks.size());
|
||||
assertEquals(list, chunks.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void chunk_CollectionSizeGreaterThanMaxSize_ReturnsMultipleSubCollections() {
|
||||
List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7);
|
||||
int maxSize = 3;
|
||||
List<List<Integer>> chunks = CollectionUtil.chunk(list, maxSize, ArrayList::new);
|
||||
|
||||
// Expect 3 subcollections: [1,2,3], [4,5,6], [7]
|
||||
assertEquals(3, chunks.size());
|
||||
assertEquals(List.of(1, 2, 3), chunks.get(0));
|
||||
assertEquals(List.of(4, 5, 6), chunks.get(1));
|
||||
assertEquals(List.of(7), chunks.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void chunk_UsesDifferentCollectionTypeAsSubCollections() {
|
||||
LinkedList<Integer> list = new LinkedList<>(List.of(1, 2, 3, 4));
|
||||
Supplier<LinkedList<Integer>> factory = LinkedList::new;
|
||||
List<LinkedList<Integer>> chunks = CollectionUtil.chunk(list, 2, factory);
|
||||
assertEquals(2, chunks.size());
|
||||
assertInstanceOf(LinkedList.class, chunks.get(0));
|
||||
assertInstanceOf(LinkedList.class, chunks.get(1));
|
||||
assertEquals(List.of(1, 2), chunks.get(0));
|
||||
assertEquals(List.of(3, 4), chunks.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void chunk_CollectionWithOneElementAndMaxSizeOne_ReturnsOneSubCollection() {
|
||||
List<String> list = List.of("a");
|
||||
List<List<String>> chunks = CollectionUtil.chunk(list, 1, ArrayList::new);
|
||||
assertEquals(1, chunks.size());
|
||||
assertEquals(list, chunks.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void chunk_MaxSizeZero_ThrowsException() {
|
||||
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||
() -> CollectionUtil.chunk(List.of(1), 0, ArrayList::new));
|
||||
assertEquals("maxSize must greater than 0.", ex.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 OnixByte.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.onixbyte.devkit.utils;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class HashUtilTest {
|
||||
|
||||
// Test MD2 hashing with explicit charset and default charset
|
||||
@Test
|
||||
void testMd2() {
|
||||
String input = "test";
|
||||
// Known MD2 hash of "test" with UTF-8
|
||||
String expectedHash = "dd34716876364a02d0195e2fb9ae2d1b";
|
||||
assertEquals(expectedHash, HashUtil.md2(input, StandardCharsets.UTF_8));
|
||||
assertEquals(expectedHash, HashUtil.md2(input));
|
||||
// Test null charset fallback to UTF-8
|
||||
assertEquals(expectedHash, HashUtil.md2(input, null));
|
||||
}
|
||||
|
||||
// Test MD5 hashing with explicit charset and default charset
|
||||
@Test
|
||||
void testMd5() {
|
||||
String input = "test";
|
||||
// Known MD5 hash of "test"
|
||||
String expectedHash = "098f6bcd4621d373cade4e832627b4f6";
|
||||
assertEquals(expectedHash, HashUtil.md5(input, StandardCharsets.UTF_8));
|
||||
assertEquals(expectedHash, HashUtil.md5(input));
|
||||
assertEquals(expectedHash, HashUtil.md5(input, null));
|
||||
}
|
||||
|
||||
// Test SHA-1 hashing with explicit charset and default charset
|
||||
@Test
|
||||
void testSha1() {
|
||||
String input = "test";
|
||||
// Known SHA-1 hash of "test"
|
||||
String expectedHash = "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3";
|
||||
assertEquals(expectedHash, HashUtil.sha1(input, StandardCharsets.UTF_8));
|
||||
assertEquals(expectedHash, HashUtil.sha1(input));
|
||||
assertEquals(expectedHash, HashUtil.sha1(input, null));
|
||||
}
|
||||
|
||||
// Test SHA-224 hashing with explicit charset and default charset
|
||||
@Test
|
||||
void testSha224() {
|
||||
String input = "test";
|
||||
// Known SHA-224 hash of "test"
|
||||
String expectedHash = "90a3ed9e32b2aaf4c61c410eb925426119e1a9dc53d4286ade99a809";
|
||||
assertEquals(expectedHash, HashUtil.sha224(input, StandardCharsets.UTF_8));
|
||||
assertEquals(expectedHash, HashUtil.sha224(input));
|
||||
assertEquals(expectedHash, HashUtil.sha224(input, null));
|
||||
}
|
||||
|
||||
// Test SHA-256 hashing with explicit charset and default charset
|
||||
@Test
|
||||
void testSha256() {
|
||||
String input = "test";
|
||||
// Known SHA-256 hash of "test"
|
||||
String expectedHash = "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08";
|
||||
assertEquals(expectedHash, HashUtil.sha256(input, StandardCharsets.UTF_8));
|
||||
assertEquals(expectedHash, HashUtil.sha256(input));
|
||||
assertEquals(expectedHash, HashUtil.sha256(input, null));
|
||||
}
|
||||
|
||||
// Test SHA-384 hashing with explicit charset and default charset
|
||||
@Test
|
||||
void testSha384() {
|
||||
String input = "test";
|
||||
// Known SHA-384 hash of "test"
|
||||
String expectedHash = "768412320f7b0aa5812fce428dc4706b3cae50e02a64caa16a782249bfe8efc4b7ef1ccb126255d196047dfedf17a0a9";
|
||||
assertEquals(expectedHash, HashUtil.sha384(input, StandardCharsets.UTF_8));
|
||||
assertEquals(expectedHash, HashUtil.sha384(input));
|
||||
assertEquals(expectedHash, HashUtil.sha384(input, null));
|
||||
}
|
||||
|
||||
// Test SHA-512 hashing with explicit charset and default charset
|
||||
@Test
|
||||
void testSha512() {
|
||||
String input = "test";
|
||||
// Known SHA-512 hash of "test"
|
||||
String expectedHash = "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff";
|
||||
// remove all whitespace in expected to match format generated
|
||||
expectedHash = expectedHash.replaceAll("\\s+", "");
|
||||
assertEquals(expectedHash, HashUtil.sha512(input, StandardCharsets.UTF_8));
|
||||
assertEquals(expectedHash, HashUtil.sha512(input));
|
||||
assertEquals(expectedHash, HashUtil.sha512(input, null));
|
||||
}
|
||||
|
||||
// Test empty string input
|
||||
@Test
|
||||
void testEmptyString() {
|
||||
String input = "";
|
||||
// MD5 hash of empty string
|
||||
String expectedMd5 = "d41d8cd98f00b204e9800998ecf8427e";
|
||||
assertEquals(expectedMd5, HashUtil.md5(input));
|
||||
// SHA-256 hash of empty string
|
||||
String expectedSha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
|
||||
assertEquals(expectedSha256, HashUtil.sha256(input));
|
||||
}
|
||||
|
||||
// Test null charset fallback for one algorithm as a sample
|
||||
@Test
|
||||
void testNullCharsetFallsBackToUtf8() {
|
||||
String input = "abc";
|
||||
String hashWithNull = HashUtil.md5(input, null);
|
||||
String hashWithUtf8 = HashUtil.md5(input, StandardCharsets.UTF_8);
|
||||
assertEquals(hashWithUtf8, hashWithNull);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 OnixByte.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.onixbyte.devkit.utils;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class RangeUtilTest {
|
||||
|
||||
/**
|
||||
* Tests generating ascending range from 0 up to end (exclusive).
|
||||
*/
|
||||
@Test
|
||||
void testRangeEndValid() {
|
||||
int[] expected = {0, 1, 2, 3, 4};
|
||||
assertArrayEquals(expected, RangeUtil.range(5).toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that range(end) throws IllegalArgumentException for end less than or equal to zero.
|
||||
*/
|
||||
@Test
|
||||
void testRangeEndInvalidThrows() {
|
||||
IllegalArgumentException ex1 = assertThrows(IllegalArgumentException.class,
|
||||
() -> RangeUtil.range(0));
|
||||
assertTrue(ex1.getMessage().contains("should not be less than or equal to 0"));
|
||||
|
||||
IllegalArgumentException ex2 = assertThrows(IllegalArgumentException.class,
|
||||
() -> RangeUtil.range(-3));
|
||||
assertTrue(ex2.getMessage().contains("should not be less than or equal to 0"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests ascending range where start is less than end.
|
||||
*/
|
||||
@Test
|
||||
void testRangeStartEndAscending() {
|
||||
int[] expected = {3, 4, 5, 6, 7};
|
||||
assertArrayEquals(expected, RangeUtil.range(3, 8).toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests descending range where start is greater than end.
|
||||
*/
|
||||
@Test
|
||||
void testRangeStartEndDescending() {
|
||||
int[] expected = {8, 7, 6, 5, 4};
|
||||
assertArrayEquals(expected, RangeUtil.range(8, 3).toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests empty stream when start equals end.
|
||||
*/
|
||||
@Test
|
||||
void testRangeStartEqualsEndReturnsEmpty() {
|
||||
assertEquals(0, RangeUtil.range(5, 5).count());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that rangeClosed generates inclusive range in ascending order.
|
||||
*/
|
||||
@Test
|
||||
void testRangeClosedAscending() {
|
||||
int[] expected = {3, 4, 5, 6, 7, 8};
|
||||
assertArrayEquals(expected, RangeUtil.rangeClosed(3, 8).toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests range method with positive step generating ascending sequence.
|
||||
*/
|
||||
@Test
|
||||
void testRangeWithPositiveStep() {
|
||||
int[] expected = {2, 4, 6, 8};
|
||||
assertArrayEquals(expected, RangeUtil.range(2, 10, 2).toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests range method with negative step generating descending sequence.
|
||||
*/
|
||||
@Test
|
||||
void testRangeWithNegativeStep() {
|
||||
int[] expected = {10, 7, 4, 1};
|
||||
assertArrayEquals(expected, RangeUtil.range(10, 0, -3).toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that passing zero step throws IllegalArgumentException.
|
||||
*/
|
||||
@Test
|
||||
void testRangeStepZeroThrows() {
|
||||
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||
() -> RangeUtil.range(0, 10, 0));
|
||||
assertEquals("Step value must not be zero.", ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that range with positive step but invalid start/end throws IllegalArgumentException.
|
||||
*/
|
||||
@Test
|
||||
void testRangePositiveStepInvalidRangeThrows() {
|
||||
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||
() -> RangeUtil.range(10, 5, 1));
|
||||
assertEquals("Range parameters are inconsistent with the step value.", ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that range with negative step but invalid start/end throws IllegalArgumentException.
|
||||
*/
|
||||
@Test
|
||||
void testRangeNegativeStepInvalidRangeThrows() {
|
||||
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||
() -> RangeUtil.range(5, 10, -1));
|
||||
assertEquals("Range parameters are inconsistent with the step value.", ex.getMessage());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user