Work in progress ...
This commit is contained in:
+2
-2
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ import java.util.Iterator;
|
||||
* The ArgumentProvider class is a helper utility for iterating over an array
|
||||
* of command-line arguments. It provides methods to check for available arguments
|
||||
* and retrieve them in sequence.
|
||||
*
|
||||
* This class is designed to work seamlessly with a command-line parser
|
||||
* and handle tokenized inputs efficiently. It implements the Iterator interface
|
||||
* for ease of iteration.
|
||||
* <p>
|
||||
* This class is designed to work seamlessly with a command-line parser and handle
|
||||
* tokenized inputs efficiently. It implements the {@link Iterator} interface for ease
|
||||
* of iteration and provides convenience methods for peeking ahead.
|
||||
*/
|
||||
public class ArgumentProvider implements Iterator<String> {
|
||||
|
||||
@@ -19,18 +19,15 @@ public class ArgumentProvider implements Iterator<String> {
|
||||
* and processing by the application logic. It is used within the {@code ArgumentProvider}
|
||||
* class to iterate through and retrieve arguments systematically.
|
||||
*/
|
||||
private String[] arguments;
|
||||
private final String[] arguments;
|
||||
|
||||
/**
|
||||
* Tracks the current position within an array of arguments.
|
||||
*
|
||||
* This variable is used to index into the arguments array, enabling
|
||||
* sequential access to command-line tokens. It is incremented as arguments
|
||||
* are processed or retrieved using methods such as {@code next()} or {@code peek()}
|
||||
* in the {@link ArgumentProvider} class.
|
||||
*
|
||||
* Its value starts at 0 and increases until it reaches the length of
|
||||
* the provided arguments array, at which point iteration ends.
|
||||
* This variable is used to index into the arguments array, enabling sequential access
|
||||
* to command-line tokens. It is incremented as arguments are processed or retrieved
|
||||
* using methods such as {@code next()} or {@code peek()} in the {@link ArgumentProvider}
|
||||
* class. Its value starts at 0 and increases until it reaches the length of the provided
|
||||
* arguments array, at which point iteration ends.
|
||||
*/
|
||||
private int current = 0;
|
||||
|
||||
@@ -43,21 +40,12 @@ public class ArgumentProvider implements Iterator<String> {
|
||||
*/
|
||||
public ArgumentProvider(final String[] arguments) {
|
||||
if (arguments == null) {
|
||||
this.arguments = new String[] {};
|
||||
this.arguments = new String[]{};
|
||||
} else {
|
||||
this.arguments = arguments;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there are more arguments available to iterate over.
|
||||
*
|
||||
* @return true if there are additional arguments available; false otherwise.
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return current < arguments.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the specified number of additional arguments are available in the collection.
|
||||
*
|
||||
@@ -68,6 +56,26 @@ public class ArgumentProvider implements Iterator<String> {
|
||||
return current + count <= arguments.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next argument in the sequence without advancing the iterator.
|
||||
* If there are no more arguments available, this method returns null.
|
||||
*
|
||||
* @return the next argument in the sequence or null if no arguments are available
|
||||
*/
|
||||
public String peek() {
|
||||
if (!hasNext()) return null;
|
||||
return arguments[current];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there are more arguments available to iterate over.
|
||||
*
|
||||
* @return true if there are additional arguments available; false otherwise.
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return current < arguments.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the next argument in the sequence.
|
||||
* If no more arguments are available, returns {@code null}.
|
||||
@@ -81,15 +89,4 @@ public class ArgumentProvider implements Iterator<String> {
|
||||
current++;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next argument in the sequence without advancing the iterator.
|
||||
* If there are no more arguments available, this method returns null.
|
||||
*
|
||||
* @return the next argument in the sequence or null if no arguments are available
|
||||
*/
|
||||
public String peek() {
|
||||
if (!hasNext()) return null;
|
||||
return arguments[current];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import java.util.function.Consumer;
|
||||
* The `Parameter` class defines a command-line parameter with associated metadata,
|
||||
* such as constraints on the number of values it accepts, descriptions, and aliases.
|
||||
* It also allows specifying callbacks to handle parameter processing.
|
||||
*
|
||||
* <p>
|
||||
* This class is intended to be used as part of a command-line parser, enabling
|
||||
* structured handling of arguments provided via the command line.
|
||||
*/
|
||||
@@ -23,14 +23,141 @@ import java.util.function.Consumer;
|
||||
@Setter
|
||||
public class Parameter {
|
||||
|
||||
/**
|
||||
* The `name` variable represents the primary identifier for a parameter.
|
||||
* This string is used to uniquely identify a command-line parameter when parsing
|
||||
* arguments. It serves as the key for registering and retrieving parameters in a
|
||||
* command-line parser.
|
||||
* <p>
|
||||
* The value of `name` is case-insensitive and can be used alongside aliases to
|
||||
* recognize and process parameters provided in the command-line input.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Specifies the minimum number of values required for this parameter.
|
||||
* <p>
|
||||
* This variable enforces a constraint on the number of arguments that must
|
||||
* be provided for the parameter during command-line parsing. If the number of
|
||||
* provided arguments is less than this value, an exception will be thrown during parsing.
|
||||
* <p>
|
||||
* It is primarily used in validation logic within the command-line parser
|
||||
* to ensure the required input is received for proper processing of the parameter.
|
||||
*/
|
||||
private int minNumberValues;
|
||||
|
||||
/**
|
||||
* Specifies the maximum number of values that the corresponding parameter can accept.
|
||||
* <p>
|
||||
* This field is used to validate and enforce constraints during command-line parsing.
|
||||
* If more values than specified are provided for a parameter, the parser throws an exception
|
||||
* to indicate a violation of this constraint.
|
||||
* <p>
|
||||
* A value of 0 implies that the parameter does not support any values, while a positive
|
||||
* value indicates the exact maximum limit of acceptable values.
|
||||
*/
|
||||
private int maxNumberValues;
|
||||
|
||||
/**
|
||||
* Indicates whether the parameter allows multiple entries.
|
||||
* <p>
|
||||
* If set to {@code true}, the parameter can be specified multiple times
|
||||
* on the command-line. This allows the association of multiple values
|
||||
* or options with the same parameter name.
|
||||
* <p>
|
||||
* If set to {@code false}, the parameter can be specified only once
|
||||
* during command-line parsing.
|
||||
*/
|
||||
private boolean multipleEntries;
|
||||
|
||||
/**
|
||||
* A concise, human-readable description of the parameter's purpose and functionality.
|
||||
* <p>
|
||||
* This description provides a brief summary to help users understand the
|
||||
* essential role of the parameter within the command-line parser. It is typically
|
||||
* displayed in usage instructions, help messages, or command summaries.
|
||||
*/
|
||||
private String shortDescription;
|
||||
|
||||
/**
|
||||
* A detailed, extended description of the parameter's purpose and usage.
|
||||
* <p>
|
||||
* This description provides deeper context about what the parameter represents,
|
||||
* how it fits into the overall command-line application, and any nuances
|
||||
* associated with its use. It is displayed when help or additional documentation
|
||||
* for a specific parameter is requested.
|
||||
*/
|
||||
private String longDescription;
|
||||
|
||||
/**
|
||||
* A callback function that processes a list of string arguments for a specific parameter.
|
||||
* The callback is invoked during command-line parsing when a parameter is recognized,
|
||||
* passing the associated values of the parameter for further processing.
|
||||
* <p>
|
||||
* The provided {@link Consumer} implementation defines the logic to
|
||||
* handle or validate the values supplied for a command-line parameter. The values
|
||||
* passed are determined based on the parameter's configuration (e.g., minimum and
|
||||
* maximum number of associated values).
|
||||
* <p>
|
||||
* This field is typically set for the `Parameter` class to enable custom handling
|
||||
* of parameter-specific logic, such as invoking a help command or performing
|
||||
* business logic with the values parsed from the command-line arguments.
|
||||
*/
|
||||
private Consumer<List<String>> callback;
|
||||
|
||||
/**
|
||||
* Indicates whether the parameter is designated as the help command.
|
||||
* <p>
|
||||
* When set to {@code true}, this parameter is treated as the special help command
|
||||
* within the command-line parser. A parameter marked as the help command typically
|
||||
* provides users with information about available options or detailed descriptions
|
||||
* of specific commands when invoked. If this flag is enabled, a custom callback
|
||||
* method for displaying help context is automatically associated with the parameter.
|
||||
*/
|
||||
private boolean isHelpCommand;
|
||||
|
||||
/**
|
||||
* Indicates whether the parameter is designated as the default parameter.
|
||||
* <p>
|
||||
* The default parameter is a special type of parameter that can accept arguments
|
||||
* without an explicit prefix or identifier. It is used when a provided command-line
|
||||
* argument does not match any defined parameter and does not start with a special
|
||||
* character (e.g., '-') typically used to denote named parameters.
|
||||
* <p>
|
||||
* If this field is set to {@code true}, the parameter is treated as the default
|
||||
* parameter. Only one parameter can be assigned this role within the parser.
|
||||
* Attempting to assign multiple default parameters or a default parameter without
|
||||
* accepting values (both `minNumberValues` and `maxNumberValues` set to 0) will
|
||||
* result in an exception during configuration.
|
||||
* <p>
|
||||
* This property is utilized during the parsing process to determine whether an
|
||||
* unmatched argument should be handled as a default parameter value, simplifying
|
||||
* the handling of positional arguments or other unnamed input data.
|
||||
*/
|
||||
private boolean isDefaultParameter;
|
||||
|
||||
/**
|
||||
* A list of alias names associated with a parameter.
|
||||
* <p>
|
||||
* This variable holds alternative names that can be used
|
||||
* to reference the parameter in command-line input. Each alias
|
||||
* functions as an equivalent to the primary parameter name.
|
||||
* Aliases are case-insensitive when used within the command-line parser.
|
||||
* <p>
|
||||
* The aliases associated with a parameter allow greater flexibility
|
||||
* and user convenience when specifying parameters during command-line execution.
|
||||
*/
|
||||
@Singular("alias")
|
||||
private List<String> aliasList;
|
||||
|
||||
/**
|
||||
* Represents a command-line parameter definition within the application.
|
||||
*
|
||||
* <p>
|
||||
* This class encapsulates the metadata and configuration of a command-line parameter,
|
||||
* including its name, aliases, descriptions, value constraints, and behavior. Instances
|
||||
* of this class are used to define and manage the parameters that the `Parser` class
|
||||
* recognizes and processes.
|
||||
*
|
||||
* <p>
|
||||
* A parameter can be configured as a default parameter or as a help command. The default
|
||||
* parameter serves as a catch-all for unmatched command-line inputs, while the help
|
||||
* command provides usage information for users.
|
||||
@@ -41,16 +168,16 @@ public class Parameter {
|
||||
/**
|
||||
* Constructs a new Parameter with the given attributes.
|
||||
*
|
||||
* @param name The name of the parameter.
|
||||
* @param minNumberValues The minimum number of values allowed for this parameter.
|
||||
* @param maxNumberValues The maximum number of values allowed for this parameter.
|
||||
* @param multipleEntries Indicates whether multiple entries are allowed for this parameter.
|
||||
* @param shortDescription A brief description of the parameter.
|
||||
* @param longDescription A detailed description of the parameter.
|
||||
* @param callback A consumer function that processes a list of values associated with this parameter.
|
||||
* @param isHelpCommand Indicates whether this parameter represents a help command.
|
||||
* @param name The name of the parameter.
|
||||
* @param minNumberValues The minimum number of values allowed for this parameter.
|
||||
* @param maxNumberValues The maximum number of values allowed for this parameter.
|
||||
* @param multipleEntries Indicates whether multiple entries are allowed for this parameter.
|
||||
* @param shortDescription A brief description of the parameter.
|
||||
* @param longDescription A detailed description of the parameter.
|
||||
* @param callback A consumer function that processes a list of values associated with this parameter.
|
||||
* @param isHelpCommand Indicates whether this parameter represents a help command.
|
||||
* @param isDefaultParameter Indicates whether this parameter is the default parameter.
|
||||
* @param aliasList A list of aliases for this parameter.
|
||||
* @param aliasList A list of aliases for this parameter.
|
||||
*/
|
||||
public Parameter(String name, int minNumberValues, int maxNumberValues, boolean multipleEntries, String shortDescription, String longDescription, Consumer<List<String>> callback, boolean isHelpCommand, boolean isDefaultParameter, List<String> aliasList) {
|
||||
this.name = name;
|
||||
@@ -64,131 +191,4 @@ public class Parameter {
|
||||
this.isDefaultParameter = isDefaultParameter;
|
||||
this.aliasList = aliasList;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `name` variable represents the primary identifier for a parameter.
|
||||
* This string is used to uniquely identify a command-line parameter when parsing
|
||||
* arguments. It serves as the key for registering and retrieving parameters in a
|
||||
* command-line parser.
|
||||
*
|
||||
* The value of `name` is case-insensitive and can be used alongside aliases to
|
||||
* recognize and process parameters provided in the command-line input.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Specifies the minimum number of values required for this parameter.
|
||||
*
|
||||
* This variable enforces a constraint on the number of arguments that must
|
||||
* be provided for the parameter during command-line parsing. If the number of
|
||||
* provided arguments is less than this value, an exception will be thrown during parsing.
|
||||
*
|
||||
* It is primarily used in validation logic within the command-line parser
|
||||
* to ensure the required input is received for proper processing of the parameter.
|
||||
*/
|
||||
private int minNumberValues;
|
||||
|
||||
/**
|
||||
* Specifies the maximum number of values that the corresponding parameter can accept.
|
||||
*
|
||||
* This field is used to validate and enforce constraints during command-line parsing.
|
||||
* If more values than specified are provided for a parameter, the parser throws an exception
|
||||
* to indicate a violation of this constraint.
|
||||
*
|
||||
* A value of 0 implies that the parameter does not support any values, while a positive
|
||||
* value indicates the exact maximum limit of acceptable values.
|
||||
*/
|
||||
private int maxNumberValues;
|
||||
|
||||
/**
|
||||
* Indicates whether the parameter allows multiple entries.
|
||||
*
|
||||
* If set to {@code true}, the parameter can be specified multiple times
|
||||
* on the command-line. This allows the association of multiple values
|
||||
* or options with the same parameter name.
|
||||
*
|
||||
* If set to {@code false}, the parameter can be specified only once
|
||||
* during command-line parsing.
|
||||
*/
|
||||
private boolean multipleEntries;
|
||||
|
||||
/**
|
||||
* A concise, human-readable description of the parameter's purpose and functionality.
|
||||
*
|
||||
* This description provides a brief summary to help users understand the
|
||||
* essential role of the parameter within the command-line parser. It is typically
|
||||
* displayed in usage instructions, help messages, or command summaries.
|
||||
*/
|
||||
private String shortDescription;
|
||||
|
||||
/**
|
||||
* A detailed, extended description of the parameter's purpose and usage.
|
||||
*
|
||||
* This description provides deeper context about what the parameter represents,
|
||||
* how it fits into the overall command-line application, and any nuances
|
||||
* associated with its use. It is displayed when help or additional documentation
|
||||
* for a specific parameter is requested.
|
||||
*/
|
||||
private String longDescription;
|
||||
|
||||
/**
|
||||
* A callback function that processes a list of string arguments for a specific parameter.
|
||||
* The callback is invoked during command-line parsing when a parameter is recognized,
|
||||
* passing the associated values of the parameter for further processing.
|
||||
*
|
||||
* The provided {@link Consumer} implementation defines the logic to
|
||||
* handle or validate the values supplied for a command-line parameter. The values
|
||||
* passed are determined based on the parameter's configuration (e.g., minimum and
|
||||
* maximum number of associated values).
|
||||
*
|
||||
* This field is typically set for the `Parameter` class to enable custom handling
|
||||
* of parameter-specific logic, such as invoking a help command or performing
|
||||
* business logic with the values parsed from the command-line arguments.
|
||||
*/
|
||||
private Consumer<List<String>> callback;
|
||||
|
||||
/**
|
||||
* Indicates whether the parameter is designated as the help command.
|
||||
*
|
||||
* When set to {@code true}, this parameter is treated as the special help command
|
||||
* within the command-line parser. A parameter marked as the help command typically
|
||||
* provides users with information about available options or detailed descriptions
|
||||
* of specific commands when invoked. If this flag is enabled, a custom callback
|
||||
* method for displaying help context is automatically associated with the parameter.
|
||||
*/
|
||||
private boolean isHelpCommand;
|
||||
|
||||
/**
|
||||
* Indicates whether the parameter is designated as the default parameter.
|
||||
*
|
||||
* The default parameter is a special type of parameter that can accept arguments
|
||||
* without an explicit prefix or identifier. It is used when a provided command-line
|
||||
* argument does not match any defined parameter and does not start with a special
|
||||
* character (e.g., '-') typically used to denote named parameters.
|
||||
*
|
||||
* If this field is set to {@code true}, the parameter is treated as the default
|
||||
* parameter. Only one parameter can be assigned this role within the parser.
|
||||
* Attempting to assign multiple default parameters or a default parameter without
|
||||
* accepting values (both `minNumberValues` and `maxNumberValues` set to 0) will
|
||||
* result in an exception during configuration.
|
||||
*
|
||||
* This property is utilized during the parsing process to determine whether an
|
||||
* unmatched argument should be handled as a default parameter value, simplifying
|
||||
* the handling of positional arguments or other unnamed input data.
|
||||
*/
|
||||
private boolean isDefaultParameter;
|
||||
|
||||
/**
|
||||
* A list of alias names associated with a parameter.
|
||||
*
|
||||
* This variable holds alternative names that can be used
|
||||
* to reference the parameter in command-line input. Each alias
|
||||
* functions as an equivalent to the primary parameter name.
|
||||
* Aliases are case-insensitive when used within the command-line parser.
|
||||
*
|
||||
* The aliases associated with a parameter allow greater flexibility
|
||||
* and user convenience when specifying parameters during command-line execution.
|
||||
*/
|
||||
@Singular("alias")
|
||||
private List<String> aliasList;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,11 @@ package de.neitzel.core.commandline;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The Parser class is responsible for parsing and handling command-line arguments.
|
||||
@@ -15,32 +19,32 @@ public class Parser {
|
||||
/**
|
||||
* A map to store parameters where the key is a string representing
|
||||
* the parameter name and the value is the corresponding {@link Parameter} object.
|
||||
*
|
||||
* <p>
|
||||
* This map serves as a registry for defining, organizing, and accessing
|
||||
* command-line parameters. Each entry holds a parameter's metadata and
|
||||
* its associated configuration to facilitate effective command-line parsing.
|
||||
*
|
||||
* <p>
|
||||
* Key considerations:
|
||||
* - The key represents the primary name of the parameter.
|
||||
* - The value, encapsulated as a {@link Parameter} object, includes
|
||||
* details such as descriptions, value constraints, aliases, and processing logic.
|
||||
* details such as descriptions, value constraints, aliases, and processing logic.
|
||||
*/
|
||||
private Map<String, Parameter> parameters = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The `defaultParameter` variable represents the default command-line parameter for a parser.
|
||||
*
|
||||
* <p>
|
||||
* This parameter is used to capture arguments that do not explicitly match any named parameter
|
||||
* or alias. It acts as a catch-all for unnamed command-line input, often simplifying the handling
|
||||
* of positional arguments or other free-form input provided by the user.
|
||||
*
|
||||
* <p>
|
||||
* It is essential to note:
|
||||
* - Only one parameter can be designated as the default parameter in a command-line parser.
|
||||
* - The parameter must allow values to be processed (e.g., its `minNumberValues` or `maxNumberValues`
|
||||
* should not disallow input).
|
||||
* should not disallow input).
|
||||
* - This parameter is automatically invoked if an input does not match any explicitly named
|
||||
* parameter or alias in the parser configuration.
|
||||
*
|
||||
* parameter or alias in the parser configuration.
|
||||
* <p>
|
||||
* When set to `null`, the parser does not handle unmatched arguments, and unrecognized inputs
|
||||
* may result in an error or exception, depending on the parser's implementation.
|
||||
*/
|
||||
@@ -48,12 +52,12 @@ public class Parser {
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the `Parser` class.
|
||||
*
|
||||
* <p>
|
||||
* The `Parser` class is responsible for parsing and processing
|
||||
* command-line arguments. It interprets input data based on defined
|
||||
* parameters and provides structured access to arguments, enabling
|
||||
* streamlined application configuration and execution.
|
||||
*
|
||||
* <p>
|
||||
* This constructor initializes the parser without any predefined
|
||||
* configuration or parameters. Users can define parameters,
|
||||
* add handlers, and parse command-line arguments using available
|
||||
@@ -71,7 +75,6 @@ public class Parser {
|
||||
* and other metadata such as whether it is a help command or default parameter.
|
||||
* The parameter must fulfill specific constraints if defined as the default
|
||||
* parameter (e.g., accepting values).
|
||||
*
|
||||
* @throws IllegalArgumentException if the parameter is defined as a default parameter and
|
||||
* does not accept values (both minNumberValues and maxNumberValues
|
||||
* are set to 0).
|
||||
@@ -81,7 +84,7 @@ public class Parser {
|
||||
parameters.put(parameter.getName().toLowerCase(), parameter);
|
||||
|
||||
// Add for all aliases
|
||||
for (String alias: parameter.getAliasList()) {
|
||||
for (String alias : parameter.getAliasList()) {
|
||||
parameters.put(alias.toLowerCase(), parameter);
|
||||
}
|
||||
|
||||
@@ -98,22 +101,39 @@ public class Parser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given parameter string matches a valid parameter within the defined constraints.
|
||||
* Handles the help command when invoked in the command-line interface, providing information about available parameters.
|
||||
* If no arguments are provided, it lists all possible parameters and their short descriptions.
|
||||
* If specific arguments are supplied, it provides the detailed description of the corresponding parameter.
|
||||
* In case an unknown parameter is specified, it indicates so to the user.
|
||||
*
|
||||
* @param param the parameter string to be checked. This can either be a key defined in the `parameters` map
|
||||
* or a potential default parameter if it does not start with a dash ("-").
|
||||
* @return {@code true} if the parameter is a valid entry in the `parameters` map or matches the default parameter;
|
||||
* {@code false} otherwise, including when the parameter starts with a dash ("-").
|
||||
* @param arguments a list of strings representing the user-provided arguments. If empty or {@code null},
|
||||
* the method lists all available parameters with their short descriptions. If a parameter name
|
||||
* is provided in the list, its detailed information is displayed. If an unrecognized parameter
|
||||
* is provided, a corresponding message is shown.
|
||||
*/
|
||||
protected boolean isParameter(final String param) {
|
||||
if (parameters.containsKey(param)) return true;
|
||||
if (param.startsWith("-")) return false;
|
||||
return defaultParameter != null;
|
||||
public void helpCommandCallback(final List<String> arguments) {
|
||||
if (arguments == null || arguments.size() == 0) {
|
||||
System.out.println("Moegliche Parameter der Applikation:");
|
||||
parameters.values().stream()
|
||||
.distinct()
|
||||
.sorted(Comparator.comparing(Parameter::getName))
|
||||
.forEach(p -> System.out.println(p.getShortDescription()));
|
||||
} else {
|
||||
Parameter parameter = null;
|
||||
if (parameters.containsKey(arguments.get(0))) parameter = parameters.get(arguments.get(0));
|
||||
if (parameters.containsKey("-" + arguments.get(0))) parameter = parameters.get("-" + arguments.get(0));
|
||||
|
||||
if (parameter == null) {
|
||||
System.out.println("Unbekannter Parameter: " + arguments.get(0));
|
||||
} else {
|
||||
System.out.println(parameter.getLongDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an array of command-line arguments and processes them as defined by the application's parameters.
|
||||
*
|
||||
* <p>
|
||||
* The method iteratively checks each argument in the provided array, validates it against
|
||||
* the registered parameters, and invokes the corresponding processing callback if applicable.
|
||||
* Unrecognized parameters or missing required values will result in an {@code IllegalArgumentException}.
|
||||
@@ -151,6 +171,20 @@ public class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given parameter string matches a valid parameter within the defined constraints.
|
||||
*
|
||||
* @param param the parameter string to be checked. This can either be a key defined in the `parameters` map
|
||||
* or a potential default parameter if it does not start with a dash ("-").
|
||||
* @return {@code true} if the parameter is a valid entry in the `parameters` map or matches the default parameter;
|
||||
* {@code false} otherwise, including when the parameter starts with a dash ("-").
|
||||
*/
|
||||
protected boolean isParameter(final String param) {
|
||||
if (parameters.containsKey(param)) return true;
|
||||
if (param.startsWith("-")) return false;
|
||||
return defaultParameter != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of options by consuming arguments from the provided {@link ArgumentProvider}
|
||||
* within the range specified by the minimum and maximum values.
|
||||
@@ -163,8 +197,8 @@ public class Parser {
|
||||
* than `min`, it will be adjusted to match `min`. Only up to `max`
|
||||
* arguments will be added to the result.
|
||||
* @return A list of argument strings, containing up to `max` elements and at least `min`
|
||||
* elements if sufficient arguments are available. The list will not include
|
||||
* arguments already recognized in the `parameters` map.
|
||||
* elements if sufficient arguments are available. The list will not include
|
||||
* arguments already recognized in the `parameters` map.
|
||||
*/
|
||||
private List<String> getOptions(ArgumentProvider provider, int min, int max) {
|
||||
if (max < min) max = min;
|
||||
@@ -182,35 +216,4 @@ public class Parser {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the help command when invoked in the command-line interface, providing information about available parameters.
|
||||
* If no arguments are provided, it lists all possible parameters and their short descriptions.
|
||||
* If specific arguments are supplied, it provides the detailed description of the corresponding parameter.
|
||||
* In case an unknown parameter is specified, it indicates so to the user.
|
||||
*
|
||||
* @param arguments a list of strings representing the user-provided arguments. If empty or {@code null},
|
||||
* the method lists all available parameters with their short descriptions. If a parameter name
|
||||
* is provided in the list, its detailed information is displayed. If an unrecognized parameter
|
||||
* is provided, a corresponding message is shown.
|
||||
*/
|
||||
public void helpCommandCallback(final List<String> arguments) {
|
||||
if (arguments == null || arguments.size() == 0) {
|
||||
System.out.println("Moegliche Parameter der Applikation:");
|
||||
parameters.values().stream()
|
||||
.distinct()
|
||||
.sorted(Comparator.comparing(Parameter::getName))
|
||||
.forEach(p -> System.out.println(p.getShortDescription() ));
|
||||
} else {
|
||||
Parameter parameter = null;
|
||||
if (parameters.containsKey(arguments.get(0))) parameter = parameters.get(arguments.get(0));
|
||||
if (parameters.containsKey("-" + arguments.get(0))) parameter = parameters.get("-" + arguments.get(0));
|
||||
|
||||
if (parameter == null) {
|
||||
System.out.println("Unbekannter Parameter: " + arguments.get(0));
|
||||
} else {
|
||||
System.out.println(parameter.getLongDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,19 @@ import java.io.InputStream;
|
||||
@Slf4j
|
||||
public class ImageScaler {
|
||||
|
||||
/**
|
||||
* Specifies the target image format for scaling operations.
|
||||
* <p>
|
||||
* This variable defines the file format that will be used when writing
|
||||
* or encoding the scaled image. The format must be compatible with
|
||||
* Java's ImageIO framework (e.g., "png", "jpg", "bmp").
|
||||
* <p>
|
||||
* In this case, the target format is set to "png", allowing images
|
||||
* to be scaled and saved or returned as PNG files. It ensures
|
||||
* consistent output format across the image scaling methods in the class.
|
||||
*/
|
||||
private static String TARGET_FORMAT = "png";
|
||||
|
||||
/**
|
||||
* Private constructor to prevent instantiation of this utility class.
|
||||
*/
|
||||
@@ -24,59 +37,17 @@ public class ImageScaler {
|
||||
throw new UnsupportedOperationException("Utility class cannot be instantiated");
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the target image format for scaling operations.
|
||||
*
|
||||
* This variable defines the file format that will be used when writing
|
||||
* or encoding the scaled image. The format must be compatible with
|
||||
* Java's ImageIO framework (e.g., "png", "jpg", "bmp").
|
||||
*
|
||||
* In this case, the target format is set to "png", allowing images
|
||||
* to be scaled and saved or returned as PNG files. It ensures
|
||||
* consistent output format across the image scaling methods in the class.
|
||||
*/
|
||||
private static String TARGET_FORMAT="png";
|
||||
|
||||
/**
|
||||
* Creates a scaled image from the given byte array representation and returns it as a byte array.
|
||||
*
|
||||
* If enforceSize is set to false, the given dimensions are used as maximum values for scaling.
|
||||
* The resulting image may retain its aspect ratio and be smaller than the specified dimensions.
|
||||
* If enforceSize is true, the resulting image will match the exact dimensions, potentially adding
|
||||
* transparent areas on the top/bottom or right/left sides to maintain the original aspect ratio.
|
||||
*
|
||||
* @param originalImageBytes The byte array representing the original image.
|
||||
* @param width The (maximum) width of the target image.
|
||||
* @param height The (maximum) height of the target image.
|
||||
* @param enforceSize A flag indicating whether the resulting image should strictly adhere to specified dimensions.
|
||||
* If false, the image will retain its aspect ratio without empty borders.
|
||||
* @return A byte array representing the scaled image, or null if the operation failed or the input was invalid.
|
||||
*/
|
||||
public static byte[] createScaledImage(final byte[] originalImageBytes, final int width, final int height, final boolean enforceSize) {
|
||||
// Validation
|
||||
if (originalImageBytes == null) return null;
|
||||
if (originalImageBytes.length==0) return null;
|
||||
|
||||
try {
|
||||
// Create the image from a byte array.
|
||||
BufferedImage originalImage = ImageIO.read(new ByteArrayInputStream(originalImageBytes));
|
||||
return createScaledImage(originalImage, width, height, enforceSize);
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scales an image provided as a byte array to the specified dimensions and returns an InputStream of the scaled image.
|
||||
*
|
||||
* <p>
|
||||
* The scaling behavior is determined by the enforceSize parameter:
|
||||
* - If enforceSize is false, the provided dimensions are treated as maximum values, maintaining the original aspect ratio.
|
||||
* - If enforceSize is true, the resulting image will match the exact dimensions, potentially with transparent borders to keep the original aspect ratio.
|
||||
*
|
||||
* @param originalImageBytes The byte array representing the original image.
|
||||
* @param width The (maximum) width of the target scaled image.
|
||||
* @param height The (maximum) height of the target scaled image.
|
||||
* @param enforceSize A flag indicating whether to enforce the exact scaled dimensions. If false, the resulting image retains its aspect ratio.
|
||||
* @param width The (maximum) width of the target scaled image.
|
||||
* @param height The (maximum) height of the target scaled image.
|
||||
* @param enforceSize A flag indicating whether to enforce the exact scaled dimensions. If false, the resulting image retains its aspect ratio.
|
||||
* @return An InputStream representing the scaled image, or null if the operation fails or the input image is invalid.
|
||||
*/
|
||||
public static InputStream scaledImage(final byte[] originalImageBytes, final int width, final int height, final boolean enforceSize) {
|
||||
@@ -91,20 +62,49 @@ public class ImageScaler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a scaled version of the given {@link BufferedImage} and returns it as a byte array.
|
||||
* Creates a scaled image from the given byte array representation and returns it as a byte array.
|
||||
* <p>
|
||||
* If enforceSize is set to false, the given dimensions are used as maximum values for scaling.
|
||||
* The resulting image may retain its aspect ratio and be smaller than the specified dimensions.
|
||||
* If enforceSize is true, the resulting image will match the exact dimensions, potentially adding
|
||||
* transparent areas on the top/bottom or right/left sides to maintain the original aspect ratio.
|
||||
*
|
||||
* @param originalImageBytes The byte array representing the original image.
|
||||
* @param width The (maximum) width of the target image.
|
||||
* @param height The (maximum) height of the target image.
|
||||
* @param enforceSize A flag indicating whether the resulting image should strictly adhere to specified dimensions.
|
||||
* If false, the image will retain its aspect ratio without empty borders.
|
||||
* @return A byte array representing the scaled image, or null if the operation failed or the input was invalid.
|
||||
*/
|
||||
public static byte[] createScaledImage(final byte[] originalImageBytes, final int width, final int height, final boolean enforceSize) {
|
||||
// Validation
|
||||
if (originalImageBytes == null) return null;
|
||||
if (originalImageBytes.length == 0) return null;
|
||||
|
||||
try {
|
||||
// Create the image from a byte array.
|
||||
BufferedImage originalImage = ImageIO.read(new ByteArrayInputStream(originalImageBytes));
|
||||
return createScaledImage(originalImage, width, height, enforceSize);
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a scaled version of the given {@link BufferedImage} and returns it as a byte array.
|
||||
* <p>
|
||||
* The scaling behavior is determined by the enforceSize parameter:
|
||||
* - If enforceSize is false, the provided dimensions are treated as maximum values, and the image
|
||||
* will maintain its original aspect ratio. The resulting image may be smaller than the specified
|
||||
* dimensions.
|
||||
* will maintain its original aspect ratio. The resulting image may be smaller than the specified
|
||||
* dimensions.
|
||||
* - If enforceSize is true, the resulting image will match the exact specified dimensions, potentially
|
||||
* adding transparent padding to fit the aspect ratio.
|
||||
* adding transparent padding to fit the aspect ratio.
|
||||
*
|
||||
* @param originalImage The original image to be scaled. Must not be null.
|
||||
* @param width The specified (maximum) width of the scaled image.
|
||||
* @param height The specified (maximum) height of the scaled image.
|
||||
* @param enforceSize A flag indicating whether the scaled image should strictly conform to the specified
|
||||
* dimensions. If true, the image may include transparent areas to maintain the aspect ratio.
|
||||
* @param width The specified (maximum) width of the scaled image.
|
||||
* @param height The specified (maximum) height of the scaled image.
|
||||
* @param enforceSize A flag indicating whether the scaled image should strictly conform to the specified
|
||||
* dimensions. If true, the image may include transparent areas to maintain the aspect ratio.
|
||||
* @return A byte array representing the scaled image, or null if the scaling operation fails or the input image is invalid.
|
||||
*/
|
||||
protected static byte[] createScaledImage(final BufferedImage originalImage, final int width, final int height, final boolean enforceSize) {
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.stream.Stream;
|
||||
/**
|
||||
* Represents the context of the application and serves as the foundation of a dependency
|
||||
* injection framework.
|
||||
*
|
||||
* <p>
|
||||
* The {@code ApplicationContext} is responsible for scanning, instantiating, and managing
|
||||
* the lifecycle of components. Components are identified through the specified base package
|
||||
* (or derived from a configuration class) and instantiated based on their dependency
|
||||
@@ -52,17 +52,17 @@ public class ApplicationContext {
|
||||
|
||||
/**
|
||||
* Retrieves an instance of the specified component type from the application context.
|
||||
*
|
||||
* <p>
|
||||
* This method uses dependency injection to construct the component if it is not already
|
||||
* a singleton instance. The component's type and scope are determined by the framework,
|
||||
* and the appropriate initialization and lifecycle management are performed.
|
||||
*
|
||||
* @param <T> the type of the component to retrieve
|
||||
* @param <T> the type of the component to retrieve
|
||||
* @param type the {@code Class} object representing the type of the component
|
||||
* @return an instance of the requested component type
|
||||
* @throws IllegalArgumentException if no component is found for the specified type
|
||||
* @throws IllegalStateException if no suitable constructor is found for the component
|
||||
* @throws RuntimeException if any error occurs during instantiation
|
||||
* @throws IllegalStateException if no suitable constructor is found for the component
|
||||
* @throws RuntimeException if any error occurs during instantiation
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getComponent(Class<? extends T> type) {
|
||||
@@ -85,7 +85,7 @@ public class ApplicationContext {
|
||||
Class<?>[] paramTypes = constructor.getParameterTypes();
|
||||
Object[] parameters = new Object[paramTypes.length];
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
parameters[i] = getComponent(paramTypes[i]);
|
||||
parameters[i] = getComponent(paramTypes[i]);
|
||||
}
|
||||
instance = constructor.newInstance(parameters);
|
||||
if (scope == Scope.SINGLETON) {
|
||||
@@ -103,12 +103,12 @@ public class ApplicationContext {
|
||||
|
||||
/**
|
||||
* Determines if a given constructor can be instantiated using the provided parameter map.
|
||||
*
|
||||
* <p>
|
||||
* The method evaluates whether every parameter type required by the constructor
|
||||
* is available in the given parameter map. If all parameter types are present,
|
||||
* the constructor is considered instantiable.
|
||||
*
|
||||
* @param constructor the constructor to check for instantiation feasibility
|
||||
* @param constructor the constructor to check for instantiation feasibility
|
||||
* @param parameterMap a map containing available parameter types and their associated component data
|
||||
* @return true if all parameter types required by the constructor are contained in the parameter map, false otherwise
|
||||
*/
|
||||
@@ -118,14 +118,14 @@ public class ApplicationContext {
|
||||
|
||||
/**
|
||||
* Registers a singleton instance of a specific type into the application context.
|
||||
*
|
||||
* <p>
|
||||
* This method allows manual addition of singleton components to the context by
|
||||
* providing a concrete instance of the required type. If the type is already mapped
|
||||
* to a different instance or type within the context, an {@link IllegalStateException}
|
||||
* is thrown to prevent replacement of an existing singleton.
|
||||
*
|
||||
* @param <T> the type of the component to register
|
||||
* @param type the class type of the component being added
|
||||
* @param <T> the type of the component to register
|
||||
* @param type the class type of the component being added
|
||||
* @param instance the singleton instance of the component to register
|
||||
* @throws IllegalStateException if the type is already registered with a different instance
|
||||
*/
|
||||
|
||||
@@ -4,7 +4,7 @@ import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Represents a component in a dependency injection framework.
|
||||
*
|
||||
* <p>
|
||||
* A component is a unit of functionality that is managed by the framework, allowing
|
||||
* for controlled instantiation and lifecycle management. The component is associated
|
||||
* with a specific type and a scope. The scope determines whether the component is
|
||||
@@ -15,7 +15,7 @@ public class ComponentData {
|
||||
|
||||
/**
|
||||
* Represents the type of the component being managed by the dependency injection framework.
|
||||
*
|
||||
* <p>
|
||||
* This variable holds the class object corresponding to the specific type of the component.
|
||||
* It is used to identify and instantiate the component during the dependency injection process.
|
||||
* The type is immutable and is specified when the component is created.
|
||||
@@ -24,10 +24,10 @@ public class ComponentData {
|
||||
|
||||
/**
|
||||
* Defines the lifecycle and instantiation rules for the associated component.
|
||||
*
|
||||
* <p>
|
||||
* The {@code Scope} determines whether the component is created as a singleton
|
||||
* (a single shared instance) or as a prototype (a new instance for each request).
|
||||
*
|
||||
* <p>
|
||||
* This variable is immutable and represents the specific {@code Scope} assigned
|
||||
* to the component, influencing its behavior within the dependency injection framework.
|
||||
*/
|
||||
@@ -35,7 +35,7 @@ public class ComponentData {
|
||||
|
||||
/**
|
||||
* Stores the instantiated object associated with the component.
|
||||
*
|
||||
* <p>
|
||||
* This field holds the actual instance of the component's type within the dependency
|
||||
* injection framework. For components with a {@code SINGLETON} scope, this field is
|
||||
* set only once and shared across the entire application. For components with a
|
||||
@@ -47,7 +47,7 @@ public class ComponentData {
|
||||
/**
|
||||
* Constructs a new Component instance with the specified type and scope.
|
||||
*
|
||||
* @param type the class type of the component
|
||||
* @param type the class type of the component
|
||||
* @param scope the scope of the component, which determines its lifecycle
|
||||
*/
|
||||
public ComponentData(Class<?> type, Scope scope) {
|
||||
@@ -57,10 +57,10 @@ public class ComponentData {
|
||||
|
||||
/**
|
||||
* Constructs a new ComponentData instance with the specified type and an initial instance.
|
||||
*
|
||||
* <p>
|
||||
* This can be used to add Singletons manually without scanning for them.
|
||||
*
|
||||
* @param type the class type of the component
|
||||
* @param type the class type of the component
|
||||
* @param instance the initial instance of the component
|
||||
*/
|
||||
public ComponentData(Class<?> type, Object instance) {
|
||||
|
||||
@@ -5,7 +5,13 @@ import de.neitzel.core.inject.annotation.Inject;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -21,13 +27,13 @@ public class ComponentScanner {
|
||||
* FXML-compatible components detected during the scanning process.
|
||||
* These components are used as part of the dependency injection mechanism
|
||||
* within the {@code InjectableComponentScanner}.
|
||||
*
|
||||
* <p>
|
||||
* The {@code fxmlComponents} set is populated during the component scanning
|
||||
* phase by identifying all classes within a specified package hierarchy
|
||||
* annotated with the {@code @Component} annotation. These classes serve
|
||||
* as the primary source for further analysis, resolution, and instantiation
|
||||
* in the scanning workflow.
|
||||
*
|
||||
* <p>
|
||||
* This field is immutable, ensuring thread safety and consistent state
|
||||
* throughout the lifetime of the {@code InjectableComponentScanner}.
|
||||
*/
|
||||
@@ -35,12 +41,12 @@ public class ComponentScanner {
|
||||
|
||||
/**
|
||||
* A set of component types that are not uniquely associated with a single implementation.
|
||||
*
|
||||
* <p>
|
||||
* This collection is populated during the analysis of discovered components to identify
|
||||
* types that have multiple implementations, preventing them from being uniquely resolved.
|
||||
* For example, if multiple components implement the same interface, that interface will be
|
||||
* added to this set.
|
||||
*
|
||||
* <p>
|
||||
* It is primarily used during the component registration process to avoid ambiguities
|
||||
* in the dependency injection system, ensuring that only resolvable, uniquely identifiable
|
||||
* components can be instantiated and injected.
|
||||
@@ -52,13 +58,13 @@ public class ComponentScanner {
|
||||
* The key represents a super type (interface or abstract class), and the value
|
||||
* is the specific implementation or subclass that is uniquely identified among
|
||||
* the scanned components.
|
||||
*
|
||||
* <p>
|
||||
* This map is populated during the component analysis process. For each super type
|
||||
* in the scanned components, if exactly one implementation is found, it is
|
||||
* considered unique and added to this mapping. In case multiple implementations
|
||||
* exist for a given super type, it is excluded from this map and classified as
|
||||
* a non-unique type.
|
||||
*
|
||||
* <p>
|
||||
* This mapping is utilized for resolving dependencies and determining which components
|
||||
* can be instantiated based on unique type information.
|
||||
*/
|
||||
@@ -70,7 +76,7 @@ public class ComponentScanner {
|
||||
* that can be instantiated. The entries are resolved through the scanning and analysis
|
||||
* of available component types, ensuring that only components with resolvable
|
||||
* dependencies are included.
|
||||
*
|
||||
* <p>
|
||||
* This field is part of the dependency injection process, where components annotated
|
||||
* with {@code @Component} or similar annotations are scanned, analyzed, and registered.
|
||||
* The resolution process checks if a component can be instantiated based on its
|
||||
@@ -81,11 +87,11 @@ public class ComponentScanner {
|
||||
/**
|
||||
* A list of error messages encountered during the scanning and analysis
|
||||
* of components in the dependency injection process.
|
||||
*
|
||||
* <p>
|
||||
* This list is populated when components cannot be resolved due to issues
|
||||
* such as multiple implementations of a superclass or interface,
|
||||
* unmet construction requirements, or unresolved dependencies.
|
||||
*
|
||||
* <p>
|
||||
* Errors added to this list provide detailed descriptions of the specific
|
||||
* issues that prevent certain components from being instantiated correctly.
|
||||
*/
|
||||
@@ -117,19 +123,19 @@ public class ComponentScanner {
|
||||
/**
|
||||
* Analyzes component types within the injected components and classifies them based on their
|
||||
* inheritance hierarchy and relationships.
|
||||
*
|
||||
* <p>
|
||||
* This method performs the following operations:
|
||||
* 1. Maps each component to all of its superclasses and interfaces.
|
||||
* 2. Identifies which superclasses or interfaces have multiple implementing components.
|
||||
* 3. Populates:
|
||||
* - A list of superclasses or interfaces that are not uniquely linked to a single component.
|
||||
* - A map where unique superclasses or interfaces are associated with a specific implementing component.
|
||||
*
|
||||
* - A list of superclasses or interfaces that are not uniquely linked to a single component.
|
||||
* - A map where unique superclasses or interfaces are associated with a specific implementing component.
|
||||
* <p>
|
||||
* The mappings are built using the following data structures:
|
||||
* - A map from superclasses/interfaces to the list of components that implement or extend them.
|
||||
* - A list of non-unique types where multiple components exist for the same superclass or interface.
|
||||
* - A map of unique superclasses/interfaces to their corresponding component.
|
||||
*
|
||||
* <p>
|
||||
* This method is a key part of the component scanning and resolution process, facilitating
|
||||
* the identification of potential instantiation ambiguities or conflicts.
|
||||
*/
|
||||
@@ -160,22 +166,22 @@ public class ComponentScanner {
|
||||
* Resolves and identifies instantiable components from a set of scanned components.
|
||||
* This process determines which components can be instantiated based on their dependencies
|
||||
* and class relationships, while tracking unresolved types and potential conflicts.
|
||||
*
|
||||
* <p>
|
||||
* The resolution process involves:
|
||||
* 1. Iteratively determining which components can be instantiated using the known types
|
||||
* map. A component is resolvable if its dependencies can be satisfied by the current
|
||||
* set of known types.
|
||||
* map. A component is resolvable if its dependencies can be satisfied by the current
|
||||
* set of known types.
|
||||
* 2. Registering resolvable components and their superclasses/interfaces into the known
|
||||
* types map for future iterations.
|
||||
* types map for future iterations.
|
||||
* 3. Removing successfully resolved components from the unresolved set.
|
||||
* 4. Repeating the process until no further components can be resolved in a given iteration.
|
||||
*
|
||||
* <p>
|
||||
* At the end of the resolution process:
|
||||
* - Resolvable components are added to the `instantiableComponents` map, which maps types
|
||||
* to their corresponding instantiable implementations.
|
||||
* to their corresponding instantiable implementations.
|
||||
* - Unresolved components are identified, and error details are collected to highlight
|
||||
* dependencies or conflicts preventing their instantiation.
|
||||
*
|
||||
* dependencies or conflicts preventing their instantiation.
|
||||
* <p>
|
||||
* If errors are encountered due to unresolved components, they are logged for further analysis.
|
||||
*/
|
||||
private void resolveInstantiableComponents() {
|
||||
@@ -208,21 +214,22 @@ public class ComponentScanner {
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a component and its superclasses or interfaces in the provided map of known types.
|
||||
* This method ensures that the component and its inheritance hierarchy are associated with the
|
||||
* component's data unless the supertype is marked as non-unique.
|
||||
* Retrieves all superclasses and interfaces of the specified class, excluding the {@code Object} class.
|
||||
*
|
||||
* @param component the {@code ComponentData} instance representing the component to be registered
|
||||
* @param knownTypes the map where component types and their data are stored
|
||||
* @param clazz the class for which to retrieve all superclasses and interfaces
|
||||
* @return a set of all superclasses and interfaces implemented by the specified class
|
||||
*/
|
||||
private void registerComponentWithSuperTypes(ComponentData component, Map<Class<?>, ComponentData> knownTypes) {
|
||||
knownTypes.put(component.getType(), component);
|
||||
private Set<Class<?>> getAllSuperTypes(Class<?> clazz) {
|
||||
Set<Class<?>> result = new HashSet<>();
|
||||
Class<?> superClass = clazz.getSuperclass();
|
||||
|
||||
for (Class<?> superType : getAllSuperTypes(component.getType())) {
|
||||
if (!notUniqueTypes.contains(superType)) {
|
||||
knownTypes.put(superType, component);
|
||||
}
|
||||
while (superClass != null && superClass != Object.class) {
|
||||
result.add(superClass);
|
||||
superClass = superClass.getSuperclass();
|
||||
}
|
||||
|
||||
result.addAll(Arrays.asList(clazz.getInterfaces()));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -232,7 +239,7 @@ public class ComponentScanner {
|
||||
* Additionally, all fields annotated with {@code @Inject} must have their types present in the
|
||||
* known types set.
|
||||
*
|
||||
* @param component the class to check for instantiability
|
||||
* @param component the class to check for instantiability
|
||||
* @param knownTypes the set of currently known types that can be used to satisfy dependencies
|
||||
* @return {@code true} if the component can be instantiated; {@code false} otherwise
|
||||
*/
|
||||
@@ -260,6 +267,24 @@ public class ComponentScanner {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a component and its superclasses or interfaces in the provided map of known types.
|
||||
* This method ensures that the component and its inheritance hierarchy are associated with the
|
||||
* component's data unless the supertype is marked as non-unique.
|
||||
*
|
||||
* @param component the {@code ComponentData} instance representing the component to be registered
|
||||
* @param knownTypes the map where component types and their data are stored
|
||||
*/
|
||||
private void registerComponentWithSuperTypes(ComponentData component, Map<Class<?>, ComponentData> knownTypes) {
|
||||
knownTypes.put(component.getType(), component);
|
||||
|
||||
for (Class<?> superType : getAllSuperTypes(component.getType())) {
|
||||
if (!notUniqueTypes.contains(superType)) {
|
||||
knownTypes.put(superType, component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the instantiation errors for a set of unresolved classes and appends
|
||||
* detailed error messages to the internal error list. This method analyzes unresolved
|
||||
@@ -304,7 +329,7 @@ public class ComponentScanner {
|
||||
*
|
||||
* @param component the class for which conflicting types need to be identified.
|
||||
* @return a comma-separated string of fully qualified names of conflicting parameter types,
|
||||
* or an empty string if no conflicts are found.
|
||||
* or an empty string if no conflicts are found.
|
||||
*/
|
||||
private String getConflictingTypes(Class<?> component) {
|
||||
return Arrays.stream(component.getConstructors())
|
||||
@@ -314,30 +339,11 @@ public class ComponentScanner {
|
||||
.collect(Collectors.joining(", "));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all superclasses and interfaces of the specified class, excluding the {@code Object} class.
|
||||
*
|
||||
* @param clazz the class for which to retrieve all superclasses and interfaces
|
||||
* @return a set of all superclasses and interfaces implemented by the specified class
|
||||
*/
|
||||
private Set<Class<?>> getAllSuperTypes(Class<?> clazz) {
|
||||
Set<Class<?>> result = new HashSet<>();
|
||||
Class<?> superClass = clazz.getSuperclass();
|
||||
|
||||
while (superClass != null && superClass != Object.class) {
|
||||
result.add(superClass);
|
||||
superClass = superClass.getSuperclass();
|
||||
}
|
||||
|
||||
result.addAll(Arrays.asList(clazz.getInterfaces()));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a map of classes representing component types to their corresponding instantiable implementations.
|
||||
*
|
||||
* @return A map where the key is a class type and the value is the corresponding class implementation
|
||||
* that can be instantiated.
|
||||
* that can be instantiated.
|
||||
*/
|
||||
public Map<Class<?>, ComponentData> getInstantiableComponents() {
|
||||
return instantiableComponents;
|
||||
@@ -349,7 +355,7 @@ public class ComponentScanner {
|
||||
* component scanning and analysis process.
|
||||
*
|
||||
* @return a set of classes representing the types that have multiple
|
||||
* implementations and cannot be resolved uniquely
|
||||
* implementations and cannot be resolved uniquely
|
||||
*/
|
||||
public Set<Class<?>> getNotUniqueTypes() {
|
||||
return notUniqueTypes;
|
||||
@@ -361,7 +367,7 @@ public class ComponentScanner {
|
||||
* implementation, ensuring no ambiguity in resolution.
|
||||
*
|
||||
* @return a map where the keys are types (e.g., interfaces or superclasses)
|
||||
* and the values are their unique component implementations.
|
||||
* and the values are their unique component implementations.
|
||||
*/
|
||||
public Map<Class<?>, Class<?>> getUniqueTypeToComponent() {
|
||||
return uniqueTypeToComponent;
|
||||
|
||||
@@ -11,14 +11,14 @@ import java.lang.annotation.Target;
|
||||
* Indicates that an annotated class is a "component" within a dependency injection framework.
|
||||
* Classes annotated with {@code @Component} are recognized during the component scanning process
|
||||
* as candidates for instantiation and management by the dependency injection framework.
|
||||
*
|
||||
* <p>
|
||||
* This annotation is typically used on classes that represent application-specific components,
|
||||
* such as service implementations, controllers, or other objects intended to be instantiated
|
||||
* and injected into other components during runtime.
|
||||
*
|
||||
* <p>
|
||||
* The annotation must be placed at the type level, and it is retained at runtime
|
||||
* to allow for reflection-based scanning of classes within specified packages.
|
||||
*
|
||||
* <p>
|
||||
* Usage of this annotation assumes that there exists a component scanning mechanism
|
||||
* that processes annotated classes and identifies their roles, dependencies, and hierarchy
|
||||
* within the application's structure.
|
||||
|
||||
@@ -10,17 +10,17 @@ import java.lang.annotation.Target;
|
||||
* injection framework. Classes annotated with {@code @Config} are used as markers
|
||||
* for defining settings and application-specific configurations required by the
|
||||
* dependency injection mechanism.
|
||||
*
|
||||
* <p>
|
||||
* Typically, configuration classes provide metadata required for setting up the
|
||||
* framework, such as specifying the base package to scan for components.
|
||||
*
|
||||
* <p>
|
||||
* This annotation must be applied at the type level and is retained at runtime to
|
||||
* facilitate reflection-based processing. It is intended to serve as a declarative
|
||||
* representation of configuration options for the dependency injection container.
|
||||
*
|
||||
* <p>
|
||||
* Attributes:
|
||||
* - {@code basePackage}: Specifies the package name where the framework should scan
|
||||
* for classes annotated with dependency injection annotations such as {@code @Component}.
|
||||
* for classes annotated with dependency injection annotations such as {@code @Component}.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@@ -31,7 +31,7 @@ public @interface Config {
|
||||
* can be scanned and identified as candidates for dependency injection.
|
||||
*
|
||||
* @return the base package name as a string; returns an empty string by default
|
||||
* if no specific package is defined.
|
||||
* if no specific package is defined.
|
||||
*/
|
||||
String basePackage() default "";
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ import java.lang.annotation.Target;
|
||||
* a dependency injection framework. Fields annotated with {@code @Inject}
|
||||
* are automatically populated with the required component instance during runtime,
|
||||
* typically by the dependency injection container.
|
||||
*
|
||||
* <p>
|
||||
* This annotation must be applied at the field level and is retained at runtime
|
||||
* to enable reflection-based identification and assignment of dependencies.
|
||||
*
|
||||
* <p>
|
||||
* The framework's dependency resolution mechanism identifies the appropriate
|
||||
* instance to inject based on the field's type or custom configuration,
|
||||
* ensuring loose coupling and easier testability.
|
||||
|
||||
@@ -2,7 +2,11 @@ package de.neitzel.core.io;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.IllegalCharsetNameException;
|
||||
|
||||
|
||||
@@ -3,7 +3,15 @@ package de.neitzel.core.io;
|
||||
import de.neitzel.core.util.ArrayUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@@ -13,7 +13,7 @@ public class StringEncoder {
|
||||
* static utility methods for array-related operations.
|
||||
*
|
||||
* @throws UnsupportedOperationException always, to indicate that this class
|
||||
* should not be instantiated.
|
||||
* should not be instantiated.
|
||||
*/
|
||||
private StringEncoder() {
|
||||
throw new UnsupportedOperationException("Utility class");
|
||||
@@ -27,7 +27,7 @@ public class StringEncoder {
|
||||
* @param data the string to decode; may contain encoded characters or regular text. If null, an empty string is returned.
|
||||
* @return the decoded string with all encoded characters replaced by their original representations.
|
||||
* @throws IllegalArgumentException if the input string has encoding markup
|
||||
* that is improperly formatted or incomplete.
|
||||
* that is improperly formatted or incomplete.
|
||||
*/
|
||||
public static String decodeData(final String data) {
|
||||
if (data == null) return "";
|
||||
@@ -38,17 +38,17 @@ public class StringEncoder {
|
||||
int indexAmp = remaining.indexOf("&");
|
||||
if (indexAmp == -1) {
|
||||
result.append(remaining);
|
||||
remaining="";
|
||||
remaining = "";
|
||||
} else {
|
||||
// First get the elements till the &
|
||||
if (indexAmp > 0) {
|
||||
result.append(remaining.substring(0, indexAmp));
|
||||
remaining = remaining.substring(indexAmp);
|
||||
}
|
||||
int endSpecial=remaining.indexOf(";");
|
||||
int endSpecial = remaining.indexOf(";");
|
||||
if (endSpecial == -1) throw new IllegalArgumentException("String couldn't be decoded! (" + data + ")");
|
||||
String special = remaining.substring(0, endSpecial+1);
|
||||
remaining = remaining.substring(endSpecial+1);
|
||||
String special = remaining.substring(0, endSpecial + 1);
|
||||
remaining = remaining.substring(endSpecial + 1);
|
||||
result.append(decodeCharacter(special));
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ public class StringEncoder {
|
||||
public static char decodeCharacter(final String data) {
|
||||
if (!data.startsWith("&#")) throw new IllegalArgumentException("Data does not start with &# (" + data + ")");
|
||||
if (!data.endsWith(";")) throw new IllegalArgumentException("Data does not end with ; (" + data + ")");
|
||||
return (char)Integer.parseInt(data.substring(2, data.length()-1));
|
||||
return (char) Integer.parseInt(data.substring(2, data.length() - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,16 +77,16 @@ public class StringEncoder {
|
||||
*
|
||||
* @param data the input string to encode; if null, an empty string is returned
|
||||
* @return an encoded string where non-ASCII and ampersand characters
|
||||
* are replaced with numeric character references
|
||||
* are replaced with numeric character references
|
||||
*/
|
||||
public static String encodeData(final String data) {
|
||||
if (data == null) return "";
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (int index=0; index < data.length(); index++) {
|
||||
for (int index = 0; index < data.length(); index++) {
|
||||
char character = data.charAt(index);
|
||||
if (character < 32 || character > 127 || character == 38) {
|
||||
result.append("&#" + (int)character + ";");
|
||||
result.append("&#" + (int) character + ";");
|
||||
} else {
|
||||
result.append(character);
|
||||
}
|
||||
|
||||
@@ -16,16 +16,30 @@ public class ToneGenerator {
|
||||
* static utility methods for array-related operations.
|
||||
*
|
||||
* @throws UnsupportedOperationException always, to indicate that this class
|
||||
* should not be instantiated.
|
||||
* should not be instantiated.
|
||||
*/
|
||||
private ToneGenerator() {
|
||||
throw new UnsupportedOperationException("Utility class");
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays one or more specified tones for a given duration.
|
||||
* Each tone is played sequentially in the order they are provided.
|
||||
*
|
||||
* @param duration the duration of each tone in milliseconds
|
||||
* @param tones the names of the tones to play, specified as a variable-length argument
|
||||
* @throws LineUnavailableException if the audio line cannot be opened or accessed
|
||||
*/
|
||||
public static void playTone(int duration, String... tones) throws LineUnavailableException {
|
||||
for (String tone : tones) {
|
||||
playTone(tone, duration);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays a tone based on a predefined tone name for a specified duration.
|
||||
*
|
||||
* @param tone The name of the tone to play. Must correspond to a predefined tone in the tone table.
|
||||
* @param tone The name of the tone to play. Must correspond to a predefined tone in the tone table.
|
||||
* @param duration The duration of the tone in milliseconds.
|
||||
* @throws LineUnavailableException If a line for audio playback cannot be opened.
|
||||
*/
|
||||
@@ -64,18 +78,4 @@ public class ToneGenerator {
|
||||
line.drain();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays one or more specified tones for a given duration.
|
||||
* Each tone is played sequentially in the order they are provided.
|
||||
*
|
||||
* @param duration the duration of each tone in milliseconds
|
||||
* @param tones the names of the tones to play, specified as a variable-length argument
|
||||
* @throws LineUnavailableException if the audio line cannot be opened or accessed
|
||||
*/
|
||||
public static void playTone(int duration, String... tones) throws LineUnavailableException {
|
||||
for (String tone : tones) {
|
||||
playTone(tone, duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,34 +7,23 @@ import java.util.HashMap;
|
||||
* with their corresponding frequencies in hertz (Hz). It allows users to
|
||||
* retrieve the frequency of a tone based on its standard notation name,
|
||||
* such as "C3", "A4", or "G#5".
|
||||
*
|
||||
* <p>
|
||||
* This class can be particularly useful in applications related to sound synthesis,
|
||||
* music theory, signal processing, and other audio-related domains that require precise
|
||||
* frequency information for specific tones.
|
||||
*/
|
||||
public class ToneTable {
|
||||
/**
|
||||
* Private constructor to prevent instantiation of the utility class.
|
||||
* This utility class is not meant to be instantiated, as it only provides
|
||||
* static utility methods for array-related operations.
|
||||
*
|
||||
* @throws UnsupportedOperationException always, to indicate that this class
|
||||
* should not be instantiated.
|
||||
*/
|
||||
private ToneTable() {
|
||||
throw new UnsupportedOperationException("Utility class");
|
||||
}
|
||||
|
||||
/**
|
||||
* A static map that associates written tone names with their corresponding frequencies in hertz (Hz).
|
||||
* The keys represent tone names (e.g., "C4", "D#5"), and the values are their respective frequencies.
|
||||
* This map serves as a reference for converting tone names into their precise frequency values,
|
||||
* which are used in applications such as tone generation or audio playback.
|
||||
*
|
||||
* <p>
|
||||
* The map is a crucial component of the ToneTable class, providing quick lookup of frequencies
|
||||
* for predefined tone names.
|
||||
*/
|
||||
private static final HashMap<String, Double> toneMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
toneMap.put("C0", 16.35);
|
||||
toneMap.put("C#0", 17.32);
|
||||
@@ -191,6 +180,18 @@ public class ToneTable {
|
||||
toneMap.put("B8", 7902.13);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor to prevent instantiation of the utility class.
|
||||
* This utility class is not meant to be instantiated, as it only provides
|
||||
* static utility methods for array-related operations.
|
||||
*
|
||||
* @throws UnsupportedOperationException always, to indicate that this class
|
||||
* should not be instantiated.
|
||||
*/
|
||||
private ToneTable() {
|
||||
throw new UnsupportedOperationException("Utility class");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the frequency of the tone based on the given tone name.
|
||||
* If the tone name exists in the tone map, its corresponding frequency is returned.
|
||||
|
||||
@@ -8,7 +8,14 @@ import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.Scanner;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
@@ -23,311 +30,312 @@ import java.util.stream.StreamSupport;
|
||||
@Slf4j
|
||||
public class Query<T> {
|
||||
|
||||
/**
|
||||
* A factory function that extracts an Integer from the first column of a given ResultSet.
|
||||
* <p>
|
||||
* This function is designed to facilitate the conversion of a ResultSet row into an Integer
|
||||
* by accessing the value in the first column of the result set. If an SQL exception is encountered
|
||||
* during the retrieval of the integer value, it is wrapped and re-thrown as a runtime exception.
|
||||
*/
|
||||
public static final Function<ResultSet, Integer> INTEGER_FACTORY = rs -> {
|
||||
try {
|
||||
return rs.getInt(1);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a database connection instance.
|
||||
* This connection is used to interact with a database
|
||||
* through executing queries and retrieving results.
|
||||
* It is immutable and initialized once.
|
||||
*/
|
||||
private final Connection connection;
|
||||
|
||||
/**
|
||||
* A list of ParameterSetter objects used to configure parameters.
|
||||
* This collection serves as a storage for managing parameter-setting logic dynamically.
|
||||
* It is initialized as an empty ArrayList and is immutable since it is declared as final.
|
||||
*/
|
||||
private final List<ParameterSetter> parameterSetters = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* A functional interface representing a factory method used to produce instances of type T.
|
||||
* This factory is typically implemented to map rows from a {@link ResultSet} to objects of type T.
|
||||
* The input parameter is a {@link ResultSet}, which provides access to database query results.
|
||||
* The resulting output is an instance of type T created based on the data in the provided ResultSet.
|
||||
*/
|
||||
private Function<ResultSet, T> factory;
|
||||
|
||||
/**
|
||||
* Represents the text of a query.
|
||||
* This variable stores the query string used for processing or execution purposes within the application.
|
||||
*/
|
||||
private String queryText;
|
||||
|
||||
/**
|
||||
* Constructs a new Query object with the given database connection.
|
||||
*
|
||||
* @param connection The Connection object used to interact with the database.
|
||||
*/
|
||||
public Query(Connection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given SQL query using the provided database connection.
|
||||
*
|
||||
* @param connection the database connection to be used for executing the query
|
||||
* @param query the SQL query to be executed
|
||||
* @throws SQLException if a database access error occurs or the query execution fails
|
||||
*/
|
||||
public static void execute(final Connection connection, final String query) throws SQLException {
|
||||
new Query<Object>(connection)
|
||||
.setQueryText(query)
|
||||
.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the query text for the current query instance.
|
||||
*
|
||||
* @param queryText the text of the query to be set
|
||||
* @return the current instance of the query
|
||||
*/
|
||||
public Query<T> setQueryText(final String queryText) {
|
||||
this.queryText = queryText;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the query resource by loading its content from the given resource path.
|
||||
* The resource content is read and stored as the query text for the query object.
|
||||
*
|
||||
* @param resourcePath the path to the resource file containing the query text
|
||||
* @return the current Query object with the loaded query text
|
||||
*/
|
||||
public Query<T> setQueryResource(final String resourcePath) {
|
||||
log.info("loading resource: {}", resourcePath);
|
||||
try (Scanner scanner = new Scanner(Objects.requireNonNull(getClass().getResourceAsStream(resourcePath)),
|
||||
StandardCharsets.UTF_8)) {
|
||||
this.queryText = scanner.useDelimiter("\\A").next();
|
||||
}
|
||||
log.info("query text: {}", this.queryText);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all occurrences of the specified placeholder in the query text with the provided value.
|
||||
*
|
||||
* @param placeholder the placeholder string to be replaced in the query text
|
||||
* @param value the value to replace the placeholder with
|
||||
* @return the updated Query instance with the modified query text
|
||||
*/
|
||||
public Query<T> replace(final String placeholder, final String value) {
|
||||
this.queryText = this.queryText.replace(placeholder, value);
|
||||
log.info("query text: {}", this.queryText);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a parameter to the query at the specified index with a custom setter function.
|
||||
*
|
||||
* @param index The position of the parameter in the query starting from 1.
|
||||
* @param value The value of the parameter to be set.
|
||||
* @param setter A TriSqlFunction that defines how to set the parameter in the PreparedStatement.
|
||||
* @param <X> The type of the parameter value.
|
||||
* @return The current query instance for method chaining.
|
||||
*/
|
||||
public <X> Query<T> addParameter(final int index, final X value, final TriSqlFunction<PreparedStatement, Integer, X> setter) {
|
||||
parameterSetters.add(ps -> setter.apply(ps, index, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a parameter to the query using the specified ParameterSetter.
|
||||
*
|
||||
* @param setter the ParameterSetter used to configure the parameter
|
||||
* @return the current Query instance for method chaining
|
||||
*/
|
||||
public Query<T> addParameter(ParameterSetter setter) {
|
||||
parameterSetters.add(setter);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the factory function used to convert a {@link ResultSet} into an instance of type {@code T}.
|
||||
*
|
||||
* @param factory the function responsible for mapping a {@code ResultSet} to an object of type {@code T}
|
||||
* @return the current {@code Query} instance with the specified factory function set
|
||||
*/
|
||||
public Query<T> factory(final Function<ResultSet, T> factory) {
|
||||
this.factory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Stream} from the result set obtained by executing a prepared statement.
|
||||
* The result set is wrapped in a {@link TrimmingResultSet} to handle data trimming.
|
||||
*
|
||||
* @return a {@link Stream} of type T populated with the query results processed using the specified factory
|
||||
* @throws SQLException if an SQL error occurs while executing the prepared statement or creating the stream
|
||||
*/
|
||||
private Stream<T> stream() throws SQLException {
|
||||
ResultSet rs = createPreparedStatement().executeQuery();
|
||||
TrimmingResultSet trimmingResultSet = new TrimmingResultSet(rs);
|
||||
return streamFromResultSet(trimmingResultSet, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a PreparedStatement object configured with the query text
|
||||
* and parameters defined for the current instance.
|
||||
*
|
||||
* @return a PreparedStatement object initialized with the query and parameter values
|
||||
* @throws SQLException if a database access error occurs or the PreparedStatement cannot be created
|
||||
*/
|
||||
private PreparedStatement createPreparedStatement() throws SQLException {
|
||||
PreparedStatement ps = connection.prepareStatement(queryText);
|
||||
for (ParameterSetter setter : parameterSetters) {
|
||||
setter.apply(ps);
|
||||
}
|
||||
return ps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the SQL statement represented by the PreparedStatement created in
|
||||
* the method {@code createPreparedStatement()}. This method is used to perform
|
||||
* database operations such as updates or other actions that do not produce a
|
||||
* result set.
|
||||
*
|
||||
* @throws SQLException if a database access error occurs or the SQL statement is invalid.
|
||||
*/
|
||||
public void execute() throws SQLException {
|
||||
try (PreparedStatement ps = createPreparedStatement()) {
|
||||
ps.execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link ResultSet} into a {@link Stream} of objects created using the provided {@link Function}
|
||||
* factory. The stream ensures resources such as the {@code ResultSet} and its associated statement are
|
||||
* closed when the stream is closed.
|
||||
*
|
||||
* @param rs the {@link ResultSet} to be transformed into a stream
|
||||
* @param factory a {@link Function} that maps rows of the {@link ResultSet} to objects of type T
|
||||
* @return a {@link Stream} of objects of type T created from the {@code ResultSet} rows
|
||||
*/
|
||||
private Stream<T> streamFromResultSet(final ResultSet rs, final Function<ResultSet, T> factory) {
|
||||
Iterator<T> iterator = new Iterator<>() {
|
||||
private boolean hasNextChecked = false;
|
||||
private boolean hasNext;
|
||||
|
||||
/**
|
||||
* Checks if the iteration has more elements. This method verifies if the
|
||||
* underlying {@link ResultSet} contains another row that has not yet been processed.
|
||||
*
|
||||
* @return {@code true} if there are more elements in the {@link ResultSet},
|
||||
* otherwise {@code false}.
|
||||
*/
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public boolean hasNext() {
|
||||
if (!hasNextChecked) {
|
||||
hasNext = rs.next();
|
||||
hasNextChecked = true;
|
||||
/**
|
||||
* A factory function that extracts an Integer from the first column of a given ResultSet.
|
||||
* <p>
|
||||
* This function is designed to facilitate the conversion of a ResultSet row into an Integer
|
||||
* by accessing the value in the first column of the result set. If an SQL exception is encountered
|
||||
* during the retrieval of the integer value, it is wrapped and re-thrown as a runtime exception.
|
||||
*/
|
||||
public static final Function<ResultSet, Integer> INTEGER_FACTORY = rs -> {
|
||||
try {
|
||||
return rs.getInt(1);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration. This method applies the provided
|
||||
* factory function to the current row of the {@link ResultSet} to create an object of type T.
|
||||
* It throws {@link NoSuchElementException} if there are no more elements to iterate.
|
||||
*
|
||||
* @return the next element of type T as created by the factory function from the current row of the {@link ResultSet}
|
||||
* @throws NoSuchElementException if the iteration has no more elements
|
||||
*/
|
||||
@Override
|
||||
public T next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
hasNextChecked = false;
|
||||
return factory.apply(rs);
|
||||
}
|
||||
};
|
||||
Spliterator<T> spliterator = Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED);
|
||||
return StreamSupport.stream(spliterator, false)
|
||||
.onClose(() -> {
|
||||
try {
|
||||
rs.getStatement().close();
|
||||
} catch (SQLException ignored) {
|
||||
// Exception is ignored.
|
||||
}
|
||||
try {
|
||||
rs.close();
|
||||
} catch (SQLException ignored) {
|
||||
// Exception is ignored.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a managed stream to the given handler and ensures proper resource closing after use.
|
||||
* A {@code Stream} is opened and passed to the specified handler as an argument.
|
||||
* The stream will be automatically closed when the handler finishes execution or throws an exception.
|
||||
*
|
||||
* @param handler a function which receives a {@code Stream<T>} and processes it, returning a result of type {@code R}.
|
||||
* @param <R> the type of the result produced by the handler.
|
||||
* @return the result returned by the handler after processing the stream.
|
||||
* @throws SQLException if an SQL error occurs during the creation or handling of the stream.
|
||||
*/
|
||||
public <R> R withStream(Function<Stream<T>, R> handler) throws SQLException {
|
||||
try (Stream<T> stream = stream()) {
|
||||
return handler.apply(stream);
|
||||
/**
|
||||
* Represents a database connection instance.
|
||||
* This connection is used to interact with a database
|
||||
* through executing queries and retrieving results.
|
||||
* It is immutable and initialized once.
|
||||
*/
|
||||
private final Connection connection;
|
||||
|
||||
/**
|
||||
* A list of ParameterSetter objects used to configure parameters.
|
||||
* This collection serves as a storage for managing parameter-setting logic dynamically.
|
||||
* It is initialized as an empty ArrayList and is immutable since it is declared as final.
|
||||
*/
|
||||
private final List<ParameterSetter> parameterSetters = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* A functional interface representing a factory method used to produce instances of type T.
|
||||
* This factory is typically implemented to map rows from a {@link ResultSet} to objects of type T.
|
||||
* The input parameter is a {@link ResultSet}, which provides access to database query results.
|
||||
* The resulting output is an instance of type T created based on the data in the provided ResultSet.
|
||||
*/
|
||||
private Function<ResultSet, T> factory;
|
||||
|
||||
/**
|
||||
* Represents the text of a query.
|
||||
* This variable stores the query string used for processing or execution purposes within the application.
|
||||
*/
|
||||
private String queryText;
|
||||
|
||||
/**
|
||||
* Constructs a new Query object with the given database connection.
|
||||
*
|
||||
* @param connection The Connection object used to interact with the database.
|
||||
*/
|
||||
public Query(Connection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a functional interface that accepts three input arguments and allows for operations
|
||||
* that can throw an {@link SQLException}. This can be useful in scenarios where SQL-related
|
||||
* logic requires processing with three parameters.
|
||||
*
|
||||
* @param <T> the type of the first input to the operation
|
||||
* @param <U> the type of the second input to the operation
|
||||
* @param <V> the type of the third input to the operation
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface TriSqlFunction<T, U, V> {
|
||||
|
||||
/**
|
||||
* Executes an operation on three input arguments and allows for the operation to throw
|
||||
* an {@link SQLException}. This method is intended to facilitate SQL-related processes
|
||||
* where three parameters are involved.
|
||||
* Executes the given SQL query using the provided database connection.
|
||||
*
|
||||
* @param t the first input argument
|
||||
* @param u the second input argument
|
||||
* @param v the third input argument
|
||||
* @throws SQLException if an SQL error occurs during execution
|
||||
* @param connection the database connection to be used for executing the query
|
||||
* @param query the SQL query to be executed
|
||||
* @throws SQLException if a database access error occurs or the query execution fails
|
||||
*/
|
||||
void apply(T t, U u, V v) throws SQLException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Functional interface designed to handle operations on a PreparedStatement.
|
||||
* Represents a single abstract method that performs specific work on the
|
||||
* provided PreparedStatement instance.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ParameterSetter {
|
||||
public static void execute(final Connection connection, final String query) throws SQLException {
|
||||
new Query<Object>(connection)
|
||||
.setQueryText(query)
|
||||
.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies an operation to the given PreparedStatement object.
|
||||
* This method is intended to set parameters or perform other modifications on a PreparedStatement.
|
||||
* Executes the SQL statement represented by the PreparedStatement created in
|
||||
* the method {@code createPreparedStatement()}. This method is used to perform
|
||||
* database operations such as updates or other actions that do not produce a
|
||||
* result set.
|
||||
*
|
||||
* @param ps the PreparedStatement instance to be modified or configured
|
||||
* @throws SQLException if a database access error occurs while applying the operation
|
||||
* @throws SQLException if a database access error occurs or the SQL statement is invalid.
|
||||
*/
|
||||
void apply(PreparedStatement ps) throws SQLException;
|
||||
}
|
||||
public void execute() throws SQLException {
|
||||
try (PreparedStatement ps = createPreparedStatement()) {
|
||||
ps.execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the query text for the current query instance.
|
||||
*
|
||||
* @param queryText the text of the query to be set
|
||||
* @return the current instance of the query
|
||||
*/
|
||||
public Query<T> setQueryText(final String queryText) {
|
||||
this.queryText = queryText;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a PreparedStatement object configured with the query text
|
||||
* and parameters defined for the current instance.
|
||||
*
|
||||
* @return a PreparedStatement object initialized with the query and parameter values
|
||||
* @throws SQLException if a database access error occurs or the PreparedStatement cannot be created
|
||||
*/
|
||||
private PreparedStatement createPreparedStatement() throws SQLException {
|
||||
PreparedStatement ps = connection.prepareStatement(queryText);
|
||||
for (ParameterSetter setter : parameterSetters) {
|
||||
setter.apply(ps);
|
||||
}
|
||||
return ps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the query resource by loading its content from the given resource path.
|
||||
* The resource content is read and stored as the query text for the query object.
|
||||
*
|
||||
* @param resourcePath the path to the resource file containing the query text
|
||||
* @return the current Query object with the loaded query text
|
||||
*/
|
||||
public Query<T> setQueryResource(final String resourcePath) {
|
||||
log.info("loading resource: {}", resourcePath);
|
||||
try (Scanner scanner = new Scanner(Objects.requireNonNull(getClass().getResourceAsStream(resourcePath)),
|
||||
StandardCharsets.UTF_8)) {
|
||||
this.queryText = scanner.useDelimiter("\\A").next();
|
||||
}
|
||||
log.info("query text: {}", this.queryText);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all occurrences of the specified placeholder in the query text with the provided value.
|
||||
*
|
||||
* @param placeholder the placeholder string to be replaced in the query text
|
||||
* @param value the value to replace the placeholder with
|
||||
* @return the updated Query instance with the modified query text
|
||||
*/
|
||||
public Query<T> replace(final String placeholder, final String value) {
|
||||
this.queryText = this.queryText.replace(placeholder, value);
|
||||
log.info("query text: {}", this.queryText);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a parameter to the query at the specified index with a custom setter function.
|
||||
*
|
||||
* @param index The position of the parameter in the query starting from 1.
|
||||
* @param value The value of the parameter to be set.
|
||||
* @param setter A TriSqlFunction that defines how to set the parameter in the PreparedStatement.
|
||||
* @param <X> The type of the parameter value.
|
||||
* @return The current query instance for method chaining.
|
||||
*/
|
||||
public <X> Query<T> addParameter(final int index, final X value, final TriSqlFunction<PreparedStatement, Integer, X> setter) {
|
||||
parameterSetters.add(ps -> setter.apply(ps, index, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a parameter to the query using the specified ParameterSetter.
|
||||
*
|
||||
* @param setter the ParameterSetter used to configure the parameter
|
||||
* @return the current Query instance for method chaining
|
||||
*/
|
||||
public Query<T> addParameter(ParameterSetter setter) {
|
||||
parameterSetters.add(setter);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the factory function used to convert a {@link ResultSet} into an instance of type {@code T}.
|
||||
*
|
||||
* @param factory the function responsible for mapping a {@code ResultSet} to an object of type {@code T}
|
||||
* @return the current {@code Query} instance with the specified factory function set
|
||||
*/
|
||||
public Query<T> factory(final Function<ResultSet, T> factory) {
|
||||
this.factory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a managed stream to the given handler and ensures proper resource closing after use.
|
||||
* A {@code Stream} is opened and passed to the specified handler as an argument.
|
||||
* The stream will be automatically closed when the handler finishes execution or throws an exception.
|
||||
*
|
||||
* @param handler a function which receives a {@code Stream<T>} and processes it, returning a result of type {@code R}.
|
||||
* @param <R> the type of the result produced by the handler.
|
||||
* @return the result returned by the handler after processing the stream.
|
||||
* @throws SQLException if an SQL error occurs during the creation or handling of the stream.
|
||||
*/
|
||||
public <R> R withStream(Function<Stream<T>, R> handler) throws SQLException {
|
||||
try (Stream<T> stream = stream()) {
|
||||
return handler.apply(stream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Stream} from the result set obtained by executing a prepared statement.
|
||||
* The result set is wrapped in a {@link TrimmingResultSet} to handle data trimming.
|
||||
*
|
||||
* @return a {@link Stream} of type T populated with the query results processed using the specified factory
|
||||
* @throws SQLException if an SQL error occurs while executing the prepared statement or creating the stream
|
||||
*/
|
||||
private Stream<T> stream() throws SQLException {
|
||||
ResultSet rs = createPreparedStatement().executeQuery();
|
||||
TrimmingResultSet trimmingResultSet = new TrimmingResultSet(rs);
|
||||
return streamFromResultSet(trimmingResultSet, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link ResultSet} into a {@link Stream} of objects created using the provided {@link Function}
|
||||
* factory. The stream ensures resources such as the {@code ResultSet} and its associated statement are
|
||||
* closed when the stream is closed.
|
||||
*
|
||||
* @param rs the {@link ResultSet} to be transformed into a stream
|
||||
* @param factory a {@link Function} that maps rows of the {@link ResultSet} to objects of type T
|
||||
* @return a {@link Stream} of objects of type T created from the {@code ResultSet} rows
|
||||
*/
|
||||
private Stream<T> streamFromResultSet(final ResultSet rs, final Function<ResultSet, T> factory) {
|
||||
Iterator<T> iterator = new Iterator<>() {
|
||||
private boolean hasNextChecked = false;
|
||||
|
||||
private boolean hasNext;
|
||||
|
||||
/**
|
||||
* Checks if the iteration has more elements. This method verifies if the
|
||||
* underlying {@link ResultSet} contains another row that has not yet been processed.
|
||||
*
|
||||
* @return {@code true} if there are more elements in the {@link ResultSet},
|
||||
* otherwise {@code false}.
|
||||
*/
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public boolean hasNext() {
|
||||
if (!hasNextChecked) {
|
||||
hasNext = rs.next();
|
||||
hasNextChecked = true;
|
||||
}
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration. This method applies the provided
|
||||
* factory function to the current row of the {@link ResultSet} to create an object of type T.
|
||||
* It throws {@link NoSuchElementException} if there are no more elements to iterate.
|
||||
*
|
||||
* @return the next element of type T as created by the factory function from the current row of the {@link ResultSet}
|
||||
* @throws NoSuchElementException if the iteration has no more elements
|
||||
*/
|
||||
@Override
|
||||
public T next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
hasNextChecked = false;
|
||||
return factory.apply(rs);
|
||||
}
|
||||
};
|
||||
Spliterator<T> spliterator = Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED);
|
||||
return StreamSupport.stream(spliterator, false)
|
||||
.onClose(() -> {
|
||||
try {
|
||||
rs.getStatement().close();
|
||||
} catch (SQLException ignored) {
|
||||
// Exception is ignored.
|
||||
}
|
||||
try {
|
||||
rs.close();
|
||||
} catch (SQLException ignored) {
|
||||
// Exception is ignored.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a functional interface that accepts three input arguments and allows for operations
|
||||
* that can throw an {@link SQLException}. This can be useful in scenarios where SQL-related
|
||||
* logic requires processing with three parameters.
|
||||
*
|
||||
* @param <T> the type of the first input to the operation
|
||||
* @param <U> the type of the second input to the operation
|
||||
* @param <V> the type of the third input to the operation
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface TriSqlFunction<T, U, V> {
|
||||
|
||||
/**
|
||||
* Executes an operation on three input arguments and allows for the operation to throw
|
||||
* an {@link SQLException}. This method is intended to facilitate SQL-related processes
|
||||
* where three parameters are involved.
|
||||
*
|
||||
* @param t the first input argument
|
||||
* @param u the second input argument
|
||||
* @param v the third input argument
|
||||
* @throws SQLException if an SQL error occurs during execution
|
||||
*/
|
||||
void apply(T t, U u, V v) throws SQLException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Functional interface designed to handle operations on a PreparedStatement.
|
||||
* Represents a single abstract method that performs specific work on the
|
||||
* provided PreparedStatement instance.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ParameterSetter {
|
||||
|
||||
/**
|
||||
* Applies an operation to the given PreparedStatement object.
|
||||
* This method is intended to set parameters or perform other modifications on a PreparedStatement.
|
||||
*
|
||||
* @param ps the PreparedStatement instance to be modified or configured
|
||||
* @throws SQLException if a database access error occurs while applying the operation
|
||||
*/
|
||||
void apply(PreparedStatement ps) throws SQLException;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@ public class ArrayUtils {
|
||||
* static utility methods for array-related operations.
|
||||
*
|
||||
* @throws UnsupportedOperationException always, to indicate that this class
|
||||
* should not be instantiated.
|
||||
* should not be instantiated.
|
||||
*/
|
||||
private ArrayUtils() {
|
||||
throw new UnsupportedOperationException("Utility class");
|
||||
@@ -23,11 +23,11 @@ public class ArrayUtils {
|
||||
* Checks if the given character array contains the specified character.
|
||||
*
|
||||
* @param array the character array to be searched
|
||||
* @param ch the character to search for in the array
|
||||
* @param ch the character to search for in the array
|
||||
* @return true if the character is found in the array, false otherwise
|
||||
*/
|
||||
public static boolean contains(char[] array, char ch) {
|
||||
for(int index=0; index < array.length; index++) {
|
||||
for (int index = 0; index < array.length; index++) {
|
||||
if (array[index] == ch) return true;
|
||||
}
|
||||
return false;
|
||||
@@ -37,11 +37,11 @@ public class ArrayUtils {
|
||||
* Checks if the specified integer array contains the given integer value.
|
||||
*
|
||||
* @param array the array of integers to search
|
||||
* @param ch the integer value to search for in the array
|
||||
* @param ch the integer value to search for in the array
|
||||
* @return true if the array contains the specified integer value, false otherwise
|
||||
*/
|
||||
public static boolean contains(int[] array, int ch) {
|
||||
for(int index=0; index < array.length; index++) {
|
||||
for (int index = 0; index < array.length; index++) {
|
||||
if (array[index] == ch) return true;
|
||||
}
|
||||
return false;
|
||||
@@ -51,11 +51,11 @@ public class ArrayUtils {
|
||||
* Checks if the specified long array contains the given long value.
|
||||
*
|
||||
* @param array the array of long values to search
|
||||
* @param ch the long value to search for in the array
|
||||
* @param ch the long value to search for in the array
|
||||
* @return true if the array contains the specified long value, false otherwise
|
||||
*/
|
||||
public static boolean contains(long[] array, long ch) {
|
||||
for(int index=0; index < array.length; index++) {
|
||||
for (int index = 0; index < array.length; index++) {
|
||||
if (array[index] == ch) return true;
|
||||
}
|
||||
return false;
|
||||
@@ -65,12 +65,12 @@ public class ArrayUtils {
|
||||
* Checks if the specified array contains the given element.
|
||||
*
|
||||
* @param array the array to be searched
|
||||
* @param ch the element to search for in the array
|
||||
* @param <T> the type of the elements in the array
|
||||
* @param ch the element to search for in the array
|
||||
* @param <T> the type of the elements in the array
|
||||
* @return true if the element is found in the array, false otherwise
|
||||
*/
|
||||
public static <T> boolean contains(T[] array, T ch) {
|
||||
for(int index=0; index < array.length; index++) {
|
||||
for (int index = 0; index < array.length; index++) {
|
||||
if (Objects.equals(array[index], ch)) return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -14,7 +14,7 @@ public class EnumUtil {
|
||||
* static utility methods for array-related operations.
|
||||
*
|
||||
* @throws UnsupportedOperationException always, to indicate that this class
|
||||
* should not be instantiated.
|
||||
* should not be instantiated.
|
||||
*/
|
||||
private EnumUtil() {
|
||||
throw new UnsupportedOperationException("Utility class");
|
||||
@@ -25,7 +25,7 @@ public class EnumUtil {
|
||||
* of the enum constants within the specified Enum class. The pattern also includes optional delimiters
|
||||
* such as commas, spaces, and empty values, enabling the matching of lists or sequences of flag values.
|
||||
*
|
||||
* @param <T> The type of the Enum.
|
||||
* @param <T> The type of the Enum.
|
||||
* @param clazz The Enum class for which the regular expression is to be generated.
|
||||
* @return A String containing the regular expression pattern for matching the Enum's flag values.
|
||||
*/
|
||||
@@ -33,9 +33,9 @@ public class EnumUtil {
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append("(|,|\\s");
|
||||
|
||||
for (T flag: clazz.getEnumConstants()) {
|
||||
for (T flag : clazz.getEnumConstants()) {
|
||||
result.append("|");
|
||||
for(char ch: flag.toString().toUpperCase().toCharArray()) {
|
||||
for (char ch : flag.toString().toUpperCase().toCharArray()) {
|
||||
if (Character.isAlphabetic(ch)) {
|
||||
result.append("[");
|
||||
result.append(ch);
|
||||
@@ -52,25 +52,25 @@ public class EnumUtil {
|
||||
|
||||
/**
|
||||
* Parses a delimited string containing Enum constant names into a list of Enum constants.
|
||||
*
|
||||
* <p>
|
||||
* This method takes an Enum class and a string of flags, splits the string by commas
|
||||
* or whitespace, and converts each substring into an Enum constant of the given class.
|
||||
* The flag names are case-insensitive and will be converted to uppercase before matching
|
||||
* to the Enum constants.
|
||||
*
|
||||
* @param <T> The type of the Enum.
|
||||
* @param <T> The type of the Enum.
|
||||
* @param clazz The Enum class to which the flags should be parsed.
|
||||
* @param flags A string containing the delimited list of flag names to parse.
|
||||
* Individual names can be separated by commas or whitespace.
|
||||
* @return A list of Enum constants parsed from the input string. If the input string
|
||||
* is null or empty, an empty list is returned.
|
||||
* is null or empty, an empty list is returned.
|
||||
* @throws IllegalArgumentException if any of the flag names do not match the constants in the given Enum class.
|
||||
* @throws NullPointerException if the clazz parameter is null.
|
||||
* @throws NullPointerException if the clazz parameter is null.
|
||||
*/
|
||||
public static <T extends Enum<T>> List<T> parseFlags(final Class<T> clazz, final String flags) {
|
||||
List<T> result = new ArrayList<>();
|
||||
if (flags != null) {
|
||||
for (String flag: flags.split("[,\\s]")) {
|
||||
for (String flag : flags.split("[,\\s]")) {
|
||||
if (!flag.isEmpty()) result.add(T.valueOf(clazz, flag.toUpperCase()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public class RegionalizationMessage {
|
||||
* which is used to retrieve locale-specific objects and messages.
|
||||
* It facilitates the process of internationalization by loading resources
|
||||
* such as text and messages from specified bundles based on the provided locale.
|
||||
*
|
||||
* <p>
|
||||
* This variable is initialized in constructors of the `RegionalizationMessage` class
|
||||
* and is used internally by various methods to fetch localized messages.
|
||||
*/
|
||||
@@ -50,21 +50,36 @@ public class RegionalizationMessage {
|
||||
*
|
||||
* @param key The key for which the localized message needs to be retrieved.
|
||||
* @return The localized message as a String if the key exists in the resource bundle;
|
||||
* otherwise, null.
|
||||
* otherwise, null.
|
||||
*/
|
||||
public String getMessage(final String key) {
|
||||
if (!res.containsKey(key)) return null;
|
||||
return res.getString(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a localized and formatted message from a resource bundle based on a key.
|
||||
* If the key is not found in the resource bundle, a default message is used.
|
||||
* The message supports parameter substitution using the supplied arguments.
|
||||
*
|
||||
* @param key The key used to retrieve the localized message from the resource bundle.
|
||||
* @param defaultMessage The default message to be used if the key is not found in the resource bundle.
|
||||
* @param params The parameters to substitute into the message placeholders.
|
||||
* @return A formatted string containing the localized message with substituted parameters.
|
||||
*/
|
||||
public String getFormattedMessage(final String key, final String defaultMessage, final Object... params) {
|
||||
MessageFormat format = new MessageFormat(getMessage(key, defaultMessage));
|
||||
return format.format(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a localized message for the given key from the resource bundle.
|
||||
* If the key is not found, the specified default message is returned.
|
||||
*
|
||||
* @param key The key to look up in the resource bundle.
|
||||
* @param key The key to look up in the resource bundle.
|
||||
* @param defaultMessage The default message to return if the key is not found.
|
||||
* @return The localized message corresponding to the key, or the default message
|
||||
* if the key does not exist in the resource bundle.
|
||||
* if the key does not exist in the resource bundle.
|
||||
*/
|
||||
public String getMessage(final String key, final String defaultMessage) {
|
||||
if (res.containsKey(key))
|
||||
@@ -72,19 +87,4 @@ public class RegionalizationMessage {
|
||||
|
||||
return defaultMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a localized and formatted message from a resource bundle based on a key.
|
||||
* If the key is not found in the resource bundle, a default message is used.
|
||||
* The message supports parameter substitution using the supplied arguments.
|
||||
*
|
||||
* @param key The key used to retrieve the localized message from the resource bundle.
|
||||
* @param defaultMessage The default message to be used if the key is not found in the resource bundle.
|
||||
* @param params The parameters to substitute into the message placeholders.
|
||||
* @return A formatted string containing the localized message with substituted parameters.
|
||||
*/
|
||||
public String getFormattedMessage(final String key, final String defaultMessage, final Object... params) {
|
||||
MessageFormat format = new MessageFormat(getMessage(key, defaultMessage));
|
||||
return format.format(params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,122 +7,140 @@ import java.util.Locale;
|
||||
/**
|
||||
* A utility class for measuring elapsed time. The StopWatch can be started, stopped, and queried for the elapsed time in various formats.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class StopWatch {
|
||||
|
||||
/**
|
||||
* Represents the starting time of the stopwatch. This variable is set when the stopwatch is started and is used to calculate the elapsed
|
||||
* duration between the start and the stop or the current time.
|
||||
*/
|
||||
private Instant startTime;
|
||||
/**
|
||||
* Represents the stopping time of the stopwatch. This variable is set when the stopwatch is stopped and is used to calculate the elapsed
|
||||
* duration between the start and stop times.
|
||||
*/
|
||||
private Instant stopTime;
|
||||
/**
|
||||
* Represents the starting time of the stopwatch. This variable is set when the stopwatch is started and is used to calculate the elapsed
|
||||
* duration between the start and the stop or the current time.
|
||||
*/
|
||||
private Instant startTime;
|
||||
|
||||
/**
|
||||
* Starts the stopwatch by recording the current time as the starting time. If the stopwatch was previously stopped or not yet started,
|
||||
* this method resets the starting time to the current time and clears the stopping time. This method is typically called before measuring
|
||||
* elapsed time.
|
||||
*/
|
||||
public void start() {
|
||||
this.startTime = Instant.now();
|
||||
this.stopTime = null;
|
||||
}
|
||||
/**
|
||||
* Represents the stopping time of the stopwatch. This variable is set when the stopwatch is stopped and is used to calculate the elapsed
|
||||
* duration between the start and stop times.
|
||||
*/
|
||||
private Instant stopTime;
|
||||
|
||||
/**
|
||||
* Stops the stopwatch by recording the current time as the stopping time.
|
||||
* <p>
|
||||
* This method should only be called after the stopwatch has been started using the {@code start()} method. If the stopwatch has not been
|
||||
* started, an {@code IllegalStateException} will be thrown. Once this method is called, the elapsed time can be calculated as the
|
||||
* duration between the starting and stopping times.
|
||||
*
|
||||
* @throws IllegalStateException if the stopwatch has not been started prior to calling this method.
|
||||
*/
|
||||
public void stop() {
|
||||
if (startTime == null) {
|
||||
throw new IllegalStateException("StopWatch must be started before stopping.");
|
||||
}
|
||||
this.stopTime = Instant.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the amount of time elapsed between the stopwatch's starting time and either its stopping time or the current time if the
|
||||
* stopwatch is still running.
|
||||
*
|
||||
* @return the duration representing the elapsed time between the start and end points of the stopwatch.
|
||||
* @throws IllegalStateException if the stopwatch has not been started before calling this method.
|
||||
*/
|
||||
public Duration getUsedTime() {
|
||||
if (startTime == null) {
|
||||
throw new IllegalStateException("StopWatch has not been started.");
|
||||
}
|
||||
Instant end = (stopTime != null) ? stopTime : Instant.now();
|
||||
return Duration.between(startTime, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the duration of elapsed time measured by the stopwatch into a human-readable string. The formatted output may include days,
|
||||
* hours, minutes, seconds, and milliseconds, depending on the parameters. The method retrieves the elapsed time via the
|
||||
* {@code getUsedTime} method and formats it based on the specified flags.
|
||||
*
|
||||
* @param includeMillis whether to include milliseconds in the formatted output
|
||||
* @param includeSeconds whether to include seconds in the formatted output
|
||||
* @param includeMinutes whether to include minutes in the formatted output
|
||||
* @param includeHours whether to include hours in the formatted output
|
||||
* @param includeDays whether to include days in the formatted output
|
||||
* @return a formatted string representing the elapsed time, including the components specified by the parameters
|
||||
*/
|
||||
public String getUsedTimeFormatted(boolean includeMillis, boolean includeSeconds, boolean includeMinutes, boolean includeHours,
|
||||
boolean includeDays) {
|
||||
Duration duration = getUsedTime();
|
||||
|
||||
long millis = duration.toMillis();
|
||||
long days = millis / (24 * 60 * 60 * 1000);
|
||||
millis %= (24 * 60 * 60 * 1000);
|
||||
|
||||
long hours = millis / (60 * 60 * 1000);
|
||||
millis %= (60 * 60 * 1000);
|
||||
long minutes = millis / (60 * 1000);
|
||||
millis %= (60 * 1000);
|
||||
long seconds = millis / 1000;
|
||||
millis %= 1000;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (includeDays && days > 0) {
|
||||
sb.append(days).append("d ");
|
||||
}
|
||||
if (includeHours && (hours > 0 || sb.length() > 0)) {
|
||||
sb.append(hours).append("h ");
|
||||
}
|
||||
if (includeMinutes && (minutes > 0 || sb.length() > 0)) {
|
||||
sb.append(minutes).append("m ");
|
||||
}
|
||||
if (includeSeconds && (seconds > 0 || sb.length() > 0)) {
|
||||
sb.append(seconds);
|
||||
}
|
||||
if (includeMillis) {
|
||||
if (includeSeconds) {
|
||||
sb.append(String.format(Locale.US, ".%03d", millis));
|
||||
} else {
|
||||
sb.append(millis).append("ms");
|
||||
}
|
||||
/**
|
||||
* Creates a new StopWatch instance in the reset state.
|
||||
*
|
||||
* <p>The constructor does not start timing. Both {@link #startTime} and {@link #stopTime}
|
||||
* are initialized to {@code null}. To begin measuring elapsed time, call {@link #start()}.
|
||||
* After calling {@link #stop()}, retrieve the measured duration with {@link #getUsedTime()} or
|
||||
* a human-readable string via {@link #getUsedTimeFormatted(boolean, boolean, boolean, boolean, boolean)}.
|
||||
* </p>
|
||||
*
|
||||
* <p>Note: This class is not synchronized; synchronize externally if the same instance
|
||||
* is accessed from multiple threads.</p>
|
||||
*/
|
||||
public StopWatch() {
|
||||
// default constructor only ...
|
||||
}
|
||||
|
||||
String result = sb.toString().trim();
|
||||
return result.isEmpty() ? "0ms" : result;
|
||||
}
|
||||
/**
|
||||
* Starts the stopwatch by recording the current time as the starting time. If the stopwatch was previously stopped or not yet started,
|
||||
* this method resets the starting time to the current time and clears the stopping time. This method is typically called before measuring
|
||||
* elapsed time.
|
||||
*/
|
||||
public void start() {
|
||||
this.startTime = Instant.now();
|
||||
this.stopTime = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a compact and human-readable formatted string representing the elapsed time measured by the stopwatch. The method formats the
|
||||
* duration using a combination of days, hours, minutes, seconds, and milliseconds. This compact format removes additional verbosity in
|
||||
* favor of a shorter, more concise representation.
|
||||
*
|
||||
* @return a compact formatted string representing the elapsed time, including days, hours, minutes, seconds, and milliseconds as
|
||||
* applicable
|
||||
*/
|
||||
public String getUsedTimeFormattedCompact() {
|
||||
return getUsedTimeFormatted(true, true, true, true, true);
|
||||
}
|
||||
/**
|
||||
* Stops the stopwatch by recording the current time as the stopping time.
|
||||
* <p>
|
||||
* This method should only be called after the stopwatch has been started using the {@code start()} method. If the stopwatch has not been
|
||||
* started, an {@code IllegalStateException} will be thrown. Once this method is called, the elapsed time can be calculated as the
|
||||
* duration between the starting and stopping times.
|
||||
*
|
||||
* @throws IllegalStateException if the stopwatch has not been started prior to calling this method.
|
||||
*/
|
||||
public void stop() {
|
||||
if (startTime == null) {
|
||||
throw new IllegalStateException("StopWatch must be started before stopping.");
|
||||
}
|
||||
this.stopTime = Instant.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a compact and human-readable formatted string representing the elapsed time measured by the stopwatch. The method formats the
|
||||
* duration using a combination of days, hours, minutes, seconds, and milliseconds. This compact format removes additional verbosity in
|
||||
* favor of a shorter, more concise representation.
|
||||
*
|
||||
* @return a compact formatted string representing the elapsed time, including days, hours, minutes, seconds, and milliseconds as
|
||||
* applicable
|
||||
*/
|
||||
public String getUsedTimeFormattedCompact() {
|
||||
return getUsedTimeFormatted(true, true, true, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the duration of elapsed time measured by the stopwatch into a human-readable string. The formatted output may include days,
|
||||
* hours, minutes, seconds, and milliseconds, depending on the parameters. The method retrieves the elapsed time via the
|
||||
* {@code getUsedTime} method and formats it based on the specified flags.
|
||||
*
|
||||
* @param includeMillis whether to include milliseconds in the formatted output
|
||||
* @param includeSeconds whether to include seconds in the formatted output
|
||||
* @param includeMinutes whether to include minutes in the formatted output
|
||||
* @param includeHours whether to include hours in the formatted output
|
||||
* @param includeDays whether to include days in the formatted output
|
||||
* @return a formatted string representing the elapsed time, including the components specified by the parameters
|
||||
*/
|
||||
public String getUsedTimeFormatted(boolean includeMillis, boolean includeSeconds, boolean includeMinutes, boolean includeHours,
|
||||
boolean includeDays) {
|
||||
Duration duration = getUsedTime();
|
||||
|
||||
long millis = duration.toMillis();
|
||||
long days = millis / (24 * 60 * 60 * 1000);
|
||||
millis %= (24 * 60 * 60 * 1000);
|
||||
|
||||
long hours = millis / (60 * 60 * 1000);
|
||||
millis %= (60 * 60 * 1000);
|
||||
long minutes = millis / (60 * 1000);
|
||||
millis %= (60 * 1000);
|
||||
long seconds = millis / 1000;
|
||||
millis %= 1000;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (includeDays && days > 0) {
|
||||
sb.append(days).append("d ");
|
||||
}
|
||||
if (includeHours && (hours > 0 || !sb.isEmpty())) {
|
||||
sb.append(hours).append("h ");
|
||||
}
|
||||
if (includeMinutes && (minutes > 0 || !sb.isEmpty())) {
|
||||
sb.append(minutes).append("m ");
|
||||
}
|
||||
if (includeSeconds && (seconds > 0 || !sb.isEmpty())) {
|
||||
sb.append(seconds);
|
||||
}
|
||||
if (includeMillis) {
|
||||
if (includeSeconds) {
|
||||
sb.append(String.format(Locale.US, ".%03d", millis));
|
||||
} else {
|
||||
sb.append(millis).append("ms");
|
||||
}
|
||||
}
|
||||
|
||||
String result = sb.toString().trim();
|
||||
return result.isEmpty() ? "0ms" : result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the amount of time elapsed between the stopwatch's starting time and either its stopping time or the current time if the
|
||||
* stopwatch is still running.
|
||||
*
|
||||
* @return the duration representing the elapsed time between the start and end points of the stopwatch.
|
||||
* @throws IllegalStateException if the stopwatch has not been started before calling this method.
|
||||
*/
|
||||
public Duration getUsedTime() {
|
||||
if (startTime == null) {
|
||||
throw new IllegalStateException("StopWatch has not been started.");
|
||||
}
|
||||
Instant end = (stopTime != null) ? stopTime : Instant.now();
|
||||
return Duration.between(startTime, end);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,33 +8,33 @@ import java.util.Map;
|
||||
* Utility class providing common string manipulation methods.
|
||||
*/
|
||||
public class Strings {
|
||||
/**
|
||||
* A map that holds the system's environment variables. The keys represent
|
||||
* environment variable names, and the values represent their corresponding
|
||||
* values. It is initialized with the current system environment variables using
|
||||
* {@link System#getenv()}.
|
||||
* <p>
|
||||
* This variable provides access to the underlying system environment, which can
|
||||
* be used for various purposes such as configuration, path resolution, or
|
||||
* dynamic value substitution.
|
||||
* <p>
|
||||
* Note: Modifications to this map will not affect the system environment, as it
|
||||
* is a copy of the environment at the time of initialization.
|
||||
*/
|
||||
private static Map<String, String> environmentVariables = System.getenv();
|
||||
|
||||
/**
|
||||
* Private constructor to prevent instantiation of the utility class.
|
||||
* This utility class is not meant to be instantiated, as it only provides
|
||||
* static utility methods for array-related operations.
|
||||
*
|
||||
* @throws UnsupportedOperationException always, to indicate that this class
|
||||
* should not be instantiated.
|
||||
* should not be instantiated.
|
||||
*/
|
||||
private Strings() {
|
||||
throw new UnsupportedOperationException("Utility class");
|
||||
}
|
||||
|
||||
/**
|
||||
* A map that holds the system's environment variables. The keys represent
|
||||
* environment variable names, and the values represent their corresponding
|
||||
* values. It is initialized with the current system environment variables using
|
||||
* {@link System#getenv()}.
|
||||
*
|
||||
* This variable provides access to the underlying system environment, which can
|
||||
* be used for various purposes such as configuration, path resolution, or
|
||||
* dynamic value substitution.
|
||||
*
|
||||
* Note: Modifications to this map will not affect the system environment, as it
|
||||
* is a copy of the environment at the time of initialization.
|
||||
*/
|
||||
private static Map<String, String> environmentVariables = System.getenv();
|
||||
|
||||
/**
|
||||
* Expands environment variable placeholders within the provided text.
|
||||
* Placeholders in the format ${VARIABLE_NAME} are replaced with their
|
||||
@@ -43,8 +43,8 @@ public class Strings {
|
||||
* @param text The input string containing environment variable placeholders.
|
||||
* If null, the method returns null.
|
||||
* @return A string with the placeholders replaced by their corresponding
|
||||
* environment variable values. If no placeholders are found,
|
||||
* the original string is returned.
|
||||
* environment variable values. If no placeholders are found,
|
||||
* the original string is returned.
|
||||
*/
|
||||
public static String expandEnvironmentVariables(String text) {
|
||||
if (text == null) return null;
|
||||
@@ -63,7 +63,7 @@ public class Strings {
|
||||
* @return true if the string is null or has a length of 0; false otherwise.
|
||||
*/
|
||||
public static boolean isNullOrEmpty(final String string) {
|
||||
return (string == null || string.length()==0);
|
||||
return (string == null || string.length() == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,12 +73,12 @@ public class Strings {
|
||||
* @param value The input string that might contain surrounding double quotes.
|
||||
* The input cannot be null, and leading/trailing whitespaces will be ignored.
|
||||
* @return A string with leading and trailing double quotes removed if present.
|
||||
* Returns the original string if no surrounding double quotes are detected.
|
||||
* Returns the original string if no surrounding double quotes are detected.
|
||||
*/
|
||||
public static String removeQuotes(final String value) {
|
||||
String trimmedValue = value.trim();
|
||||
if (trimmedValue.length() > 1 && trimmedValue.startsWith("\"") && trimmedValue.endsWith("\""))
|
||||
return trimmedValue.substring(1, trimmedValue.length()-1);
|
||||
return trimmedValue.substring(1, trimmedValue.length() - 1);
|
||||
|
||||
return value;
|
||||
}
|
||||
@@ -87,11 +87,11 @@ public class Strings {
|
||||
* Replaces illegal characters in a given string with a specified replacement string.
|
||||
* Optionally, consecutive illegal characters can be combined into a single replacement.
|
||||
*
|
||||
* @param value The input string in which illegal characters are to be replaced.
|
||||
* @param value The input string in which illegal characters are to be replaced.
|
||||
* @param illegalCharacters A string specifying the set of illegal characters to be matched.
|
||||
* @param replacement The string to replace each illegal character or group of characters.
|
||||
* @param combine A boolean flag indicating whether consecutive illegal characters should be replaced
|
||||
* with a single replacement string. If true, groups of illegal characters are combined.
|
||||
* @param replacement The string to replace each illegal character or group of characters.
|
||||
* @param combine A boolean flag indicating whether consecutive illegal characters should be replaced
|
||||
* with a single replacement string. If true, groups of illegal characters are combined.
|
||||
* @return A new string with the illegal characters replaced by the provided replacement string.
|
||||
*/
|
||||
public static String replaceIllegalCharacters(final String value, final String illegalCharacters, final String replacement, final boolean combine) {
|
||||
@@ -104,12 +104,12 @@ public class Strings {
|
||||
* with a specified replacement string. Optionally combines consecutive non-allowed
|
||||
* characters into a single replacement.
|
||||
*
|
||||
* @param value The input string to be processed.
|
||||
* @param value The input string to be processed.
|
||||
* @param allowedCharacters A string containing the set of characters that are allowed.
|
||||
* Any character not in this set will be replaced.
|
||||
* @param replacement The string to replace non-allowed characters with.
|
||||
* @param combine If true, consecutive non-allowed characters will be replaced with
|
||||
* a single instance of the replacement string.
|
||||
* Any character not in this set will be replaced.
|
||||
* @param replacement The string to replace non-allowed characters with.
|
||||
* @param combine If true, consecutive non-allowed characters will be replaced with
|
||||
* a single instance of the replacement string.
|
||||
* @return A new string with non-allowed characters replaced according to the specified rules.
|
||||
*/
|
||||
public static String replaceNonAllowedCharacters(final String value, final String allowedCharacters, final String replacement, final boolean combine) {
|
||||
@@ -131,11 +131,11 @@ public class Strings {
|
||||
public static String increment(@NonNull final String element) {
|
||||
if (element.isEmpty()) return "1";
|
||||
|
||||
String firstPart = element.substring(0, element.length()-1);
|
||||
char lastChar = element.charAt(element.length()-1);
|
||||
String firstPart = element.substring(0, element.length() - 1);
|
||||
char lastChar = element.charAt(element.length() - 1);
|
||||
if (lastChar == '9') return firstPart + 'A';
|
||||
if (lastChar == 'Z') return increment(firstPart) + '0';
|
||||
return firstPart + (char)(lastChar+1);
|
||||
return firstPart + (char) (lastChar + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,10 +144,10 @@ public class Strings {
|
||||
* the string is returned unchanged. If the input string's length exceeds the max
|
||||
* length, it is truncated to that length.
|
||||
*
|
||||
* @param original The original input string to be processed. If null, the method returns null.
|
||||
* @param original The original input string to be processed. If null, the method returns null.
|
||||
* @param maxLength The maximum number of characters allowed in the resulting string.
|
||||
* @return The original string if its length is less than or equal to maxLength,
|
||||
* otherwise a truncated version of the string up to maxLength characters.
|
||||
* otherwise a truncated version of the string up to maxLength characters.
|
||||
*/
|
||||
public static String limitCharNumber(final String original, final int maxLength) {
|
||||
if (original == null || original.length() <= maxLength) return original;
|
||||
|
||||
@@ -8,7 +8,12 @@ import org.w3c.dom.Node;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.transform.*;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Result;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
@@ -25,214 +30,211 @@ import java.util.Date;
|
||||
*/
|
||||
@Slf4j
|
||||
public class XmlUtils {
|
||||
/**
|
||||
* Private constructor to prevent instantiation of the utility class.
|
||||
* This utility class is not meant to be instantiated, as it only provides
|
||||
* static utility methods for array-related operations.
|
||||
*
|
||||
* @throws UnsupportedOperationException always, to indicate that this class
|
||||
* should not be instantiated.
|
||||
*/
|
||||
private XmlUtils() {
|
||||
throw new UnsupportedOperationException("Utility class");
|
||||
}
|
||||
/**
|
||||
* A {@link DateTimeFormatter} instance used for formatting or parsing dates in the "yyyy-MM-dd" pattern.
|
||||
* <p>
|
||||
* This formatter adheres to the XML date format standard (ISO-8601). It can be used
|
||||
* to ensure consistent date representations in XML or other similar text-based formats.
|
||||
* <p>
|
||||
* Thread-safe and immutable, this formatter can be shared across multiple threads.
|
||||
*/
|
||||
public static final DateTimeFormatter XML_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
|
||||
/**
|
||||
* A {@link DateTimeFormatter} instance used for formatting or parsing dates in the "yyyy-MM-dd" pattern.
|
||||
*
|
||||
* This formatter adheres to the XML date format standard (ISO-8601). It can be used
|
||||
* to ensure consistent date representations in XML or other similar text-based formats.
|
||||
*
|
||||
* Thread-safe and immutable, this formatter can be shared across multiple threads.
|
||||
*/
|
||||
public static final DateTimeFormatter XML_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
/**
|
||||
* Private constructor to prevent instantiation of the utility class.
|
||||
* This utility class is not meant to be instantiated, as it only provides
|
||||
* static utility methods for array-related operations.
|
||||
*
|
||||
* @throws UnsupportedOperationException always, to indicate that this class
|
||||
* should not be instantiated.
|
||||
*/
|
||||
private XmlUtils() {
|
||||
throw new UnsupportedOperationException("Utility class");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new element in the provided XML document with the specified name.
|
||||
*
|
||||
* @param doc The XML document in which the new element is to be created. Must not be null.
|
||||
* @param name The name of the element to be created. Must not be null or empty.
|
||||
* @return The newly created element with the given name. Never returns null.
|
||||
*/
|
||||
public static Element createElement(final Document doc, final String name) {
|
||||
log.debug("Creating a new element " + name);
|
||||
return doc.createElement(name);
|
||||
}
|
||||
/**
|
||||
* Creates an XML element with the specified name and value, formatted as a date string.
|
||||
* The date value is converted to an XML-compatible string format using a predefined formatter.
|
||||
*
|
||||
* @param doc the XML document to which the element belongs; must not be null
|
||||
* @param name the name of the element to be created; must not be null or empty
|
||||
* @param value the date value to be assigned to the created element; must not be null
|
||||
* @return the created XML element containing the specified name and formatted date value
|
||||
*/
|
||||
public static Element createElement(final Document doc, final String name, final Date value) {
|
||||
return createElement(doc, name, XML_DATE_FORMATTER.format(value.toInstant()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new XML element with the specified name and value, appends the value
|
||||
* as a text node to the element, and returns the resulting element.
|
||||
*
|
||||
* @param doc the XML document to which the element belongs. Must not be null.
|
||||
* @param name the name of the element to create. Must not be null.
|
||||
* @param value the text value to be set as the content of the created element.
|
||||
* If null, an empty string will be used as the content.
|
||||
* @return the newly created XML element containing the specified value as a text node.
|
||||
*/
|
||||
public static Element createElement(final Document doc, final String name, final String value) {
|
||||
log.debug("Creating a new element " + name + " with value: " + value);
|
||||
Element element = doc.createElement(name);
|
||||
/**
|
||||
* Creates a new XML element with the specified name and value, appends the value
|
||||
* as a text node to the element, and returns the resulting element.
|
||||
*
|
||||
* @param doc the XML document to which the element belongs. Must not be null.
|
||||
* @param name the name of the element to create. Must not be null.
|
||||
* @param value the text value to be set as the content of the created element.
|
||||
* If null, an empty string will be used as the content.
|
||||
* @return the newly created XML element containing the specified value as a text node.
|
||||
*/
|
||||
public static Element createElement(final Document doc, final String name, final String value) {
|
||||
log.debug("Creating a new element " + name + " with value: " + value);
|
||||
Element element = doc.createElement(name);
|
||||
|
||||
Node content = doc.createTextNode(value != null ? value : "");
|
||||
element.appendChild(content);
|
||||
Node content = doc.createTextNode(value != null ? value : "");
|
||||
element.appendChild(content);
|
||||
|
||||
return element;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an XML element with the specified name and value, formatted as a date string.
|
||||
* The date value is converted to an XML-compatible string format using a predefined formatter.
|
||||
*
|
||||
* @param doc the XML document to which the element belongs; must not be null
|
||||
* @param name the name of the element to be created; must not be null or empty
|
||||
* @param value the date value to be assigned to the created element; must not be null
|
||||
* @return the created XML element containing the specified name and formatted date value
|
||||
*/
|
||||
public static Element createElement(final Document doc, final String name, final Date value) {
|
||||
return createElement(doc, name, XML_DATE_FORMATTER.format(value.toInstant()));
|
||||
}
|
||||
/**
|
||||
* Creates an XML element with the specified name and optional value.
|
||||
*
|
||||
* @param doc The Document object to which the element will belong. Must not be null.
|
||||
* @param name The name of the element to be created. Must not be null or empty.
|
||||
* @param value The optional value to be set as the text content of the element. If null,
|
||||
* the element will have an empty text content.
|
||||
* @return The newly created Element object with the specified name and value.
|
||||
*/
|
||||
public static Element createElement(final Document doc, final String name, final Integer value) {
|
||||
log.debug("Creating a new element " + name + " with value: " + value);
|
||||
Element element = doc.createElement(name);
|
||||
|
||||
/**
|
||||
* Creates an XML element with the specified name and optional value.
|
||||
*
|
||||
* @param doc The Document object to which the element will belong. Must not be null.
|
||||
* @param name The name of the element to be created. Must not be null or empty.
|
||||
* @param value The optional value to be set as the text content of the element. If null,
|
||||
* the element will have an empty text content.
|
||||
* @return The newly created Element object with the specified name and value.
|
||||
*/
|
||||
public static Element createElement(final Document doc, final String name, final Integer value) {
|
||||
log.debug("Creating a new element " + name + " with value: " + value);
|
||||
Element element = doc.createElement(name);
|
||||
Node content = doc.createTextNode(value != null ? "" + value : "");
|
||||
element.appendChild(content);
|
||||
|
||||
Node content = doc.createTextNode(value != null ? ""+value : "");
|
||||
element.appendChild(content);
|
||||
return element;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
/**
|
||||
* Creates a new element with the specified name, appends it to the provided parent element,
|
||||
* and returns the newly created element.
|
||||
*
|
||||
* @param doc The Document to which the new element belongs. Must not be null.
|
||||
* @param name The name of the new element to be created. Must not be null or empty.
|
||||
* @param parent The parent element to which the new element will be appended. Must not be null.
|
||||
* @return The newly created and appended Element object.
|
||||
*/
|
||||
public static Element createAndInsertElement(final Document doc, final String name, @NonNull final Element parent) {
|
||||
log.debug("Creating a new element " + name + " and adding it to a parent.");
|
||||
Element element = createElement(doc, name);
|
||||
parent.appendChild(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new element with the specified name, appends it to the provided parent element,
|
||||
* and returns the newly created element.
|
||||
*
|
||||
* @param doc The Document to which the new element belongs. Must not be null.
|
||||
* @param name The name of the new element to be created. Must not be null or empty.
|
||||
* @param parent The parent element to which the new element will be appended. Must not be null.
|
||||
* @return The newly created and appended Element object.
|
||||
*/
|
||||
public static Element createAndInsertElement(final Document doc, final String name, @NonNull final Element parent) {
|
||||
log.debug("Creating a new element " + name + " and adding it to a parent.");
|
||||
Element element = createElement(doc, name);
|
||||
parent.appendChild(element);
|
||||
return element;
|
||||
}
|
||||
/**
|
||||
* Creates a new element in the provided XML document with the specified name.
|
||||
*
|
||||
* @param doc The XML document in which the new element is to be created. Must not be null.
|
||||
* @param name The name of the element to be created. Must not be null or empty.
|
||||
* @return The newly created element with the given name. Never returns null.
|
||||
*/
|
||||
public static Element createElement(final Document doc, final String name) {
|
||||
log.debug("Creating a new element " + name);
|
||||
return doc.createElement(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new XML element with a specified name and value, adds it to the specified parent element,
|
||||
* and returns the created element.
|
||||
*
|
||||
* @param doc The XML document to which the new element belongs. Must not be null.
|
||||
* @param name The name of the element to create. Must not be null.
|
||||
* @param value The value to be set for the created element. Can be null if no value is required.
|
||||
* @param parent The parent element to which the new element will be appended. Must not be null.
|
||||
* @return The newly created and inserted element.
|
||||
*/
|
||||
public static Element createAndInsertElement(final Document doc, final String name, final String value, @NonNull final Element parent) {
|
||||
log.debug("Creating a new element " + name + " with value: " + value + " and adding it to a parent.");
|
||||
Element element = createElement(doc, name, value);
|
||||
parent.appendChild(element);
|
||||
return element;
|
||||
}
|
||||
/**
|
||||
* Creates a new XML element with a specified name and value, adds it to the specified parent element,
|
||||
* and returns the created element.
|
||||
*
|
||||
* @param doc The XML document to which the new element belongs. Must not be null.
|
||||
* @param name The name of the element to create. Must not be null.
|
||||
* @param value The value to be set for the created element. Can be null if no value is required.
|
||||
* @param parent The parent element to which the new element will be appended. Must not be null.
|
||||
* @return The newly created and inserted element.
|
||||
*/
|
||||
public static Element createAndInsertElement(final Document doc, final String name, final String value, @NonNull final Element parent) {
|
||||
log.debug("Creating a new element " + name + " with value: " + value + " and adding it to a parent.");
|
||||
Element element = createElement(doc, name, value);
|
||||
parent.appendChild(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a given XML string by applying proper indentation to enhance readability.
|
||||
* The method uses a transformer to process the XML input, applying indentation
|
||||
* with a four-space configuration. In case of an error, the original XML string
|
||||
* is returned without any modifications.
|
||||
*
|
||||
* @param xmlStream The raw XML string to be formatted. Cannot be null.
|
||||
* @return The formatted XML string with proper indentation. If an exception occurs
|
||||
* during formatting, the original XML string is returned.
|
||||
*/
|
||||
public static String format(final String xmlStream) {
|
||||
log.debug("formatXML");
|
||||
|
||||
/**
|
||||
* Formats a given XML string by applying proper indentation to enhance readability.
|
||||
* The method uses a transformer to process the XML input, applying indentation
|
||||
* with a four-space configuration. In case of an error, the original XML string
|
||||
* is returned without any modifications.
|
||||
*
|
||||
* @param xmlStream The raw XML string to be formatted. Cannot be null.
|
||||
* @return The formatted XML string with proper indentation. If an exception occurs
|
||||
* during formatting, the original XML string is returned.
|
||||
*/
|
||||
public static String format(final String xmlStream) {
|
||||
log.debug("formatXML");
|
||||
try {
|
||||
Source xmlInput = new StreamSource(new StringReader(xmlStream));
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
StreamResult xmlOutput = new StreamResult(stringWriter);
|
||||
|
||||
try {
|
||||
Source xmlInput = new StreamSource(new StringReader(xmlStream));
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
StreamResult xmlOutput = new StreamResult(stringWriter);
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
transformerFactory.setAttribute("indent-number", "4");
|
||||
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
transformerFactory.setAttribute("indent-number", "4");
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
transformer.transform(xmlInput, xmlOutput);
|
||||
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
transformer.transform(xmlInput, xmlOutput);
|
||||
return xmlOutput.getWriter().toString();
|
||||
} catch (TransformerException e) {
|
||||
log.error("Error in XML: " + e.getMessage() + "\n" + xmlStream, e);
|
||||
}
|
||||
|
||||
return xmlOutput.getWriter().toString();
|
||||
}
|
||||
catch(TransformerException e) {
|
||||
log.error("Error in XML: " + e.getMessage() + "\n"+xmlStream, e);
|
||||
}
|
||||
return xmlStream;
|
||||
}
|
||||
|
||||
return xmlStream;
|
||||
}
|
||||
/**
|
||||
* Formats a given XML Document into a human-readable string representation.
|
||||
* The method applies indentation and specific output properties to the XML content.
|
||||
* If an exception occurs during the transformation process, it logs the error
|
||||
* and returns null.
|
||||
*
|
||||
* @param doc The XML Document to be formatted. Must not be null.
|
||||
* @return A formatted string representation of the XML document, or null if an error occurs during processing.
|
||||
*/
|
||||
public static String format(final Document doc) {
|
||||
try {
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
transformerFactory.setAttribute("indent-number", "4");
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
|
||||
transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
|
||||
/**
|
||||
* Formats a given XML Document into a human-readable string representation.
|
||||
* The method applies indentation and specific output properties to the XML content.
|
||||
* If an exception occurs during the transformation process, it logs the error
|
||||
* and returns null.
|
||||
*
|
||||
* @param doc The XML Document to be formatted. Must not be null.
|
||||
* @return A formatted string representation of the XML document, or null if an error occurs during processing.
|
||||
*/
|
||||
public static String format(final Document doc) {
|
||||
try {
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
transformerFactory.setAttribute("indent-number", "4");
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
|
||||
transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
Source source = new DOMSource(doc);
|
||||
Result result = new StreamResult(stringWriter);
|
||||
transformer.transform(source, result);
|
||||
|
||||
Source source = new DOMSource(doc);
|
||||
Result result = new StreamResult(stringWriter);
|
||||
transformer.transform(source, result);
|
||||
String xmlString = stringWriter.toString();
|
||||
log.info("MO Request: " + xmlString);
|
||||
return xmlString;
|
||||
} catch (TransformerException e) {
|
||||
log.error("Error in XML Transformation: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
String xmlString = stringWriter.toString();
|
||||
log.info("MO Request: " + xmlString);
|
||||
return xmlString;
|
||||
}
|
||||
catch(TransformerException e) {
|
||||
log.error("Error in XML Transformation: " + e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates whether a given XML string is well-formed.
|
||||
* This method attempts to parse the input XML string and checks
|
||||
* if it can successfully create a valid DOM object from it.
|
||||
*
|
||||
* @param xml The XML string to be validated. Must not be null.
|
||||
* If null or invalid, the method will return false.
|
||||
* @return true if the XML string is well-formed and can be successfully parsed;
|
||||
* false otherwise, such as in the case of invalid content or parsing errors.
|
||||
*/
|
||||
public static boolean checkXml(final String xml) {
|
||||
try {
|
||||
InputStream stream = new ByteArrayInputStream(xml.getBytes());
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder docBuilder = dbf.newDocumentBuilder();
|
||||
Document document = docBuilder.parse(stream);
|
||||
return document != null;
|
||||
} catch (Exception ex) {
|
||||
log.warn("Exception when validating xml.", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Validates whether a given XML string is well-formed.
|
||||
* This method attempts to parse the input XML string and checks
|
||||
* if it can successfully create a valid DOM object from it.
|
||||
*
|
||||
* @param xml The XML string to be validated. Must not be null.
|
||||
* If null or invalid, the method will return false.
|
||||
* @return true if the XML string is well-formed and can be successfully parsed;
|
||||
* false otherwise, such as in the case of invalid content or parsing errors.
|
||||
*/
|
||||
public static boolean checkXml(final String xml) {
|
||||
try {
|
||||
InputStream stream = new ByteArrayInputStream(xml.getBytes());
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder docBuilder = dbf.newDocumentBuilder();
|
||||
Document document = docBuilder.parse(stream);
|
||||
return document != null;
|
||||
} catch (Exception ex) {
|
||||
log.warn("Exception when validating xml.", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,11 @@ import de.neitzel.core.inject.testcomponents.test1ok.TestInterface1_2;
|
||||
import de.neitzel.core.inject.testcomponents.test1ok.sub.TestComponent1_2;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertAll;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class InjectableComponentScannerTest {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user