Skip to content

Decrease usage of deprecated elements #572

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

Merged
merged 1 commit into from
Jun 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ The library has independent developers, release cycle and versioning from core m
If you're in Scala 2.12 you'll probably want to add the compiler flag `-Ypartial-unification`, if you don't you risk some compile errors when trying to stub complex types using the idiomatic syntax

## Notes for 2.0.0
We dropped support for Scala 2.11 and Java 8, as Mockito 5 dropped support for Java 8.
We dropped support for Scala 2.11 and Java 8, as Mockito 5 dropped support for Java 8.
Java 11 is now the minimum supported version.

## Notes for 1.13.6

Expand Down
9 changes: 3 additions & 6 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import scala.io.Source
import scala.language.postfixOps
import sbt.io.Using

val currentScalaVersion = "2.13.16"

Expand All @@ -21,7 +19,7 @@ lazy val commonSettings =
scalacOptions ++= Seq(
"-unchecked",
"-feature",
"-deprecation:false",
"-deprecation",
"-encoding",
"UTF-8",
"-Xfatal-warnings",
Expand All @@ -48,7 +46,8 @@ lazy val commonSettings =
case _ =>
Seq("org.scala-lang.modules" %% "scala-parallel-collections" % "1.2.0")
}
}
},
libraryDependencies += "org.scala-lang.modules" %% "scala-collection-compat" % "2.13.0"
)

lazy val publishSettings = Seq(
Expand Down Expand Up @@ -154,8 +153,6 @@ lazy val core = (project in file("core"))
name := "mockito-scala",
libraryDependencies ++= Dependencies.commonLibraries,
libraryDependencies ++= Dependencies.scalaReflection.value,
// TODO remove when we remove the deprecated classes in org.mockito.integrations.Dependencies.scalatest
libraryDependencies += Dependencies.scalatest % "provided",
// include the macro classes and resources in the main jar
Compile / packageBin / mappings ++= (macroSub / Compile / packageBin / mappings).value,
// include the macro sources in the main source jar
Expand Down
12 changes: 6 additions & 6 deletions cats/src/test/scala/org/mockito/cats/DoSomethingCatsTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class DoSomethingCatsTest
ValueClass("mocked!") willBe returnedFG by aMock.returnsFutureEither("hello")
Error("boom") willBe raisedG by aMock.returnsFutureEither("bye")

whenReady(aMock.returnsFutureEither("hello"))(_.right.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsFutureEither("hello"))(_.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsFutureEither("bye"))(_.left.value shouldBe Error("boom"))
}

Expand All @@ -68,7 +68,7 @@ class DoSomethingCatsTest
ValueClass("mocked!") willBe returnedF by aMock.returnsMT[ErrorOr, ValueClass](ValueClass("hi"))
Error("error") willBe raised by aMock.returnsMT[ErrorOr, ValueClass](ValueClass("bye"))

aMock.returnsMT[ErrorOr, ValueClass](ValueClass("hi")).right.value shouldBe ValueClass("mocked!")
aMock.returnsMT[ErrorOr, ValueClass](ValueClass("hi")).value shouldBe ValueClass("mocked!")
aMock.returnsMT[ErrorOr, ValueClass](ValueClass("bye")).left.value shouldBe Error("error")
}

Expand All @@ -89,7 +89,7 @@ class DoSomethingCatsTest
ValueClass("mocked!") willBe returnedF by aMock.returnsEitherT("hello")

whenReady(aMock.returnsEitherT("bye").value)(_.left.value shouldBe Error("error"))
whenReady(aMock.returnsEitherT("hello").value)(_.right.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsEitherT("hello").value)(_.value shouldBe ValueClass("mocked!"))
}

