Search code examples
scaladependency-injectionscala-catsscala-java-interopreader-monad

How to inject dependencies through Scala Reader from Java code


Here is a dependency service:

  public class Service1 {}

Scala code that uses it via reader:

object TupleEx {
  type FailFast[A] = Either[List[String], A]
  type Env[A] = ReaderT[FailFast, Service1, A]

  import cats.syntax.applicative._
  import cats.instances.either._

  def f:Env[Int] = 10.pure[Env]
}

Java test where I try to inject Service1:

  @Test
  public void testf() {
    Service1 s = new Service1();
    TupleEx.f().run(s);
  }

I am getting an exception:

Error:(10, 16) java: method run in class cats.data.Kleisli cannot be applied to given types; required: no arguments found: com.savdev.Service1 reason: actual and formal argument lists differ in length

Although in Scala I would be able to run it as:

TupleEx.f().run(s);

Solution

  • Try:

    TupleEx.f().run().apply(s);
    
    • run() is the "getter" method of the val inside Kleisli
    • apply() is what is usually hidden by Scala's syntactic sugar

    General advice:

    1. Write down an interface in Java
    2. Implement the interface in Scala
    3. Use whatever you've written only through Java interfaces when writing code in Java.
    4. Do not attempt to use Scala interfaces directly when writing code in Java.

    Remember: Scala compiler understands Java. Java does not know anything about Scala. Implementing Java interfaces in Scala is trivial. Using Scala interfaces from Java is awkward.