11package org .mockito
22
3- import java .lang .reflect .{ Field , Method , Modifier }
4-
5- import org .mockito .internal .ValueClassWrapper
3+ import org .mockito .JavaReflectionUtils .resolveWithJavaGenerics
64import org .mockito .invocation .InvocationOnMock
75import org .scalactic .TripleEquals ._
8- import ru .vyarus .java .generics .resolver .GenericsResolver
96
7+ import java .lang .reflect .Method
108import scala .reflect .ClassTag
119import scala .reflect .internal .Symbols
1210import scala .util .{ Try => uTry }
13- import scala .util .control .NonFatal
1411
1512object ReflectionUtils {
1613 import scala .reflect .runtime .{ universe => ru }
@@ -23,58 +20,37 @@ object ReflectionUtils {
2320 def methodToJava (sym : Symbols # MethodSymbol ): Method
2421 }]
2522
26- def listToTuple (l : List [Object ]): Any =
27- l match {
28- case Nil => Nil
29- case h :: Nil => h
30- case _ => Class .forName(s " scala.Tuple ${l.size}" ).getDeclaredConstructors.head.newInstance(l : _* )
31- }
32-
33- implicit class InvocationOnMockOps (val invocation : InvocationOnMock ) extends AnyVal {
34- def mock [M ]: M = invocation.getMock.asInstanceOf [M ]
35- def method : Method = invocation.getMethod
36- def arg [A : ValueClassWrapper ](index : Int ): A = ValueClassWrapper [A ].wrapAs[A ](invocation.getArgument(index))
37- def args : List [Any ] = invocation.getArguments.toList
38- def callRealMethod [R ](): R = invocation.callRealMethod.asInstanceOf [R ]
39- def argsAsTuple : Any = listToTuple(args.map(_.asInstanceOf [Object ]))
40-
41- def returnType : Class [_] = {
42- val javaReturnType = method.getReturnType
23+ private [mockito] def returnType (invocation : InvocationOnMock ): Class [_] = {
24+ val javaReturnType = invocation.method.getReturnType
4325
44- if (javaReturnType == classOf [Object ])
45- resolveWithScalaGenerics
46- .orElse(resolveWithJavaGenerics)
47- .getOrElse(javaReturnType)
48- else javaReturnType
49- }
26+ if (javaReturnType == classOf [Object ])
27+ resolveWithScalaGenerics(invocation)
28+ .orElse(resolveWithJavaGenerics(invocation) )
29+ .getOrElse(javaReturnType)
30+ else javaReturnType
31+ }
5032
51- def returnsValueClass : Boolean = findTypeSymbol.exists(_.returnType.typeSymbol.isDerivedValueClass)
33+ private [mockito] def returnsValueClass (invocation : InvocationOnMock ): Boolean =
34+ findTypeSymbol(invocation).exists(_.returnType.typeSymbol.isDerivedValueClass)
5235
53- private def resolveWithScalaGenerics : Option [Class [_]] =
54- uTry {
55- findTypeSymbol
56- .filter(_.returnType.typeSymbol.isClass)
57- .map(_.asMethod.returnType.typeSymbol.asClass)
58- .map(mirror.runtimeClass)
59- }.toOption.flatten
60-
61- private def findTypeSymbol =
62- uTry {
63- mirror
64- .classSymbol(method.getDeclaringClass)
65- .info
66- .decls
67- .collectFirst {
68- case symbol if isNonConstructorMethod(symbol) && customMirror.methodToJava(symbol) === method => symbol
69- }
70- }.toOption.flatten
36+ private def resolveWithScalaGenerics (invocation : InvocationOnMock ): Option [Class [_]] =
37+ uTry {
38+ findTypeSymbol(invocation)
39+ .filter(_.returnType.typeSymbol.isClass)
40+ .map(_.asMethod.returnType.typeSymbol.asClass)
41+ .map(mirror.runtimeClass)
42+ }.toOption.flatten
7143
72- private def resolveWithJavaGenerics : Option [Class [_]] =
73- try Some (GenericsResolver .resolve(invocation.getMock.getClass).`type`(method.getDeclaringClass).method(method).resolveReturnClass())
74- catch {
75- case _ : Throwable => None
76- }
77- }
44+ private def findTypeSymbol (invocation : InvocationOnMock ) =
45+ uTry {
46+ mirror
47+ .classSymbol(invocation.method.getDeclaringClass)
48+ .info
49+ .decls
50+ .collectFirst {
51+ case symbol if isNonConstructorMethod(symbol) && customMirror.methodToJava(symbol) === invocation.method => symbol
52+ }
53+ }.toOption.flatten
7854
7955 private def isNonConstructorMethod (d : ru.Symbol ): Boolean = d.isMethod && ! d.isConstructor
8056
@@ -113,37 +89,4 @@ object ReflectionUtils {
11389 .getOrElse(Seq .empty)
11490 }
11591
116- def setFinalStatic (field : Field , newValue : AnyRef ): Unit =
117- try {
118- // Try to get Unsafe instance (works with both sun.misc.Unsafe and jdk.internal.misc.Unsafe)
119- val unsafeClass : Class [_] =
120- try
121- Class .forName(" sun.misc.Unsafe" )
122- catch {
123- case _ : ClassNotFoundException => Class .forName(" jdk.internal.misc.Unsafe" )
124- }
125-
126- val unsafeField = unsafeClass.getDeclaredField(" theUnsafe" )
127- unsafeField.setAccessible(true )
128- val unsafe = unsafeField.get(null )
129-
130- // Get methods via reflection to handle both Unsafe implementations
131- val staticFieldBaseMethod = unsafeClass.getMethod(" staticFieldBase" , classOf [Field ])
132- val staticFieldOffsetMethod = unsafeClass.getMethod(" staticFieldOffset" , classOf [Field ])
133- val putObjectMethod = unsafeClass.getMethod(" putObject" , classOf [Object ], classOf [Long ], classOf [Object ])
134-
135- // Make the field accessible
136- field.setAccessible(true )
137-
138- // Get base and offset for the field
139- val base : Object = staticFieldBaseMethod.invoke(unsafe, field)
140- val offset : Long = staticFieldOffsetMethod.invoke(unsafe, field).asInstanceOf [Long ]
141-
142- // Set the field value directly
143- putObjectMethod.invoke(unsafe, base, java.lang.Long .valueOf(offset), newValue)
144- } catch {
145- case NonFatal (e) =>
146- throw new IllegalStateException (s " Cannot modify final field ${field.getName}" , e)
147- }
148-
14992}
0 commit comments