"work with OptionT" in {
Expand Down Expand Up @@ -125,9 +125,9 @@ class DoSomethingCatsTest
.returnsFutureEither("hola")
((i: Int, b: Boolean) => s"$i, $b") willBe answeredFG by aMock.returnsFutureOptionFrom(42, true)

whenReady(aMock.returnsFutureEither("hello"))(_.right.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsFutureEither("hi"))(_.right.value shouldBe ValueClass("hi mocked!"))
whenReady(aMock.returnsFutureEither("hola"))(_.right.value shouldBe ValueClass("hola invocation mocked!"))
whenReady(aMock.returnsFutureEither("hello"))(_.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsFutureEither("hi"))(_.value shouldBe ValueClass("hi mocked!"))
whenReady(aMock.returnsFutureEither("hola"))(_.value shouldBe ValueClass("hola invocation mocked!"))
whenReady(aMock.returnsFutureOptionFrom(42, true))(_.value shouldBe "42, true")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class IdiomaticMockitoCatsTest
aMock.returnsFutureEither("hello") returnsFG ValueClass("mocked!")
aMock.returnsFutureEither("bye") raisesG Error("boom")

whenReady(aMock.returnsFutureEither("hello"))(_.right.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsFutureEither("hello"))(_.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsFutureEither("bye"))(_.left.value shouldBe Error("boom"))
}

Expand All @@ -76,7 +76,7 @@ class IdiomaticMockitoCatsTest
aMock.returnsMT[ErrorOr, ValueClass](ValueClass("hi")) returnsF ValueClass("mocked!")
aMock.returnsMT[ErrorOr, ValueClass](ValueClass("bye")) raises Error("error")

aMock.returnsMT[ErrorOr, ValueClass](ValueClass("hi")).right.value shouldBe ValueClass("mocked!")
aMock.returnsMT[ErrorOr, ValueClass](ValueClass("hi")).value shouldBe ValueClass("mocked!")
aMock.returnsMT[ErrorOr, ValueClass](ValueClass("bye")).left.value shouldBe Error("error")
}

Expand Down Expand Up @@ -125,7 +125,7 @@ class IdiomaticMockitoCatsTest
aMock.returnsEitherT("hello") returnsF ValueClass("mocked!")

whenReady(aMock.returnsEitherT("bye").value)(_.left.value shouldBe Error("error"))
whenReady(aMock.returnsEitherT("hello").value)(_.right.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsEitherT("hello").value)(_.value shouldBe ValueClass("mocked!"))
}

"work with OptionT" in {
Expand Down Expand Up @@ -160,9 +160,9 @@ class IdiomaticMockitoCatsTest
aMock.returnsFutureEither("hola") answersFG ((i: InvocationOnMock) => ValueClass(i.arg[String](0) + " invocation mocked!"))
aMock.returnsFutureOptionFrom(42, true) answersFG ((i: Int, b: Boolean) => s"$i, $b")

whenReady(aMock.returnsFutureEither("hello"))(_.right.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsFutureEither("hi"))(_.right.value shouldBe ValueClass("hi mocked!"))
whenReady(aMock.returnsFutureEither("hola"))(_.right.value shouldBe ValueClass("hola invocation mocked!"))
whenReady(aMock.returnsFutureEither("hello"))(_.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsFutureEither("hi"))(_.value shouldBe ValueClass("hi mocked!"))
whenReady(aMock.returnsFutureEither("hola"))(_.value shouldBe ValueClass("hola invocation mocked!"))
whenReady(aMock.returnsFutureOptionFrom(42, true))(_.value shouldBe "42, true")
}
}
Expand Down
24 changes: 12 additions & 12 deletions cats/src/test/scala/org/mockito/cats/MockitoCatsTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class MockitoCatsTest extends AnyWordSpec with Matchers with MockitoSugar with A
whenFG(aMock.returnsFutureEither("hello")) thenReturn ValueClass("mocked!")
whenFG(aMock.returnsFutureEither("bye")) thenFailWith Error("boom")

whenReady(aMock.returnsFutureEither("hello"))(_.right.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsFutureEither("hello"))(_.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsFutureEither("bye"))(_.left.value shouldBe Error("boom"))
}

