GithubHelp home page GithubHelp logo

Ensure in compile time that the specified serializer is used for every message, event and persistent state about akka-serialization-helper HOT 4 CLOSED

virtuslab avatar virtuslab commented on June 16, 2024
Ensure in compile time that the specified serializer is used for every message, event and persistent state

from akka-serialization-helper.

Comments (4)

PawelLipski avatar PawelLipski commented on June 16, 2024

@MarconZet I think you can take this as the next priority, given that we got discouraged from delving into #7 🤔

from akka-serialization-helper.

PawelLipski avatar PawelLipski commented on June 16, 2024

Not sure how this can be achieved tho... compiler plugin maybe? 🤔

from akka-serialization-helper.

PawelLipski avatar PawelLipski commented on June 16, 2024

Pls start with runtime-reflection-based solution, similar to what's currently in ArchUnit (but without using ArchUnit as a dependency):

  // The below tests (roughly) check that the classes used as messages/events/state in Akka
  // are always marked as CborSerializable, to ensure that Jackson CBOR and not legacy Java serialization
  // is used for their serialization.
  // For Akka to ensure that condition statically, a major redesign would be necessary -
  // all methods like `ask`, `tell`, `Effect.persist` etc. would need to require an implicit `Codec` (?) parameter.

  // The below tests do NOT ensure that the Jackson serialization of messages/events/state will actually succeed in the runtime.

  "Messages, events and entity state classes" should {
    "implement CborSerializable" in {
      classes
        .should(new ArchCondition[JavaClass]("only use CborSerializable message/event/state types") {
          override def check(clazz: JavaClass, events: ConditionEvents): Unit = {

            clazz.getAllMethods.asScala.foreach { method =>
              def checkType(tpe: Type, category: String, failsWhen: String): Unit = {
                tpe match {
                  case clazz: Class[_] if clazz.getPackageName.startsWith("akka") =>
                  // OK, acceptable

                  case clazz: Class[_] if clazz == classOf[scala.Nothing] =>
                  // OK, acceptable

                  case clazz: Class[_] if !classOf[CborSerializable].isAssignableFrom(clazz) =>
                    val message =
                      s"Type ${clazz.getName} is used as Akka $category (as observed in the return type of method ${method.getFullName}), " +
                      s"but does NOT extend CborSerializable; this will fail in the runtime $failsWhen"
                    events.add(SimpleConditionEvent.violated(clazz, message))

                  case _ =>
                }
              }

              val returnType = method.getRawReturnType
              val genericReturnType = method.reflect.getGenericReturnType

              if (returnType.isEquivalentTo(classOf[akka.persistence.typed.scaladsl.ReplyEffect[_, _]])) {
                genericReturnType match {
                  case parameterizedType: ParameterizedType =>
                    val Array(eventType, stateType) = parameterizedType.getActualTypeArguments
                    checkType(eventType, "event", "when saving to the journal")
                    checkType(stateType, "persistent state", "when doing a snapshot")
                  case _ =>
                }
              } else if (returnType.isEquivalentTo(classOf[akka.projection.eventsourced.EventEnvelope[_]])) {
                genericReturnType match {
                  case parameterizedType: ParameterizedType =>
                    val Array(eventType) = parameterizedType.getActualTypeArguments
                    checkType(eventType, "event", "when saving to the journal")
                  case _ =>
                }
              } else if (returnType.isEquivalentTo(classOf[akka.actor.typed.Behavior[_]])) {
                genericReturnType match {
                  case parameterizedType: ParameterizedType =>
                    val Array(messageType) = parameterizedType.getActualTypeArguments
                    checkType(messageType, "message", "when sending a message outside of the current JVM")
                  case _ =>
                }
              }
            }
          }
        })
        .check(importedProductionClasses)
    }
  }

from akka-serialization-helper.

PawelLipski avatar PawelLipski commented on June 16, 2024

^ This is very suboptimal since e.g. it can't ever check the type of objects passed to tell/ask though :/

from akka-serialization-helper.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.