Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limitations of the InteractionInstances: Lambda interface implementation with higher kinded types #253

Open
VledicFranco opened this issue Jul 16, 2019 · 3 comments
Labels
known-issue Issues that wont be addressed immediately but are documented using the issue tracking system

Comments

@VledicFranco
Copy link
Contributor

VledicFranco commented Jul 16, 2019

Implementing an interaction by creating an interface, instantiating the interface with a lambda, and then using the reflection API to create an InteractionInstance blows into a runtime exception WHEN the ingredients have a higher kinded type like List[A]. This is because the lambda instantiation of the interface erases the parametrized type. See example below:

trait ReserveItems {

  def apply(orderId: String, items: List[String]): Future[WebshopRecipeReflection.ReserveItemsOutput]
}

  val reserveItemsImplementation: ReserveItems =
    (orderId: String, items: List[String]) => {

      // Http call to the Warehouse service
      val response: Future[Either[List[String], List[String]]] =
      // This is mocked for the sake of the example
        Future.successful(Right(items))

      // Build an event instance that Baker understands
      response.map {
        case Left(unavailableItems) =>
          WebshopRecipeReflection.OrderHadUnavailableItems(unavailableItems)
        case Right(reservedItems) =>
          WebshopRecipeReflection.ItemsReserved(reservedItems)
      }
    }

  val alternativeReserveItemInstance: InteractionInstance =
    InteractionInstance.unsafeFrom(reserveItemsImplementation)
Caused by: java.lang.IllegalArgumentException: Unsupported parameter type for interaction implementation 'ReserveItems'
	at com.ing.baker.runtime.scaladsl.InteractionInstance$.$anonfun$unsafeFrom$7(InteractionInstance.scala:89)
	at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:234)
	at scala.collection.IndexedSeqOptimized.foreach(IndexedSeqOptimized.scala:32)
	at scala.collection.IndexedSeqOptimized.foreach$(IndexedSeqOptimized.scala:29)
	at scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:191)
	at scala.collection.TraversableLike.map(TraversableLike.scala:234)
	at scala.collection.TraversableLike.map$(TraversableLike.scala:227)
	at scala.collection.mutable.ArrayOps$ofRef.map(ArrayOps.scala:191)
	at com.ing.baker.runtime.scaladsl.InteractionInstance$.unsafeFrom(InteractionInstance.scala:86)
	at webshop.WebshopInstancesReflection$.<init>(WebshopInstancesReflection.scala:54)
	at webshop.WebshopInstancesReflection$.<clinit>(WebshopInstancesReflection.scala)
	... 11 more
Caused by: java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
	at com.ing.baker.types.package$.getTypeParameter(package.scala:25)
	at com.ing.baker.types.modules.ScalaModules$ListModule.readType(ScalaModules.scala:13)
	at com.ing.baker.types.modules.ScalaModules$ListModule.readType(ScalaModules.scala:10)
	at com.ing.baker.types.TypeAdapter.readType(TypeAdapter.scala:48)
	at com.ing.baker.types.Converters$.readJavaType(Converters.scala:47)
	at com.ing.baker.runtime.scaladsl.InteractionInstance$.$anonfun$unsafeFrom$7(InteractionInstance.scala:87)
	... 21 more
@VledicFranco
Copy link
Contributor Author

It was found that it is not lambda specific, this will also break it:

val reserveItemsInstance: InteractionInstance = InteractionInstance.unsafeFrom(
    new ReserveItems {

      def apply(orderId: String, items: List[String]): Future[WebshopRecipeReflection.ReserveItemsOutput] = {

        // Http call to the Warehouse service
        val response: Future[Either[List[String], List[String]]] =
        // This is mocked for the sake of the example
          Future.successful(Right(items))

        // Build an event instance that Baker understands
        response.map {
          case Left(unavailableItems) =>
            WebshopRecipeReflection.OrderHadUnavailableItems(unavailableItems)
          case Right(reservedItems) =>
            WebshopRecipeReflection.ItemsReserved(reservedItems)
        }
      }
    }
  )

@VledicFranco VledicFranco added the known-issue Issues that wont be addressed immediately but are documented using the issue tracking system label Jul 17, 2019
@VledicFranco
Copy link
Contributor Author

Also in Java interactions must be direct class instances, if they are a reference to other class members or to static attributes, the Interactionmanager can't access them

@SemanticBeeng
Copy link

SemanticBeeng commented Aug 29, 2019

Not sure if my issue is rooted in same cause but sounds close so posting here first.

Have interactions that use SessionId as ingredient.

case class SessionId(value: java.util.UUID) extends AnyVal

At runtime am getting "No implementation provided for interaction".
Tried to trace in debugger and seems the issue is the mismatch between these

RecordType(WrappedArray(RecordField(mostSigBits,Int64), RecordField(leastSigBits,Int64)))

RecordType(WrappedArray(RecordField(value,RecordType(WrappedArray(RecordField(mostSigBits,Int64), RecordField(leastSigBits,Int64))))))

Sounds like the UUID value gets unwrapped. 🤔
Does this make any sense to you?
Is my design of interaction valid (taking case classes as ingredients?

I do use complex case classes as ingredients and they do not cause this issue.


UPDATE: Solved. This was caused by SessionId being an AnyVal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
known-issue Issues that wont be addressed immediately but are documented using the issue tracking system
Projects
None yet
Development

No branches or pull requests

2 participants