Skip to content

Commit

Permalink
Refactor utility classes for improved query, JSON, and error handling:
Browse files Browse the repository at this point in the history
* ParamSql updated for clearer SQL parameter structure and documentation.
* CriteriaUtils extended with pagination, sorting utilities, and parameter building for dynamic SQL.
* Introduced JsonException to manage JSON processing issues with detailed status messages.
* Enhanced QueryJson for constructing JSON path-based queries and sorting.
* BeanUtils upgraded with JSON path bean conversion, cache key gen, and advanced copying features.
* RestServerException now supports custom error codes and detailed messaging.

These refinements optimize data manipulation, error management, and query dynamics.
  • Loading branch information
vnobo committed Sep 5, 2024
1 parent 52e25e0 commit cb1e1d1
Show file tree
Hide file tree
Showing 6 changed files with 357 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,44 @@
import java.io.IOException;

/**
* @author <a href="https://github.com/vnobo">Alex bob</a>
* Exception class specifically designed to handle JSON processing errors, extending {@link RestServerException}.
* This exception is typically thrown when there is an issue with parsing or generating JSON data.
*/
public class JsonException extends RestServerException {

/**
* Constructs a new {@code JsonException} instance initialized with a default status code of 500 and a predefined error message,
* wrapping the provided {@link IOException} which represents a JSON processing error.
*
* @param jsonProcessingException The {@link IOException} that was encountered during JSON processing, providing specifics about the processing failure.
*/
public JsonException(IOException jsonProcessingException) {
this(500, "Json processing exception", jsonProcessingException);
}

/**
* Constructs a new {@code JsonException} with a specified status code, error message, and additional details.
* This exception is typically utilized to wrap issues encountered during JSON processing, adding a layer of specificity
* over the broader {@link RestServerException}.
*
* @param status The HTTP status code representing the type of error occurred. This helps in categorizing the exception.
* @param message A human-readable description of the error, providing context about what went wrong during JSON processing.
* @param msg An optional object containing further information or metadata related to the error, which can assist in diagnosing the issue.
*/
public JsonException(int status, String message, Object msg) {
super(status, message, msg);
}

/**
* Constructs and returns a new {@code JsonException} instance wrapping the provided {@link IOException},
* which is indicative of a JSON processing error. This method is a convenience factory for creating
* {@code JsonException} objects without needing to explicitly reference the constructor arguments.
*
* @param jsonProcessingException The {@link IOException} that occurred during JSON processing,
* providing details about the processing error.
* @return A new instance of {@code JsonException} initialized with the given {@code IOException}
* as the cause, carrying a default status code and message indicative of a JSON processing failure.
*/
public static JsonException withError(IOException jsonProcessingException) {
return new JsonException(jsonProcessingException);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,82 @@
import java.io.Serializable;

/**
* @author <a href="https://github.com/vnobo">Alex bob</a>
* Represents a custom exception class for handling REST server errors, which includes an error message, a status code,
* and additional details. This exception extends {@link RuntimeException} and implements {@link Serializable} to support
* serialization when transmitted across networks or persisted.
* <p>
* It provides factory methods to conveniently create instances with predefined or custom error messages and codes,
* facilitating standardization of error responses in a RESTful API context.
*
* <h3>Features:</h3>
* <ul>
* <li>Custom error code to supplement HTTP status codes.</li>
* <li>Holds an arbitrary object ({@code msg}) for detailed error information.</li>
* <li>Convenience static factory methods for instantiation.</li>
* </ul>
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class RestServerException extends RuntimeException implements Serializable {

/**
* Encapsulates additional metadata or details about the error condition.
* This field can hold any type of object, enabling the transmission of structured
* information alongside the exception, such as maps, lists, or custom objects that
* provide context for the error scenario.
*/
protected Object msg;
/**
* The error code associated with this {@link RestServerException}.
* This field represents a custom error code that provides more granular information
* about the specific error scenario beyond standard HTTP status codes.
* It is intended for use in identifying and differentiating between various error conditions.
*/
protected int code;

/**
* Constructs a new instance of {@code RestServerException} with specified error code, message, and additional details.
* This exception is intended for conveying REST server-side error conditions, providing a more granular error code
* alongside a standard exception message and an optional object that can carry detailed contextual information.
*
* @param code The custom error code associated with the exception. This can be used to differentiate between
* various error scenarios beyond the standard HTTP status codes.
* @param message The human-readable error message explaining the exception circumstances. Should be concise and informative.
* @param msg An optional object containing additional metadata or details about the error. Can be any type,
* facilitating the passing of structured error information (e.g., maps, lists, or domain-specific objects).
*/
public RestServerException(int code, String message, Object msg) {
super(message);
this.msg = msg;
this.code = code;
}

/**
* Creates a new instance of {@code RestServerException} with a predefined HTTP status code of 500 (Internal Server Error),
* a custom message, and additional details encapsulated in the {@code msg} parameter.
* This method serves as a convenience factory for generating exceptions that indicate a generic server error
* along with specific contextual information.
*
* @param message A descriptive message explaining the reason for the exception.
* @param msg An arbitrary object containing additional details about the error. This can be used to provide more
* extensive error context or metadata.
* @return A new instance of {@code RestServerException} initialized with the provided message, a status code of 500,
* and the additional details object.
*/
public static RestServerException withMsg(String message, Object msg) {
return withMsg(500, message, msg);
}

/**
* Creates a new instance of {@code RestServerException} with a specified error code, message, and additional details.
* This static factory method allows for customization of the error response by providing a unique error code and
* a message along with an arbitrary object that can contain further information about the error condition.
*
* @param code The custom error code to identify the specific error scenario. This code supplements the HTTP status code.
* @param message The error message describing the exception's nature. Should be informative for debugging purposes.
* @param msg An optional object holding additional metadata or details related to the error. Can be any type.
* @return A new instance of {@code RestServerException} initialized with the provided code, message, and additional details.
*/
public static RestServerException withMsg(int code, String message, Object msg) {
return new RestServerException(code, message, msg);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
import java.util.StringJoiner;

/**
* @author <a href="https://github.com/vnobo">Alex bob</a>
* Converts a JavaBean object into a Map representation.
* Each property of the bean is represented as a key-value pair in the map,
* with the property name as the key and its corresponding value as the value.
*/
@Log4j2
@Component
Expand All @@ -46,6 +48,21 @@ public final class BeanUtils implements InitializingBean {
}
}

/**
* Converts a JSON node at a specified JSON Path into an object of the provided class type.
* <p>
* This method takes a JsonNode, a JSON Path string, and a target class type, then navigates to the
* JSON node located at the specified path within the input JSON. If the node exists, it is converted
* into an instance of the target class. If the path does not exist or conversion fails, exceptions are thrown.
*
* @param <T> The type of the object to be returned.
* @param json The JsonNode from which to extract data.
* @param path A comma-separated string representing the JSON Path to the desired node.
* @param clazz The class of the type that the JSON node should be converted into.
* @return An instance of the specified class containing the data from the JSON node at the given path.
* @throws JsonException If the JSON Pointer path does not exist in the JSON structure,
* or if there is an issue converting the JsonNode to the target class.
*/
public static <T> T jsonPathToBean(JsonNode json, String path, Class<T> clazz) {
try {
String[] paths = StringUtils.commaDelimitedListToStringArray(path);
Expand All @@ -65,6 +82,14 @@ public static <T> T jsonPathToBean(JsonNode json, String path, Class<T> clazz) {
}
}

/**
* Converts the given object into a byte array using JSON serialization.
*
* @param <T> The type of the object to be serialized.
* @param object The object instance to be converted into bytes.
* @return A byte array representing the serialized form of the input object.
* @throws JsonException If the object cannot be serialized into JSON.
*/
public static <T> byte[] objectToBytes(T object) {
try {
return ContextUtils.OBJECT_MAPPER.writeValueAsBytes(object);
Expand All @@ -73,11 +98,26 @@ public static <T> byte[] objectToBytes(T object) {
}
}

/**
* Generates a cache key based on the hash codes of the provided objects.
* This method is useful for creating unique keys for caching purposes when the key is derived from multiple parameters.
*
* @param objects A variable number of objects whose hash codes will be combined to form the cache key.
* @return A string representation of the combined hash code, serving as a unique cache key.
*/
public static String cacheKey(Object... objects) {
int hashCode = Objects.hash(objects);
return String.valueOf(hashCode);
}

/**
* Inserts an object into the specified cache if its size does not exceed the maximum allowed in-memory size.
*
* @param cache The cache instance where the object will be stored.
* @param cacheKey The key under which the object will be stored in the cache.
* @param obj The object to be cached. Its size will be evaluated against the maximum allowed size.
* If the object exceeds the limit, it will not be cached and a warning will be logged.
*/
public static void cachePut(Cache cache, String cacheKey, Object obj) {
DataSize objectSize = getBeanSize(obj);
if (objectSize.toBytes() > MAX_IN_MEMORY_SIZE.toBytes()) {
Expand All @@ -88,6 +128,15 @@ public static void cachePut(Cache cache, String cacheKey, Object obj) {
cache.put(cacheKey, obj);
}

/**
* Calculates the size of the given Java bean by serializing it into a byte array and measuring its length.
* This method provides an estimate of the space the object occupies when serialized.
*
* @param obj The Java bean object whose size is to be calculated. Must not be null.
* @return The size of the bean as a {@link DataSize} object, representing the size in a human-readable format.
* If the object is empty or serialization fails, returns a DataSize of 0 bytes.
* @throws IllegalArgumentException If the provided object is null, since null cannot be sized.
*/
public static DataSize getBeanSize(Object obj) {
if (ObjectUtils.isEmpty(obj)) {
log.warn("Object is empty,This object not null.");
Expand All @@ -104,16 +153,41 @@ public static DataSize getBeanSize(Object obj) {
}
}

/**
* Copies the properties from the source object to a new instance of the specified target class.
* This method utilizes Spring's BeanUtils to perform the deep copy, allowing for copying nested properties as well.
*
* @param <T> The type of the target class.
* @param source The source object from which properties are to be copied.
* @param clazz The class of the target object to be instantiated and populated with the source's properties.
* @return A new instance of the target class with properties copied from the source object.
* @throws IllegalArgumentException If the source is null or the clazz cannot be instantiated.
*/
public static <T> T copyProperties(Object source, Class<T> clazz) {
T target = org.springframework.beans.BeanUtils.instantiateClass(clazz);
BeanUtils.copyProperties(source, target, true);
return target;
}

/**
* Copies the properties from the source object to the target object.
*
* @param source The source object whose properties are to be copied.
* @param target The target object where the properties from the source will be set.
*/
public static void copyProperties(Object source, Object target) {
BeanUtils.copyProperties(source, target, false);
}

/**
* Copies properties from the source object to the target object.
* Optionally, properties with null values can be ignored during the copy process.
*
* @param source The source object from which properties are to be copied.
* @param target The target object to which properties are to be copied.
* @param ignoreNullValue If true, properties with null values in the source object will not be copied to the target object.
* If false, all properties including those with null values are copied.
*/
public static void copyProperties(Object source, Object target, boolean ignoreNullValue) {
Map<String, Object> targetMap = BeanUtils.beanToMap(source);
String[] nullKeys = new String[0];
Expand All @@ -127,14 +201,41 @@ public static void copyProperties(Object source, Object target, boolean ignoreNu
}
}

/**
* Converts a JavaBean object into a Map representation.
*
* @param <T> The type of the bean.
* @param bean The JavaBean object to be converted.
* @return A Map containing the properties of the JavaBean with keys as String and values as Object.
* The returned Map reflects the properties of the input bean including any nested beans.
*/
public static <T> Map<String, Object> beanToMap(T bean) {
return BeanUtils.beanToMap(bean, false);
}

/**
* Converts a JavaBean object into a Map, with keys representing the property names
* and values representing the corresponding property values.
*
* @param <T> The type of the bean to convert.
* @param bean The JavaBean object to be converted into a Map.
* @param ignoreNullValue If true, properties with null values will not be included in the Map.
* @return A Map where each key-value pair corresponds to a property name and its value from the input bean.
* If ignoreNullValue is true, properties with null values are excluded.
*/
public static <T> Map<String, Object> beanToMap(T bean, final boolean ignoreNullValue) {
return BeanUtils.beanToMap(bean, false, ignoreNullValue);
}

/**
* Converts a JavaBean object into a Map, with options to transform field names to snake_case and ignore null values.
*
* @param <T> The type of the bean to convert.
* @param bean The JavaBean object to be converted into a Map.
* @param isToUnderlineCase If true, converts camelCase keys in the Map to snake_case. Defaults to false.
* @param ignoreNullValue If true, excludes keys with null values from the resulting Map. Defaults to false.
* @return A Map representation of the input JavaBean, optionally with keys transformed to snake_case and null values excluded.
*/
public static <T> Map<String, Object> beanToMap(T bean, final boolean isToUnderlineCase, final boolean ignoreNullValue) {
if (ObjectUtils.isEmpty(bean)) {
return null;
Expand Down
Loading

0 comments on commit cb1e1d1

Please sign in to comment.