docs(global): Optimised javadoc, changed the spelling to British English.

This commit is contained in:
Zihlu Wang
2023-09-18 15:04:10 +08:00
parent fee85d5d84
commit f80c47e8ad
41 changed files with 459 additions and 438 deletions
@@ -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 entire JDevKit 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>.
@@ -34,12 +34,12 @@ import java.util.Objects;
import java.util.UUID; import java.util.UUID;
/** /**
* AES Util helps you encrypt and decrypt data with specified key and AES * {@link AesUtil} can help you encrypt and decrypt data with specified secret
* algorithm. * by AES algorithm.
* *
* @author hubin@baomidou * @author hubin@baomidou
* @since 1.1.0
* @version 1.1.0 * @version 1.1.0
* @since 1.1.0
*/ */
@Slf4j @Slf4j
public final class AesUtil { public final class AesUtil {
@@ -52,17 +52,17 @@ public final class AesUtil {
private static final String AES_CBC_CIPHER = "AES/CBC/PKCS5Padding"; private static final String AES_CBC_CIPHER = "AES/CBC/PKCS5Padding";
/** /**
* Encrypt the given data with given key with AES algorithm. * Encrypts the data using the AES algorithm with the given secret.
* *
* @param data the data to be encrypted * @param data the data to be encrypted
* @param key the key to encrypt the data * @param secret the secret to encrypt the data
* @return the encryption result or {@code null} if encryption failed * @return the encryption result or {@code null} if encryption failed
*/ */
public static byte[] encrypt(byte[] data, byte[] key) { public static byte[] encrypt(byte[] data, byte[] secret) {
try { try {
var secretKeySpec = new SecretKeySpec(new SecretKeySpec(key, AES).getEncoded(), AES); var secretKeySpec = new SecretKeySpec(new SecretKeySpec(secret, AES).getEncoded(), AES);
var cipher = Cipher.getInstance(AES_CBC_CIPHER); var cipher = Cipher.getInstance(AES_CBC_CIPHER);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(key)); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(secret));
return cipher.doFinal(data); return cipher.doFinal(data);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | UnsupportedOperationException | } catch (NoSuchAlgorithmException | NoSuchPaddingException | UnsupportedOperationException |
InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException |
@@ -76,17 +76,17 @@ public final class AesUtil {
} }
/** /**
* Decrypt the given data with given key with AES algorithm. * Decrypts the data using the AES algorithm with the given secret.
* *
* @param data the data to be decrypted * @param data the data to be decrypted
* @param key the key to encrypt the data * @param secret the secret to encrypt the data
* @return the decryption result or {@code null} if decryption failed * @return the decryption result or {@code null} if decryption failed
*/ */
public static byte[] decrypt(byte[] data, byte[] key) { public static byte[] decrypt(byte[] data, byte[] secret) {
try { try {
var secretKeySpec = new SecretKeySpec(new SecretKeySpec(key, AES).getEncoded(), AES); var secretKeySpec = new SecretKeySpec(new SecretKeySpec(secret, AES).getEncoded(), AES);
var cipher = Cipher.getInstance(AES_CBC_CIPHER); var cipher = Cipher.getInstance(AES_CBC_CIPHER);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(key)); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(secret));
return cipher.doFinal(data); return cipher.doFinal(data);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | UnsupportedOperationException | } catch (NoSuchAlgorithmException | NoSuchPaddingException | UnsupportedOperationException |
InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException |
@@ -100,36 +100,36 @@ public final class AesUtil {
} }
/** /**
* Encrypt the given data with given key with AES algorithm. * Encrypts the data using the AES algorithm with the given secret.
* *
* @param data the data to be encrypted * @param data the data to be encrypted
* @param key the key to encrypt the data * @param secret the secret to encrypt the data
* @return the encryption result or {@code null} if encryption failed * @return the encryption result or {@code null} if encryption failed
*/ */
public static String encrypt(String data, String key) { public static String encrypt(String data, String secret) {
return Base64.getEncoder().encodeToString(encrypt(data.getBytes(StandardCharsets.UTF_8), key.getBytes(StandardCharsets.UTF_8))); return Base64.getEncoder().encodeToString(encrypt(data.getBytes(StandardCharsets.UTF_8), secret.getBytes(StandardCharsets.UTF_8)));
} }
/** /**
* Decrypt the given data with given key with AES algorithm. * Decrypts the data using the AES algorithm with the given secret.
* *
* @param data the data to be decrypted * @param data the data to be decrypted
* @param key the key to encrypt the data * @param secret the secret to encrypt the data
* @return the decryption result or {@code null} if decryption failed * @return the decryption result or {@code null} if decryption failed
*/ */
public static String decrypt(String data, String key) { public static String decrypt(String data, String secret) {
return new String(Objects.requireNonNull( return new String(Objects.requireNonNull(
decrypt(Base64.getDecoder().decode(data.getBytes()), decrypt(Base64.getDecoder().decode(data.getBytes()),
key.getBytes(StandardCharsets.UTF_8))) secret.getBytes(StandardCharsets.UTF_8)))
); );
} }
/** /**
* Generates 16 characters-long random key. * Generates 16 characters-long random secret.
* *
* @return the generated secure secret * @return the generated secure secret
*/ */
public static String generateRandomKey() { public static String generateRandomSecret() {
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16); return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
} }
@@ -20,10 +20,11 @@ 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;
/** /**
* The {@code Base64Util} class provides static methods to encode and decode * The {@link Base64Util} class provides static methods to encode and decode
* strings using Base64 encoding. It utilizes the {@link Base64} class from the * strings with 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.
@@ -55,6 +56,34 @@ import java.util.Base64;
*/ */
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.
*/ */
@@ -69,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);
} }
@@ -93,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,24 +23,24 @@ import java.util.function.BooleanSupplier;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
* The BranchUtil class provides static methods to simplify conditional logic * The {@link BranchUtil} class provides static methods to simplify conditional
* in Java development by leveraging lambda expressions. It offers convenient * logic in Java development by leveraging lambda expressions. It offers
* methods to replace verbose if...else statements with more concise and * convenient methods to replace verbose {@code if...else} statements with more
* expressive functional constructs. * concise and expressive functional constructs.
* <p> * <p>
* Developers can use the methods in this utility class to streamline their * Developers can use methods in this utility class to streamline their code,
* code, enhance readability, and promote a more functional style of * enhance readability, and promote a more functional style of programming when
* programming when dealing with branching logic and conditional statements. * 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.");
* *
@@ -26,14 +26,12 @@ import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
/** /**
* Utility class for chained high-precision calculations using BigDecimal. * The {@code ChainedCalcUtil} class provides a convenient way to perform
* <p> * chained high-precision calculations using {@link BigDecimal}. It allows
* The ChainedCalcUtil class provides a convenient way to perform chained * users to perform mathematical operations such as addition, subtraction,
* high-precision calculations using BigDecimal. It allows users to perform * multiplication, and division with customisable precision and scale. By using
* mathematical operations such as addition, subtraction, multiplication, * this utility class, developers can achieve accurate results and avoid
* and division with customisable precision and scale. By using this utility * precision loss in their calculations.
* class, developers can achieve accurate results and avoid precision loss
* in their calculations.
* <p> * <p>
* <b>Usage:</b> * <b>Usage:</b>
* <pre> * <pre>
@@ -81,13 +79,13 @@ 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.1.0 * @version 1.1.0
@@ -104,7 +102,8 @@ public final class ChainedCalcUtil {
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
*/ */
@@ -116,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);
@@ -126,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);
@@ -138,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);
@@ -148,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);
@@ -160,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);
@@ -170,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);
@@ -182,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);
@@ -192,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);
@@ -204,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);
@@ -215,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 ->
@@ -229,54 +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 with the specified scale. * Returns the current value as a {@link 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();
@@ -332,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,12 +25,10 @@ import java.util.Objects;
import java.util.Optional; import java.util.Optional;
/** /**
* Utility class for performing hash operations on strings. * The {@code HashUtil} class provides convenient methods for calculating
* <p> * various hash functions on strings, including MD2, MD5, SHA-1, SHA-224,
* The HashUtil class provides convenient methods for calculating various hash * SHA-256, SHA-384, and SHA-512. It allows developers to easily obtain the
* functions on strings, including MD2, MD5, SHA-1, SHA-224, SHA-256, SHA-384, * hash value of a given string using different algorithms.
* 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>
@@ -55,8 +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
@@ -24,8 +24,8 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* MapUtil is a utility class that provides methods for converting objects to * {@code MapUtil} is a utility class that provides methods for converting
* maps and maps to objects. * objects to 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.
@@ -207,10 +207,10 @@ public final class MapUtil {
/** /**
* Casts the specified value to the required type. * Casts the specified value to the required type.
* *
* @param value the value to be casted * @param value the value to be cast
* @param requiredType the type to which the value should be casted * @param requiredType the type to which the value should be cast
* @param <T> the type to which the value should be casted * @param <T> the type to which the value should be cast
* @return the casted value, or null if the value cannot be casted to the * @return the cast value, or null if the value cannot be cast to the
* required type * required type
*/ */
public static <T> T cast(Object value, Class<T> requiredType) { public static <T> T cast(Object value, Class<T> requiredType) {
@@ -24,12 +24,10 @@ import java.time.ZoneId;
import java.time.ZoneOffset; import java.time.ZoneOffset;
/** /**
* SnowflakeGuidCreator - GUID generator based on the Snowflake algorithm. * The {@code SnowflakeGuidCreator} generates unique identifiers using the
* <p> * Snowflake algorithm, which combines a timestamp, worker ID, and data centre
* The SnowflakeGuidCreator generates unique identifiers using the Snowflake * ID to create 64-bit long integers. The bit distribution for the generated
* algorithm, which combines a timestamp, worker ID, and data centre ID to * IDs is as follows:
* 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>
@@ -38,10 +36,10 @@ import java.time.ZoneOffset;
* <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 centre 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.
* *
@@ -18,8 +18,8 @@
package cn.org.codecrafters.guid.exceptions; package cn.org.codecrafters.guid.exceptions;
/** /**
* The TimingException class represents an exception that is thrown when there * The {@code TimingException} class represents an exception that is thrown
* is an error related to time sequence. * when there is an error related to time sequence.
* <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
@@ -40,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);
@@ -50,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) {
@@ -61,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
*/ */
+1 -1
View File
@@ -57,7 +57,7 @@ import cn.org.codecrafters.simplejwt.SecretCreator;
class GenerateRandomKeySample { class GenerateRandomKeySample {
public static void main(String[] args) { public static void main(String[] args) {
var secret1 = AesUtil.generateRandomKey(); var secret1 = AesUtil.generateRandomSecret();
var secret2 = SecretCreator.createSecret(16, true, true, true); var secret2 = SecretCreator.createSecret(16, true, true, true);
} }
} }
@@ -29,17 +29,27 @@ import java.util.HashMap;
import java.util.Optional; import java.util.Optional;
/** /**
* PropertyEncryptor is a utility class designed for encrypting configuration * {@code PropertyGuard} is a utility class designed for encrypting
* information in Spring Boot applications. * configuration properties in Spring Boot applications.
* <p> * <p>
* Spring Boot applications often need to store sensitive configuration details * Spring Boot applications often need to store sensitive configuration details
* such as database passwords, API keys, etc. To ensure that these sensitive * such as database passwords, API keys, etc. To ensure that these sensitive
* pieces of information are not exposed, developers can utilize the * pieces of information are not exposed to the public, developers can utilize
* {@code PropertyGuard} class to encrypt and store them within configuration * the {@code PropertyGuard} class to encrypt and store them within
* files. * configuration files.
* <p> * <p>
* <b>Usage</b> * <b>Usage</b>
* In {@code application.yml} or {@code application.properties}: * 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> * <pre>
* # original * # original
* app.example-properties=Sample Value * app.example-properties=Sample Value
@@ -47,16 +57,15 @@ import java.util.Optional;
* # encrypted with key 3856faef0d2d4f33 * # encrypted with key 3856faef0d2d4f33
* app.example-properties=pg:t4YBfv8M9ZmTzWgTi2gJqg== * app.example-properties=pg:t4YBfv8M9ZmTzWgTi2gJqg==
* </pre> * </pre>
* Then, add the command line arguments like {@code --pe.key=3856faef0d2d4f33}. * After that, before running, you need to add the command line arguments
* "pg.key" as the following codes: {@code --pg.key=<the secret>}.
* <p> * <p>
* This class is extracted from <a href="https://baomidou.com/pages/e0a5ce/" * This class is extracted from <a href="https://baomidou.com/pages/e0a5ce/"
* >MyBatis-Plus</a>. * >MyBatis-Plus</a>.
* <p>
* The prefix to specify the encrypted value is {@code pg}.
* *
* @author hubin@baomidou * @author hubin@baomidou
* @version 1.1.0 * @version 1.1.0
* @see org.springframework.boot.env.EnvironmentPostProcessor * @see EnvironmentPostProcessor
* @since 1.1.0 (3.3.2 of MyBatis-Plus) * @since 1.1.0 (3.3.2 of MyBatis-Plus)
*/ */
public class PropertyGuard implements EnvironmentPostProcessor { public class PropertyGuard implements EnvironmentPostProcessor {
@@ -122,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
@@ -151,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
@@ -168,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);
@@ -177,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,
@@ -193,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);
@@ -202,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);
@@ -286,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
@@ -310,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.
* *
@@ -324,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
@@ -387,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());
} }
} }
@@ -395,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) {
@@ -449,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;
} }
@@ -475,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}
@@ -489,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}
@@ -511,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,29 +31,29 @@ 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.1.0 * @version 1.1.0
@@ -60,39 +62,34 @@ import java.util.function.Function;
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);
@@ -101,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)) {
@@ -119,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
@@ -33,18 +33,21 @@
* 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}
@@ -22,9 +22,9 @@ 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.1.0 * @version 1.1.0
@@ -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}
@@ -22,10 +22,10 @@ import java.time.Duration;
import java.util.Map; import java.util.Map;
/** /**
* The {@code TokenResolver} interface defines methods for creating, * {@code TokenResolver} defines methods for creating, extracting, and
* extracting, and renewing tokens, particularly JSON Web Tokens (JWTs). It * renewing tokens, particularly JSON Web Tokens (JWTs). It provides a set of
* provides a set of methods to generate tokens with various payload * methods to generate tokens with various payload configurations, extract
* configurations, extract payload from tokens, and renew expired tokens. * 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
@@ -23,11 +23,10 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* <p> * Annotation {@code ExcludeFromPayload} is used to mark a property of a data
* This annotation is used to mark a property of a data class that should be * class that should be excluded from being automatically injected into the
* excluded from being automatically injected into the JSON Web Token (JWT) * JSON Web Token (JWT) payload during token generation. When a property is
* payload during token generation. When a property is annotated with this * annotated by this annotation, it will not be included in the JWT payloads.
* annotation, it will not be included as part of the JWT payload.
* <p> * <p>
* <b>Usage:</b> * <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
@@ -46,10 +45,10 @@ import java.lang.annotation.Target;
* }</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.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.1.0 * @version 1.1.0
@@ -17,19 +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;
/** /**
* The TokenResolverConfig interface provides a mechanism to configure a * The {@code TokenResolverConfig} provides a mechanism to configure a
* TokenResolver with algorithm functions. * {@link 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
@@ -37,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);
@@ -17,14 +17,15 @@
/** /**
* 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
* customisation 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
*/ */
@@ -87,11 +87,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,8 +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><b>Supported Algorithms:</b> * <p>
* This enum includes the following supported algorithms: * <b>Supported Algorithms:</b>
* <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>
@@ -18,10 +18,15 @@
package cn.org.codecrafters.simplejwt.exceptions; package cn.org.codecrafters.simplejwt.exceptions;
/** /**
* This {@code UnsupportedAlgorithmException} is to indicates that the given * This {@code UnsupportedAlgorithmException} represents the given
* algorithm is not supported by TokenResolver yet. * algorithm is not supported by {@link
* cn.org.codecrafters.simplejwt.TokenResolver} yet.
* <p> * <p>
* To support a specified algorithm, you could * If you want the supports to an unsupported algorithm, you could
* <ul>
* <li>Commit an issue at GitHub Issues or;</li>
* <li>Communicate with us on Discord Community.</li>
* </ul>
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.1.0 * @version 1.1.0
@@ -30,17 +35,17 @@ package cn.org.codecrafters.simplejwt.exceptions;
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.
@@ -50,12 +55,8 @@ public class UnsupportedAlgorithmException extends RuntimeException {
} }
/** /**
* Constructs a new runtime exception with the specified detail message and * Constructs a new {@code UnsupportedAlgorithmException} with the
* cause. * specified detail message and 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).
@@ -70,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
@@ -87,9 +89,9 @@ 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,
@@ -18,8 +18,12 @@
package cn.org.codecrafters.simplejwt.exceptions; package cn.org.codecrafters.simplejwt.exceptions;
/** /**
* This Exception indicates that your secret is too weak to be used in signing * {@code WeakSecretException} represents that your secret is too weak to be
* JWTs. * 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 * @version 1.1.0
@@ -28,7 +32,7 @@ package cn.org.codecrafters.simplejwt.exceptions;
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}.
*/ */
@@ -36,9 +40,9 @@ public class WeakSecretException extends RuntimeException {
} }
/** /**
* 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.
@@ -48,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).
@@ -59,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);
@@ -17,20 +17,22 @@
/** /**
* 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
*/ */
@@ -17,22 +17,22 @@
/** /**
* 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 customisable, 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
@@ -58,7 +58,7 @@ import java.util.UUID;
* To use the {@code JjwtTokenResolver}, first, create an instance of this * To use the {@code JjwtTokenResolver}, first, create an instance of this
* class: * class:
* <pre>{@code * <pre>{@code
* TokenResolver<DecodedJWT> tokenResolver = * TokenResolver<Jws<Claims>> tokenResolver =
* new JjwtTokenResolver(TokenAlgorithm.HS256, * new JjwtTokenResolver(TokenAlgorithm.HS256,
* "Token Subject", * "Token Subject",
* "Token Issuer", * "Token Issuer",
@@ -256,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
@@ -287,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,6 +17,7 @@
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;
@@ -27,23 +28,23 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* The JjwtTokenResolverConfig class provides the configuration for the * The {@code JjwtTokenResolverConfig} class provides the configuration for the
* JjwtTokenResolverConfig. * {@link JjwtTokenResolver}.
* <p> * <p>
* This configuration class is used to establish the mapping between the * This configuration class is used to establish the mapping between the
* standard TokenAlgorithm defined within the JjwtTokenResolverConfig and * standard {@link TokenAlgorithm} defined within the
* the specific algorithms used by the {@code io.jsonwebtoken:jjwt} library, * {@code JjwtTokenResolverConfig} and the specific algorithms used by the
* which is the underlying library used by JjwtTokenResolverConfig to handle * {@code io.jsonwebtoken:jjwt} library, which is the underlying library used
* JSON Web Tokens (JWTs). * by {@code JjwtTokenResolver} to handle JSON Web Tokens (JWTs).
* <p> * <p>
* <b>Algorithm Mapping:</b> * <b>Algorithm Mapping:</b>
* The JjwtTokenResolverConfig class allows specifying the relationship * The {@code JjwtTokenResolverConfig} allows specifying the relationship
* between the standard TokenAlgorithm instances supported by * between the standard {@link TokenAlgorithm} instances supported by {@link
* JjwtTokenResolverConfig and the corresponding algorithms used by the * JjwtTokenResolver} and the corresponding algorithms used by the
* {@code io.jsonwebtoken:jjwt} library. The mapping is achieved using a Map, * {@code io.jsonwebtoken:jjwt} library. The mapping is achieved using a Map,
* where the keys are the standard TokenAlgorithm instances, and the values * where the keys are the standard {@link TokenAlgorithm} instances, and the
* represent the algorithm functions used by {@code io.jsonwebtoken:jjwt} * values represent the algorithm functions used by
* library for each corresponding key. * {@code io.jsonwebtoken:jjwt} library for each 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
@@ -78,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);
} }
@@ -33,18 +33,20 @@
* 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}
@@ -34,20 +34,21 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.DependsOn;
/** /**
* SimpleJwtAutoConfiguration is responsible for automatically configuring the * {@code AuthzeroTokenResolverAutoConfiguration} is responsible for
* Simple JWT library with {@code com.auth0:java-jwt} when used in a Spring * automatically configuring the Simple JWT library with
* Boot application. It provides default settings and configurations to ensure * {@code com.auth0:java-jwt} when used in a Spring Boot application. It
* that the library works smoothly without requiring manual configuration. * provides default settings and configurations to ensure that the library
* works smoothly without requiring manual configuration.
* <p> * <p>
* This autoconfiguration 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 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 autoconfiguration 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
@@ -29,7 +29,7 @@ import org.springframework.context.annotation.Conditional;
import java.util.UUID; import java.util.UUID;
/** /**
* Autoconfiguration for injecting a {@code GuidCreator} for generating jwt id. * Autoconfiguration for injecting a {@link GuidCreator} for generating jwt id.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.1.0 * @version 1.1.0
@@ -34,7 +34,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
/** /**
* JjwtTokenResolverAutoConfiguration is responsible for automatically * {@code 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
@@ -42,8 +42,8 @@ import org.springframework.context.annotation.Bean;
* <p> * <p>
* This autoconfiguration 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 autoconfiguration takes care of * explicitly configure the library, as the autoconfiguration takes care of
@@ -9,7 +9,7 @@ import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Objects; import java.util.Objects;
/** /**
* The condition to create bean {@code jtiCreator}. * The conditions to create bean {@code jtiCreator}.
* *
* @author Zihlu Wang * @author Zihlu Wang
* @version 1.1.0 * @version 1.1.0
@@ -25,20 +25,20 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
/** /**
* {@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} and {@link * AuthzeroTokenResolverAutoConfiguration} and {@link
* cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver} to set up the * cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver} to set up the
* necessary configurations for JWT generation and 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 * @author Zihlu Wang
* @version 1.1.0 * @version 1.1.0
@@ -21,11 +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>Usage Example: * <p>
* Usage Example:
* <pre> * <pre>
* WebCalendar calendar = new WebCalendar() * WebCalendar calendar = new WebCalendar()
* .setName("My Web Calendar") * .setName("My Web Calendar")
@@ -38,9 +39,9 @@ import java.util.List;
* 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.1.0 * @version 1.1.0
@@ -49,7 +50,7 @@ import java.util.List;
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";
@@ -60,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}.
*/ */
@@ -68,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,17 +28,16 @@ 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.1.0 * @version 1.1.0
@@ -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,14 +25,13 @@ 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.1.0 * @version 1.1.0
@@ -20,8 +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:
@@ -44,7 +44,6 @@ import lombok.Getter;
* @version 1.1.0 * @version 1.1.0
* @since 1.0.0 * @since 1.0.0
*/ */
@Getter
public enum Classification { public enum Classification {
/** /**
@@ -53,7 +52,7 @@ public enum Classification {
* 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.
@@ -61,7 +60,7 @@ public enum Classification {
* 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.
@@ -69,22 +68,7 @@ public enum Classification {
* 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.
*/
private final String classification;
/**
* Constructor for Classification enum.
*
* @param classification the classification level as a string representation
*/
Classification(String classification) {
this.classification = classification;
}
} }
@@ -16,10 +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>