Expand All @@ -69,7 +69,7 @@ class MockitoCatsTest extends AnyWordSpec with Matchers with MockitoSugar with A
whenF(aMock.returnsMT[ErrorOr, ValueClass](ValueClass("hi"))) thenReturn ValueClass("mocked!")
whenF(aMock.returnsMT[ErrorOr, ValueClass](ValueClass("bye"))) thenFailWith Error("error")

aMock.returnsMT[ErrorOr, ValueClass](ValueClass("hi")).right.value shouldBe ValueClass("mocked!")
aMock.returnsMT[ErrorOr, ValueClass](ValueClass("hi")).value shouldBe ValueClass("mocked!")
aMock.returnsMT[ErrorOr, ValueClass](ValueClass("bye")).left.value shouldBe Error("error")
}

Expand Down Expand Up @@ -103,7 +103,7 @@ class MockitoCatsTest extends AnyWordSpec with Matchers with MockitoSugar with A
whenF(aMock.returnsEitherT("hello")) thenReturn ValueClass("mocked!")

whenReady(aMock.returnsEitherT("bye").value)(_.left.value shouldBe Error("error"))
whenReady(aMock.returnsEitherT("hello").value)(_.right.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsEitherT("hello").value)(_.value shouldBe ValueClass("mocked!"))
}

"work with OptionT" in {
Expand Down Expand Up @@ -138,9 +138,9 @@ class MockitoCatsTest extends AnyWordSpec with Matchers with MockitoSugar with A
whenFG(aMock.returnsFutureEither("hola")) thenAnswer ((i: InvocationOnMock) => ValueClass(i.arg[String](0) + " invocation mocked!"))
whenFG(aMock.returnsFutureOptionFrom(42, true)) thenAnswer ((i: Int, b: Boolean) => s"$i, $b")

whenReady(aMock.returnsFutureEither("hello"))(_.right.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsFutureEither("hi"))(_.right.value shouldBe ValueClass("hi mocked!"))
whenReady(aMock.returnsFutureEither("hola"))(_.right.value shouldBe ValueClass("hola invocation mocked!"))
whenReady(aMock.returnsFutureEither("hello"))(_.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsFutureEither("hi"))(_.value shouldBe ValueClass("hi mocked!"))
whenReady(aMock.returnsFutureEither("hola"))(_.value shouldBe ValueClass("hola invocation mocked!"))
whenReady(aMock.returnsFutureOptionFrom(42, true))(_.value shouldBe "42, true")
}
}
Expand Down Expand Up @@ -176,7 +176,7 @@ class MockitoCatsTest extends AnyWordSpec with Matchers with MockitoSugar with A
doReturnFG[Future, ErrorOr, ValueClass](ValueClass("mocked!")).when(aMock).returnsFutureEither("hello")
doFailWithG[Future, ErrorOr, Error, ValueClass](Error("boom")).when(aMock).returnsFutureEither("bye")

whenReady(aMock.returnsFutureEither("hello"))(_.right.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsFutureEither("hello"))(_.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsFutureEither("bye"))(_.left.value shouldBe Error("boom"))
}

Expand All @@ -194,7 +194,7 @@ class MockitoCatsTest extends AnyWordSpec with Matchers with MockitoSugar with A
doReturnF[ErrorOr, ValueClass](ValueClass("mocked!")).when(aMock).returnsMT(ValueClass("hi"))
doFailWith[ErrorOr, Error, ValueClass](Error("error")).when(aMock).returnsMT(ValueClass("bye"))

aMock.returnsMT[ErrorOr, ValueClass](ValueClass("hi")).right.value shouldBe ValueClass("mocked!")
aMock.returnsMT[ErrorOr, ValueClass](ValueClass("hi")).value shouldBe ValueClass("mocked!")
aMock.returnsMT[ErrorOr, ValueClass](ValueClass("bye")).left.value shouldBe Error("error")
}

Expand All @@ -216,7 +216,7 @@ class MockitoCatsTest extends AnyWordSpec with Matchers with MockitoSugar with A
doReturnF[F, ValueClass](ValueClass("mocked!")).when(aMock).returnsEitherT("hello")

