This is an automated email from the ASF dual-hosted git repository.
He-Pin pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pekko.git
The following commit(s) were added to refs/heads/main by this push:
new 9f2b4ac67b feat: add with-methods to typed query EventEnvelope (#3646)
9f2b4ac67b is described below
commit 9f2b4ac67b5654214d27d2a69ffa9f4380616193
Author: PJ Fanning <[email protected]>
AuthorDate: Fri Oct 23 04:35:29 2026 +0100
feat: add with-methods to typed query EventEnvelope (#3646)
Motivation:
The typed persistence query `EventEnvelope` is a final class with a long
constructor and no copy support. Changing one field (for example the event
payload or the tags when transforming envelopes) means rebuilding the whole
envelope by hand.
Modification:
Add `withPersistenceId(persistenceId, entityType, slice)`, `withEvent`,
`withEventOption`, `withTags` and `withMetadata` (`withEventOption` and
`withTags` each have Scala and Java overloads) to
`org.apache.pekko.persistence.query.typed.EventEnvelope`, backed by a private
`copy` helper. `withPersistenceId` takes `entityType` and `slice` explicitly,
because both are derived from the persistence id.
Result:
Envelopes can be changed with additive, binary compatible methods.
Tests:
- Not run locally - left to CI
- New case in `EventEnvelopeSpec`
References:
Ported from (Apache-2.0 since 2026-10-23):
- https://github.com/akka/akka-core/pull/32067
Notes for reviewers:
- Only additive methods on a final class (plus a private helper), so no
MiMa excludes are needed.
- `withTags` has Scala `Set` and Java `java.util.Set` overloads;
`withEventOption` has Scala `Option` and Java `java.util.Optional` overloads.
- `EventEnvelope` is `@ApiMayChange`.
---
.../persistence/query/typed/EventEnvelope.scala | 70 ++++++++++++++++++++++
.../query/typed/EventEnvelopeSpec.scala | 35 +++++++++++
2 files changed, 105 insertions(+)
diff --git
a/persistence-query/src/main/scala/org/apache/pekko/persistence/query/typed/EventEnvelope.scala
b/persistence-query/src/main/scala/org/apache/pekko/persistence/query/typed/EventEnvelope.scala
index be42dc8161..d6d0d0313c 100644
---
a/persistence-query/src/main/scala/org/apache/pekko/persistence/query/typed/EventEnvelope.scala
+++
b/persistence-query/src/main/scala/org/apache/pekko/persistence/query/typed/EventEnvelope.scala
@@ -234,6 +234,76 @@ final class EventEnvelope[Event](
tags.asJava
}
+ /**
+ * `entityType` and `slice` should be derived from the `persistenceId`, but
must be explicitly defined
+ * when changing the `persistenceId` of the envelope.
+ * The `slice` should be calculated with
[[pekko.persistence.Persistence.sliceForPersistenceId]] for
+ * the given `persistenceId`.
+ * The `entityType` should be extracted from the `persistenceId` with
+ * `org.apache.pekko.persistence.typed.PersistenceId.extractEntityType`.
+ */
+ def withPersistenceId(persistenceId: String, entityType: String, slice:
Int): EventEnvelope[Event] =
+ copy(persistenceId = persistenceId, entityType = entityType, slice = slice)
+
+ def withEvent(event: Event): EventEnvelope[Event] =
+ copy(eventOption = Option(event))
+
+ /**
+ * Scala API
+ */
+ def withEventOption(eventOption: Option[Event]): EventEnvelope[Event] =
+ copy(eventOption = eventOption)
+
+ /**
+ * Java API
+ */
+ def withEventOption(eventOption: Optional[Event]): EventEnvelope[Event] = {
+ import scala.jdk.OptionConverters._
+ copy(eventOption = eventOption.toScala)
+ }
+
+ /**
+ * Scala API
+ */
+ def withTags(tags: Set[String]): EventEnvelope[Event] =
+ copy(tags = tags)
+
+ /**
+ * Java API
+ */
+ def withTags(tags: JSet[String]): EventEnvelope[Event] = {
+ import scala.jdk.CollectionConverters._
+ copy(tags = tags.asScala.toSet)
+ }
+
+ def withMetadata(metadata: Any): EventEnvelope[Event] =
+ copy(eventMetadata = Option(metadata))
+
+ private def copy(
+ offset: Offset = offset,
+ persistenceId: String = persistenceId,
+ sequenceNr: Long = sequenceNr,
+ eventOption: Option[Event] = eventOption,
+ timestamp: Long = timestamp,
+ eventMetadata: Option[Any] = eventMetadata,
+ entityType: String = entityType,
+ slice: Int = slice,
+ filtered: Boolean = filtered,
+ source: String = source,
+ tags: Set[String] = tags): EventEnvelope[Event] =
+ new EventEnvelope(
+ offset,
+ persistenceId,
+ sequenceNr,
+ eventOption,
+ timestamp,
+ eventMetadata,
+ entityType,
+ slice,
+ filtered,
+ source,
+ tags)
+
override def hashCode(): Int = {
var result = HashCode.SEED
result = HashCode.hash(result, offset)
diff --git
a/persistence-query/src/test/scala/org/apache/pekko/persistence/query/typed/EventEnvelopeSpec.scala
b/persistence-query/src/test/scala/org/apache/pekko/persistence/query/typed/EventEnvelopeSpec.scala
index ff482463d6..62a64863d3 100644
---
a/persistence-query/src/test/scala/org/apache/pekko/persistence/query/typed/EventEnvelopeSpec.scala
+++
b/persistence-query/src/test/scala/org/apache/pekko/persistence/query/typed/EventEnvelopeSpec.scala
@@ -49,5 +49,40 @@ class EventEnvelopeSpec extends PekkoSpec {
intercept[IllegalStateException](env.event).getMessage should
include("not loaded")
intercept[IllegalStateException](env.getEvent()).getMessage should
include("not loaded")
}
+
+ "create modified copies with the with-methods" in {
+ val env = envelope(filtered = false)
+
+ val withPid = env.withPersistenceId("pid-2", "entity2", 17)
+ withPid.persistenceId should ===("pid-2")
+ withPid.entityType should ===("entity2")
+ withPid.slice should ===(17)
+ withPid.sequenceNr should ===(env.sequenceNr)
+
+ val withEvent = env.withEvent("evt")
+ withEvent.eventOption should ===(Some("evt"))
+ withEvent.event should ===("evt")
+ withEvent.persistenceId should ===(env.persistenceId)
+ env.eventOption should ===(None)
+
+ env.withEvent("evt").withEventOption(None).eventOption should ===(None)
+ env.withEventOption(Some("evt2")).eventOption should ===(Some("evt2"))
+ env.withEventOption(java.util.Optional.of("evt3")).eventOption should
===(Some("evt3"))
+
env.withEvent("evt").withEventOption(java.util.Optional.empty[String]()).eventOption
should ===(None)
+
+ val withTags = env.withTags(Set("a", "b"))
+ withTags.tags should ===(Set("a", "b"))
+ env.tags should ===(Set.empty[String])
+
+ val javaTags = new java.util.HashSet[String]()
+ javaTags.add("c")
+ val withJavaTags = env.withTags(javaTags)
+ withJavaTags.tags should ===(Set("c"))
+ withJavaTags.getTags() should ===(javaTags)
+
+ val withMeta = env.withMetadata("meta")
+ withMeta.eventMetadata should ===(Some("meta"))
+ withMeta.getEventMetaData().get should ===("meta")
+ }
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]