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-projection.git


The following commit(s) were added to refs/heads/main by this push:
     new 38d83125 refactor: replace deprecated `extends App` with explicit main 
method (#560)
38d83125 is described below

commit 38d83125a28059e03b78d4a7d2e9c4e7e79be1da
Author: He-Pin(kerr) <[email protected]>
AuthorDate: Mon Jul 6 16:23:22 2026 +0800

    refactor: replace deprecated `extends App` with explicit main method (#560)
    
    Motivation:
    `extends App` is deprecated in Scala 3. Replace with explicit `def main`
    method for forward compatibility.
    
    Modification:
    Replace `object X extends App { ... }` with
    `object X { def main(args: Array[String]): Unit = { ... } }`
    in 3 example files.
    
    Result:
    No more usage of deprecated `scala.App` trait. Code is compatible with 
Scala 3.
    
    Tests:
    Not run - docs only
    
    References:
    None - Scala 3 compatibility
---
 .../test/scala/docs/guide/EventGeneratorApp.scala  | 210 +++++++++++----------
 .../test/scala/docs/guide/ShoppingCartApp.scala    |  62 +++---
 .../scala/docs/guide/ShoppingCartClusterApp.scala  |  70 +++----
 3 files changed, 174 insertions(+), 168 deletions(-)

diff --git a/examples/src/test/scala/docs/guide/EventGeneratorApp.scala 
b/examples/src/test/scala/docs/guide/EventGeneratorApp.scala
index 29fa7e30..2b550e7c 100644
--- a/examples/src/test/scala/docs/guide/EventGeneratorApp.scala
+++ b/examples/src/test/scala/docs/guide/EventGeneratorApp.scala
@@ -39,109 +39,111 @@ import com.typesafe.config.ConfigFactory
  * Generate a shopping cart every 1 second and check it out. Each cart will 
contain a variety of `ItemAdded`,
  * `ItemQuantityAdjusted` and `ItemRemoved` events preceding the the cart 
`Checkout` event.
  */
-object EventGeneratorApp extends App {
-  import ShoppingCartEvents._
-
-  val Products = List("cat t-shirt", "pekko t-shirt", "skis", "bowling shoes")
-
-  val MaxQuantity = 5
-  val MaxItems = 3
-  val MaxItemsAdjusted = 3
-
-  val EntityKey: EntityTypeKey[Event] = 
EntityTypeKey[Event]("shopping-cart-event")
-
-  val config = ConfigFactory
-    .parseString("pekko.actor.provider = cluster")
-    .withFallback(ConfigFactory.load("guide-shopping-cart-app.conf"))
-
-  ActorSystem(Behaviors.setup[String] {
-      ctx =>
-        implicit val system = ctx.system
-        val cluster = Cluster(system)
-        cluster.manager ! Join(cluster.selfMember.address)
-        val sharding = ClusterSharding(system)
-        val _ = sharding.init(Entity(EntityKey) { entityCtx =>
-          cartBehavior(entityCtx.entityId, tagFactory(entityCtx.entityId))
-        })
-
-        Source
-          .tick(1.second, 1.second, "checkout")
-          .mapConcat {
-            case "checkout" =>
-              val cartId = java.util.UUID.randomUUID().toString.take(5)
-              val items = randomItems()
-              val itemEvents = (0 to items).flatMap {
-                _ =>
-                  val itemId = Products(Random.nextInt(Products.size))
-
-                  // add the item
-                  val quantity = randomQuantity()
-                  val itemAdded = ItemAdded(cartId, itemId, quantity)
-
-                  // make up to `MaxItemAdjusted` adjustments to quantity of 
item
-                  val adjustments = Random.nextInt(MaxItemsAdjusted)
-                  val itemQuantityAdjusted = (0 to 
adjustments).foldLeft(Seq[ItemQuantityAdjusted]()) {
-                    case (events, _) =>
-                      val newQuantity = randomQuantity()
-                      val oldQuantity =
-                        if (events.isEmpty) itemAdded.quantity
-                        else events.last.newQuantity
-                      events :+ ItemQuantityAdjusted(cartId, itemId, 
newQuantity, oldQuantity)
-                  }
-
-                  // flip a coin to decide whether or not to remove the item
-                  val itemRemoved =
-                    if (Random.nextBoolean())
-                      List(ItemRemoved(cartId, itemId, 
itemQuantityAdjusted.last.newQuantity))
-                    else Nil
-
-                  List(itemAdded) ++ itemQuantityAdjusted ++ itemRemoved
-              }
-
-              // checkout the cart and all its preceding item events
-              itemEvents :+ CheckedOut(cartId, Instant.now())
-          }
-          // send each event to the sharded entity represented by the event's 
cartId
-          .runWith(Sink.foreach(event => sharding.entityRefFor(EntityKey, 
event.cartId).ref.tell(event)))
-
-        Behaviors.empty
-    }, "EventGeneratorApp", config)
-
-  /**
-   * Random non-zero based quantity for `ItemAdded` and `ItemQuantityAdjusted` 
events
-   */
-  def randomQuantity(): Int = Random.nextInt(MaxQuantity - 1) + 1
-
-  /**
-   * Random non-zero based count for how many `ItemAdded` events to generate
-   */
-  def randomItems(): Int = Random.nextInt(MaxItems - 1) + 1
-
-  /**
-   * Choose a tag from `ShoppingCartTags` based on the entity id (cart id)
-   */
-  def tagFactory(entityId: String): String =
-    if (args.contains("cluster")) {
-      val n = math.abs(entityId.hashCode % ShoppingCartTags.Tags.size)
-      val selectedTag = ShoppingCartTags.Tags(n)
-      selectedTag
-    } else ShoppingCartTags.Single
-
-  /**
-   * Construct an Actor that persists shopping cart events for a particular 
persistence id (cart id) and tag.
-   * This is not how real Event Sourced actors should be be implemented. 
Please look at
-   * https://pekko.apache.org/docs/pekko/current/typed/persistence.html for 
more information about `EventSourcedBehavior`.
-   */
-  def cartBehavior(persistenceId: String, tag: String): Behavior[Event] =
-    Behaviors.setup { ctx =>
-      EventSourcedBehavior[Event, Event, List[Any]](
-        persistenceId = PersistenceId.ofUniqueId(persistenceId),
-        Nil,
-        (_, event) => {
-          ctx.log.info("id [{}] tag [{}] event: {}", persistenceId, tag, event)
-          Effect.persist(event)
-        },
-        (_, _) => Nil).withTagger(_ => Set(tag))
-    }
+object EventGeneratorApp {
+  def main(args: Array[String]): Unit = {
+    import ShoppingCartEvents._
+
+    val Products = List("cat t-shirt", "pekko t-shirt", "skis", "bowling 
shoes")
+
+    val MaxQuantity = 5
+    val MaxItems = 3
+    val MaxItemsAdjusted = 3
+
+    val EntityKey: EntityTypeKey[Event] = 
EntityTypeKey[Event]("shopping-cart-event")
+
+    val config = ConfigFactory
+      .parseString("pekko.actor.provider = cluster")
+      .withFallback(ConfigFactory.load("guide-shopping-cart-app.conf"))
+
+    ActorSystem(Behaviors.setup[String] {
+        ctx =>
+          implicit val system = ctx.system
+          val cluster = Cluster(system)
+          cluster.manager ! Join(cluster.selfMember.address)
+          val sharding = ClusterSharding(system)
+          val _ = sharding.init(Entity(EntityKey) { entityCtx =>
+            cartBehavior(entityCtx.entityId, tagFactory(entityCtx.entityId))
+          })
+
+          Source
+            .tick(1.second, 1.second, "checkout")
+            .mapConcat {
+              case "checkout" =>
+                val cartId = java.util.UUID.randomUUID().toString.take(5)
+                val items = randomItems()
+                val itemEvents = (0 to items).flatMap {
+                  _ =>
+                    val itemId = Products(Random.nextInt(Products.size))
+
+                    // add the item
+                    val quantity = randomQuantity()
+                    val itemAdded = ItemAdded(cartId, itemId, quantity)
+
+                    // make up to `MaxItemAdjusted` adjustments to quantity of 
item
+                    val adjustments = Random.nextInt(MaxItemsAdjusted)
+                    val itemQuantityAdjusted = (0 to 
adjustments).foldLeft(Seq[ItemQuantityAdjusted]()) {
+                      case (events, _) =>
+                        val newQuantity = randomQuantity()
+                        val oldQuantity =
+                          if (events.isEmpty) itemAdded.quantity
+                          else events.last.newQuantity
+                        events :+ ItemQuantityAdjusted(cartId, itemId, 
newQuantity, oldQuantity)
+                    }
+
+                    // flip a coin to decide whether or not to remove the item
+                    val itemRemoved =
+                      if (Random.nextBoolean())
+                        List(ItemRemoved(cartId, itemId, 
itemQuantityAdjusted.last.newQuantity))
+                      else Nil
+
+                    List(itemAdded) ++ itemQuantityAdjusted ++ itemRemoved
+                }
+
+                // checkout the cart and all its preceding item events
+                itemEvents :+ CheckedOut(cartId, Instant.now())
+            }
+            // send each event to the sharded entity represented by the 
event's cartId
+            .runWith(Sink.foreach(event => sharding.entityRefFor(EntityKey, 
event.cartId).ref.tell(event)))
+
+          Behaviors.empty
+      }, "EventGeneratorApp", config)
+
+    /**
+     * Random non-zero based quantity for `ItemAdded` and 
`ItemQuantityAdjusted` events
+     */
+    def randomQuantity(): Int = Random.nextInt(MaxQuantity - 1) + 1
+
+    /**
+     * Random non-zero based count for how many `ItemAdded` events to generate
+     */
+    def randomItems(): Int = Random.nextInt(MaxItems - 1) + 1
+
+    /**
+     * Choose a tag from `ShoppingCartTags` based on the entity id (cart id)
+     */
+    def tagFactory(entityId: String): String =
+      if (args.contains("cluster")) {
+        val n = math.abs(entityId.hashCode % ShoppingCartTags.Tags.size)
+        val selectedTag = ShoppingCartTags.Tags(n)
+        selectedTag
+      } else ShoppingCartTags.Single
+
+    /**
+     * Construct an Actor that persists shopping cart events for a particular 
persistence id (cart id) and tag.
+     * This is not how real Event Sourced actors should be be implemented. 
Please look at
+     * https://pekko.apache.org/docs/pekko/current/typed/persistence.html for 
more information about `EventSourcedBehavior`.
+     */
+    def cartBehavior(persistenceId: String, tag: String): Behavior[Event] =
+      Behaviors.setup { ctx =>
+        EventSourcedBehavior[Event, Event, List[Any]](
+          persistenceId = PersistenceId.ofUniqueId(persistenceId),
+          Nil,
+          (_, event) => {
+            ctx.log.info("id [{}] tag [{}] event: {}", persistenceId, tag, 
event)
+            Effect.persist(event)
+          },
+          (_, _) => Nil).withTagger(_ => Set(tag))
+      }
+  }
 }
 // #guideEventGeneratorApp
diff --git a/examples/src/test/scala/docs/guide/ShoppingCartApp.scala 
b/examples/src/test/scala/docs/guide/ShoppingCartApp.scala
index ed8df67e..dd333a54 100644
--- a/examples/src/test/scala/docs/guide/ShoppingCartApp.scala
+++ b/examples/src/test/scala/docs/guide/ShoppingCartApp.scala
@@ -39,41 +39,43 @@ import 
pekko.stream.connectors.cassandra.scaladsl.CassandraSessionRegistry
 
 //#guideSetup
 
-object ShoppingCartApp extends App {
-  val config = ConfigFactory.load("guide-shopping-cart-app.conf")
+object ShoppingCartApp {
+  def main(args: Array[String]): Unit = {
+    val config = ConfigFactory.load("guide-shopping-cart-app.conf")
 
-  ActorSystem(
-    Behaviors.setup[String] { context =>
-      val system = context.system
+    ActorSystem(
+      Behaviors.setup[String] { context =>
+        val system = context.system
 
-      // ...
+        // ...
 
-      // #guideSetup
-      // #guideSourceProviderSetup
-      val sourceProvider: SourceProvider[Offset, 
EventEnvelope[ShoppingCartEvents.Event]] =
-        EventSourcedProvider
-          .eventsByTag[ShoppingCartEvents.Event](
-            system,
-            readJournalPluginId = CassandraReadJournal.Identifier,
-            tag = ShoppingCartTags.Single)
-      // #guideSourceProviderSetup
+        // #guideSetup
+        // #guideSourceProviderSetup
+        val sourceProvider: SourceProvider[Offset, 
EventEnvelope[ShoppingCartEvents.Event]] =
+          EventSourcedProvider
+            .eventsByTag[ShoppingCartEvents.Event](
+              system,
+              readJournalPluginId = CassandraReadJournal.Identifier,
+              tag = ShoppingCartTags.Single)
+        // #guideSourceProviderSetup
 
-      // #guideProjectionSetup
-      implicit val ec = system.executionContext
-      val session = 
CassandraSessionRegistry(system).sessionFor("pekko.projection.cassandra.session-config")
-      val repo = new ItemPopularityProjectionRepositoryImpl(session)
-      val projection = CassandraProjection.atLeastOnce(
-        projectionId = ProjectionId("shopping-carts", ShoppingCartTags.Single),
-        sourceProvider,
-        handler = () => new 
ItemPopularityProjectionHandler(ShoppingCartTags.Single, system, repo))
+        // #guideProjectionSetup
+        implicit val ec = system.executionContext
+        val session = 
CassandraSessionRegistry(system).sessionFor("pekko.projection.cassandra.session-config")
+        val repo = new ItemPopularityProjectionRepositoryImpl(session)
+        val projection = CassandraProjection.atLeastOnce(
+          projectionId = ProjectionId("shopping-carts", 
ShoppingCartTags.Single),
+          sourceProvider,
+          handler = () => new 
ItemPopularityProjectionHandler(ShoppingCartTags.Single, system, repo))
 
-      context.spawn(ProjectionBehavior(projection), projection.projectionId.id)
-      // #guideProjectionSetup
+        context.spawn(ProjectionBehavior(projection), 
projection.projectionId.id)
+        // #guideProjectionSetup
 
-      // #guideSetup
-      Behaviors.empty
-    },
-    "ShoppingCartApp",
-    config)
+        // #guideSetup
+        Behaviors.empty
+      },
+      "ShoppingCartApp",
+      config)
+  }
 }
 //#guideSetup
diff --git a/examples/src/test/scala/docs/guide/ShoppingCartClusterApp.scala 
b/examples/src/test/scala/docs/guide/ShoppingCartClusterApp.scala
index 65ed54e0..4b03753a 100644
--- a/examples/src/test/scala/docs/guide/ShoppingCartClusterApp.scala
+++ b/examples/src/test/scala/docs/guide/ShoppingCartClusterApp.scala
@@ -29,45 +29,47 @@ import pekko.projection.scaladsl.SourceProvider
 import pekko.stream.connectors.cassandra.scaladsl.CassandraSessionRegistry
 import com.typesafe.config.ConfigFactory
 
-object ShoppingCartClusterApp extends App {
-  val port = args.headOption match {
-    case Some(portString) if portString.matches("""\d+""") => portString.toInt
-    case _                                                 => throw new 
IllegalArgumentException("A pekko cluster port argument is required")
-  }
+object ShoppingCartClusterApp {
+  def main(args: Array[String]): Unit = {
+    val port = args.headOption match {
+      case Some(portString) if portString.matches("""\d+""") => 
portString.toInt
+      case _                                                 => throw new 
IllegalArgumentException("A pekko cluster port argument is required")
+    }
 
-  val config = ConfigFactory
-    .parseString(s"pekko.remote.artery.canonical.port = $port")
-    .withFallback(ConfigFactory.load("guide-shopping-cart-cluster-app.conf"))
+    val config = ConfigFactory
+      .parseString(s"pekko.remote.artery.canonical.port = $port")
+      .withFallback(ConfigFactory.load("guide-shopping-cart-cluster-app.conf"))
 
-  ActorSystem(
-    Behaviors.setup[String] { context =>
-      val system = context.system
-      implicit val ec = system.executionContext
-      val session = 
CassandraSessionRegistry(system).sessionFor("pekko.projection.cassandra.session-config")
-      val repo = new ItemPopularityProjectionRepositoryImpl(session)
+    ActorSystem(
+      Behaviors.setup[String] { context =>
+        val system = context.system
+        implicit val ec = system.executionContext
+        val session = 
CassandraSessionRegistry(system).sessionFor("pekko.projection.cassandra.session-config")
+        val repo = new ItemPopularityProjectionRepositoryImpl(session)
 
-      def sourceProvider(tag: String): SourceProvider[Offset, 
EventEnvelope[ShoppingCartEvents.Event]] =
-        EventSourcedProvider
-          .eventsByTag[ShoppingCartEvents.Event](
-            system,
-            readJournalPluginId = CassandraReadJournal.Identifier,
-            tag = tag)
+        def sourceProvider(tag: String): SourceProvider[Offset, 
EventEnvelope[ShoppingCartEvents.Event]] =
+          EventSourcedProvider
+            .eventsByTag[ShoppingCartEvents.Event](
+              system,
+              readJournalPluginId = CassandraReadJournal.Identifier,
+              tag = tag)
 
-      def projection(tag: String) =
-        CassandraProjection.atLeastOnce(
-          projectionId = ProjectionId("shopping-carts", tag),
-          sourceProvider(tag),
-          handler = () => new ItemPopularityProjectionHandler(tag, system, 
repo))
+        def projection(tag: String) =
+          CassandraProjection.atLeastOnce(
+            projectionId = ProjectionId("shopping-carts", tag),
+            sourceProvider(tag),
+            handler = () => new ItemPopularityProjectionHandler(tag, system, 
repo))
 
-      ShardedDaemonProcess(system).init[ProjectionBehavior.Command](
-        name = "shopping-carts",
-        numberOfInstances = ShoppingCartTags.Tags.size,
-        behaviorFactory = (i: Int) => 
ProjectionBehavior(projection(ShoppingCartTags.Tags(i))),
-        stopMessage = ProjectionBehavior.Stop)
+        ShardedDaemonProcess(system).init[ProjectionBehavior.Command](
+          name = "shopping-carts",
+          numberOfInstances = ShoppingCartTags.Tags.size,
+          behaviorFactory = (i: Int) => 
ProjectionBehavior(projection(ShoppingCartTags.Tags(i))),
+          stopMessage = ProjectionBehavior.Stop)
 
-      Behaviors.empty
-    },
-    "ShoppingCartClusterApp",
-    config)
+        Behaviors.empty
+      },
+      "ShoppingCartClusterApp",
+      config)
+  }
 }
 //#guideClusterSetup


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to