Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are nested Java classes not importable from Scala?

Tags:

scala

How am I supposed to mock a nested Java class using scalamock, especially when said nested Java class is coming from a third party library?

Given the following sources:

src/main/java/Outer.java

/**
  * Outer class that offers a Nested class inaccessible from Scala :(
  */
 public class Outer {
   public class Nested {

   }
 }

src/main/java/UseNestedJavaClassFromJava.java

public class UseNestedJavaClassFromJava {
   private Outer.Nested nested;
 }

src/main/scala/ImportNestedJavaClass.scala

// TODO uncomment the below line to break the build
//import Outer.Nested

Uncommenting the scala import line results in a compilation failure while compiling UseNestedJavaClassFromJava.java works just fine.

Full minimal example with gradle: https://github.com/billyjf/async-http-client-gradle-scala.

Apparently this was somewhat already addressed in the below question, but resorting to Java glue code or reflection trickery just for the sake of testing Scala code that leverages a Java library with nested Java classes seems a bit unreasonable to me, is there really no other solution?

Scala can't access Java inner class?

like image 958
Billy Fisher Avatar asked Jan 01 '23 22:01

Billy Fisher


2 Answers

I finally found a solution using Mockito:

import org.mockito.Mockito
import org.scalamock.scalatest.MockFactory
import org.scalatest.mockito.MockitoSugar
import org.scalatest.{FlatSpec, Matchers}

class OuterNestedTest extends FlatSpec with MockFactory with Matchers with MockitoSugar {
  "Nested Java class" should "be mockable using Mockito from within a scalatest" in {
    val mockedNestedJavaClass = Mockito.mock(classOf[Outer#Nested])

    Mockito.when(mockedNestedJavaClass.methodWithAParam("some value"))
      .thenReturn("mocked", Nil: _*)

    mockedNestedJavaClass.methodWithAParam("some value") shouldBe "mocked"
  }
}
like image 68
Billy Fisher Avatar answered Jan 16 '23 03:01

Billy Fisher


class Main { 
  val z = new Outer; 
  private[this] val y:z.Inner = null 
}

For more context:

  1. Outer.Inner is interpreted as Outer$.Inner (companion object).
  2. Official Scala website:

As opposed to Java-like languages where such inner classes are members of the enclosing class, in Scala such inner classes are bound to the outer object.

https://docs.scala-lang.org/tour/inner-classes.html

like image 27
Dragonborn Avatar answered Jan 16 '23 01:01

Dragonborn