Added StopWatch class and a generic type adapter that can exclude fields.
This commit is contained in:
parent
547c582dbf
commit
78f78adea7
128
core/src/main/java/de/neitzel/core/util/StopWatch.java
Normal file
128
core/src/main/java/de/neitzel/core/util/StopWatch.java
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
package de.neitzel.core.util;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String result = sb.toString().trim();
|
||||||
|
return result.isEmpty() ? "0ms" : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,136 @@
|
|||||||
|
package de.neitzel.gson.adapter;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.TypeAdapter;
|
||||||
|
import com.google.gson.internal.Streams;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A custom {@link TypeAdapter} implementation for selectively excluding specified fields during JSON serialization.
|
||||||
|
*
|
||||||
|
* This adapter facilitates both serialization and deserialization of objects while providing functionality to remove specified
|
||||||
|
* fields from the serialized output. The set of excluded field names is provided during the adapter's initialization.
|
||||||
|
*
|
||||||
|
* @param <T> the type of objects that this adapter can serialize and deserialize
|
||||||
|
*/
|
||||||
|
public class ExcludeFieldsAdapter<T> extends TypeAdapter<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of objects that this adapter handles for serialization and deserialization.
|
||||||
|
*
|
||||||
|
* This is a generic class type parameter representing the class of objects that the
|
||||||
|
* {@link ExcludeFieldsAdapter} instance is designed to process. It ensures type
|
||||||
|
* safety and guarantees the compatibility of the adapter with a specific object type.
|
||||||
|
*/
|
||||||
|
private final Class<T> type;
|
||||||
|
/**
|
||||||
|
* A set containing the names of fields to be excluded during JSON serialization.
|
||||||
|
*
|
||||||
|
* This collection is used in the {@link ExcludeFieldsAdapter} to determine which fields should be removed from the
|
||||||
|
* serialized JSON representation of an object. The fields to be excluded are specified during the initialization
|
||||||
|
* of the adapter.
|
||||||
|
*/
|
||||||
|
private final Set<String> excludedFields;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An instance of the Gson library used for JSON serialization and deserialization.
|
||||||
|
*
|
||||||
|
* This variable holds the Gson object that is utilized to handle the conversion processes within the
|
||||||
|
* custom serialization and deserialization logic. If not explicitly provided during initialization,
|
||||||
|
* it can be lazily initialized using a GsonBuilder.
|
||||||
|
*/
|
||||||
|
private Gson gson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link GsonBuilder} instance used for configuring and creating {@link Gson} objects within the adapter.
|
||||||
|
*
|
||||||
|
* This variable serves as a reference to a GsonBuilder that allows customization of the Gson instance,
|
||||||
|
* including registering custom type adapters, serializers, and deserializers, as well as adjusting serialization policies.
|
||||||
|
*
|
||||||
|
* The {@link #gsonBuilder} is primarily utilized when an existing {@link Gson} instance is not directly provided.
|
||||||
|
* It ensures that the adapter can defer the creation of a Gson object until it is explicitly required.
|
||||||
|
*/
|
||||||
|
private GsonBuilder gsonBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of {@code ExcludeFieldsAdapter} for managing the serialization and deserialization
|
||||||
|
* of objects of the specified {@code type}, while excluding certain fields during serialization.
|
||||||
|
*
|
||||||
|
* @param type the class type of the objects to be serialized and deserialized
|
||||||
|
* @param excludedFields the set of field names to be excluded during serialization
|
||||||
|
* @param gson the Gson instance to be used for serialization and deserialization
|
||||||
|
*/
|
||||||
|
public ExcludeFieldsAdapter(Class<T> type, Set<String> excludedFields, Gson gson) {
|
||||||
|
this.type = type;
|
||||||
|
this.excludedFields = new HashSet<>(excludedFields);
|
||||||
|
this.gsonBuilder = null;
|
||||||
|
this.gson = gson;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of {@code ExcludeFieldsAdapter} that selectively excludes specified fields from
|
||||||
|
* the JSON output based on the configuration provided during initialization.
|
||||||
|
*
|
||||||
|
* @param type the class of the type to be serialized and deserialized
|
||||||
|
* @param excludedFields a set of field names to be excluded from the serialized JSON output
|
||||||
|
* @param gsonBuilder an instance of {@code GsonBuilder} used to create a custom {@code Gson} instance if needed
|
||||||
|
*/
|
||||||
|
public ExcludeFieldsAdapter(Class<T> type, Set<String> excludedFields, GsonBuilder gsonBuilder) {
|
||||||
|
this.type = type;
|
||||||
|
this.excludedFields = new HashSet<>(excludedFields);
|
||||||
|
this.gsonBuilder = gsonBuilder;
|
||||||
|
this.gson = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lazily initializes and retrieves the {@link Gson} instance. If the instance is null, it creates a new {@link Gson}
|
||||||
|
* object using the {@link GsonBuilder} provided during the adapter's initialization.
|
||||||
|
*
|
||||||
|
* @return the {@link Gson} instance used for serialization and deserialization
|
||||||
|
*/
|
||||||
|
private Gson getGson() {
|
||||||
|
if (gson == null) {
|
||||||
|
gson = gsonBuilder.create();
|
||||||
|
}
|
||||||
|
return gson;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes an object of type {@code T} into JSON format, excluding certain fields specified during the initialization of this adapter.
|
||||||
|
* The object is first converted into a {@link JsonObject}, then the fields listed in the excluded fields set are removed from the JSON
|
||||||
|
* representation before writing it to the provided {@link JsonWriter}.
|
||||||
|
*
|
||||||
|
* @param out the {@link JsonWriter} to write the serialized JSON data to
|
||||||
|
* @param value the object of type {@code T} to serialize into JSON
|
||||||
|
* @throws IOException if an I/O error occurs during writing
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void write(JsonWriter out, T value) throws IOException {
|
||||||
|
JsonObject obj = getGson().toJsonTree(value).getAsJsonObject();
|
||||||
|
|
||||||
|
for (String field : excludedFields) {
|
||||||
|
obj.remove(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
Streams.write(obj, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a JSON input stream and deserializes it into an object of the specified type.
|
||||||
|
*
|
||||||
|
* @param in the {@link JsonReader} to read the JSON input from
|
||||||
|
* @return an instance of type {@code T} deserialized from the JSON input
|
||||||
|
* @throws IOException if an error occurs during reading or deserialization
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public T read(JsonReader in) throws IOException {
|
||||||
|
return getGson().fromJson(in, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user