From ab9990ae6ad0184597a91d00ae5ce5239d43df12 Mon Sep 17 00:00:00 2001 From: Andrey Belonogov Date: Tue, 15 Sep 2026 09:00:46 -0700 Subject: [PATCH] feat(events): make event serialization usable from another package The Android SDK's event durability work summarizes and serializes events on the recording thread, in front of the bounded queue DefaultEventProcessor keeps. It therefore needs the summarizers and the output formatter directly, and there is no public way to hand java-sdk-internal a summary that has already been aggregated. Today the Android SDK reaches them by declaring a class in this package, which is a split package across two artifacts. Widening these five declarations lets it use its own package instead and keeps one implementation of the wire format rather than a second copy that could drift. Visibility only. No behavior changes, and every member that was package-private stays that way except the two constructors and the one method the caller needs: EventOutputFormatter class, constructor, writeOutputEvents EventSummarizerInterface interface AggregatedEventSummarizer class, constructor PerContextEventSummarizer class, constructor EventSummarizer class only, so EventSummary can be named EventSummarizer.EventSummary class only; an opaque token to a caller Co-authored-by: Cursor --- .../events/AggregatedEventSummarizer.java | 4 ++-- .../internal/events/EventOutputFormatter.java | 16 +++++++++++++--- .../sdk/internal/events/EventSummarizer.java | 7 +++++-- .../events/EventSummarizerInterface.java | 2 +- .../events/PerContextEventSummarizer.java | 4 ++-- 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/AggregatedEventSummarizer.java b/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/AggregatedEventSummarizer.java index ec81c25e..710c8937 100644 --- a/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/AggregatedEventSummarizer.java +++ b/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/AggregatedEventSummarizer.java @@ -16,10 +16,10 @@ * Note that the methods of this class are deliberately not thread-safe, because they should * always be called from EventProcessor's single message-processing thread. */ -final class AggregatedEventSummarizer implements EventSummarizerInterface { +public final class AggregatedEventSummarizer implements EventSummarizerInterface { private final EventSummarizer summarizer; - AggregatedEventSummarizer() { + public AggregatedEventSummarizer() { this.summarizer = new EventSummarizer(); } diff --git a/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/EventOutputFormatter.java b/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/EventOutputFormatter.java index 4f5cf5b3..6815812d 100644 --- a/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/EventOutputFormatter.java +++ b/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/EventOutputFormatter.java @@ -25,18 +25,28 @@ * handling of context data and private attribute redaction is implemented in EventContextFormatter * and tested in more detail in EventContextFormatterTest. */ -final class EventOutputFormatter { +public final class EventOutputFormatter { private final EventContextFormatter contextFormatter; private final boolean redactAnonymousAllEvents; - EventOutputFormatter(EventsConfiguration config) { + public EventOutputFormatter(EventsConfiguration config) { this.contextFormatter = new EventContextFormatter( config.allAttributesPrivate, config.privateAttributes.toArray(new AttributeRef[config.privateAttributes.size()])); this.redactAnonymousAllEvents = config.redactAnonymousAllEvents; } - int writeOutputEvents(Event[] events, List summaries, Writer writer) throws IOException { + /** + * Writes events and summaries as the JSON array that makes up a request body. + * + * @param events the individual events to write + * @param summaries the summaries to write; empty ones are skipped + * @param writer where to write the JSON + * @return how many output events were written, counting each summary as one + * @throws IOException if the writer failed + */ + public int writeOutputEvents(Event[] events, List summaries, Writer writer) + throws IOException { int count = 0; JsonWriter jsonWriter = new JsonWriter(writer); jsonWriter.beginArray(); diff --git a/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/EventSummarizer.java b/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/EventSummarizer.java index 3b942d7e..e4a87daf 100644 --- a/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/EventSummarizer.java +++ b/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/EventSummarizer.java @@ -14,7 +14,7 @@ * methods of this class are deliberately not thread-safe, because they should always * be called from EventProcessor's single message-processing thread. */ -final class EventSummarizer { +public final class EventSummarizer { private EventSummary eventsState; private final LDContext context; // nullable - only set for per-context summarization @@ -85,7 +85,10 @@ void clear() { eventsState = new EventSummary(context); } - static final class EventSummary { + /** + * A snapshot of the evaluations counted since the last reset. + */ + public static final class EventSummary { final Map counters; long startDate; long endDate; diff --git a/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/EventSummarizerInterface.java b/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/EventSummarizerInterface.java index 6dcffba1..87a352f0 100644 --- a/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/EventSummarizerInterface.java +++ b/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/EventSummarizerInterface.java @@ -13,7 +13,7 @@ * Note that implementations are deliberately not thread-safe, as they should always * be called from EventProcessor's single message-processing thread. */ -interface EventSummarizerInterface { +public interface EventSummarizerInterface { /** * Adds information about an evaluation to the summary. * diff --git a/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/PerContextEventSummarizer.java b/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/PerContextEventSummarizer.java index b96d9f90..d621378c 100644 --- a/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/PerContextEventSummarizer.java +++ b/lib/shared/internal/src/main/java/com/launchdarkly/sdk/internal/events/PerContextEventSummarizer.java @@ -19,10 +19,10 @@ * Note that the methods of this class are deliberately not thread-safe, because they should * always be called from EventProcessor's single message-processing thread. */ -final class PerContextEventSummarizer implements EventSummarizerInterface { +public final class PerContextEventSummarizer implements EventSummarizerInterface { private final Map summarizersByContext; - PerContextEventSummarizer() { + public PerContextEventSummarizer() { this.summarizersByContext = new HashMap<>(); }