diff --git a/core/src/main/java/dev/faststats/core/data/ArrayMetric.java b/core/src/main/java/dev/faststats/core/data/ArrayMetric.java index bcba91a5..4a6e027b 100644 --- a/core/src/main/java/dev/faststats/core/data/ArrayMetric.java +++ b/core/src/main/java/dev/faststats/core/data/ArrayMetric.java @@ -8,7 +8,7 @@ import java.util.concurrent.Callable; final class ArrayMetric extends SimpleMetric { - public ArrayMetric(@SourceId final String id, final Callable callable) throws IllegalArgumentException { + public ArrayMetric(@SourceId final String id, final Callable callable) throws IllegalArgumentException { super(id, callable); } diff --git a/core/src/main/java/dev/faststats/core/data/MapMetric.java b/core/src/main/java/dev/faststats/core/data/MapMetric.java new file mode 100644 index 00000000..c9a5e80e --- /dev/null +++ b/core/src/main/java/dev/faststats/core/data/MapMetric.java @@ -0,0 +1,28 @@ +package dev.faststats.core.data; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.jspecify.annotations.Nullable; + +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.Callable; + +final class MapMetric extends SimpleMetric> { + public MapMetric(@SourceId final String id, final Callable> callable) throws IllegalArgumentException { + super(id, callable); + } + + @Override + public Optional getData() throws Exception { + return compute().map(data -> { + final var object = new JsonObject(); + data.forEach((key, value) -> { + if (value instanceof final Boolean bool) object.addProperty(key, bool); + else if (value instanceof final Number number) object.addProperty(key, number); + else object.addProperty(key, value.toString()); + }); + return object; + }); + } +} diff --git a/core/src/main/java/dev/faststats/core/data/Metric.java b/core/src/main/java/dev/faststats/core/data/Metric.java index 7fb753cb..40ee7830 100644 --- a/core/src/main/java/dev/faststats/core/data/Metric.java +++ b/core/src/main/java/dev/faststats/core/data/Metric.java @@ -4,6 +4,7 @@ import org.jetbrains.annotations.Contract; import org.jspecify.annotations.Nullable; +import java.util.Map; import java.util.Optional; import java.util.concurrent.Callable; @@ -33,7 +34,7 @@ public interface Metric { * @since 0.16.0 */ @Contract(pure = true) - Optional compute() throws Exception; + Optional compute() throws Exception; /** * Get the metric data as a JSON element. @@ -96,6 +97,54 @@ static Metric numberArray(@SourceId final String id, final Callable(id, callable); } + /** + * Create a string map metric. + * + * @param id the source id + * @param callable the metric data callable + * @return the string map metric + * @throws IllegalArgumentException if the source id is invalid + * @apiNote The callable must be thread-safe and pure (i.e. not modify any shared state). + * @see #compute() + * @since 0.23.0 + */ + @Contract(value = "_, _ -> new", pure = true) + static Metric> stringMap(@SourceId final String id, final Callable> callable) throws IllegalArgumentException { + return new MapMetric<>(id, callable); + } + + /** + * Create a boolean map metric. + * + * @param id the source id + * @param callable the metric data callable + * @return the boolean map metric + * @throws IllegalArgumentException if the source id is invalid + * @apiNote The callable must be thread-safe and pure (i.e. not modify any shared state). + * @see #compute() + * @since 0.23.0 + */ + @Contract(value = "_, _ -> new", pure = true) + static Metric> booleanMap(@SourceId final String id, final Callable> callable) throws IllegalArgumentException { + return new MapMetric<>(id, callable); + } + + /** + * Create a number map metric. + * + * @param id the source id + * @param callable the metric data callable + * @return the number map metric + * @throws IllegalArgumentException if the source id is invalid + * @apiNote The callable must be thread-safe and pure (i.e. not modify any shared state). + * @see #compute() + * @since 0.23.0 + */ + @Contract(value = "_, _ -> new", pure = true) + static Metric> numberMap(@SourceId final String id, final Callable> callable) throws IllegalArgumentException { + return new MapMetric<>(id, callable); + } + /** * Create a metric for a boolean value. * diff --git a/core/src/main/java/dev/faststats/core/data/SimpleMetric.java b/core/src/main/java/dev/faststats/core/data/SimpleMetric.java index 8d635e46..e3f55476 100644 --- a/core/src/main/java/dev/faststats/core/data/SimpleMetric.java +++ b/core/src/main/java/dev/faststats/core/data/SimpleMetric.java @@ -8,9 +8,9 @@ abstract class SimpleMetric implements Metric { private final @SourceId String id; - private final Callable<@Nullable T> callable; + private final Callable callable; - public SimpleMetric(@SourceId final String id, final Callable<@Nullable T> callable) throws IllegalArgumentException { + public SimpleMetric(@SourceId final String id, final Callable callable) throws IllegalArgumentException { if (!id.matches(SourceId.PATTERN)) { throw new IllegalArgumentException("Invalid source id '" + id + "', must match '" + SourceId.PATTERN + "'"); } @@ -28,7 +28,7 @@ public final Optional compute() throws Exception { } @Override - public boolean equals(final Object o) { + public boolean equals(@Nullable final Object o) { if (o == null || getClass() != o.getClass()) return false; final SimpleMetric that = (SimpleMetric) o; return Objects.equals(id, that.id); diff --git a/core/src/main/java/dev/faststats/core/data/SingleValueMetric.java b/core/src/main/java/dev/faststats/core/data/SingleValueMetric.java index 458679ce..cbfc7e69 100644 --- a/core/src/main/java/dev/faststats/core/data/SingleValueMetric.java +++ b/core/src/main/java/dev/faststats/core/data/SingleValueMetric.java @@ -8,7 +8,7 @@ import java.util.concurrent.Callable; final class SingleValueMetric extends SimpleMetric { - public SingleValueMetric(@SourceId final String id, final Callable<@Nullable T> callable) throws IllegalArgumentException { + public SingleValueMetric(@SourceId final String id, final Callable callable) throws IllegalArgumentException { super(id, callable); } diff --git a/gradle.properties b/gradle.properties index 1df5d313..4433e215 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.22.1 +version=0.23.0