Merge pull request #15 from CodeCraftersCN/dev/v1.1.0

Upgrade to v1.1.0
This commit is contained in:
Zihlu Wang
2023-09-19 14:19:32 +08:00
committed by GitHub
64 changed files with 1041 additions and 672 deletions
+1 -1
View File
@@ -27,7 +27,7 @@ A module for generating globally unique IDs. It includes a facade interface and
<span style="font-size: 14px;">_[Learn more](https://github.com/CodeCraftersCN/jdevkit/webcal/README.md)_</span> <span style="font-size: 14px;">_[Learn more](https://github.com/CodeCraftersCN/jdevkit/webcal/README.md)_</span>
The module `webcal` is a Java library that facilitates the generation and resolution of iCalendar content for web-based calendar applications. It provides a flexible and easy-to-use API for creating web calendars with customizable settings and events. The module `webcal` is a Java library that facilitates the generation and resolution of iCalendar content for web-based calendar applications. It provides a flexible and easy-to-use API for creating web calendars with customisable settings and events.
With the `webcal` module, developers can easily integrate calendar functionality into web applications, enabling users to view, add, and manage events in a structured and standardized format. It is designed to simplify calendar-related tasks and enhance the overall user experience when dealing with calendar data on the web. With the `webcal` module, developers can easily integrate calendar functionality into web applications, enabling users to view, add, and manage events in a structured and standardized format. It is designed to simplify calendar-related tasks and enhance the overall user experience when dealing with calendar data on the web.
+1 -1
View File
@@ -23,7 +23,7 @@
<parent> <parent>
<groupId>cn.org.codecrafters</groupId> <groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId> <artifactId>jdevkit</artifactId>
<version>1.0.1</version> <version>1.1.0</version>
</parent> </parent>
<artifactId>devkit-core</artifactId> <artifactId>devkit-core</artifactId>
@@ -18,31 +18,23 @@
package cn.org.codecrafters.devkit.core.exceptions; package cn.org.codecrafters.devkit.core.exceptions;
/** /**
* NotImplementedException - Custom Runtime Exception
* <p>
* The {@code NotImplementedException} class is a custom runtime exception * The {@code NotImplementedException} class is a custom runtime exception
* that represents a situation where a particular method or functionality is * that represents a situation where a particular method or functionality is
* not implemented or is currently unavailable in the codebase. It extends the * not implemented or is currently unavailable in the codebase.
* standard {@code RuntimeException} class, making it an unchecked exception.
*
* <p> * <p>
* This exception is typically thrown when developers need to indicate that a * This exception is typically thrown when developers need to indicate that a
* specific part of the code is incomplete or requires further implementation. * specific part of the code is incomplete or requires further implementation.
* It serves as a placeholder to highlight unfinished sections of the * It serves as a placeholder to highlight unfinished sections of the
* application during development and testing phases. * application during development and testing phases.
*
* <p> * <p>
* Usage Example: * Usage Example:
*
* <pre> * <pre>
* public void someMethod() { * public void someMethod() {
* // Some code... * // Some code...
* throw new NotImplementedException(""" * throw new NotImplementedException("""
* This feature will be implemented in a future release. * This feature will be implemented in a future release.""");
* """);
* } * }
* </pre> * </pre>
*
* <b>Contact</b> * <b>Contact</b>
* <ul> * <ul>
* <li> * <li>
@@ -55,7 +47,7 @@ package cn.org.codecrafters.devkit.core.exceptions;
* </ul> * </ul>
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.1.0
* @see RuntimeException * @see RuntimeException
* @since 1.0.0 * @since 1.0.0
*/ */
@@ -16,7 +16,7 @@
*/ */
/** /**
* Commonly used exceptions will be used in JDevKit. * This package contains commonly used exceptions will be used in JDevKit.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @since 1.0.0 * @since 1.0.0
@@ -16,19 +16,16 @@
*/ */
/** /**
* This package is a part of JDevKit, an open-source Java Development Kit that * This package is the core part of JDevKit, an open-source Java Development
* provides a set of convenient tools to streamline code development and * Kit that provides a set of convenient tools to streamline code development
* enhance productivity. This package serves as the core package containing * and enhance productivity. This package serves as the core package containing
* common exceptions that are used throughout the entireJDevKit project. * common exceptions that are used throughout the entire JDevKit project.
*
* <p> * <p>
* JDevKit is designed to be modular, and other specific feature modules within * JDevKit is designed to be modular, and other specific feature modules within
* the library may rely on these exceptions from the core package. * the library may rely on these exceptions from the core package.
*
* <p> * <p>
* For more information and the latest version of JDevKit, please visit our * For more information and the latest version of JDevKit, please visit our
* website <a href="https://codecrafters.org.cn">codecrafters.org.cn</a>. * website <a href="https://codecrafters.org.cn">codecrafters.org.cn</a>.
*
* <p> * <p>
* <b>Contact</b> * <b>Contact</b>
* <ul> * <ul>
@@ -19,8 +19,8 @@
* This package is the main part of JDevKit, an open-source Java class library * This package is the main part of JDevKit, an open-source Java class library
* that provides a set of convenient tools to streamline code development and * that provides a set of convenient tools to streamline code development and
* enhance productivity. This package serves as the root package for several * enhance productivity. This package serves as the root package for several
* modules, containing devkit-core, guid and dev-utils module. * modules, containing {@code devkit-core}, {@code guid} and {@code dev-utils}
* * module.
* <p> * <p>
* For more information and the latest version of JDevKit, please visit our * For more information and the latest version of JDevKit, please visit our
* website <a href="https://codecrafters.org.cn">codecrafters.org.cn</a>. * website <a href="https://codecrafters.org.cn">codecrafters.org.cn</a>.
+1 -1
View File
@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>cn.org.codecrafters</groupId> <groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId> <artifactId>jdevkit</artifactId>
<version>1.0.1</version> <version>1.1.0</version>
</parent> </parent>
<artifactId>devkit-utils</artifactId> <artifactId>devkit-utils</artifactId>
@@ -0,0 +1,136 @@
/*
* Copyright (C) 2023 CodeCraftersCN.
*
* 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 cn.org.codecrafters.devkit.utils;
import lombok.extern.slf4j.Slf4j;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Objects;
import java.util.UUID;
/**
* {@link AesUtil} can help you encrypt and decrypt data with specified secret
* by AES algorithm.
*
* @author hubin@baomidou
* @version 1.1.0
* @since 1.1.0
*/
@Slf4j
public final class AesUtil {
private AesUtil() {
}
private static final String AES = "AES";
private static final String AES_CBC_CIPHER = "AES/CBC/PKCS5Padding";
/**
* Encrypts the data using the AES algorithm with the given secret.
*
* @param data the data to be encrypted
* @param secret the secret to encrypt the data
* @return the encryption result or {@code null} if encryption failed
*/
public static byte[] encrypt(byte[] data, byte[] secret) {
try {
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);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | UnsupportedOperationException |
InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException |
BadPaddingException exception) {
log.error(exception.getMessage());
for (var stackTraceElement : exception.getStackTrace()) {
log.error("{}", stackTraceElement.toString());
}
}
return null;
}
/**
* Decrypts the data using the AES algorithm with the given secret.
*
* @param data the data to be decrypted
* @param secret the secret to encrypt the data
* @return the decryption result or {@code null} if decryption failed
*/
public static byte[] decrypt(byte[] data, byte[] secret) {
try {
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);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | UnsupportedOperationException |
InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException |
BadPaddingException exception) {
log.error(exception.getMessage());
for (var stackTraceElement : exception.getStackTrace()) {
log.error("{}", stackTraceElement.toString());
}
}
return null;
}
/**
* Encrypts the data using the AES algorithm with the given secret.
*
* @param data the data to be encrypted
* @param secret the secret to encrypt the data
* @return the encryption result or {@code null} if encryption failed
*/
public static String encrypt(String data, String secret) {
return Base64.getEncoder().encodeToString(encrypt(data.getBytes(StandardCharsets.UTF_8), secret.getBytes(StandardCharsets.UTF_8)));
}
/**
* Decrypts the data using the AES algorithm with the given secret.
*
* @param data the data to be decrypted
* @param secret the secret to encrypt the data
* @return the decryption result or {@code null} if decryption failed
*/
public static String decrypt(String data, String secret) {
return new String(Objects.requireNonNull(
decrypt(Base64.getDecoder().decode(data.getBytes()),
secret.getBytes(StandardCharsets.UTF_8)))
);
}
/**
* Generates 16 characters-long random secret.
*
* @return the generated secure secret
*/
public static String generateRandomSecret() {
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
}
}
@@ -20,20 +20,18 @@ package cn.org.codecrafters.devkit.utils;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Base64; import java.util.Base64;
import java.util.Objects;
/** /**
* <p> * The {@link Base64Util} class provides static methods to encode and decode
* The {@code Base64Util} class provides static methods to encode and decode * strings with Base64 encoding. It utilizes the {@link Base64} class from the
* strings using Base64 encoding. It utilizes the {@link Base64} class from the
* Java standard library for performing the encoding and decoding operations. * Java standard library for performing the encoding and decoding operations.
* This utility class offers convenient methods to encode and decode strings * This utility class offers convenient methods to encode and decode strings
* with different character sets. * with different character sets.
*
* <p> * <p>
* This class is designed as a final class with a private constructor to * This class is designed as a final class with a private constructor to
* prevent instantiation. All methods in this class are static, allowing easy * prevent instantiation. All methods in this class are static, allowing easy
* access to the Base64 encoding and decoding functionality. * access to the Base64 encoding and decoding functionality.
*
* <p> * <p>
* Example usage: * Example usage:
* <pre> * <pre>
@@ -47,19 +45,45 @@ import java.util.Base64;
* String decoded = Base64Util.decode(encoded); * String decoded = Base64Util.decode(encoded);
* System.out.println("Decoded string: " + decoded); * System.out.println("Decoded string: " + decoded);
* </pre> * </pre>
*
* <p> * <p>
* <b>Note:</b> This utility class uses the default charset (UTF-8) if no * <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 * specific charset is provided. It is recommended to specify the charset
* explicitly to ensure consistent encoding and decoding. * explicitly to ensure consistent encoding and decoding.
* *
*
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.1.0
* @since 1.0.0 * @since 1.0.0
*/ */
public final class Base64Util { public final class Base64Util {
private static Base64.Encoder encoder;
private static Base64.Decoder decoder;
/**
* 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;
}
/** /**
* Private constructor to prevent instantiation of the class. * Private constructor to prevent instantiation of the class.
*/ */
@@ -74,8 +98,7 @@ public final class Base64Util {
* @return the Base64 encoded string * @return the Base64 encoded string
*/ */
public static String encode(String value, Charset charset) { public static String encode(String value, Charset charset) {
var encoder = Base64.getEncoder(); var encoded = getEncoder().encode(value.getBytes(charset));
var encoded = encoder.encode(value.getBytes(charset));
return new String(encoded); return new String(encoded);
} }
@@ -98,8 +121,7 @@ public final class Base64Util {
* @return the decoded string * @return the decoded string
*/ */
public static String decode(String value, Charset charset) { public static String decode(String value, Charset charset) {
var decoder = Base64.getDecoder(); var decoded = getDecoder().decode(value.getBytes(charset));
var decoded = decoder.decode(value.getBytes(charset));
return new String(decoded); return new String(decoded);
} }
@@ -23,29 +23,24 @@ import java.util.function.BooleanSupplier;
import java.util.function.Supplier; 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> * <p>
* The BranchUtil class provides static methods to simplify conditional logic * Developers can use methods in this utility class to streamline their code,
* in Java development by leveraging lambda expressions. It offers convenient * enhance readability, and promote a more functional style of programming when
* methods to replace verbose if...else statements with more concise and * dealing with branching logic and conditional statements.
* expressive functional constructs.
*
*
* <p>
* Developers can use the 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> * <p>
* <b>Example:</b> * <b>Example:</b>
* <pre> * <pre>
* // If you want to simplify an if (exp1 || exp2), you can use the * // If you want to simplify an if (exp1 || exp2), you can use the
* // following code: * // following code:
* var r1 = BranchUtil.or(1 == 1, 2 == 1) * String r1 = BranchUtil.or(1 == 1, 2 == 1)
* .handle(() -> "1 is equal to 1 or 2 is equal to 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: * // If you have an else branch, you can use the following code:
* var r2 = BranchUtil.or(1 == 1, 2 == 1) * String r2 = BranchUtil.or(1 == 1, 2 == 1)
* .handle(() -> "1 is equal to 1 or 2 is equal to 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."); * () -> "1 is not equal to 1 and 2 is not equal to 1.");
* *
@@ -67,7 +62,6 @@ import java.util.function.Supplier;
* // do something * // do something
* }); * });
* </pre> * </pre>
*
* <p> * <p>
* <b>Note:</b> * <b>Note:</b>
* The {@link #and(Boolean...)} and {@link #or(Boolean...)} methods accept any * The {@link #and(Boolean...)} and {@link #or(Boolean...)} methods accept any
@@ -75,7 +69,7 @@ import java.util.function.Supplier;
* *
* @param <T> the type of the result to be handled by the methods * @param <T> the type of the result to be handled by the methods
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.1.0
* @see java.util.function.Supplier * @see java.util.function.Supplier
* @see java.util.function.BooleanSupplier * @see java.util.function.BooleanSupplier
* @see java.lang.Runnable * @see java.lang.Runnable
@@ -164,15 +158,12 @@ public final class BranchUtil<T> {
} }
/** /**
* <p>
* Handles the result of the boolean expressions by executing the * Handles the result of the boolean expressions by executing the
* appropriate handler based on the result. * appropriate handler based on the result.
*
* <p> * <p>
* If the result is {@code true}, the {@code ifHandler} is executed. If the * 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 * result is {@code false} and an {@code elseHandler} is provided, it is
* executed. * executed.
*
* <p> * <p>
* Returns the result of the executed handler. * Returns the result of the executed handler.
* *
@@ -181,7 +172,8 @@ public final class BranchUtil<T> {
* @param elseHandler the handler to be executed if the result is * @param elseHandler the handler to be executed if the result is
* {@code false} (optional) * {@code false} (optional)
* @return the result of the executed handler, or {@code null} if no * @return the result of the executed handler, or {@code null} if no
* {@code elseHandler} is provided * {@code elseHandler} is provided and the result of the evaluation is
* {@code false}
*/ */
public T handle(Supplier<T> ifHandler, Supplier<T> elseHandler) { public T handle(Supplier<T> ifHandler, Supplier<T> elseHandler) {
if (this.result && Objects.nonNull(ifHandler)) { if (this.result && Objects.nonNull(ifHandler)) {
@@ -196,26 +188,23 @@ public final class BranchUtil<T> {
} }
/** /**
* <p>
* Handles the result of the boolean expressions by executing the provided * Handles the result of the boolean expressions by executing the provided
* handler if the result is {@code true}. * handler if the result is {@code true}.
*
* <p> * <p>
* Returns the result of the executed handler. * Returns the result of the executed handler.
* *
* @param ifHandler the handler to be executed if the result is * @param ifHandler the handler to be executed if the result is
* {@code true} * {@code true}
* @return the result of the executed handler * @return the result of the executed handler, or {@code null} if result of
* evaluation is {@code false}
*/ */
public T handle(Supplier<T> ifHandler) { public T handle(Supplier<T> ifHandler) {
return handle(ifHandler, null); return handle(ifHandler, null);
} }
/** /**
* <p>
* Handles the result of the boolean expressions by executing the * Handles the result of the boolean expressions by executing the
* appropriate handler based on the result. * appropriate handler based on the result.
*
* <p> * <p>
* If the result is {@code true}, the {@code ifHandler} is executed. If the * 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 * result is {@code false} and an {@code elseHandler} is provided, it is
@@ -17,6 +17,8 @@
package cn.org.codecrafters.devkit.utils; package cn.org.codecrafters.devkit.utils;
import lombok.Getter;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.util.Objects; import java.util.Objects;
@@ -24,19 +26,12 @@ import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
/** /**
* <p> * The {@code ChainedCalcUtil} class provides a convenient way to perform
* Utility class for chained high-precision calculations using BigDecimal. * chained high-precision calculations using {@link BigDecimal}. It allows
* * users to perform mathematical operations such as addition, subtraction,
* * multiplication, and division with customisable precision and scale. By using
* <p> * this utility class, developers can achieve accurate results and avoid
* The ChainedCalcUtil class provides a convenient way to perform chained * precision loss in their calculations.
* high-precision calculations using BigDecimal. It allows users to perform
* mathematical operations such as addition, subtraction, multiplication,
* and division with customizable precision and scale. By using this utility
* class, developers can achieve accurate results and avoid precision loss
* in their calculations.
*
*
* <p> * <p>
* <b>Usage:</b> * <b>Usage:</b>
* <pre> * <pre>
@@ -84,26 +79,31 @@ import java.util.function.Function;
* .getValue(2); * .getValue(2);
* </pre> * </pre>
* The above expressions perform various mathematical calculations using the * The above expressions perform various mathematical calculations using the
* ChainedCalcUtil class. * {@code ChainedCalcUtil} class.
*
* <p> * <p>
* <b>Note:</b> * <b>Note:</b>
* The ChainedCalcUtil class internally uses BigDecimal to handle * The {@code ChainedCalcUtil} class internally uses {@link BigDecimal} to
* high-precision calculations. It is important to note that BigDecimal * handle high-precision calculations. It is important to note that {@link
* operations can be memory-intensive and may have performance implications * BigDecimal} operations can be memory-intensive and may have performance
* for extremely large numbers or complex calculations. * implications for extremely large numbers or complex calculations.
* *
* @author sunzsh * @author sunzsh
* @version 1.0.0 * @version 1.1.0
* @see java.math.BigDecimal * @see java.math.BigDecimal
* @since 9 Jul 2023 * @since 1.0.0
*/ */
@Getter
public final class ChainedCalcUtil { public final class ChainedCalcUtil {
/**
* -- GETTER --
* Returns the current value as a BigDecimal.
*/
private BigDecimal value; private BigDecimal value;
/** /**
* Creates a ChainedCalcUtil instance with the specified initial value. * Creates a {@code ChainedCalcUtil} instance with the specified initial
* value.
* *
* @param value the initial value for the calculation * @param value the initial value for the calculation
*/ */
@@ -115,7 +115,7 @@ public final class ChainedCalcUtil {
* Starts a chained calculation with the specified initial value. * Starts a chained calculation with the specified initial value.
* *
* @param value the initial value for the calculation * @param value the initial value for the calculation
* @return a ChainedCalcUtil instance for performing chained calculations * @return a {@code ChainedCalcUtil} instance for performing chained calculations
*/ */
public static ChainedCalcUtil startWith(Number value) { public static ChainedCalcUtil startWith(Number value) {
return new ChainedCalcUtil(value); return new ChainedCalcUtil(value);
@@ -125,7 +125,7 @@ public final class ChainedCalcUtil {
* Adds the specified value to the current value. * Adds the specified value to the current value.
* *
* @param other the value to be added * @param other the value to be added
* @return a ChainedCalcUtil instance with the updated value * @return a {@code ChainedCalcUtil} instance with the updated value
*/ */
public ChainedCalcUtil add(Number other) { public ChainedCalcUtil add(Number other) {
return operator(BigDecimal::add, other); return operator(BigDecimal::add, other);
@@ -137,7 +137,7 @@ public final class ChainedCalcUtil {
* *
* @param other the value to be added * @param other the value to be added
* @param beforeOperateScale the scale to be applied before the operation * @param beforeOperateScale the scale to be applied before the operation
* @return a ChainedCalcUtil instance with the updated value * @return a {@code ChainedCalcUtil} instance with the updated value
*/ */
public ChainedCalcUtil add(Number other, Integer beforeOperateScale) { public ChainedCalcUtil add(Number other, Integer beforeOperateScale) {
return operator(BigDecimal::add, other, beforeOperateScale); return operator(BigDecimal::add, other, beforeOperateScale);
@@ -147,7 +147,7 @@ public final class ChainedCalcUtil {
* Subtracts the specified value from the current value. * Subtracts the specified value from the current value.
* *
* @param other the value to be subtracted * @param other the value to be subtracted
* @return a ChainedCalcUtil instance with the updated value * @return a {@code ChainedCalcUtil} instance with the updated value
*/ */
public ChainedCalcUtil subtract(Number other) { public ChainedCalcUtil subtract(Number other) {
return operator(BigDecimal::subtract, other); return operator(BigDecimal::subtract, other);
@@ -159,7 +159,7 @@ public final class ChainedCalcUtil {
* *
* @param other the value to be subtracted * @param other the value to be subtracted
* @param beforeOperateScale the scale to be applied before the operation * @param beforeOperateScale the scale to be applied before the operation
* @return a ChainedCalcUtil instance with the updated value * @return a {@code ChainedCalcUtil} instance with the updated value
*/ */
public ChainedCalcUtil subtract(Number other, Integer beforeOperateScale) { public ChainedCalcUtil subtract(Number other, Integer beforeOperateScale) {
return operator(BigDecimal::subtract, other, beforeOperateScale); return operator(BigDecimal::subtract, other, beforeOperateScale);
@@ -169,7 +169,7 @@ public final class ChainedCalcUtil {
* Multiplies the current value by the specified value. * Multiplies the current value by the specified value.
* *
* @param other the value to be multiplied by * @param other the value to be multiplied by
* @return a ChainedCalcUtil instance with the updated value * @return a {@code ChainedCalcUtil} instance with the updated value
*/ */
public ChainedCalcUtil multiply(Number other) { public ChainedCalcUtil multiply(Number other) {
return operator(BigDecimal::multiply, other); return operator(BigDecimal::multiply, other);
@@ -181,7 +181,7 @@ public final class ChainedCalcUtil {
* *
* @param other the value to be multiplied by * @param other the value to be multiplied by
* @param beforeOperateScale the scale to be applied before the operation * @param beforeOperateScale the scale to be applied before the operation
* @return a ChainedCalcUtil instance with the updated value * @return a {@code ChainedCalcUtil} instance with the updated value
*/ */
public ChainedCalcUtil multiply(Number other, Integer beforeOperateScale) { public ChainedCalcUtil multiply(Number other, Integer beforeOperateScale) {
return operator(BigDecimal::multiply, other, beforeOperateScale); return operator(BigDecimal::multiply, other, beforeOperateScale);
@@ -191,7 +191,7 @@ public final class ChainedCalcUtil {
* Divides the current value by the specified value. * Divides the current value by the specified value.
* *
* @param other the value to divide by * @param other the value to divide by
* @return a ChainedCalcUtil instance with the updated value * @return a {@code ChainedCalcUtil} instance with the updated value
*/ */
public ChainedCalcUtil divide(Number other) { public ChainedCalcUtil divide(Number other) {
return operator(BigDecimal::divide, other); return operator(BigDecimal::divide, other);
@@ -203,7 +203,7 @@ public final class ChainedCalcUtil {
* *
* @param other the value to divide by * @param other the value to divide by
* @param beforeOperateScale the scale to be applied before the operation * @param beforeOperateScale the scale to be applied before the operation
* @return a ChainedCalcUtil instance with the updated value * @return a {@code ChainedCalcUtil} instance with the updated value
*/ */
public ChainedCalcUtil divide(Number other, Integer beforeOperateScale) { public ChainedCalcUtil divide(Number other, Integer beforeOperateScale) {
return operator(BigDecimal::divide, other, beforeOperateScale); return operator(BigDecimal::divide, other, beforeOperateScale);
@@ -214,7 +214,7 @@ public final class ChainedCalcUtil {
* *
* @param other the value to divide by * @param other the value to divide by
* @param scale the scale for the result * @param scale the scale for the result
* @return a ChainedCalcUtil instance with the updated value * @return a {@code ChainedCalcUtil} instance with the updated value
*/ */
public ChainedCalcUtil divideWithScale(Number other, Integer scale) { public ChainedCalcUtil divideWithScale(Number other, Integer scale) {
return baseOperator(otherValue -> return baseOperator(otherValue ->
@@ -228,63 +228,54 @@ public final class ChainedCalcUtil {
* @param other the value to divide by * @param other the value to divide by
* @param scale the scale for the result * @param scale the scale for the result
* @param beforeOperateScale the scale to be applied before the operation * @param beforeOperateScale the scale to be applied before the operation
* @return a ChainedCalcUtil instance with the updated value * @return a {@code ChainedCalcUtil} instance with the updated value
*/ */
public ChainedCalcUtil divideWithScale(Number other, Integer scale, Integer beforeOperateScale) { public ChainedCalcUtil divideWithScale(Number other, Integer scale, Integer beforeOperateScale) {
return baseOperator(otherValue -> this.value.divide(otherValue, scale, RoundingMode.HALF_UP), other, beforeOperateScale); return baseOperator(otherValue -> this.value.divide(otherValue, scale, RoundingMode.HALF_UP), other, beforeOperateScale);
} }
/** /**
* Returns the current value as a BigDecimal. * Returns the current value as a {@link BigDecimal} with the specified scale.
*
* @return the current value as a BigDecimal
*/
public BigDecimal getValue() {
return value;
}
/**
* Returns the current value as a BigDecimal with the specified scale.
* *
* @param scale the scale for the result * @param scale the scale for the result
* @return the current value as a BigDecimal with the specified scale * @return the current value as a {@link BigDecimal} with the specified scale
*/ */
public BigDecimal getValue(int scale) { public BigDecimal getValue(int scale) {
return value.setScale(scale, RoundingMode.HALF_UP); return value.setScale(scale, RoundingMode.HALF_UP);
} }
/** /**
* Returns the current value as a Double. * Returns the current value as a {@link Double}.
* *
* @return the current value as a Double * @return the current value as a {@link Double}
*/ */
public Double getDouble() { public Double getDouble() {
return getValue().doubleValue(); return getValue().doubleValue();
} }
/** /**
* Returns the current value as a Double with the specified scale. * Returns the current value as a {@link Double} with the specified scale.
* *
* @param scale the scale for the result * @param scale the scale for the result
* @return the current value as a Double with the specified scale * @return the current value as a {@link Double} with the specified scale
*/ */
public Double getDouble(int scale) { public Double getDouble(int scale) {
return getValue(scale).doubleValue(); return getValue(scale).doubleValue();
} }
/** /**
* Returns the current value as a Long. * Returns the current value as a {@link Long}.
* *
* @return the current value as a Long * @return the current value as a {@link Long}
*/ */
public Long getLong() { public Long getLong() {
return getValue().longValue(); return getValue().longValue();
} }
/** /**
* Returns the current value as an Integer. * Returns the current value as an {@link Integer}.
* *
* @return the current value as an Integer * @return the current value as an {@link Integer}
*/ */
public Integer getInteger() { public Integer getInteger() {
return getValue().intValue(); return getValue().intValue();
@@ -340,7 +331,7 @@ public final class ChainedCalcUtil {
} }
/** /**
* Converts the specified value to a BigDecimal. * Converts the specified value to a {@link BigDecimal}.
* *
* @param value the value to convert * @param value the value to convert
* @param scale the scale to apply to the resulting BigDecimal, or null if * @param scale the scale to apply to the resulting BigDecimal, or null if
@@ -25,15 +25,10 @@ import java.util.Objects;
import java.util.Optional; import java.util.Optional;
/** /**
* <p> * The {@code HashUtil} class provides convenient methods for calculating
* Utility class for performing hash operations on strings. * 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
* <p> * hash value of a given string using different algorithms.
* The 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> * <p>
* Example usage: * Example usage:
* <pre> * <pre>
@@ -58,9 +53,8 @@ import java.util.Optional;
* // Perform SHA-512 hash operation * // Perform SHA-512 hash operation
* String sha512Hash = HashUtil.sha512("someString"); * String sha512Hash = HashUtil.sha512("someString");
* </pre> * </pre>
* The above examples demonstrate how to use the HashUtil class to calculate * The above examples demonstrate how to use the {@code HashUtil} class to
* hash values for a given string using different algorithms. * calculate hash values for a given string using different algorithms.
*
* <p> * <p>
* <b>Note:</b> * <b>Note:</b>
* The hash functions provided by the HashUtil class are one-way hash * The hash functions provided by the HashUtil class are one-way hash
@@ -69,7 +63,7 @@ import java.util.Optional;
* password storage, but they should not be used for encryption purposes. * password storage, but they should not be used for encryption purposes.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.1.0
* @see java.security.MessageDigest * @see java.security.MessageDigest
* @since 1.0.0 * @since 1.0.0
*/ */
@@ -121,7 +115,7 @@ public final class HashUtil {
* Calculates the MD2 hash value of the specified string using the given * Calculates the MD2 hash value of the specified string using the given
* charset. * charset.
* *
* @param value the string to calculate the MD2 hash value for * @param value the string to calculate with the MD2 algorithm
* @param charset the charset to use for encoding the string (default is * @param charset the charset to use for encoding the string (default is
* UTF-8 if null) * UTF-8 if null)
* @return the MD2 hash value as a hexadecimal string * @return the MD2 hash value as a hexadecimal string
@@ -135,7 +129,7 @@ public final class HashUtil {
* Calculates the MD2 hash value of the specified string using the UTF-8 * Calculates the MD2 hash value of the specified string using the UTF-8
* charset. * charset.
* *
* @param value the string to calculate the MD2 hash value for * @param value the string to calculate with the MD2 algorithm
* @return the MD2 hash value as a hexadecimal string * @return the MD2 hash value as a hexadecimal string
*/ */
public static String md2(String value) { public static String md2(String value) {
@@ -146,7 +140,7 @@ public final class HashUtil {
* Calculates the MD5 hash value of the specified string using the given * Calculates the MD5 hash value of the specified string using the given
* charset. * charset.
* *
* @param value the string to calculate the MD5 hash value for * @param value the string to calculate with the MD5 algorithm
* @param charset the charset to use for encoding the string (default is * @param charset the charset to use for encoding the string (default is
* UTF-8 if null) * UTF-8 if null)
* @return the MD5 hash value as a hexadecimal string * @return the MD5 hash value as a hexadecimal string
@@ -160,7 +154,7 @@ public final class HashUtil {
* Calculates the MD5 hash value of the specified string using the UTF-8 * Calculates the MD5 hash value of the specified string using the UTF-8
* charset. * charset.
* *
* @param value the string to calculate the MD5 hash value for * @param value the string to calculate with the MD5 algorithm
* @return the MD5 hash value as a hexadecimal string * @return the MD5 hash value as a hexadecimal string
*/ */
public static String md5(String value) { public static String md5(String value) {
@@ -171,7 +165,7 @@ public final class HashUtil {
* Calculates the SHA-1 hash value of the specified string using the given * Calculates the SHA-1 hash value of the specified string using the given
* charset. * charset.
* *
* @param value the string to calculate the SHA-1 hash value for * @param value the string to calculate with the SHA-1 algorithm
* @param charset the charset to use for encoding the string (default is * @param charset the charset to use for encoding the string (default is
* UTF-8 if null) * UTF-8 if null)
* @return the SHA-1 hash value as a hexadecimal string * @return the SHA-1 hash value as a hexadecimal string
@@ -185,7 +179,7 @@ public final class HashUtil {
* Calculates the SHA-1 hash value of the specified string using the UTF-8 * Calculates the SHA-1 hash value of the specified string using the UTF-8
* charset. * charset.
* *
* @param value the string to calculate the SHA-1 hash value for * @param value the string to calculate with the SHA-1 algorithm
* @return the SHA-1 hash value as a hexadecimal string * @return the SHA-1 hash value as a hexadecimal string
*/ */
public static String sha1(String value) { public static String sha1(String value) {
@@ -196,7 +190,7 @@ public final class HashUtil {
* Calculates the SHA-224 hash value of the specified string using the * Calculates the SHA-224 hash value of the specified string using the
* given charset. * given charset.
* *
* @param value the string to calculate the SHA-224 hash value for * @param value the string to calculate with the SHA-225 algorithm
* @param charset the charset to use for encoding the string (default is * @param charset the charset to use for encoding the string (default is
* UTF-8 if null) * UTF-8 if null)
* @return the SHA-224 hash value as a hexadecimal string * @return the SHA-224 hash value as a hexadecimal string
@@ -210,7 +204,7 @@ public final class HashUtil {
* Calculates the SHA-224 hash value of the specified string using the * Calculates the SHA-224 hash value of the specified string using the
* UTF-8 charset. * UTF-8 charset.
* *
* @param value the string to calculate the SHA-224 hash value for * @param value the string to calculate with the SHA-224 algorithm
* @return the SHA-224 hash value as a hexadecimal string * @return the SHA-224 hash value as a hexadecimal string
*/ */
public static String sha224(String value) { public static String sha224(String value) {
@@ -221,7 +215,7 @@ public final class HashUtil {
* Calculates the SHA-256 hash value of the specified string using the * Calculates the SHA-256 hash value of the specified string using the
* given charset. * given charset.
* *
* @param value the string to calculate the SHA-256 hash value for * @param value the string to calculate with the SHA-256 algorithm
* @param charset the charset to use for encoding the string (default is * @param charset the charset to use for encoding the string (default is
* UTF-8 if null) * UTF-8 if null)
* @return the SHA-256 hash value as a hexadecimal string * @return the SHA-256 hash value as a hexadecimal string
@@ -235,7 +229,7 @@ public final class HashUtil {
* Calculates the SHA-256 hash value of the specified string using the * Calculates the SHA-256 hash value of the specified string using the
* UTF-8 charset. * UTF-8 charset.
* *
* @param value the string to calculate the SHA-256 hash value for * @param value the string to calculate with the SHA-256 algorithm
* @return the SHA-256 hash value as a hexadecimal string * @return the SHA-256 hash value as a hexadecimal string
*/ */
public static String sha256(String value) { public static String sha256(String value) {
@@ -246,7 +240,7 @@ public final class HashUtil {
* Calculates the SHA-384 hash value of the specified string using the * Calculates the SHA-384 hash value of the specified string using the
* given charset. * given charset.
* *
* @param value the string to calculate the SHA-384 hash value for * @param value the string to calculate with the SHA-384 algorithm
* @param charset the charset to use for encoding the string (default is * @param charset the charset to use for encoding the string (default is
* UTF-8 if null) * UTF-8 if null)
* @return the SHA-384 hash value as a hexadecimal string * @return the SHA-384 hash value as a hexadecimal string
@@ -260,7 +254,7 @@ public final class HashUtil {
* Calculates the SHA-384 hash value of the specified string using the * Calculates the SHA-384 hash value of the specified string using the
* UTF-8 charset. * UTF-8 charset.
* *
* @param value the string to calculate the SHA-384 hash value for * @param value the string to calculate with the SHA-384 algorithm
* @return the SHA-384 hash value as a hexadecimal string * @return the SHA-384 hash value as a hexadecimal string
*/ */
public static String sha384(String value) { public static String sha384(String value) {
@@ -271,7 +265,7 @@ public final class HashUtil {
* Calculates the SHA-512 hash value of the specified string using the * Calculates the SHA-512 hash value of the specified string using the
* given charset. * given charset.
* *
* @param value the string to calculate the SHA-384 hash value for * @param value the string to calculate with the SHA-512 algorithm
* @param charset the charset to use for encoding the string (default is * @param charset the charset to use for encoding the string (default is
* UTF-8 if null) * UTF-8 if null)
* @return the SHA-512 hash value as a hexadecimal string * @return the SHA-512 hash value as a hexadecimal string
@@ -285,7 +279,7 @@ public final class HashUtil {
* Calculates the SHA-512 hash value of the specified string using the * Calculates the SHA-512 hash value of the specified string using the
* UTF-8 charset. * UTF-8 charset.
* *
* @param value the string to calculate the SHA-384 hash value for * @param value the string to calculate with the SHA-512 algorithm
* @return the SHA-512 hash value as a hexadecimal string * @return the SHA-512 hash value as a hexadecimal string
*/ */
public static String sha512(String value) { public static String sha512(String value) {
@@ -24,17 +24,15 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* <p> * {@code MapUtil} is a utility class that provides methods for converting
* MapUtil is a utility class that provides methods for converting objects to * objects to maps and maps to objects.
* maps and maps to objects.
*
* <p> * <p>
* It also provides methods for getting and setting field values using * It also provides methods for getting and setting field values using
* reflection. * reflection.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.1.0
* @since 16 Jul 2023 * @since 1.0.0
*/ */
@Slf4j @Slf4j
public final class MapUtil { public final class MapUtil {
@@ -180,6 +178,22 @@ public final class MapUtil {
method.invoke(obj, fieldValue); method.invoke(obj, fieldValue);
} }
/**
* Casts the specified value to the required type.
*
* @param value the value to be cast
* @param requiredType the type to which the value should be cast
* @param <T> the type to which the value should be cast
* @return the cast value, or null if the value cannot be cast to the
* required type
*/
public static <T> T cast(Object value, Class<T> requiredType) {
if (requiredType.isInstance(value)) {
return requiredType.cast(value);
}
return null;
}
/** /**
* Constructs a method name based on the given prefix and field name. * Constructs a method name based on the given prefix and field name.
* *
@@ -205,20 +219,4 @@ public final class MapUtil {
return String.valueOf(obj); return String.valueOf(obj);
} }
} }
/**
* Casts the specified value to the required type.
*
* @param value the value to be casted
* @param requiredType the type to which the value should be casted
* @param <T> the type to which the value should be casted
* @return the casted value, or null if the value cannot be casted to the
* required type
*/
public static <T> T cast(Object value, Class<T> requiredType) {
if (requiredType.isInstance(value)) {
return requiredType.cast(value);
}
return null;
}
} }
+1 -1
View File
@@ -23,7 +23,7 @@
<parent> <parent>
<groupId>cn.org.codecrafters</groupId> <groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId> <artifactId>jdevkit</artifactId>
<version>1.0.1</version> <version>1.1.0</version>
</parent> </parent>
<artifactId>guid</artifactId> <artifactId>guid</artifactId>
@@ -18,17 +18,14 @@
package cn.org.codecrafters.guid; package cn.org.codecrafters.guid;
/** /**
* <p>
* The {@code GuidCreator} is a generic interface for generating globally unique * The {@code GuidCreator} is a generic interface for generating globally unique
* identifiers (GUIDs) of a specific type. * identifiers (GUIDs) of a specific type.
*
* <p> * <p>
* The type of ID is determined by the class implementing this interface. * The type of ID is determined by the class implementing this interface.
* *
*
* @param <IdType> this represents the type of the Global Unique Identifier * @param <IdType> this represents the type of the Global Unique Identifier
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.1.0
* @since 1.0.0 * @since 1.0.0
*/ */
public interface GuidCreator<IdType> { public interface GuidCreator<IdType> {
@@ -20,35 +20,31 @@ package cn.org.codecrafters.guid;
import cn.org.codecrafters.guid.exceptions.TimingException; import cn.org.codecrafters.guid.exceptions.TimingException;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset; import java.time.ZoneOffset;
/** /**
* <p> * The {@code SnowflakeGuidCreator} generates unique identifiers using the
* SnowflakeGuidCreator - GUID generator based on the Snowflake algorithm. * Snowflake algorithm, which combines a timestamp, worker ID, and data centre
* * ID to create 64-bit long integers. The bit distribution for the generated
* <p> * IDs is as follows:
* The SnowflakeGuidCreator generates unique identifiers using the Snowflake
* algorithm, which combines a timestamp, worker ID, and data center ID to
* create 64-bit long integers. The bit distribution for the generated IDs is
* as follows:
* <ul> * <ul>
* <li>1 bit for sign</li> * <li>1 bit for sign</li>
* <li>41 bits for timestamp (in milliseconds)</li> * <li>41 bits for timestamp (in milliseconds)</li>
* <li>5 bits for data center ID</li> * <li>5 bits for data centre ID</li>
* <li>5 bits for worker ID</li> * <li>5 bits for worker ID</li>
* <li>12 bits for sequence number (per millisecond)</li> * <li>12 bits for sequence number (per millisecond)</li>
* </ul> * </ul>
*
* <p> * <p>
* When initializing the SnowflakeGuidCreator, you must provide the worker ID * When initializing a {@link SnowflakeGuidCreator}, you must provide the
* and data center ID, ensuring they are within the valid range defined by the * worker ID and data centre ID, ensuring they are within the valid range
* bit size. The generator maintains an internal sequence number that * defined by the bit size. The generator maintains an internal sequence number
* increments for IDs generated within the same millisecond. If the system * that increments for IDs generated within the same millisecond. If the system
* clock moves backward, an exception is thrown to prevent generating IDs with * clock moves backward, an exception is thrown to prevent generating IDs with
* repeated timestamps. * repeated timestamps.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.1.0
* @since 1.0.0 * @since 1.0.0
*/ */
public final class SnowflakeGuidCreator implements GuidCreator<Long> { public final class SnowflakeGuidCreator implements GuidCreator<Long> {
@@ -71,7 +67,7 @@ public final class SnowflakeGuidCreator implements GuidCreator<Long> {
private final long workerIdBits = 5L; private final long workerIdBits = 5L;
/** /**
* The number of bits reserved for the data center ID. * The number of bits reserved for the data centre ID.
*/ */
private final long dataCentreIdBits = 5L; private final long dataCentreIdBits = 5L;
@@ -81,7 +77,7 @@ public final class SnowflakeGuidCreator implements GuidCreator<Long> {
private final long workerId; private final long workerId;
/** /**
* The data center ID assigned to this generator. * The data centre ID assigned to this generator.
*/ */
private final long dataCentreId; private final long dataCentreId;
@@ -97,28 +93,28 @@ public final class SnowflakeGuidCreator implements GuidCreator<Long> {
/** /**
* Constructs a SnowflakeGuidGenerator with the default start epoch and * Constructs a SnowflakeGuidGenerator with the default start epoch and
* custom worker ID, data center ID. * custom worker ID, data centre ID.
* *
* @param workerId the worker ID (between 0 and 31). * @param dataCentreId the data centre ID (between 0 and 31)
* @param dataCentreId the data center ID (between 0 and 31). * @param workerId the worker ID (between 0 and 31)
*/ */
public SnowflakeGuidCreator(long workerId, long dataCentreId) { public SnowflakeGuidCreator(long dataCentreId, long workerId) {
this(workerId, dataCentreId, DEFAULT_CUSTOM_EPOCH); this(dataCentreId, workerId, DEFAULT_CUSTOM_EPOCH);
} }
/** /**
* Constructs a SnowflakeGuidGenerator with a custom epoch, worker ID, and * Constructs a SnowflakeGuidGenerator with a custom epoch, worker ID, and
* data center ID. * data centre ID.
* *
* @param dataCentreId the data centre ID (between 0 and 31)
* @param workerId the worker ID (between 0 and 31)
* @param startEpoch the custom epoch timestamp (in milliseconds) to * @param startEpoch the custom epoch timestamp (in milliseconds) to
* start generating IDs from * start generating IDs from
* @param workerId the worker ID (between 0 and 31)
* @param dataCentreId the data center ID (between 0 and 31)
* @throws IllegalArgumentException if the start epoch is greater than the * @throws IllegalArgumentException if the start epoch is greater than the
* current timestamp, or if the worker ID * current timestamp, or if the worker ID
* or data center ID is out of range * or data centre ID is out of range
*/ */
public SnowflakeGuidCreator(long workerId, long dataCentreId, long startEpoch) { public SnowflakeGuidCreator(long dataCentreId, long workerId, long startEpoch) {
if (startEpoch > currentTimestamp()) { if (startEpoch > currentTimestamp()) {
throw new IllegalArgumentException("Start Epoch can not be greater than current timestamp!"); throw new IllegalArgumentException("Start Epoch can not be greater than current timestamp!");
} }
@@ -206,7 +202,7 @@ public final class SnowflakeGuidCreator implements GuidCreator<Long> {
* @return the current timestamp * @return the current timestamp
*/ */
private long currentTimestamp() { private long currentTimestamp() {
return LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli(); return LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
} }
} }
@@ -18,28 +18,14 @@
package cn.org.codecrafters.guid.exceptions; package cn.org.codecrafters.guid.exceptions;
/** /**
* <p> * The {@code TimingException} class represents an exception that is thrown
* The TimingException class represents an exception that is thrown when there * when there is an error related to time sequence.
* is an error related to time sequence.
*
* <p>
* This class extends the RuntimeException class, which means that instances of
* TimingException do not need to be declared in a method or constructor's
* throws clause.
*
* <p> * <p>
* Instances of TimingException can be created with or without a message and a * Instances of TimingException can be created with or without a message and a
* cause. The message provides a description of the exception, while the cause * cause. The message provides a description of the exception, while the cause
* represents the underlying cause of the exception and provides additional * represents the underlying cause of the exception and provides additional
* information about the error. * information about the error.
* *
* <p>
* TimingException is typically used to handle exceptions related to timing,
* such as timeouts or synchronization issues. It is a subclass of
* RuntimeException, which means it is an unchecked exception and does not need
* to be caught or declared.
*
*
* @author Zihlu Wang * @author Zihlu Wang
* @since 1.0.0 * @since 1.0.0
*/ */
@@ -54,9 +40,9 @@ public class TimingException extends RuntimeException {
/** /**
* A custom exception that is thrown when there is an issue with timing or * A custom exception that is thrown when there is an issue with timing or
* scheduling with customized error message. * scheduling with customised error message.
* *
* @param message customized message * @param message customised message
*/ */
public TimingException(String message) { public TimingException(String message) {
super(message); super(message);
@@ -64,9 +50,9 @@ public class TimingException extends RuntimeException {
/** /**
* A custom exception that is thrown when there is an issue with timing or * A custom exception that is thrown when there is an issue with timing or
* scheduling with customized error message. * scheduling with customised error message.
* *
* @param message customized message * @param message customised message
* @param cause the cause of this exception * @param cause the cause of this exception
*/ */
public TimingException(String message, Throwable cause) { public TimingException(String message, Throwable cause) {
@@ -75,7 +61,7 @@ public class TimingException extends RuntimeException {
/** /**
* A custom exception that is thrown when there is an issue with timing or * A custom exception that is thrown when there is an issue with timing or
* scheduling with customized error message. * scheduling with customised error message.
* *
* @param cause the cause of this exception * @param cause the cause of this exception
*/ */
@@ -16,17 +16,14 @@
*/ */
/** /**
* <p>
* This package contains the custom exception classes related to GUID * This package contains the custom exception classes related to GUID
* generation. These exceptions are thrown when there are issues or errors * generation. These exceptions are thrown when there are issues or errors
* during the generation or processing of global unique identifiers (GUIDs). * during the generation or processing of global unique identifiers (GUIDs).
*
* <p> * <p>
* The main exception class in this package is {@link * The main exception class in this package is {@link
* cn.org.codecrafters.guid.exceptions.TimingException}, which is a runtime * cn.org.codecrafters.guid.exceptions.TimingException}, which is a runtime
* exception and serves as the base exception for all other custom exceptions * exception and serves as the base exception for all other custom exceptions
* related to GUID generation. * related to GUID generation.
*
* <p> * <p>
* Custom exceptions in this package provide specific information about the * Custom exceptions in this package provide specific information about the
* type of error that occurred during GUID generation, making it easier for * type of error that occurred during GUID generation, making it easier for
@@ -34,7 +31,6 @@
* GUIDs. They are designed to enhance the robustness and reliability of the * GUIDs. They are designed to enhance the robustness and reliability of the
* GUID generation process by providing clear and meaningful error messages to * GUID generation process by providing clear and meaningful error messages to
* the developers. * the developers.
*
* <p> * <p>
* Developers using the GUID generation module should be aware of the possible * Developers using the GUID generation module should be aware of the possible
* exceptions that can be thrown and handle them appropriately to ensure smooth * exceptions that can be thrown and handle them appropriately to ensure smooth
@@ -16,15 +16,12 @@
*/ */
/** /**
* <p>
* The package provides a set of tools for generating globally unique * The package provides a set of tools for generating globally unique
* identifiers (GUIDs). * identifiers (GUIDs).
*
* <p> * <p>
* The goal of this library is to provide an efficient, reliable way to * The goal of this library is to provide an efficient, reliable way to
* generate globally unique identifiers without requiring any specific * generate globally unique identifiers without requiring any specific
* environment or configuration. * environment or configuration.
*
* <p> * <p>
* Key features include: * Key features include:
* <ul> * <ul>
+2 -1
View File
@@ -29,7 +29,7 @@
<groupId>cn.org.codecrafters</groupId> <groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId> <artifactId>jdevkit</artifactId>
<version>1.0.1</version> <version>1.1.0</version>
<inceptionYear>2023</inceptionYear> <inceptionYear>2023</inceptionYear>
<packaging>pom</packaging> <packaging>pom</packaging>
@@ -42,6 +42,7 @@
<module>simple-jwt-authzero</module> <module>simple-jwt-authzero</module>
<module>simple-jwt-jjwt</module> <module>simple-jwt-jjwt</module>
<module>simple-jwt-spring-boot-starter</module> <module>simple-jwt-spring-boot-starter</module>
<module>property-guard-spring-boot-starter</module>
</modules> </modules>
<organization> <organization>
@@ -0,0 +1,97 @@
# Property Guard
## Introduction
This feature is designed to protect the security of configurations and data, to a certain extent, to control the flow of developers leading to the leakage of sensitive information.
## Prerequisites
This whole `JDevKit` is developed by **JDK 17**, which means you have to use JDK 17 for better experience. Except this, this module is designed for Spring Boot framework, so you have to install Spring Boot (v3) in your application.
## Installation
### If you are using `Maven`
It is quite simple to install this module by `Maven`. The only thing you need to do is find your `pom.xml` file in the project, then find the `<dependencies>` node in the `<project>` node, and add the following codes to `<dependencies>` node:
```xml
<dependency>
<groupId>cn.org.codecrafters</groupId>
<artifactId>property-guard-spring-boot-starter</artifactId>
<version>${property-guard-spring-boot-starter.version}</version>
</dependency>
```
And run `mvn dependency:get` in your project root folder(i.e., if your `pom.xml` is located at `/path/to/your/project/pom.xml`, then your current work folder should be `/path/to/your/project`), then `Maven` will automatically download the `jar` archive from `Maven Central Repository`. This could be **MUCH EASIER** if you are using IDE(i.e., IntelliJ IDEA), the only thing you need to do is click the refresh button of `Maven`.
If you are restricted using the Internet, and have to make `Maven` offline, you could follow the following steps.
1. Download the `jar` file from any place you can get and transfer the `jar` files to your work computer.
2. Move the `jar` files to your local `Maven` Repository as the path of `/path/to/maven_local_repo/cn/org/codecrafters/property-guard-spring-boot-starter/`.
### If you are using `Gradle`
Add this module to your project with `Gradle` is much easier than doing so with `Maven`.
Find `build.gradle` in the needed project, and add the following code to the `dependencies` closure in the build script:
```groovy
implementation 'cn.org.codecrafters:property-guard-spring-boot-starter:${property-guard-spring-boot-starter.version}'
```
### If you are not using `Maven` or `Gradle`
1. Download the `jar` file from the Internet.
2. Create a folder in your project and name it as a name you like(i.e., for me, I prefer `vendor`).
3. Put the `jar` file to the folder you just created in Step 2.
4. Add this folder to your project `classpath`.
## Usage
First, you need a 16-bit-long secret. If you don't have a good way to get a secret, you could consider using our `cn.org.codecrafters.devkit.utils.AesUtil` or `cn.org.codecrafters.simplejwt.SecretCreator` to create a secret.
For example:
```java
import cn.org.codecrafters.devkit.utils.AesUtil;
import cn.org.codecrafters.simplejwt.SecretCreator;
class GenerateRandomKeySample {
public static void main(String[] args) {
var secret1 = AesUtil.generateRandomSecret();
var secret2 = SecretCreator.createSecret(16, true, true, true);
}
}
```
Then, remember this secret and encrypt the configuration properties that are required high security. For example:
```java
import cn.org.codecrafters.devkit.utils.AesUtil;
class EncryptSample {
public static void main(String[] args) {
var dataNeedEncryption = "Sample Value";
var key = "3856faef0d2d4f33";
var encryptedData = AesUtil.encrypt(dataNeedEncryption, key);
}
}
```
After that, copy the encrypted data to `application.properties` or `application.yml`.
For `yml`:
```yaml
app:
sample-configuration: pe:t4YBfv8M9ZmTzWgTi2gJqg== # "pe:" is the prefix that declare that this property is encrypted.
```
For `properties`:
```properties
app.sample-configuration=pe:t4YBfv8M9ZmTzWgTi2gJqg==
```
## Contact
If you have any suggestions, ideas, don't hesitate contacting us via [GitHub Issues](https://github.com/CodeCraftersCN/jdevkit/issues/new) or [Discord Community](https://discord.gg/NQK9tjcBB8).
If you face any bugs while using our library and you are able to fix any bugs in our library, we would be happy to accept pull requests from you on [GitHub](https://github.com/CodeCraftersCN/jdevkit/compare).
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (C) 2023 CodeCraftersCN.
~
~ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId>
<version>1.1.0</version>
</parent>
<artifactId>property-guard-spring-boot-starter</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>cn.org.codecrafters</groupId>
<artifactId>devkit-utils</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,111 @@
/*
* Copyright (C) 2023 CodeCraftersCN.
*
* 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 cn.org.codecrafters.propertyguard.autoconfiguration;
import cn.org.codecrafters.devkit.utils.AesUtil;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import java.util.HashMap;
import java.util.Optional;
/**
* {@code PropertyGuard} is a utility class designed for encrypting
* configuration properties in Spring Boot applications.
* <p>
* Spring Boot applications often need to store sensitive configuration details
* such as database passwords, API keys, etc. To ensure that these sensitive
* pieces of information are not exposed to the public, developers can utilize
* the {@code PropertyGuard} class to encrypt and store them within
* configuration files.
* <p>
* <b>Usage</b>
* You need a 16-char long secret for encrypting a configuration property. You
* can get this secret on your own, or use the helper utility class by the
* following code:
* <pre>{@code
* var secret = AesUtil.generateRandomSecret(); // Let's presume the result is
* // "3856faef0d2d4f33"
* }</pre>
* <p>
* Then, in {@code application.yml} or {@code application.properties}, change
* the original value from plain text to encrypted value with the prefix
* "<code>pg:</code>".
* <pre>
* # original
* app.example-properties=Sample Value
*
* # encrypted with key 3856faef0d2d4f33
* app.example-properties=pg:t4YBfv8M9ZmTzWgTi2gJqg==
* </pre>
* After that, before running, you need to add the command line arguments
* "pg.key" as the following codes: {@code --pg.key=<the secret>}.
* <p>
* This class is extracted from <a href="https://baomidou.com/pages/e0a5ce/"
* >MyBatis-Plus</a>.
*
* @author hubin@baomidou
* @version 1.1.0
* @see EnvironmentPostProcessor
* @since 1.1.0 (3.3.2 of MyBatis-Plus)
*/
public class PropertyGuard implements EnvironmentPostProcessor {
private final String PREFIX = "pg";
/**
* Process the encryption environment variables.
*
* @param environment the environment to post-process
* @param application the application to which the environment belongs
*/
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
// Get the key for encryption from command line.
var encryptionKey = "";
for (var ps : environment.getPropertySources()) {
if (ps instanceof SimpleCommandLinePropertySource source) {
encryptionKey = source.getProperty("%s.key".formatted(PREFIX));
break;
}
}
if (Optional.ofNullable(encryptionKey).map((key) -> !key.isEmpty()).orElse(false)) {
var map = new HashMap<String, Object>();
for (var propertySources : environment.getPropertySources()) {
if (propertySources instanceof OriginTrackedMapPropertySource source) {
for (var name : source.getPropertyNames()) {
if (source.getProperty(name) instanceof String str) {
if (str.startsWith("%s:".formatted(PREFIX))) {
map.put(name, AesUtil.decrypt(str.substring(3), encryptionKey));
}
}
}
}
}
// Put the decrypted data into environment variables, and made them at top-level.
if (!map.isEmpty()) {
environment.getPropertySources().addFirst(new MapPropertySource("custom-encrypt", map));
}
}
}
}
@@ -0,0 +1 @@
org.springframework.boot.env.EnvironmentPostProcessor=cn.org.codecrafters.propertyguard.autoconfiguration.PropertyGuard
+1 -1
View File
@@ -23,7 +23,7 @@
<parent> <parent>
<groupId>cn.org.codecrafters</groupId> <groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId> <artifactId>jdevkit</artifactId>
<version>1.0.1</version> <version>1.1.0</version>
</parent> </parent>
<artifactId>simple-jwt-authzero</artifactId> <artifactId>simple-jwt-authzero</artifactId>
@@ -39,19 +39,16 @@ import java.time.ZoneId;
import java.util.*; import java.util.*;
/** /**
* <p>
* The {@code AuthzeroTokenResolver} class is an implementation of the {@link * The {@code AuthzeroTokenResolver} class is an implementation of the {@link
* cn.org.codecrafters.simplejwt.TokenResolver} interface. It uses the {@code * cn.org.codecrafters.simplejwt.TokenResolver} interface. It uses the {@code
* com.auth0:java-jwt} library to handle JSON Web Token (JWT) resolution. This * com.auth0:java-jwt} library to handle JSON Web Token (JWT) resolution. This
* resolver provides functionality to create, extract, verify, and renew JWT * resolver provides functionality to create, extract, verify, and renew JWT
* tokens using various algorithms and custom payload data. * tokens using various algorithms and custom payload data.
*
* <p> * <p>
* <b>Dependencies:</b> * <b>Dependencies:</b>
* This implementation relies on the {@code com.auth0:java-jwt} library. Please * This implementation relies on the {@code com.auth0:java-jwt} library. Please
* ensure you have added this library as a dependency to your project before * ensure you have added this library as a dependency to your project before
* using this resolver. * using this resolver.
*
* <p> * <p>
* <b>Usage:</b> * <b>Usage:</b>
* To use the {@code AuthzeroTokenResolver}, first, create an instance of this * To use the {@code AuthzeroTokenResolver}, first, create an instance of this
@@ -63,11 +60,9 @@ import java.util.*;
* "Token Issuer", * "Token Issuer",
* "Token Secret"); * "Token Secret");
* }</pre> * }</pre>
*
* <p> * <p>
* Then, you can utilize the various methods provided by this resolver to * Then, you can utilize the various methods provided by this resolver to
* handle JWT tokens: * handle JWT tokens:
*
* <pre>{@code * <pre>{@code
* // Creating a new JWT token * // Creating a new JWT token
* String token = * String token =
@@ -84,7 +79,6 @@ import java.util.*;
* String renewedToken = * String renewedToken =
* tokenResolver.renew(token, Duration.ofMinutes(30), customPayloads); * tokenResolver.renew(token, Duration.ofMinutes(30), customPayloads);
* }</pre> * }</pre>
*
* <p> * <p>
* <b>Note:</b> * <b>Note:</b>
* It is essential to configure the appropriate algorithms, secret, and issuer * It is essential to configure the appropriate algorithms, secret, and issuer
@@ -93,7 +87,7 @@ import java.util.*;
* correctly configured in your project's dependencies. * correctly configured in your project's dependencies.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.1.0
* @see GuidCreator * @see GuidCreator
* @see Algorithm * @see Algorithm
* @see JWTVerifier * @see JWTVerifier
@@ -128,11 +122,11 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
private final AuthzeroTokenResolverConfig config = AuthzeroTokenResolverConfig.getInstance(); private final AuthzeroTokenResolverConfig config = AuthzeroTokenResolverConfig.getInstance();
/** /**
* Creates a new instance of AuthzeroTokenResolver with the provided * Creates a new instance of {@code AuthzeroTokenResolver} with the
* configurations. * provided configurations.
* *
* @param jtiCreator the GuidCreator used for generating unique identifiers * @param jtiCreator the {@link GuidCreator} used for generating unique
* for "jti" claim in JWT tokens * identifiers for "jti" claim in JWT tokens
* @param algorithm the algorithm used for signing and verifying JWT * @param algorithm the algorithm used for signing and verifying JWT
* tokens * tokens
* @param issuer the issuer claim value to be included in JWT tokens * @param issuer the issuer claim value to be included in JWT tokens
@@ -157,8 +151,8 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
} }
/** /**
* Creates a new instance of AuthzeroTokenResolver with the provided * Creates a new instance of {@link AuthzeroTokenResolver} with the
* configurations and a simple UUID GuidCreator. * provided configurations and a simple UUID GuidCreator.
* *
* @param algorithm the algorithm used for signing and verifying JWT tokens * @param algorithm the algorithm used for signing and verifying JWT tokens
* @param issuer the issuer claim value to be included in JWT tokens * @param issuer the issuer claim value to be included in JWT tokens
@@ -174,7 +168,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
log.warn("The provided secret which owns {} characters is too weak. Please consider replacing it with a stronger one.", secret.length()); log.warn("The provided secret which owns {} characters is too weak. Please consider replacing it with a stronger one.", secret.length());
} }
this.jtiCreator = (GuidCreator<UUID>) UUID::randomUUID; this.jtiCreator = UUID::randomUUID;
this.algorithm = config this.algorithm = config
.getAlgorithm(algorithm) .getAlgorithm(algorithm)
.apply(secret); .apply(secret);
@@ -183,8 +177,9 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
} }
/** /**
* Creates a new instance of AuthzeroTokenResolver with the provided * Creates a new instance of {@link AuthzeroTokenResolver} with the
* configurations, HMAC256 algorithm and a simple UUID GuidCreator. * provided configurations, HMAC256 algorithm and a simple
* UUID GuidCreator.
* *
* @param issuer the issuer claim value to be included in JWT tokens * @param issuer the issuer claim value to be included in JWT tokens
* @param secret the secret used for HMAC-based algorithms (HS256, * @param secret the secret used for HMAC-based algorithms (HS256,
@@ -199,7 +194,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
log.warn("The provided secret which owns {} characters is too weak. Please consider replacing it with a stronger one.", secret.length()); log.warn("The provided secret which owns {} characters is too weak. Please consider replacing it with a stronger one.", secret.length());
} }
this.jtiCreator = (GuidCreator<UUID>) UUID::randomUUID; this.jtiCreator = UUID::randomUUID;
this.algorithm = config this.algorithm = config
.getAlgorithm(TokenAlgorithm.HS256) .getAlgorithm(TokenAlgorithm.HS256)
.apply(secret); .apply(secret);
@@ -208,15 +203,16 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
} }
/** /**
* Creates a new instance of AuthzeroTokenResolver with the provided * Creates a new instance of {@link AuthzeroTokenResolver} with the
* configurations, HMAC256 algorithm and a simple UUID GuidCreator. * provided configurations, HMAC256 algorithm and a simple
* UUID GuidCreator.
* *
* @param issuer the issuer claim value to be included in JWT tokens * @param issuer the issuer claim value to be included in JWT tokens
*/ */
public AuthzeroTokenResolver(String issuer) { public AuthzeroTokenResolver(String issuer) {
var secret = SecretCreator.createSecret(32, true, true, true); var secret = SecretCreator.createSecret(32, true, true, true);
this.jtiCreator = (GuidCreator<UUID>) UUID::randomUUID; this.jtiCreator = UUID::randomUUID;
this.algorithm = config this.algorithm = config
.getAlgorithm(TokenAlgorithm.HS256) .getAlgorithm(TokenAlgorithm.HS256)
.apply(secret); .apply(secret);
@@ -283,8 +279,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
builder.withClaim(name, v); builder.withClaim(name, v);
} else { } else {
log.warn(""" log.warn("""
Unable to determine the type of field {}, converting it to a string now. Unable to determine the type of field {}, converting it to a string now.""", name);
""", name);
builder.withClaim(name, value.toString()); builder.withClaim(name, value.toString());
} }
} else { } else {
@@ -293,16 +288,13 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
} }
/** /**
* <p>
* Builds the custom claims of the JSON Web Token (JWT) using the provided * Builds the custom claims of the JSON Web Token (JWT) using the provided
* Map of claims and adds them to the JWTCreator.Builder. * Map of claims and adds them to the JWTCreator.Builder.
* <p> * <p>
* <p>
* This method is used to add custom claims to the JWT. It takes a Map of * This method is used to add custom claims to the JWT. It takes a Map of
* claims, where each entry represents a custom claim name (key) and its * claims, where each entry represents a custom claim name (key) and its
* corresponding value (value). The custom claims will be added to the JWT * corresponding value (value). The custom claims will be added to the JWT
* using the JWTCreator.Builder. * using the JWTCreator.Builder.
* <p>
* *
* @param claims a Map containing the custom claims to be added to the JWT * @param claims a Map containing the custom claims to be added to the JWT
* @param builder the JWTCreator.Builder instance to which the custom * @param builder the JWTCreator.Builder instance to which the custom
@@ -317,9 +309,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
} }
/** /**
* <p>
* Finish creating a token. * Finish creating a token.
*
* <p> * <p>
* This is the final step of create a token, to sign this token. * This is the final step of create a token, to sign this token.
* *
@@ -331,7 +321,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
} }
/** /**
* Creates a new token with the specified expiration time, subject, and * Creates a new token with the specified expiration duration, subject, and
* audience. * audience.
* *
* @param expireAfter the duration after which the token will expire * @param expireAfter the duration after which the token will expire
@@ -394,7 +384,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
// Build Claims // Build Claims
addClaim(builder, field.getName(), field.get(payload)); addClaim(builder, field.getName(), field.get(payload));
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
log.error("Cannot access field %s!".formatted(field.getName())); log.error("Cannot access field {}!", field.getName());
} }
} }
@@ -402,10 +392,10 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
} }
/** /**
* Resolves the given token into a DecodedJWT object. * Resolves the given token into a {@link DecodedJWT} object.
* *
* @param token the token to be resolved * @param token the token to be resolved
* @return a ResolvedToken object * @return a {@link DecodedJWT} object
*/ */
@Override @Override
public DecodedJWT resolve(String token) { public DecodedJWT resolve(String token) {
@@ -456,9 +446,9 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
return bean; return bean;
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
log.error("Unable to find a no-argument constructor declaration for class %s.".formatted(targetType.getCanonicalName())); log.error("Unable to find a no-argument constructor declaration for class {}.", targetType.getCanonicalName());
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
log.error("Unable to create a new instance of class %s.".formatted(targetType.getCanonicalName())); log.error("Unable to create a new instance of class {}.", targetType.getCanonicalName());
} }
return null; return null;
} }
@@ -482,7 +472,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
/** /**
* Renews the given expired token with the specified custom payload data. * Renews the given expired token with the specified custom payload data.
* *
* @param oldToken the expired token to be renewed * @param oldToken the expiring token to be renewed
* @param payload the custom payload data to be included in the renewed * @param payload the custom payload data to be included in the renewed
* token * token
* @return the renewed token as a {@code String} * @return the renewed token as a {@code String}
@@ -496,7 +486,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
* Renews the given expired token with the new specified strongly-typed * Renews the given expired token with the new specified strongly-typed
* payload data. * payload data.
* *
* @param oldToken the expired token to be renewed * @param oldToken the expiring token to be renewed
* @param payload the strongly-typed payload data to be included in the * @param payload the strongly-typed payload data to be included in the
* renewed token * renewed token
* @return the renewed token as a {@code String} * @return the renewed token as a {@code String}
@@ -518,7 +508,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
* @param oldToken the expired token to be renewed * @param oldToken the expired token to be renewed
* @param payload the strongly-typed payload data to be included in the * @param payload the strongly-typed payload data to be included in the
* renewed token * renewed token
* @return the renewed token as a {@code String} * @return the renewed token as a {@link String}
*/ */
@Override @Override
public <T extends TokenPayload> String renew(String oldToken, T payload) { public <T extends TokenPayload> String renew(String oldToken, T payload) {
@@ -17,6 +17,8 @@
package cn.org.codecrafters.simplejwt.authzero.config; package cn.org.codecrafters.simplejwt.authzero.config;
import cn.org.codecrafters.simplejwt.TokenResolver;
import cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver;
import cn.org.codecrafters.simplejwt.config.TokenResolverConfig; import cn.org.codecrafters.simplejwt.config.TokenResolverConfig;
import cn.org.codecrafters.simplejwt.constants.TokenAlgorithm; import cn.org.codecrafters.simplejwt.constants.TokenAlgorithm;
import cn.org.codecrafters.simplejwt.exceptions.UnsupportedAlgorithmException; import cn.org.codecrafters.simplejwt.exceptions.UnsupportedAlgorithmException;
@@ -29,72 +31,65 @@ import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
/** /**
* The AuthzeroTokenResolverConfig class provides the configuration for the * The {@code AuthzeroTokenResolverConfig} class provides the configuration for
* AuthzeroTokenResolver. * the {@link AuthzeroTokenResolver}.
* <p> * <p>
* This configuration class is used to establish the mapping between the * This configuration is used to establish the mapping between the standard
* standard TokenAlgorithm defined within the AuthzeroTokenResolver facade and * {@link TokenAlgorithm} defined within the {@link AuthzeroTokenResolver}
* the specific algorithms used by the Auth0 Java JWT library, which is the * facade and the specific algorithms used by the {@code com.auth0:java-jwt}
* underlying library used by AuthzeroTokenResolver to handle JSON Web Tokens * library, which is the underlying library used by {@link
* (JWTs). * AuthzeroTokenResolver} to handle JSON Web Tokens (JWTs).
*
* <p> * <p>
* <b>Algorithm Mapping:</b> * <b>Algorithm Mapping:</b>
* The AuthzeroTokenResolverConfig class allows specifying the relationship * The {@code AuthzeroTokenResolverConfig} allows specifying the relationship
* between the standard TokenAlgorithm instances supported by * between the standard {@link TokenAlgorithm} instances supported by
* AuthzeroTokenResolver and the corresponding algorithms used by the * {@link AuthzeroTokenResolver} and the corresponding algorithms used by the
* com.auth0:java-jwt library. The mapping is achieved using a Map, where the * {@code com.auth0:java-jwt} library. The mapping is achieved using a Map,
* keys are the standard TokenAlgorithm instances, and the values represent the * where the keys are the standard TokenAlgorithm instances, and the values
* algorithm functions used by Auth0 Java JWT library for each corresponding * represent the algorithm functions used by Auth0 Java JWT library for each
* key. * corresponding key.
*
* <p> * <p>
* <b>Note:</b> * <b>Note:</b>
* The provided algorithm mapping should be consistent with the actual * The provided algorithm mapping should be consistent with the actual
* algorithms supported and used by the Auth0 Java JWT library. It is crucial * algorithms supported and used by the {@code com.auth0:java-jwt} library. It
* to ensure that the mapping is accurate to enable proper token validation * is crucial to ensure that the mapping is accurate to enable proper token
* and processing within the AuthzeroTokenResolver. * validation and processing within the {@link AuthzeroTokenResolver}.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.1.0
* @since 1.0.0 * @since 1.0.0
*/ */
public final class AuthzeroTokenResolverConfig implements TokenResolverConfig<Function<String, Algorithm>> { public final class AuthzeroTokenResolverConfig implements TokenResolverConfig<Function<String, Algorithm>> {
/** /**
* <p> * Constructs a new instance of {@code AuthzeroTokenResolverConfig}.
* Constructs a new instance of AuthzeroTokenResolverConfig.
*
* <p> * <p>
* The constructor is set as private to enforce the singleton pattern for * The constructor is set as private to enforce the singleton pattern for
* this configuration class. Instances of AuthzeroTokenResolverConfig * this configuration class. Instances of
* should be obtained through the {@link #getInstance()} method. * {@code AuthzeroTokenResolverConfig} should be obtained through the
* {@link #getInstance()} method.
*/ */
private AuthzeroTokenResolverConfig() { private AuthzeroTokenResolverConfig() {
} }
/** /**
* <p> * The singleton instance of {@code AuthzeroTokenResolverConfig}.
* The singleton instance of AuthzeroTokenResolverConfig.
*
* <p> * <p>
* This instance is used to ensure that only one instance of * This instance is used to ensure that only one instance of
* AuthzeroTokenResolverConfig is created and shared throughout the * {@code AuthzeroTokenResolverConfig} is created and shared throughout the
* application. The singleton pattern is implemented to provide centralized * application. The singleton pattern is implemented to provide centralised
* configuration and avoid redundant object creation. * configuration and avoid redundant object creation.
*/ */
private static AuthzeroTokenResolverConfig instance; private static AuthzeroTokenResolverConfig instance;
/** /**
* <p>
* The supported algorithms and their corresponding algorithm functions. * The supported algorithms and their corresponding algorithm functions.
*
* <p> * <p>
* This map stores the supported algorithms as keys and their corresponding * This map stores the supported algorithms as keys and their corresponding
* algorithm functions as values. The algorithm functions represent the * algorithm functions as values. The algorithm functions represent the
* functions used by the Auth0 Java JWT library to handle the specific * functions used by the {@code com.auth0:java-jwt} library to handle the
* algorithms. The mapping is used to provide proper algorithm resolution * specific algorithms. The mapping is used to provide proper algorithm
* and processing within the AuthzeroTokenResolver. * resolution and processing within the {@link AuthzeroTokenResolver}.
*/ */
private static final Map<TokenAlgorithm, Function<String, Algorithm>> SUPPORTED_ALGORITHMS = new HashMap<>() {{ private static final Map<TokenAlgorithm, Function<String, Algorithm>> SUPPORTED_ALGORITHMS = new HashMap<>() {{
put(TokenAlgorithm.HS256, Algorithm::HMAC256); put(TokenAlgorithm.HS256, Algorithm::HMAC256);
@@ -103,14 +98,14 @@ public final class AuthzeroTokenResolverConfig implements TokenResolverConfig<Fu
}}; }};
/** /**
* Gets the instance of AuthzeroTokenResolverConfig. * Gets the instance of {@code AuthzeroTokenResolverConfig}.
* <p> * <p>
* This method returns the singleton instance of * This method returns the singleton instance of
* AuthzeroTokenResolverConfig. If the instance is not yet created, it will * {@code AuthzeroTokenResolverConfig}. If the instance is not yet created,
* create a new instance and return it. Otherwise, it returns the existing * it will create a new instance and return it. Otherwise, it returns the
* instance. * existing instance.
* *
* @return the instance of AuthzeroTokenResolverConfig * @return the instance of {@code AuthzeroTokenResolverConfig}
*/ */
public static AuthzeroTokenResolverConfig getInstance() { public static AuthzeroTokenResolverConfig getInstance() {
if (Objects.isNull(instance)) { if (Objects.isNull(instance)) {
@@ -121,20 +116,20 @@ public final class AuthzeroTokenResolverConfig implements TokenResolverConfig<Fu
} }
/** /**
* <p>
* Gets the algorithm function corresponding to the specified * Gets the algorithm function corresponding to the specified
* TokenAlgorithm. * {@link TokenAlgorithm}.
*
* <p> * <p>
* This method returns the algorithm function associated with the given * This method returns the algorithm function associated with the given
* TokenAlgorithm. The provided TokenAlgorithm represents the specific * {@link TokenAlgorithm}. The provided {@link TokenAlgorithm} represents
* algorithm for which the corresponding algorithm function is required. * the specific algorithm for which the corresponding algorithm function
* The returned AlgorithmFunction represents the function implementation * is required. The returned Algorithm Function represents the function
* that can be used by the TokenResolver to handle the specific algorithm. * implementation that can be used by the {@link TokenResolver} to handle
* the specific algorithm.
* *
* @param algorithm the TokenAlgorithm for which the algorithm function is * @param algorithm the {@link TokenAlgorithm} for which the algorithm
* required * function isrequired
* @return the algorithm function associated with the given TokenAlgorithm * @return the algorithm function associated with the given {@link
* TokenAlgorithm}
* @throws UnsupportedAlgorithmException if the given {@code algorithm} is * @throws UnsupportedAlgorithmException if the given {@code algorithm} is
* not supported by this * not supported by this
* implementation * implementation
@@ -16,17 +16,14 @@
*/ */
/** /**
* <p>
* The package {@code cn.org.codecrafters.simplejwt.authzero.config} contains * The package {@code cn.org.codecrafters.simplejwt.authzero.config} contains
* configuration classes related to the {@link * configuration classes related to the {@link
* cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver} * cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver}
* implementation. * implementation.
*
* <p> * <p>
* The classes in this package provide configuration options and settings for * The classes in this package provide configuration options and settings for
* the {@link cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver}, * the {@link cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver},
* which is used for resolving JSON Web Tokens (JWT) using the Auth0 library. * which is used for resolving JSON Web Tokens (JWT) using the Auth0 library.
*
* <p> * <p>
* The {@link * The {@link
* cn.org.codecrafters.simplejwt.authzero.config.AuthzeroTokenResolverConfig} * cn.org.codecrafters.simplejwt.authzero.config.AuthzeroTokenResolverConfig}
@@ -37,7 +34,6 @@
* JWT algorithms. It enables developers to specify and customize the * JWT algorithms. It enables developers to specify and customize the
* algorithm functions according to the chosen JWT algorithm and the library * algorithm functions according to the chosen JWT algorithm and the library
* being used. * being used.
*
* <p> * <p>
* The configuration options in this package help developers integrate and * The configuration options in this package help developers integrate and
* configure the {@link * configure the {@link
@@ -45,13 +41,12 @@
* into their Spring Boot applications. Developers can fine-tune the token * into their Spring Boot applications. Developers can fine-tune the token
* resolution process and customize algorithm handling to align with their * resolution process and customize algorithm handling to align with their
* specific requirements and desired level of security. * specific requirements and desired level of security.
*
* <p> * <p>
* It is recommended to explore the classes in this package to understand how * It is recommended to explore the classes in this package to understand how
* to configure and use the {@link * to configure and use the {@link
* cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver} effectively * cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver} effectively
* in the Spring Boot environment to handle JWT authentication and * in the Spring Boot environment to handle JWT authentication and
* authorization securely and efficiently. * authorisation securely and efficiently.
* *
* @since 1.0.0 * @since 1.0.0
*/ */
@@ -19,11 +19,10 @@
* This package contains classes related to the integration of the {@code * This package contains classes related to the integration of the {@code
* com.auth0:java-jwt} library in the Simple JWT project. {@code * com.auth0:java-jwt} library in the Simple JWT project. {@code
* com.auth0:java-jwt} is a powerful and widely-used Identity as a Service * com.auth0:java-jwt} is a powerful and widely-used Identity as a Service
* (IDaaS) platform that provides secure authentication and authorization * (IDaaS) platform that provides secure authentication and authorisation
* solutions for web and mobile applications. The classes in this package * solutions for web and mobile applications. The classes in this package
* provide the necessary functionality to handle JSON Web Tokens (JWTs) using * provide the necessary functionality to handle JSON Web Tokens (JWTs) using
* the {@code com.auth0:java-jwt} library. * the {@code com.auth0:java-jwt} library.
*
* <p> * <p>
* The main class in this package is the {@link * The main class in this package is the {@link
* cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver}, which * cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver}, which
@@ -33,22 +32,22 @@
* {@code com.auth0:java-jwt} library. Developers can use this class as the * {@code com.auth0:java-jwt} library. Developers can use this class as the
* main token resolver in the Simple JWT project when integrating {@code * main token resolver in the Simple JWT project when integrating {@code
* com.auth0:java-jwt} as the JWT management library. * com.auth0:java-jwt} as the JWT management library.
*
* <p> * <p>
* The {@code AuthzeroTokenResolver} relies on the {@code com.auth0:java-jwt} * The {@link cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver}
* library to handle the underlying JWT operations, including token creation, * relies on the {@code com.auth0:java-jwt} library to handle the underlying
* validation, and extraction. It utilizes the {@code com.auth0:java-jwt} * JWT operations, including token creation, validation, and extraction. It
* {@code Algorithm} class to define and use different algorithms for JWT * utilizes the {@code com.auth0:java-jwt} {@link
* signing and verification. * com.auth0.jwt.algorithms.Algorithm} class to define and use different
* * algorithms for JWT signing and verification.
* <p> * <p>
* To use the {@code AuthzeroTokenResolver}, developers must provide the * To use the {@link
* necessary configurations and dependencies, such as the {@code GuidCreator} * cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver}, developers
* for generating unique JWT IDs (JTI), the supported algorithm function, the * must provide the necessary configurations and dependencies, such as the
* issuer name, and the secret key used for token signing and validation. The * {@link cn.org.codecrafters.guid.GuidCreator} for generating unique JWT IDs
* {@code AuthzeroTokenResolverConfig} class provides a convenient way to * (JTI), the supported algorithm function, the issuer name, and the secret key
* configure these dependencies. * used for token signing and validation. The {@link
* * cn.org.codecrafters.simplejwt.authzero.config.AuthzeroTokenResolverConfig}
* class provides a convenient way to configure these dependencies.
* <p> * <p>
* Developers using the {@code com.auth0:java-jwt} integration should be * Developers using the {@code com.auth0:java-jwt} integration should be
* familiar with the concepts and usage of the {@code com.auth0:java-jwt} * familiar with the concepts and usage of the {@code com.auth0:java-jwt}
+1 -1
View File
@@ -23,7 +23,7 @@
<parent> <parent>
<groupId>cn.org.codecrafters</groupId> <groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId> <artifactId>jdevkit</artifactId>
<version>1.0.1</version> <version>1.1.0</version>
</parent> </parent>
<artifactId>simple-jwt-facade</artifactId> <artifactId>simple-jwt-facade</artifactId>
@@ -22,12 +22,12 @@ import cn.org.codecrafters.simplejwt.exceptions.WeakSecretException;
import java.util.Random; import java.util.Random;
/** /**
* SecretCreator is a utility class that provides methods to generate secure * {@code SecretCreator} is a utility class that provides methods to generate
* secret strings. The generated secrets can be used as cryptographic keys or * secure secret strings. The generated secrets can be used as cryptographic
* passwords for various security-sensitive purposes. * keys or passwords for various security-sensitive purposes.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.1.0
* @since 1.0.0 * @since 1.0.0
*/ */
public final class SecretCreator { public final class SecretCreator {
@@ -83,24 +83,23 @@ public final class SecretCreator {
if (length < 32) { if (length < 32) {
throw new WeakSecretException(""" throw new WeakSecretException("""
The requested secret, which is only %d characters long, is too weak. \ The requested secret, which is only %d characters long, is too weak. \
Please replace it with a stronger secret. Please replace it with a stronger secret.""".formatted(length));
""".formatted(length));
} }
final var randomizer = new Random(); final var randomiser = new Random();
var charset = new StringBuilder(LOWERCASE_CHARACTERS); var charset = new StringBuilder(LOWERCASE_CHARACTERS);
if (isContainCapital) charset.append(UPPERCASE_CHARACTERS); if (isContainCapital) charset.append(UPPERCASE_CHARACTERS);
if (isContainDigital) charset.append(DIGITS); if (isContainDigital) charset.append(DIGITS);
if (isContainSpecialSign) charset.append(SPECIAL_SIGNS); if (isContainSpecialSign) charset.append(SPECIAL_SIGNS);
var password = new StringBuilder(); var secretBuilder = new StringBuilder();
var charsetSize = charset.length(); var charsetSize = charset.length();
for (var i = 0; i < length; ++i) { for (var i = 0; i < length; ++i) {
password.append(charset.charAt(randomizer.nextInt(charsetSize))); secretBuilder.append(charset.charAt(randomiser.nextInt(charsetSize)));
} }
return password.toString(); return secretBuilder.toString();
} }
/** /**
@@ -115,6 +114,7 @@ public final class SecretCreator {
* @return the generated secure secret * @return the generated secure secret
* @throws WeakSecretException if the requested secret length is less than * @throws WeakSecretException if the requested secret length is less than
* 32 characters * 32 characters
* @see #createSecret(int, boolean, boolean, boolean)
*/ */
public static String createSecret(int length, public static String createSecret(int length,
boolean isContainCapital, boolean isContainCapital,
@@ -132,6 +132,7 @@ public final class SecretCreator {
* @return the generated secure secret * @return the generated secure secret
* @throws WeakSecretException if the requested secret length is less than * @throws WeakSecretException if the requested secret length is less than
* 32 characters * 32 characters
* @see #createSecret(int, boolean, boolean, boolean)
*/ */
public static String createSecret(int length, public static String createSecret(int length,
boolean isContainCapital) { boolean isContainCapital) {
@@ -146,6 +147,7 @@ public final class SecretCreator {
* @return the generated secure secret * @return the generated secure secret
* @throws WeakSecretException if the requested secret length is less than * @throws WeakSecretException if the requested secret length is less than
* 32 characters * 32 characters
* @see #createSecret(int, boolean, boolean, boolean)
*/ */
public static String createSecret(int length) { public static String createSecret(int length) {
return createSecret(length, false, false, false); return createSecret(length, false, false, false);
@@ -20,21 +20,15 @@ package cn.org.codecrafters.simplejwt;
import java.util.Map; import java.util.Map;
/** /**
* <p> * {@code TokenPayload} interface is used to mark a data class as suitable
* TokenPayload - Interface for JWT Payload Data Classes.
*
* <p>
* The {@code TokenPayload} interface is used to mark a data class as suitable
* for being used as the payload in a JSON Web Token (JWT). Any class * for being used as the payload in a JSON Web Token (JWT). Any class
* implementing this interface can be used to represent the payload data that * implementing this interface can be used to represent the payload data that
* will be included in a JWT. * will be included in a JWT.
*
* <p> * <p>
* Implementing this interface indicates that the data class contains * Implementing this interface indicates that the data class contains
* information that needs to be securely transmitted and verified as part of a * information that needs to be securely transmitted and verified as part of a
* JWT. The payload typically contains claims or attributes that provide * JWT. The payload typically contains claims or attributes that provide
* additional information about the JWT subject or context. * additional information about the JWT subject or context.
*
* <p> * <p>
* <b>Usage:</b> * <b>Usage:</b>
* To use a class as a JWT payload, simply implement the {@code TokenPayload} * To use a class as a JWT payload, simply implement the {@code TokenPayload}
@@ -45,8 +39,9 @@ import java.util.Map;
* } * }
* </pre> * </pre>
* *
* @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0 * @since 1.0.0
* @version 1.0.0
*/ */
public interface TokenPayload { public interface TokenPayload {
@@ -22,25 +22,21 @@ import java.time.Duration;
import java.util.Map; import java.util.Map;
/** /**
* <p> * {@code TokenResolver} defines methods for creating, extracting, and
* The {@code TokenResolver} interface defines methods for creating, * renewing tokens, particularly JSON Web Tokens (JWTs). It provides a set of
* extracting, and renewing tokens, particularly JSON Web Tokens (JWTs). It * methods to generate tokens with various payload configurations, extract
* provides a set of methods to generate tokens with various payload * payload from tokens, and renew expired tokens.
* configurations, extract payload from tokens, and renew expired tokens.
*
* <p> * <p>
* <b>Token Creation:</b> * <b>Token Creation:</b>
* The interface provides overloaded methods for creating tokens with different * The interface provides overloaded methods for creating tokens with different
* payload configurations, including expiration time, audience, subject, and * payload configurations, including expiration time, audience, subject, and
* custom payload data. Clients can choose the appropriate method based on * custom payload data. Clients can choose the appropriate method based on
* their specific token requirements. * their specific token requirements.
*
* <p> * <p>
* <b>Token Extraction:</b> * <b>Token Extraction:</b>
* The interface includes methods to extract payload information from a given * The interface includes methods to extract payload information from a given
* token. Clients can use these methods to obtain the payload data encoded in * token. Clients can use these methods to obtain the payload data encoded in
* the token. * the token.
*
* <p> * <p>
* <b>Token Renewal:</b> * <b>Token Renewal:</b>
* The interface also offers methods for token renewal. Clients can renew an * The interface also offers methods for token renewal. Clients can renew an
@@ -50,7 +46,7 @@ import java.util.Map;
* @param <ResolvedTokenType> the type of the result obtained by the * @param <ResolvedTokenType> the type of the result obtained by the
* third-party library when parsing JWTs * third-party library when parsing JWTs
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.1.0
* @since 1.0.0 * @since 1.0.0
*/ */
public interface TokenResolver<ResolvedTokenType> { public interface TokenResolver<ResolvedTokenType> {
@@ -23,14 +23,12 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* Annotation {@code ExcludeFromPayload} is used to mark a property of a data
* class that should be excluded from being automatically injected into the
* JSON Web Token (JWT) payload during token generation. When a property is
* annotated by this annotation, it will not be included in the JWT payloads.
* <p> * <p>
* This annotation is used to mark a property of a data class that should be * <b>Usage:</b>
* excluded from being automatically injected into the JSON Web Token (JWT)
* payload during token generation. When a property is annotated with this
* annotation, it will not be included as part of the JWT payload.
*
*
* <p><b>Usage:</b>
* To exclude a property from the JWT payload, annotate the property with * To exclude a property from the JWT payload, annotate the property with
* {@code @ExcludeFromPayload}: * {@code @ExcludeFromPayload}:
* *
@@ -45,14 +43,15 @@ import java.lang.annotation.Target;
* // Getters and setters... * // Getters and setters...
* } * }
* }</pre> * }</pre>
* * <p>
* <p><b>Note:</b> * <b>Note:</b>
* This annotation should be used only on properties that are not intended to * This annotation should be used on properties that are not intended to
* be included in the JWT payload due to their sensitive nature or for other * be included in the JWT payload due to their sensitive nature or for other
* reasons. It is important to carefully choose which properties are excluded * reasons only. It is important to carefully choose which properties are
* from the payload to ensure the JWT remains secure and efficient. * excluded from the payload to ensure the JWT remains secure and efficient.
* *
* @version 1.0.0 * @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0 * @since 1.0.0
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@@ -22,7 +22,6 @@
* properties of a data class to exclude them from being included as part * properties of a data class to exclude them from being included as part
* of the JWT payload. * of the JWT payload.
* *
* @version 1.0.0
* @since 1.0.0 * @since 1.0.0
*/ */
package cn.org.codecrafters.simplejwt.annotations; package cn.org.codecrafters.simplejwt.annotations;
@@ -17,21 +17,21 @@
package cn.org.codecrafters.simplejwt.config; package cn.org.codecrafters.simplejwt.config;
import cn.org.codecrafters.simplejwt.TokenResolver;
import cn.org.codecrafters.simplejwt.constants.TokenAlgorithm; import cn.org.codecrafters.simplejwt.constants.TokenAlgorithm;
/** /**
* <p> * The {@code TokenResolverConfig} provides a mechanism to configure a
* The TokenResolverConfig interface provides a mechanism to configure a * {@link TokenResolver} with algorithm functions.
* TokenResolver with algorithm functions.
*
* <p> * <p>
* This generic interface is used to define the configuration details for a * This generic interface is used to define the configuration details for a
* TokenResolver that utilizes algorithm functions. The interface allows for * {@link TokenResolver} that utilizes algorithm functions. The interface
* specifying algorithm functions corresponding to different TokenAlgorithm * allows for specifying algorithm functions corresponding to different {@link
* instances supported by the TokenResolver implementation. * TokenAlgorithm} instances supported by the {@link TokenResolver}
* implementation.
* *
* @param <Algo> the type representing algorithm functions used by the * @param <Algo> the type representing algorithm functions used by the
* {@code TokenResolver} * {@link TokenResolver}
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.0.0
* @since 1.0.0 * @since 1.0.0
@@ -39,18 +39,20 @@ import cn.org.codecrafters.simplejwt.constants.TokenAlgorithm;
public interface TokenResolverConfig<Algo> { public interface TokenResolverConfig<Algo> {
/** /**
* Gets the algorithm function corresponding to the specified * Gets the algorithm function corresponding to the specified {@link
* TokenAlgorithm. * TokenAlgorithm}.
* <p> * <p>
* This method returns the algorithm function associated with the given * This method returns the algorithm function associated with the given
* TokenAlgorithm. The provided TokenAlgorithm represents the specific * {@link TokenAlgorithm}. The provided TokenAlgorithm represents the
* algorithm for which the corresponding algorithm function is required. * specific algorithm for which the corresponding algorithm function is
* The returned AlgorithmFunction represents the function implementation * required. The returned {@code Algo} represents the function
* that can be used by the TokenResolver to handle the specific algorithm. * implementation that can be used by the {@link TokenResolver} to handle
* the specific algorithm.
* *
* @param algorithm the TokenAlgorithm for which the algorithm function is * @param algorithm the {@link TokenAlgorithm} for which the algorithm
* required * function is required
* @return the algorithm function associated with the given TokenAlgorithm * @return the algorithm function associated with the given {@link
* TokenAlgorithm}
*/ */
Algo getAlgorithm(TokenAlgorithm algorithm); Algo getAlgorithm(TokenAlgorithm algorithm);
@@ -16,17 +16,16 @@
*/ */
/** /**
* <p>
* The classes in this package provide configuration options and settings for * The classes in this package provide configuration options and settings for
* the Simple JWT library. They are used to customize the behavior of the * the {@code cn.org.codecrafters:simple-jwt-facade} library. They are used
* library and allow developers to fine-tune various aspects of JWT generation * to customize the behavior of the library and allow developers to fine-tune
* and validation. * various aspects of JWT generation and validation.
*
* <p> * <p>
* Other configuration classes may be added in the future to support additional * Other configuration classes may be added in the future to support additional
* customization options and features. Developers using the Simple JWT library * customisation options and features. Developers using the
* should be familiar with the available configuration options to ensure proper * {@code cn.org.codecrafters:simple-jwt-facade} library should be familiar
* integration and usage of the library. * with the available configuration options to ensure proper integration and
* usage of the library.
* *
* @since 1.0.0 * @since 1.0.0
*/ */
@@ -23,8 +23,8 @@ import java.util.List;
* The {@code PredefinedKeys} class contains constants for standard JSON Web Token (JWT) claims. These constants * The {@code PredefinedKeys} class contains constants for standard JSON Web Token (JWT) claims. These constants
* represent the names of the standard claims that can be included in a JWT payload. Developers can use these constants * represent the names of the standard claims that can be included in a JWT payload. Developers can use these constants
* when working with JWTs to ensure consistent naming of the claims. * when working with JWTs to ensure consistent naming of the claims.
* * <p>
* <p>The class provides the following standard JWT claim constants: * The class provides the following standard JWT claim constants:
* <ul> * <ul>
* <li>{@link #ISSUER}: Represents the "iss" (Issuer) claim.</li> * <li>{@link #ISSUER}: Represents the "iss" (Issuer) claim.</li>
* <li>{@link #SUBJECT}: Represents the "sub" (Subject) claim.</li> * <li>{@link #SUBJECT}: Represents the "sub" (Subject) claim.</li>
@@ -34,13 +34,15 @@ import java.util.List;
* <li>{@link #ISSUED_AT}: Represents the "iat" (Issued At) claim.</li> * <li>{@link #ISSUED_AT}: Represents the "iat" (Issued At) claim.</li>
* <li>{@link #JWT_ID}: Represents the "jti" (JWT ID) claim.</li> * <li>{@link #JWT_ID}: Represents the "jti" (JWT ID) claim.</li>
* </ul> * </ul>
* * <p>
* <p>The class also contains a list of all the standard claim constants, accessible via the {@link #KEYS} field. This * The class also contains a list of all the standard claim constants, accessible via the {@link #KEYS} field. This
* list can be useful for iterating through all the standard claims or checking for the presence of specific claims. * list can be useful for iterating through all the standard claims or checking for the presence of specific claims.
* * <p>
* <p>Note: This class is final and cannot be instantiated. It only serves as a utility class to hold the standard JWT * Note: This class is final and cannot be instantiated. It only serves as a utility class to hold the standard JWT
* claim constants. * claim constants.
* *
* @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0 * @since 1.0.0
*/ */
public final class PredefinedKeys { public final class PredefinedKeys {
@@ -86,11 +88,13 @@ public final class PredefinedKeys {
public static final List<String> KEYS = List.of(ISSUER, SUBJECT, AUDIENCE, EXPIRATION_TIME, NOT_BEFORE, ISSUED_AT, JWT_ID); public static final List<String> KEYS = List.of(ISSUER, SUBJECT, AUDIENCE, EXPIRATION_TIME, NOT_BEFORE, ISSUED_AT, JWT_ID);
/** /**
* Private constructor to prevent instantiation of the {@code PredefinedKeys} class. * Private constructor to prevent instantiation of the
* This class is intended to be used as a utility class with only static constants and methods. * {@code PredefinedKeys} class.
* <p>
* This class is intended to be used as a utility class with only static
* constants and methods.
*/ */
private PredefinedKeys() { private PredefinedKeys() {
// Private constructor to prevent instantiation
} }
} }
@@ -25,9 +25,8 @@ import lombok.Getter;
* cryptographic algorithms to be used for secure token generation and * cryptographic algorithms to be used for secure token generation and
* validation. This enum provides a list of supported algorithms to ensure * validation. This enum provides a list of supported algorithms to ensure
* consistent usage and avoid potential security issues. * consistent usage and avoid potential security issues.
* * <p>
* <p><b>Supported Algorithms:</b> * <b>Supported Algorithms:</b>
* This enum includes the following supported algorithms:
* <ul> * <ul>
* <li>{@link TokenAlgorithm#HS256}: HMAC SHA-256</li> * <li>{@link TokenAlgorithm#HS256}: HMAC SHA-256</li>
* <li>{@link TokenAlgorithm#HS384}: HMAC SHA-384</li> * <li>{@link TokenAlgorithm#HS384}: HMAC SHA-384</li>
@@ -40,7 +39,8 @@ import lombok.Getter;
* <li>{@link TokenAlgorithm#ES512}: ECDSA with SHA-512</li> * <li>{@link TokenAlgorithm#ES512}: ECDSA with SHA-512</li>
* </ul> * </ul>
* *
* @version 1.0.0 * @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0 * @since 1.0.0
*/ */
@Getter @Getter
@@ -22,6 +22,5 @@
* configuration parameters. * configuration parameters.
* *
* @since 1.0.0 * @since 1.0.0
* @version 1.0.0
*/ */
package cn.org.codecrafters.simplejwt.constants; package cn.org.codecrafters.simplejwt.constants;
@@ -18,30 +18,34 @@
package cn.org.codecrafters.simplejwt.exceptions; package cn.org.codecrafters.simplejwt.exceptions;
/** /**
* This {@code UnsupportedAlgorithmException} represents the given
* algorithm is not supported by {@link
* cn.org.codecrafters.simplejwt.TokenResolver} yet.
* <p> * <p>
* This {@code UnsupportedAlgorithmException} is to indicates that the given * If you want the supports to an unsupported algorithm, you could
* algorithm is not supported by TokenResolver yet. * <ul>
* * <li>Commit an issue at GitHub Issues or;</li>
* <p> * <li>Communicate with us on Discord Community.</li>
* To support a specified algorithm, you could * </ul>
*
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0
*/ */
public class UnsupportedAlgorithmException extends RuntimeException { public class UnsupportedAlgorithmException extends RuntimeException {
/** /**
* Constructs a new runtime exception with {@code null} as its detail * Constructs a new {@code UnsupportedAlgorithmException} with {@code null}
* message. The cause is not initialized, and may subsequently be * as its detail message. The cause is not initialized, and may
* initialized by a call to {@link #initCause}. * subsequently be initialized by a call to {@link #initCause}.
*/ */
public UnsupportedAlgorithmException() { public UnsupportedAlgorithmException() {
} }
/** /**
* Constructs a new runtime exception with the specified detail message. * Constructs a new {@code UnsupportedAlgorithmException} with the
* The cause is not initialized, and may subsequently be initialized by a * specified detail message. The cause is not initialized, and may
* call to {@link #initCause}. * subsequently be initialized by a call to {@link #initCause}.
* *
* @param message the detail message. The detail message is saved for * @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method. * later retrieval by the {@link #getMessage()} method.
@@ -51,14 +55,8 @@ public class UnsupportedAlgorithmException extends RuntimeException {
} }
/** /**
* <p> * Constructs a new {@code UnsupportedAlgorithmException} with the
* Constructs a new runtime exception with the specified detail message and * specified detail message and cause.
* cause.
*
* <p>Note that the detail message associated with
* {@code cause} is <i>not</i> automatically incorporated in
* this runtime exception's detail message.
*
* *
* @param message the detail message (which is saved for later retrieval * @param message the detail message (which is saved for later retrieval
* by the {@link #getMessage()} method). * by the {@link #getMessage()} method).
@@ -73,11 +71,12 @@ public class UnsupportedAlgorithmException extends RuntimeException {
} }
/** /**
* Constructs a new runtime exception with the specified cause and a * Constructs a new {@code UnsupportedAlgorithmException} with the
* detail message of {@code (cause==null ? null : cause.toString())} * specified cause and a detail message of
* (which typically contains the class and detail message of * {@code (cause==null ? null : cause.toString())} (which typically
* {@code cause}). This constructor is useful for runtime exceptions * contains the class and detail message of {@code cause}). This
* that are little more than wrappers for other throwables. * constructor is useful for runtime exceptions that are little more
* than wrappers for other throwable.
* *
* @param cause the cause (which is saved for later retrieval by the * @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A {@code null} value is * {@link #getCause()} method). (A {@code null} value is
@@ -90,18 +89,17 @@ public class UnsupportedAlgorithmException extends RuntimeException {
} }
/** /**
* Constructs a new runtime exception with the specified detail * Constructs a new {@code UnsupportedAlgorithmException} with the
* message, cause, suppression enabled or disabled, and writable * specified detail message, cause, suppression enabled or disabled, and
* stack trace enabled or disabled. * writable stack trace enabled or disabled.
* *
* @param message the detail message. * @param message the detail message.
* @param cause the cause. (A {@code null} value is permitted, * @param cause the cause (A {@code null} value is permitted,
* and indicates that the cause is nonexistent or unknown.) * and indicates that the cause is nonexistent or
* @param enableSuppression whether or not suppression is enabled * unknown.)
* or disabled * @param enableSuppression whether suppression is enabled or disabled
* @param writableStackTrace whether or not the stack trace should * @param writableStackTrace whether the stack trace should be writable
* be writable * @since 1.0.0
* @since 1.7
*/ */
public UnsupportedAlgorithmException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { public UnsupportedAlgorithmException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace); super(message, cause, enableSuppression, writableStackTrace);
@@ -18,24 +18,31 @@
package cn.org.codecrafters.simplejwt.exceptions; package cn.org.codecrafters.simplejwt.exceptions;
/** /**
* WeakSecretException * {@code WeakSecretException} represents that your secret is too weak to be
* used in signing JWTs.
* <p>
* {@code WeakSecretException} will only appears that if you are using the
* implementation module {@code cn.org.codecrafters:simple-jwt-jjwt} due to
* it is implemented by {@code io.jsonwebtoken:jjwt}.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0
*/ */
public class WeakSecretException extends RuntimeException { public class WeakSecretException extends RuntimeException {
/** /**
* Constructs a new runtime exception with {@code null} as its * Constructs a new {@code WeakSecretException} with {@code null} as its
* detail message. The cause is not initialized, and may subsequently be * detail message. The cause is not initialized, and may subsequently be
* initialized by a call to {@link #initCause}. * initialized by a call to {@link #initCause}.
*/ */
public WeakSecretException() { public WeakSecretException() {
} }
/** /**
* Constructs a new runtime exception with the specified detail message. * Constructs a new {@code WeakSecretException} with the specified detail
* The cause is not initialized, and may subsequently be initialized by a * message. The cause is not initialized, and may subsequently be
* call to {@link #initCause}. * initialized by a call to {@link #initCause}.
* *
* @param message the detail message. The detail message is saved for * @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method. * later retrieval by the {@link #getMessage()} method.
@@ -45,10 +52,11 @@ public class WeakSecretException extends RuntimeException {
} }
/** /**
* Constructs a new runtime exception with the specified detail message and * Constructs a new {@code WeakSecretException} with the specified detail
* cause. <p>Note that the detail message associated with * message and cause.
* {@code cause} is <i>not</i> automatically incorporated in * <p>
* this runtime exception's detail message. * Note that the detail message associated with {@code cause} is <i>not</i>
* automatically incorporated in this runtime exception's detail message.
* *
* @param message the detail message (which is saved for later retrieval * @param message the detail message (which is saved for later retrieval
* by the {@link #getMessage()} method). * by the {@link #getMessage()} method).
@@ -56,42 +64,41 @@ public class WeakSecretException extends RuntimeException {
* {@link #getCause()} method). (A {@code null} value is * {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or * permitted, and indicates that the cause is nonexistent or
* unknown.) * unknown.)
* @since 1.4 * @since 1.0.0
*/ */
public WeakSecretException(String message, Throwable cause) { public WeakSecretException(String message, Throwable cause) {
super(message, cause); super(message, cause);
} }
/** /**
* Constructs a new runtime exception with the specified cause and a * Constructs a new {@code WeakSecretException} with the specified cause
* detail message of {@code (cause==null ? null : cause.toString())} * and a detail message of {@code (cause==null ? null : cause.toString())}
* (which typically contains the class and detail message of * (which typically contains the class and detail message of
* {@code cause}). This constructor is useful for runtime exceptions * {@code cause}). This constructor is useful for runtime exceptions that
* that are little more than wrappers for other throwables. * are little more than wrappers for other throwable.
* *
* @param cause the cause (which is saved for later retrieval by the * @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A {@code null} value is * {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or * permitted, and indicates that the cause is nonexistent or
* unknown.) * unknown.)
* @since 1.4 * @since 1.0.0
*/ */
public WeakSecretException(Throwable cause) { public WeakSecretException(Throwable cause) {
super(cause); super(cause);
} }
/** /**
* Constructs a new runtime exception with the specified detail * Constructs a new {@code WeakSecretException} with the specified detail
* message, cause, suppression enabled or disabled, and writable * message, cause, suppression enabled or disabled, and writable
* stack trace enabled or disabled. * stack trace enabled or disabled.
* *
* @param message the detail message. * @param message the detail message.
* @param cause the cause. (A {@code null} value is permitted, * @param cause the cause. (A {@code null} value is permitted,
* and indicates that the cause is nonexistent or unknown.) * and indicates that the cause is nonexistent or
* @param enableSuppression whether or not suppression is enabled * unknown.)
* or disabled * @param enableSuppression whether suppression is enabled or disabled
* @param writableStackTrace whether or not the stack trace should * @param writableStackTrace whether the stack trace should be writable
* be writable * @since 1.0.0
* @since 1.7
*/ */
public WeakSecretException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { public WeakSecretException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace); super(message, cause, enableSuppression, writableStackTrace);
@@ -16,26 +16,23 @@
*/ */
/** /**
* <p>
* The {@code cn.org.codecrafters.simplejwt.exceptions} package contains * The {@code cn.org.codecrafters.simplejwt.exceptions} package contains
* custom exception classes related to the Simple JWT library. These * custom exception classes related to the
* exceptions are thrown when there are issues or errors during the generation * {@code cn.org.codecrafters:simple-jwt-facade} library. These exceptions are
* , validation, or processing of JSON Web Tokens (JWTs) in Java applications. * thrown when there are issues or errors during the generation , validation,
* * or processing of JSON Web Tokens (JWTs) in Java applications.
*
* <p> * <p>
* Custom exception classes in this package are designed to enhance the * Custom exception classes in this package are designed to enhance the
* robustness and reliability of the JWT handling process by providing clear * robustness and reliability of the JWT handling process by providing clear
* and meaningful error messages to the developers. They help developers * and meaningful error messages to the developers. They help developers
* identify and troubleshoot issues related to JWT generation, validation, or * identify and troubleshoot issues related to JWT generation, validation, or
* extraction and ensure smooth operation and error handling in their * extraction and ensure smooth operation and error handling in
* applications. * their applications.
*
*
* <p> * <p>
* Developers using the Simple JWT library should be aware of the possible * Developers using the {@code cn.org.codecrafters:simple-jwt-facade} library
* exceptions that can be thrown and handle them appropriately to ensure secure * should be aware of the possible exceptions that can be thrown and handle
* and reliable JWT handling in their Java applications. * them appropriately to ensure secure and reliable JWT handling in their
* Java applications.
* *
* @since 1.0.0 * @since 1.0.0
*/ */
@@ -16,28 +16,23 @@
*/ */
/** /**
* <p>
* The {@code cn.org.codecrafters.simplejwt} package is the core package of the * The {@code cn.org.codecrafters.simplejwt} package is the core package of the
* Simple JWT project, which provides a lightweight and easy-to-use library for * <b>Simple JWT</b> project, which provides a lightweight and easy-to-use
* working with JSON Web Tokens (JWTs) in Java applications. JWT is a * library for working with JSON Web Tokens (JWTs) in Java applications. JWT is
* widely-used standard for representing claims between two parties, typically * a widely-used standard for representing claims between two parties,
* used to secure web and mobile applications. This library aims to simplify * typically used to secure web and mobile applications. This library aims to
* the JWT handling process and provide convenient abstractions for JWT * simplify the JWT handling process and provide convenient abstractions for
* generation, validation, and extraction. * JWT generation, validation, and extraction.
*
*
* <p> * <p>
* The Simple JWT library is designed to be flexible and customizable, allowing * The <b>Simple JWT</b> library is designed to be flexible and customisable,
* developers to use different algorithms, token resolvers, and token payload * allowing developers to use different algorithms, token resolvers, and token
* classes based on their specific application requirements. It aims to * payload classes based on their specific application requirements. It aims to
* simplify the JWT handling process while maintaining security and best * simplify the JWT handling process while maintaining security and best
* practices for working with JWTs. * practices for working with JWTs.
*
*
* <p> * <p>
* Developers should refer to the official documentation and examples for the * Developers should refer to the official documentation and examples for the
* Simple JWT project to understand how to use the library effectively and * <b>Simple JWT</b> project to understand how to use the library effectively
* securely in their Java applications. * and securely in their Java applications.
* *
* *
* @since 1.0.0 * @since 1.0.0
+1 -1
View File
@@ -23,7 +23,7 @@
<parent> <parent>
<groupId>cn.org.codecrafters</groupId> <groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId> <artifactId>jdevkit</artifactId>
<version>1.0.1</version> <version>1.1.0</version>
</parent> </parent>
<artifactId>simple-jwt-jjwt</artifactId> <artifactId>simple-jwt-jjwt</artifactId>
@@ -43,9 +43,61 @@ import java.util.Map;
import java.util.UUID; import java.util.UUID;
/** /**
* JjwtTokenResolver * The {@link JjwtTokenResolver} class is an implementation of the {@link
* cn.org.codecrafters.simplejwt.TokenResolver} interface. It uses the {@code
* io.jsonwebtoken:jjwt} library to handle JSON Web Token (JWT) resolution.
* This resolver provides functionality to create, extract, verify, and renew
* JWT tokens using various algorithms and custom payload data.
* <p>
* <b>Dependencies:</b>
* This implementation relies on the {@code io.jsonwebtoken:jjwt} library. Please
* ensure you have added this library as a dependency to your project before
* using this resolver.
* <p>
* <b>Usage:</b>
* To use the {@code JjwtTokenResolver}, first, create an instance of this
* class:
* <pre>{@code
* TokenResolver<Jws<Claims>> tokenResolver =
* new JjwtTokenResolver(TokenAlgorithm.HS256,
* "Token Subject",
* "Token Issuer",
* "Token Secret");
* }</pre>
* <p>
* Then, you can utilize the various methods provided by this resolver to
* handle JWT tokens:
* <pre>{@code
* // Creating a new JWT token
* String token =
* tokenResolver.createToken(Duration.ofHours(1),
* "your_subject",
* "your_audience",
* customPayloads);
*
* // Extracting payload data from a JWT token
* DecodedJWT decodedJWT = tokenResolver.resolve(token);
* T payloadData = decodedJWT.extract(token, T.class);
*
* // Renewing an existing JWT token
* String renewedToken =
* tokenResolver.renew(token, Duration.ofMinutes(30), customPayloads);
* }</pre>
* <p>
* <b>Note:</b>
* It is essential to configure the appropriate algorithms, secret, and issuer
* according to your specific use case when using this resolver.
* Additionally, ensure that the {@code io.jsonwebtoken:jjwt} library is
* correctly configured in your project's dependencies.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.1.0
* @see Claims
* @see Jws
* @see Jwts
* @see SignatureAlgorithm
* @see Keys
* @since 1.0.0
*/ */
@Slf4j @Slf4j
public class JjwtTokenResolver implements TokenResolver<Jws<Claims>> { public class JjwtTokenResolver implements TokenResolver<Jws<Claims>> {
@@ -67,11 +119,11 @@ public class JjwtTokenResolver implements TokenResolver<Jws<Claims>> {
if (secret.length() <= 32) { if (secret.length() <= 32) {
log.error(""" log.error("""
The provided secret which owns {} characters is too weak. Please replace it with a stronger one. The provided secret which owns {} characters is too weak. Please replace it with a stronger one.""",
""", secret.length()); secret.length());
throw new WeakSecretException(""" throw new WeakSecretException("""
The provided secret which owns %s characters is too weak. Please replace it with a stronger one. The provided secret which owns %s characters is too weak. Please replace it with a stronger one."""
""".formatted(secret.length())); .formatted(secret.length()));
} }
this.jtiCreator = jtiCreator; this.jtiCreator = jtiCreator;
@@ -86,12 +138,12 @@ public class JjwtTokenResolver implements TokenResolver<Jws<Claims>> {
} }
if (secret.length() <= 32) { if (secret.length() <= 32) {
log.error(""" log.error(
The provided secret which owns {} characters is too weak. Please replace it with a stronger one. "The provided secret which owns {} characters is too weak. Please replace it with a stronger one.",
""", secret.length()); secret.length());
throw new WeakSecretException(""" throw new WeakSecretException(
The provided secret which owns %s characters is too weak. Please replace it with a stronger one. "The provided secret which owns %s characters is too weak. Please replace it with a stronger one."
""".formatted(secret.length())); .formatted(secret.length()));
} }
this.jtiCreator = UUID::randomUUID; this.jtiCreator = UUID::randomUUID;
@@ -106,12 +158,12 @@ public class JjwtTokenResolver implements TokenResolver<Jws<Claims>> {
} }
if (secret.length() <= 32) { if (secret.length() <= 32) {
log.error(""" log.error(
The provided secret which owns {} characters is too weak. Please replace it with a stronger one. "The provided secret which owns {} characters is too weak. Please replace it with a stronger one.",
""", secret.length()); secret.length());
throw new WeakSecretException(""" throw new WeakSecretException(
The provided secret which owns %s characters is too weak. Please replace it with a stronger one. "The provided secret which owns %s characters is too weak. Please replace it with a stronger one."
""".formatted(secret.length())); .formatted(secret.length()));
} }
this.jtiCreator = UUID::randomUUID; this.jtiCreator = UUID::randomUUID;
@@ -204,7 +256,7 @@ public class JjwtTokenResolver implements TokenResolver<Jws<Claims>> {
} }
/** /**
* Resolves the given token into a ResolvedTokenType object. * Resolves the given token into a {@link Jws<Claims>} object.
* *
* @param token the token to be resolved * @param token the token to be resolved
* @return a ResolvedTokenType object * @return a ResolvedTokenType object
@@ -235,7 +287,7 @@ public class JjwtTokenResolver implements TokenResolver<Jws<Claims>> {
try { try {
return MapUtil.mapToObject(claims, targetType); return MapUtil.mapToObject(claims, targetType);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
log.info("An error occurs while invoking the constructor of type {}.", targetType.getCanonicalName()); log.error("An error occurs while invoking the constructor of type {}.", targetType.getCanonicalName());
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
log.error("The constructor of the required type {} is not found.", targetType.getCanonicalName()); log.error("The constructor of the required type {} is not found.", targetType.getCanonicalName());
} catch (InstantiationException e) { } catch (InstantiationException e) {
@@ -17,22 +17,49 @@
package cn.org.codecrafters.simplejwt.jjwt.config; package cn.org.codecrafters.simplejwt.jjwt.config;
import cn.org.codecrafters.simplejwt.TokenResolver;
import cn.org.codecrafters.simplejwt.config.TokenResolverConfig; import cn.org.codecrafters.simplejwt.config.TokenResolverConfig;
import cn.org.codecrafters.simplejwt.constants.TokenAlgorithm; import cn.org.codecrafters.simplejwt.constants.TokenAlgorithm;
import cn.org.codecrafters.simplejwt.exceptions.UnsupportedAlgorithmException; import cn.org.codecrafters.simplejwt.exceptions.UnsupportedAlgorithmException;
import cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver;
import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.SignatureAlgorithm;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* JjwtTokenResolverConfig * The {@code JjwtTokenResolverConfig} class provides the configuration for the
* {@link JjwtTokenResolver}.
* <p>
* This configuration class is used to establish the mapping between the
* standard {@link TokenAlgorithm} defined within the
* {@code JjwtTokenResolverConfig} and the specific algorithms used by the
* {@code io.jsonwebtoken:jjwt} library, which is the underlying library used
* by {@code JjwtTokenResolver} to handle JSON Web Tokens (JWTs).
* <p>
* <b>Algorithm Mapping:</b>
* The {@code JjwtTokenResolverConfig} allows specifying the relationship
* between the standard {@link TokenAlgorithm} instances supported by {@link
* JjwtTokenResolver} and the corresponding algorithms used by the
* {@code io.jsonwebtoken:jjwt} library. The mapping is achieved using a Map,
* where the keys are the standard {@link TokenAlgorithm} instances, and the
* values represent the algorithm functions used by
* {@code io.jsonwebtoken:jjwt} library for each corresponding key.
* <p>
* <b>Note:</b>
* The provided algorithm mapping should be consistent with the actual
* algorithms supported and used by the {@code io.jsonwebtoken:jjwt} library.
* It is crucial to ensure that the mapping is accurate to enable proper token
* validation and processing within the {@link JjwtTokenResolver}.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0
*/ */
public final class JjwtTokenResolverConfig implements TokenResolverConfig<SignatureAlgorithm> { public final class JjwtTokenResolverConfig implements TokenResolverConfig<SignatureAlgorithm> {
private JjwtTokenResolverConfig() {} private JjwtTokenResolverConfig() {
}
private static final Map<TokenAlgorithm, SignatureAlgorithm> SUPPORTED_ALGORITHMS = new HashMap<>() {{ private static final Map<TokenAlgorithm, SignatureAlgorithm> SUPPORTED_ALGORITHMS = new HashMap<>() {{
put(TokenAlgorithm.HS256, SignatureAlgorithm.HS256); put(TokenAlgorithm.HS256, SignatureAlgorithm.HS256);
@@ -52,24 +79,25 @@ public final class JjwtTokenResolverConfig implements TokenResolverConfig<Signat
/** /**
* Gets the algorithm function corresponding to the specified * Gets the algorithm function corresponding to the specified
* TokenAlgorithm. * {@link TokenAlgorithm}.
* <p> * <p>
* This method returns the algorithm function associated with the given * This method returns the algorithm function associated with the given
* TokenAlgorithm. The provided TokenAlgorithm represents the specific * {@link TokenAlgorithm}. The provided {@link TokenAlgorithm} represents
* algorithm for which the corresponding algorithm function is required. * the specific algorithm for which the corresponding algorithm function is
* The returned AlgorithmFunction represents the function implementation * required. The returned algorithm function represents the function
* that can be used by the TokenResolver to handle the specific algorithm. * implementation that can be used by the {@link TokenResolver} to handle
* the specific algorithm.
* *
* @param algorithm the TokenAlgorithm for which the algorithm function is * @param algorithm the {@link TokenAlgorithm} for which the algorithm
* required * function is required
* @return the algorithm function associated with the given TokenAlgorithm * @return the algorithm function associated with the given {@link
* TokenAlgorithm}
*/ */
@Override @Override
public SignatureAlgorithm getAlgorithm(TokenAlgorithm algorithm) { public SignatureAlgorithm getAlgorithm(TokenAlgorithm algorithm) {
if (!SUPPORTED_ALGORITHMS.containsKey(algorithm)) { if (!SUPPORTED_ALGORITHMS.containsKey(algorithm)) {
throw new UnsupportedAlgorithmException(""" throw new UnsupportedAlgorithmException("""
The request algorithm is not supported by our system yet. Please change to supported ones. The request algorithm is not supported by our system yet. Please change to supported ones.""");
""");
} }
return SUPPORTED_ALGORITHMS.get(algorithm); return SUPPORTED_ALGORITHMS.get(algorithm);
} }
@@ -16,17 +16,14 @@
*/ */
/** /**
* <p>
* The package {@code cn.org.codecrafters.simplejwt.jjwt.config} contains * The package {@code cn.org.codecrafters.simplejwt.jjwt.config} contains
* configuration classes related to the {@link * configuration classes related to the {@link
* cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver} * cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver}
* implementation. * implementation.
*
* <p> * <p>
* The classes in this package provide configuration options and settings for * The classes in this package provide configuration options and settings for
* the {@link cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver}, * the {@link cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver},
* which is used for resolving JSON Web Tokens (JWT) using the Auth0 library. * which is used for resolving JSON Web Tokens (JWT) using the Auth0 library.
*
* <p> * <p>
* The {@link * The {@link
* cn.org.codecrafters.simplejwt.jjwt.config.JjwtTokenResolverConfig} * cn.org.codecrafters.simplejwt.jjwt.config.JjwtTokenResolverConfig}
@@ -37,7 +34,6 @@
* JWT algorithms. It enables developers to specify and customize the * JWT algorithms. It enables developers to specify and customize the
* algorithm functions according to the chosen JWT algorithm and the library * algorithm functions according to the chosen JWT algorithm and the library
* being used. * being used.
*
* <p> * <p>
* The configuration options in this package help developers integrate and * The configuration options in this package help developers integrate and
* configure the {@link * configure the {@link
@@ -45,13 +41,12 @@
* into their Spring Boot applications. Developers can fine-tune the token * into their Spring Boot applications. Developers can fine-tune the token
* resolution process and customize algorithm handling to align with their * resolution process and customize algorithm handling to align with their
* specific requirements and desired level of security. * specific requirements and desired level of security.
*
* <p> * <p>
* It is recommended to explore the classes in this package to understand how * It is recommended to explore the classes in this package to understand how
* to configure and use the {@link * to configure and use the {@link
* cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver} effectively * cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver} effectively
* in the Spring Boot environment to handle JWT authentication and * in the Spring Boot environment to handle JWT authentication and
* authorization securely and efficiently. * authorisation securely and efficiently.
* *
* @since 1.0.0 * @since 1.0.0
*/ */
@@ -19,11 +19,10 @@
* This package contains classes related to the integration of the {@code * This package contains classes related to the integration of the {@code
* io.jsonwebtoken:jjwt-api} library in the Simple JWT project. {@code * io.jsonwebtoken:jjwt-api} library in the Simple JWT project. {@code
* io.jsonwebtoken:jjwt-api} is a powerful and widely-used Identity as a Service * io.jsonwebtoken:jjwt-api} is a powerful and widely-used Identity as a Service
* (IDaaS) platform that provides secure authentication and authorization * (IDaaS) platform that provides secure authentication and authorisation
* solutions for web and mobile applications. The classes in this package * solutions for web and mobile applications. The classes in this package
* provide the necessary functionality to handle JSON Web Tokens (JWTs) using * provide the necessary functionality to handle JSON Web Tokens (JWTs) using
* the {@code io.jsonwebtoken:jjwt-api} library. * the {@code io.jsonwebtoken:jjwt-api} library.
*
* <p> * <p>
* The main class in this package is the {@link * The main class in this package is the {@link
* cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver}, which * cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver}, which
@@ -33,22 +32,21 @@
* JWTs using the {@code io.jsonwebtoken:jjwt-api} library. Developers can use * JWTs using the {@code io.jsonwebtoken:jjwt-api} library. Developers can use
* this class as the main token resolver in the Simple JWT project when * this class as the main token resolver in the Simple JWT project when
* integrating {@code io.jsonwebtoken:jjwt-api} as the JWT management library. * integrating {@code io.jsonwebtoken:jjwt-api} as the JWT management library.
*
* <p> * <p>
* The {@code JjwtTokenResolver} relies on the {@code io.jsonwebtoken:jjwt-api} * The {@link cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver} relies on
* the {@code io.jsonwebtoken:jjwt-api}
* library to handle the underlying JWT operations, including token creation, * library to handle the underlying JWT operations, including token creation,
* validation, and extraction. It utilizes the {@code io.jsonwebtoken:jjwt-api} * validation, and extraction. It utilizes the {@code io.jsonwebtoken:jjwt-api}
* {@code Algorithm} class to define and use different algorithms for JWT * {@link io.jsonwebtoken.SignatureAlgorithm} class to define and use different
* signing and verification. * algorithms for JWT signing and verification.
*
* <p> * <p>
* To use the {@code JjwtTokenResolver}, developers must provide the necessary * To use the {@link cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver},
* configurations and dependencies, such as the {@code GuidCreator} for * developers must provide the necessary configurations and dependencies, such
* generating unique JWT IDs (JTI), the supported algorithm function, the * as the {@link cn.org.codecrafters.guid.GuidCreator} for generating unique
* issuer name, and the secret key used for token signing and validation. The * JWT IDs (JTI), the supported algorithm function, the issuer name, and the
* {@code JjwtTokenResolverConfig} class provides a convenient way to configure * secret key used for token signing and validation. The
* these dependencies. * {@link cn.org.codecrafters.simplejwt.jjwt.config.JjwtTokenResolverConfig}
* * class provides a convenient way to configure these dependencies.
* <p> * <p>
* Developers using the {@code io.jsonwebtoken:jjwt-api} integration should be * Developers using the {@code io.jsonwebtoken:jjwt-api} integration should be
* familiar with the concepts and usage of the {@code io.jsonwebtoken:jjwt-api} * familiar with the concepts and usage of the {@code io.jsonwebtoken:jjwt-api}
+1 -1
View File
@@ -23,7 +23,7 @@
<parent> <parent>
<groupId>cn.org.codecrafters</groupId> <groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId> <artifactId>jdevkit</artifactId>
<version>1.0.1</version> <version>1.1.0</version>
</parent> </parent>
<artifactId>simple-jwt-spring-boot-starter</artifactId> <artifactId>simple-jwt-spring-boot-starter</artifactId>
@@ -34,26 +34,23 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.DependsOn;
/** /**
* {@code AuthzeroTokenResolverAutoConfiguration} is responsible for
* automatically configuring the Simple JWT library with
* {@code com.auth0:java-jwt} when used in a Spring Boot application. It
* provides default settings and configurations to ensure that the library
* works smoothly without requiring manual configuration.
* <p> * <p>
* SimpleJwtAutoConfiguration is responsible for automatically configuring the * This autoconfiguration class sets up the necessary beans and components
* Simple JWT library with {@code com.auth0:java-jwt} when used in a Spring
* Boot application. It provides default settings and configurations to ensure
* that the library works smoothly without requiring manual configuration.
*
* <p>
* This auto-configuration class sets up the necessary beans and components
* required for JWT generation and validation. It automatically creates and * required for JWT generation and validation. It automatically creates and
* configures the {@link TokenResolver} bean based on the available options and * configures the {@link AuthzeroTokenResolver} bean based on the available
* properties. * options and properties.
*
* <p> * <p>
* Developers using the Simple JWT library with Spring Boot do not need to * Developers using the Simple JWT library with Spring Boot do not need to
* explicitly configure the library, as the auto-configuration takes care of * explicitly configure the library, as the autoconfiguration takes care of
* setting up the necessary components and configurations automatically. * setting up the necessary components and configurations automatically.
* However, developers still have the flexibility to customize the behavior of * However, developers still have the flexibility to customise the behavior of
* the library by providing their own configurations and properties. * the library by providing their own configurations and properties.
* *
*
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.0.0
* @since 1.0.0 * @since 1.0.0
@@ -29,9 +29,11 @@ import org.springframework.context.annotation.Conditional;
import java.util.UUID; import java.util.UUID;
/** /**
* GuidAutoConfiguration * Autoconfiguration for injecting a {@link GuidCreator} for generating jwt id.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0
*/ */
@Slf4j @Slf4j
@AutoConfiguration @AutoConfiguration
@@ -34,28 +34,25 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
/** /**
* <p> * {@code JjwtTokenResolverAutoConfiguration} is responsible for automatically
* JjwtTokenResolverAutoConfiguration is responsible for automatically
* configuring the Simple JWT library with {@code io.jsonwebtoken:jjwt-api} * configuring the Simple JWT library with {@code io.jsonwebtoken:jjwt-api}
* when used in a Spring Boot application. It provides default settings and * when used in a Spring Boot application. It provides default settings and
* configurations to ensure that the library works smoothly without requiring * configurations to ensure that the library works smoothly without requiring
* manual configuration. * manual configuration.
*
* <p> * <p>
* This auto-configuration class sets up the necessary beans and components * This autoconfiguration class sets up the necessary beans and components
* required for JWT generation and validation. It automatically creates and * required for JWT generation and validation. It automatically creates and
* configures the {@link TokenResolver} bean based on the available options and * configures the {@link JjwtTokenResolver} bean based on the available options
* properties. * and properties.
*
* <p> * <p>
* Developers using the Simple JWT library with Spring Boot do not need to * Developers using the Simple JWT library with Spring Boot do not need to
* explicitly configure the library, as the auto-configuration takes care of * explicitly configure the library, as the autoconfiguration takes care of
* setting up the necessary components and configurations automatically. * setting up the necessary components and configurations automatically.
* However, developers still have the flexibility to customize the behavior of * However, developers still have the flexibility to customize the behavior of
* the library by providing their own configurations and properties. * the library by providing their own configurations and properties.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.1.0
* @since 1.0.0 * @since 1.0.0
*/ */
@Slf4j @Slf4j
@@ -9,11 +9,11 @@ import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Objects; import java.util.Objects;
/** /**
* GuidCreatorCondition * The conditions to create bean {@code jtiCreator}.
* <p>
* Created on 28 Aug 2023
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0
*/ */
@Slf4j @Slf4j
public class GuidCreatorCondition implements Condition { public class GuidCreatorCondition implements Condition {
@@ -24,28 +24,24 @@ import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
/** /**
* <p>
* {@code SimpleJwtProperties} is a configuration properties class used to * {@code SimpleJwtProperties} is a configuration properties class used to
* store the properties related to Simple JWT library configuration. These * store the properties related to Simple JWT library configurations. These
* properties can be configured in the application's properties file (e.g., * properties can be configured in the application's properties file (e.g.,
* application.properties) with the prefix "code-crafters.simple-jwt". * application.properties) with the prefix "code-crafters.simple-jwt".
*
*
* <p> * <p>
* SimpleJwtProperties provides configuration options for the JWT algorithm, * {@code SimpleJwtProperties} provides configuration options for the JWT
* issuer, and secret. The properties are used by the {@link * algorithm, issuer, and secret. The properties are used by the {@link
* AuthzeroTokenResolverAutoConfiguration} * AuthzeroTokenResolverAutoConfiguration} and {@link
* class to set up the necessary configurations for JWT generation and * cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver} to set up the
* validation. * necessary configurations for JWT generation and validation.
*
*
* <p> * <p>
* Developers can customize the JWT algorithm, issuer, and secret by setting * Developers can customise the JWT algorithm, issuer, and secret by setting
* the corresponding properties in the application's properties file. The * the corresponding properties in the application's properties file. The
* SimpleJwtAutoConfiguration class reads these properties and uses them to * {@code SimpleJwtAutoConfiguration} class reads these properties and uses
* create the TokenResolver bean with the desired configuration. * them to create the TokenResolver bean with the desired configuration.
*
* *
* @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0 * @since 1.0.0
*/ */
@Data @Data
@@ -16,15 +16,12 @@
*/ */
/** /**
* <p>
* The "cn.org.codecrafters.simplejwt.autoconfiguration.properties" package * The "cn.org.codecrafters.simplejwt.autoconfiguration.properties" package
* contains configuration properties classes used for Simple JWT library * contains configuration properties classes used for Simple JWT library
* auto-configuration. These classes define the properties that can be * autoconfiguration. These classes define the properties that can be
* configured in the application's properties file (e.g., * configured in the application's properties file (e.g.,
* application.properties) to customize the behavior and settings of the Simple * application.properties) to customize the behavior and settings of the Simple
* JWT library. * JWT library.
*
*
* <p> * <p>
* Developers can customize the JWT algorithm, issuer, and secret by setting * Developers can customize the JWT algorithm, issuer, and secret by setting
* the corresponding properties in the application's properties file with the * the corresponding properties in the application's properties file with the
+2 -2
View File
@@ -2,12 +2,12 @@
## Introduction ## Introduction
The module `webcal` is a Java library that facilitates the generation and resolution of iCalendar content for web-based calendar applications. It provides a flexible and easy-to-use API for creating web calendars with customizable settings and events. The module `webcal` is a Java library that facilitates the generation and resolution of iCalendar content for web-based calendar applications. It provides a flexible and easy-to-use API for creating web calendars with customisable settings and events.
### Key features ### Key features
- Create and manage web calendars with events, including event details such as summary, description, location, and more. - Create and manage web calendars with events, including event details such as summary, description, location, and more.
- Define event classifications and categories for better organization and filtering of calendar data. - Define event classifications and categories for better organisation and filtering of calendar data.
- Set event start and end times, durations, and time zones to handle various scheduling scenarios. - Set event start and end times, durations, and time zones to handle various scheduling scenarios.
- Configure event priorities and completion percentages for visual representation in the calendar. - Configure event priorities and completion percentages for visual representation in the calendar.
- Generate iCalendar format output suitable for web calendar applications. - Generate iCalendar format output suitable for web calendar applications.
+1 -1
View File
@@ -23,7 +23,7 @@
<parent> <parent>
<groupId>cn.org.codecrafters</groupId> <groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId> <artifactId>jdevkit</artifactId>
<version>1.0.1</version> <version>1.1.0</version>
</parent> </parent>
<artifactId>webcal</artifactId> <artifactId>webcal</artifactId>
@@ -21,13 +21,12 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* The WebCalendar class represents a web calendar in iCalendar format. * {@code WebCalendar} class represents a web calendar in iCalendar format.
*
* <p> * <p>
* It allows users to create and customize calendar components and events and * It allows users to create and customise calendar components and events and
* generate an iCalendar string containing all the calendar information. * generate an <b>iCalendar</b> string containing all the calendar information.
* * <p>
* <p>Usage Example: * Usage Example:
* <pre> * <pre>
* WebCalendar calendar = new WebCalendar() * WebCalendar calendar = new WebCalendar()
* .setName("My Web Calendar") * .setName("My Web Calendar")
@@ -39,20 +38,19 @@ import java.util.List;
* .addEvent(event2); * .addEvent(event2);
* String iCalendarString = calendar.resolve(); * String iCalendarString = calendar.resolve();
* </pre> * </pre>
*
* <p> * <p>
* The WebCalendar class is designed to generate an iCalendar string conforming * The {@code WebCalendar} class is designed to generate an iCalendar string
* to the iCalendar specification, which can be used to share calendar data * conforming to the iCalendar specification, which can be used to share
* with other calendar applications or services. * calendar data with other calendar applications or services.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.1.0
* @since 1.0.0 * @since 1.0.0
*/ */
public final class WebCalendar { public final class WebCalendar {
/** /**
* The VCALENDAR tag for iCalendar format * The {@code VCALENDAR} tag for iCalendar format
*/ */
private final static String TAG = "VCALENDAR"; private final static String TAG = "VCALENDAR";
@@ -63,7 +61,6 @@ public final class WebCalendar {
/** /**
* The company who produces this calendar. * The company who produces this calendar.
*
* <p> * <p>
* This property will be used in {@code PRODID}. * This property will be used in {@code PRODID}.
*/ */
@@ -71,7 +68,6 @@ public final class WebCalendar {
/** /**
* The product name. * The product name.
*
* <p> * <p>
* This property will be used in {@code PRODID} * This property will be used in {@code PRODID}
*/ */
@@ -28,20 +28,19 @@ import java.util.Optional;
import java.util.UUID; import java.util.UUID;
/** /**
* The WebCalendarEvent class represents an event in the web calendar. It * The {@code WebCalendarEvent} class represents an event in the web calendar.
* extends the abstract class WebCalendarNode and provides additional methods * It extends the abstract class WebCalendarNode and provides additional
* to set properties specific to events. * methods to set properties specific to events.
*
* <p> * <p>
* Users can use the methods in this class to add categories, set the * Users can use the methods in this class to add categories, set the
* classification, add comments, descriptions, locations, set percent complete * classification, add comments, descriptions, locations, set percent
* , set priority, set summary, set start time, set end time, set duration, set * complete, set priority, set summary, set start time, set end time, set
* URL, set UID, and set timezone for the event. After setting the properties, * duration, set URL, set UID, and set timezone for the event. After setting
* users can call the {@link #resolve()} method to generate the corresponding * the properties, users can call the {@link #resolve()} method to generate the
* iCalendar content for the event. * corresponding iCalendar content for the event.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.1.0
* @since 1.0.0 * @since 1.0.0
*/ */
public final class WebCalendarEvent extends WebCalendarNode { public final class WebCalendarEvent extends WebCalendarNode {
@@ -275,7 +274,7 @@ public final class WebCalendarEvent extends WebCalendarNode {
.map((item) -> "DTEND" + Optional.ofNullable(timezone).map(tz -> ";TZID=" + tz).orElse("") + ":" + .map((item) -> "DTEND" + Optional.ofNullable(timezone).map(tz -> ";TZID=" + tz).orElse("") + ":" +
end.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + "\n").orElse("") + end.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + "\n").orElse("") +
Optional.ofNullable(classification) Optional.ofNullable(classification)
.map((item) -> "CLASS:" + item.getClassification() + "\n").orElse("") + .map((item) -> "CLASS:" + item.name() + "\n").orElse("") +
Optional.ofNullable(comment).map((item) -> "COMMENT:" + item + "\n").orElse("") + Optional.ofNullable(comment).map((item) -> "COMMENT:" + item + "\n").orElse("") +
Optional.ofNullable(description).map((item) -> "DESCRIPTION:" + item + "\n").orElse("") + Optional.ofNullable(description).map((item) -> "DESCRIPTION:" + item + "\n").orElse("") +
Optional.ofNullable(location).map((item) -> "LOCATION:" + item + "\n").orElse("") + Optional.ofNullable(location).map((item) -> "LOCATION:" + item + "\n").orElse("") +
@@ -25,17 +25,16 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* The abstract sealed class WebCalendarNode represents a node in the web * The abstract sealed class {@code WebCalendarNode} represents a node in the
* calendar, such as an event, a to-do item, or an alarm. It provides common * web calendar, such as an event, a to-do item, or an alarm. It provides
* properties and methods for all calendar components and events. * common properties and methods for all calendar components and events.
*
* <p> * <p>
* Subclasses of WebCalendarNode should implement the {@link #resolve()} method * Subclasses of {@code WebCalendarNode} should implement the {@link
* to generate the corresponding iCalendar content for the specific calendar * #resolve()} method to generate the corresponding iCalendar content for the
* component or event. * specific calendar component or event.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.1.0
* @since 1.0.0 * @since 1.0.0
*/ */
public abstract sealed class WebCalendarNode public abstract sealed class WebCalendarNode
@@ -20,9 +20,8 @@ package cn.org.codecrafters.webcal.config;
import lombok.Getter; import lombok.Getter;
/** /**
* The Classification enum represents the classification levels of calendar * The {@code Classification} enum represents the classification levels of
* content based on RFC 5545. * calendar content based on <b>RFC-5545</b>.
*
* <p> * <p>
* Calendar events or components can be classified as one of the following * Calendar events or components can be classified as one of the following
* levels: * levels:
@@ -42,55 +41,34 @@ import lombok.Getter;
* </ul> * </ul>
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.0.0 * @version 1.1.0
* @since 1.0.0 * @since 1.0.0
*/ */
@Getter
public enum Classification { public enum Classification {
/** /**
* Public classification level. * Public classification level.
*
* <p> * <p>
* Indicates that the calendar content is public and can be freely * Indicates that the calendar content is public and can be freely
* distributed. * distributed.
*/ */
PUBLIC("PUBLIC"), PUBLIC,
/** /**
* Private classification level. * Private classification level.
*
* <p> * <p>
* Indicates that the calendar content is private and should not be shared * Indicates that the calendar content is private and should not be shared
* with others. * with others.
*/ */
PRIVATE("PRIVATE"), PRIVATE,
/** /**
* Confidential classification level. * Confidential classification level.
*
* <p> * <p>
* Indicates that the calendar content is confidential and should be kept * Indicates that the calendar content is confidential and should be kept
* strictly private. * strictly private.
*/ */
CONFIDENTIAL("CONFIDENTIAL"), CONFIDENTIAL,
; ;
/**
* -- GETTER --
* Get the string representation of the classification level.
*
* @return the string representation of the classification level
*/
private final String classification;
/**
* Constructor for Classification enum.
*
* @param classification the classification level as a string representation
*/
Classification(String classification) {
this.classification = classification;
}
} }
@@ -16,11 +16,10 @@
*/ */
/** /**
* The package cn.org.codecrafters.webcal.config contains classes related to * The package {@code cn.org.codecrafters.webcal.config} contains classes
* the configuration and settings of the web calendar module. It provides * related to the configuration and settings of the web calendar module. It
* various configurations and constants used in the generation and resolution * provides various configurations and constants used in the generation and
* of iCalendar content. * resolution of iCalendar content.
*
* <p>The classes in this package include:</p> * <p>The classes in this package include:</p>
* <ul> * <ul>
* <li> * <li>
@@ -19,13 +19,12 @@
* The package {@code cn.org.codecrafters.webcal} contains classes and modules * The package {@code cn.org.codecrafters.webcal} contains classes and modules
* related to web calendar generation and resolution. It provides functionality * related to web calendar generation and resolution. It provides functionality
* to create and manage iCalendar content for web-based calendar applications. * to create and manage iCalendar content for web-based calendar applications.
*
* <p> * <p>
* The main classes and modules in this package include: * The main classes and modules in this package include:
* <ul> * <ul>
* <li> * <li>
* {@link cn.org.codecrafters.webcal.WebCalendar}: A class for * {@link cn.org.codecrafters.webcal.WebCalendar}: A class for
* generating web calendars with customizable settings and events. * generating web calendars with customisable settings and events.
* </li> * </li>
* <li> * <li>
* {@link cn.org.codecrafters.webcal.WebCalendarEvent}: A class * {@link cn.org.codecrafters.webcal.WebCalendarEvent}: A class