whenReady(aMock.returnsEitherT("bye").value)(_.left.value shouldBe Error("error"))
whenReady(aMock.returnsEitherT("hello").value)(_.right.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsEitherT("hello").value)(_.value shouldBe ValueClass("mocked!"))
}

"work with OptionT" in {
Expand Down Expand Up @@ -256,9 +256,9 @@ class MockitoCatsTest extends AnyWordSpec with Matchers with MockitoSugar with A
.returnsFutureEither("hola")
doAnswerFG[Future, Option, Int, Boolean, String]((i: Int, b: Boolean) => s"$i, $b").when(aMock).returnsFutureOptionFrom(42, true)

whenReady(aMock.returnsFutureEither("hello"))(_.right.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsFutureEither("hi"))(_.right.value shouldBe ValueClass("hi mocked!"))
whenReady(aMock.returnsFutureEither("hola"))(_.right.value shouldBe ValueClass("hola invocation mocked!"))
whenReady(aMock.returnsFutureEither("hello"))(_.value shouldBe ValueClass("mocked!"))
whenReady(aMock.returnsFutureEither("hi"))(_.value shouldBe ValueClass("hi mocked!"))
whenReady(aMock.returnsFutureEither("hola"))(_.value shouldBe ValueClass("hola invocation mocked!"))
whenReady(aMock.returnsFutureOptionFrom(42, true))(_.value shouldBe "42, true")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class ArgumentMatcherInstancesTest extends AnyFunSuiteLike with FunSuiteDiscipli
test("EqTo works with cats syntax") {
val aMock = mock[Foo]

val matcher = (EqTo("foo"), EqTo(new Integer(42))).tupled
val matcher = (EqTo("foo"), EqTo(Integer.valueOf(42))).tupled
aMock.takesTuple(argThat(matcher)) returns "mocked!"

aMock.takesTuple("foo", 42) shouldBe "mocked!"
Expand Down
10 changes: 6 additions & 4 deletions common/src/main/scala/org/mockito/MockitoAPI.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ import org.mockito.internal.util.reflection.LenientCopyTool
import org.mockito.internal.{ ValueClassExtractor, ValueClassWrapper }
import org.mockito.invocation.{ Invocation, InvocationContainer, InvocationOnMock, MockHandler }
import org.mockito.mock.MockCreationSettings
import org.mockito.quality.Strictness
import org.mockito.stubbing._
import org.mockito.verification.{ VerificationAfterDelay, VerificationMode, VerificationWithTimeout }
import org.scalactic.{ Equality, Prettifier }
import scala.collection.JavaConverters._

import scala.jdk.CollectionConverters._
import scala.reflect.ClassTag
import scala.reflect.runtime.universe.WeakTypeTag

Expand Down Expand Up @@ -543,7 +545,7 @@ private[mockito] trait MockitoEnhancer extends MockCreator {

def spy[T <: AnyRef: ClassTag: WeakTypeTag](realObj: T, lenient: Boolean = false)(implicit $pt: Prettifier): T = {
def mockSettings: MockSettings = Mockito.withSettings().defaultAnswer(CALLS_REAL_METHODS).spiedInstance(realObj)
val settings = if (lenient) mockSettings.lenient() else mockSettings
val settings = if (lenient) mockSettings.strictness(Strictness.LENIENT) else mockSettings
mock[T](settings)
}

Expand Down Expand Up @@ -584,7 +586,7 @@ private[mockito] trait MockitoEnhancer extends MockCreator {
ignoreDefaultArguments(m)
Mockito.verifyNoMoreInteractions(m)
case t: Array[AnyRef] =>
verifyNoMoreInteractions(t: _*)
verifyNoMoreInteractions(t.toIndexedSeq: _*)
case _ =>
throw notAMockPassedToVerifyNoMoreInteractions
}
Expand Down Expand Up @@ -645,7 +647,7 @@ object LeniencySettings {
}

val lenientStubs: LeniencySettings = new LeniencySettings {
override def apply(settings: MockSettings): MockSettings = settings.lenient()
override def apply(settings: MockSettings): MockSettings = settings.strictness(Strictness.LENIENT)
}
}

Expand Down
44 changes: 4 additions & 40 deletions common/src/main/scala/org/mockito/ReflectionUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,13 @@ import ru.vyarus.java.generics.resolver.GenericsResolver

import scala.reflect.ClassTag
import scala.reflect.internal.Symbols
import scala.util.{ Failure, Success, Try => uTry }
import scala.util.{ Try => uTry }
import scala.util.control.NonFatal

object ReflectionUtils {
import scala.reflect.runtime.{ universe => ru }
import ru._

private val JavaVersion: Int =
System.getProperty("java.version").split("\\.") match {
case Array("1", v, _*) => v.toInt // Java 8 style: 1.8.x
case Array(v, _*) => v.toInt // Java 9+ style: 11.x, 17.x, etc.
}

implicit def symbolToMethodSymbol(sym: Symbol): Symbols#MethodSymbol = sym.asInstanceOf[Symbols#MethodSymbol]

private val mirror = runtimeMirror(getClass.getClassLoader)
Expand Down Expand Up @@ -120,39 +114,6 @@ object ReflectionUtils {
}

def setFinalStatic(field: Field, newValue: AnyRef): Unit =
if (JavaVersion < 17)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still support Java 11. Why is this code no longer required to be checked?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's still good as you can see from checks - we run it in JDK 11 as well.
The old code was also working for versions lower than 11, which we don't need to support now, as 11 is the lowest we support

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but my confusion is as to why the check here is for Java 17 and lower, not 11. Isn't this code still relevant for Java 11 til 16?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that was my mistake as I added that when trying to make it work with JDK 17, this the naming. But it seems like that works fine for JDK 11 as well. At least it runs fine on my local and on CI.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, let's merge this and hopefully CI coverage is sufficient. If not, we revert the removal when users do run into it after all.

setFinalStatic17Minus(field, newValue)
else
setFinalStatic17Plus(field, newValue)

private def setFinalStatic17Minus(field: Field, newValue: AnyRef): Unit = {
val clazz = classOf[java.lang.Class[_]]
field.setAccessible(true)
val modifiersField: Field = uTry(clazz.getDeclaredField("modifiers")) match {
case Success(modifiers) => modifiers
case Failure(e) =>
uTry {
val getDeclaredFields0 = clazz.getDeclaredMethod("getDeclaredFields0", classOf[Boolean])
val accessibleBeforeSet: Boolean = getDeclaredFields0.isAccessible
getDeclaredFields0.setAccessible(true)
val declaredFields: Array[Field] = getDeclaredFields0
.invoke(classOf[Field], java.lang.Boolean.FALSE)
.asInstanceOf[Array[Field]]
getDeclaredFields0.setAccessible(accessibleBeforeSet)
declaredFields.find("modifiers" == _.getName).get
} match {
case Success(modifiers) => modifiers
case Failure(ex) =>
e.addSuppressed(ex)
throw e
}
}
modifiersField.setAccessible(true)
modifiersField.setInt(field, field.getModifiers & ~Modifier.FINAL)
field.set(null, newValue)
}

private def setFinalStatic17Plus(field: Field, newValue: AnyRef): Unit =
try {
// Try to get Unsafe instance (works with both sun.misc.Unsafe and jdk.internal.misc.Unsafe)
val unsafeClass: Class[_] =
Expand All @@ -171,6 +132,9 @@ object ReflectionUtils {
val staticFieldOffsetMethod = unsafeClass.getMethod("staticFieldOffset", classOf[Field])
val putObjectMethod = unsafeClass.getMethod("putObject", classOf[Object], classOf[Long], classOf[Object])

// Make the field accessible
field.setAccessible(true)

// Get base and offset for the field
val base: Object = staticFieldBaseMethod.invoke(unsafe, field)
val offset: Long = staticFieldOffsetMethod.invoke(unsafe, field).asInstanceOf[Long]
Expand Down
Loading