@@ -16,6 +16,12 @@ object ReflectionUtils {
1616 import scala .reflect .runtime .{ universe => ru }
1717 import ru ._
1818
19+ val JavaVersion : Int =
20+ System .getProperty(" java.version" ).split(" \\ ." ) match {
21+ case Array (" 1" , v, _* ) => v.toInt // Java 8 style: 1.8.x
22+ case Array (v, _* ) => v.toInt // Java 9+ style: 11.x, 17.x, etc.
23+ }
24+
1925 implicit def symbolToMethodSymbol (sym : Symbol ): Symbols # MethodSymbol = sym.asInstanceOf [Symbols # MethodSymbol ]
2026
2127 private val mirror = runtimeMirror(getClass.getClassLoader)
@@ -51,29 +57,23 @@ object ReflectionUtils {
5157 def returnsValueClass : Boolean = findTypeSymbol.exists(_.returnType.typeSymbol.isDerivedValueClass)
5258
5359 private def resolveWithScalaGenerics : Option [Class [_]] =
54- scala.util
55- .Try {
56- findTypeSymbol
57- .filter(_.returnType.typeSymbol.isClass)
58- .map(_.asMethod.returnType.typeSymbol.asClass)
59- .map(mirror.runtimeClass)
60- }
61- .toOption
62- .flatten
60+ uTry {
61+ findTypeSymbol
62+ .filter(_.returnType.typeSymbol.isClass)
63+ .map(_.asMethod.returnType.typeSymbol.asClass)
64+ .map(mirror.runtimeClass)
65+ }.toOption.flatten
6366
6467 private def findTypeSymbol =
65- scala.util
66- .Try {
67- mirror
68- .classSymbol(method.getDeclaringClass)
69- .info
70- .decls
71- .collectFirst {
72- case symbol if isNonConstructorMethod(symbol) && customMirror.methodToJava(symbol) === method => symbol
73- }
74- }
75- .toOption
76- .flatten
68+ uTry {
69+ mirror
70+ .classSymbol(method.getDeclaringClass)
71+ .info
72+ .decls
73+ .collectFirst {
74+ case symbol if isNonConstructorMethod(symbol) && customMirror.methodToJava(symbol) === method => symbol
75+ }
76+ }.toOption.flatten
7777
7878 private def resolveWithJavaGenerics : Option [Class [_]] =
7979 try Some (GenericsResolver .resolve(invocation.getMock.getClass).`type`(method.getDeclaringClass).method(method).resolveReturnClass())
@@ -85,45 +85,47 @@ object ReflectionUtils {
8585 private def isNonConstructorMethod (d : ru.Symbol ): Boolean = d.isMethod && ! d.isConstructor
8686
8787 def extraInterfaces [T ](implicit $wtt : WeakTypeTag [T ], $ct : ClassTag [T ]): List [Class [_]] =
88- scala.util
89- .Try {
90- val cls = clazz($ct)
91- $wtt.tpe match {
92- case RefinedType (types, _) =>
93- types.map($wtt.mirror.runtimeClass).collect {
94- case c : Class [_] if c.isInterface && c != cls => c
95- }
96- case _ => List .empty
97- }
88+ uTry {
89+ val cls = clazz($ct)
90+ $wtt.tpe match {
91+ case RefinedType (types, _) =>
92+ types.map($wtt.mirror.runtimeClass).collect {
93+ case c : Class [_] if c.isInterface && c != cls => c
94+ }
95+ case _ => List .empty
9896 }
99- .toOption
97+ } .toOption
10098 .getOrElse(List .empty)
10199
102100 def methodsWithLazyOrVarArgs (classes : Seq [Class [_]]): Seq [(Method , Set [Int ])] =
103101 classes.flatMap { clazz =>
104- scala.util
105- .Try {
106- mirror
107- .classSymbol(clazz)
108- .info
109- .members
110- .collect {
111- case symbol if isNonConstructorMethod(symbol) =>
112- symbol -> symbol.typeSignature.paramLists.flatten.zipWithIndex.collect {
113- case (p, idx) if p.typeSignature.toString.startsWith(" =>" ) => idx
114- case (p, idx) if p.typeSignature.toString.endsWith(" *" ) => idx
115- }.toSet
116- }
117- .collect {
118- case (symbol, indices) if indices.nonEmpty => customMirror.methodToJava(symbol) -> indices
119- }
120- .toSeq
121- }
122- .toOption
102+ uTry {
103+ mirror
104+ .classSymbol(clazz)
105+ .info
106+ .members
107+ .collect {
108+ case symbol if isNonConstructorMethod(symbol) =>
109+ symbol -> symbol.typeSignature.paramLists.flatten.zipWithIndex.collect {
110+ case (p, idx) if p.typeSignature.toString.startsWith(" =>" ) => idx
111+ case (p, idx) if p.typeSignature.toString.endsWith(" *" ) => idx
112+ }.toSet
113+ }
114+ .collect {
115+ case (symbol, indices) if indices.nonEmpty => customMirror.methodToJava(symbol) -> indices
116+ }
117+ .toSeq
118+ }.toOption
123119 .getOrElse(Seq .empty)
124120 }
125121
126- def setFinalStatic (field : Field , newValue : Any ): Unit = {
122+ def setFinalStatic (field : Field , newValue : Any ): Unit =
123+ if (JavaVersion < 17 )
124+ setFinalStatic17Minus(field, newValue)
125+ else
126+ setFinalStatic17Plus(field, newValue)
127+
128+ private def setFinalStatic17Minus (field : Field , newValue : Any ): Unit = {
127129 val clazz = classOf [java.lang.Class [_]]
128130 field.setAccessible(true )
129131 val modifiersField : Field = uTry(clazz.getDeclaredField(" modifiers" )) match {
@@ -150,4 +152,34 @@ object ReflectionUtils {
150152 field.set(null , newValue)
151153 }
152154
155+ private def setFinalStatic17Plus (field : Field , newValue : Any ): Unit =
156+ try {
157+ // Try to get Unsafe instance (works with both sun.misc.Unsafe and jdk.internal.misc.Unsafe)
158+ val unsafeClass : Class [_] =
159+ try
160+ Class .forName(" sun.misc.Unsafe" )
161+ catch {
162+ case _ : ClassNotFoundException => Class .forName(" jdk.internal.misc.Unsafe" )
163+ }
164+
165+ val unsafeField = unsafeClass.getDeclaredField(" theUnsafe" )
166+ unsafeField.setAccessible(true )
167+ val unsafe = unsafeField.get(null )
168+
169+ // Get methods via reflection to handle both Unsafe implementations
170+ val staticFieldBaseMethod = unsafeClass.getMethod(" staticFieldBase" , classOf [Field ])
171+ val staticFieldOffsetMethod = unsafeClass.getMethod(" staticFieldOffset" , classOf [Field ])
172+ val putObjectMethod = unsafeClass.getMethod(" putObject" , classOf [Object ], classOf [Long ], classOf [Object ])
173+
174+ // Get base and offset for the field
175+ val base = staticFieldBaseMethod.invoke(unsafe, field)
176+ val offset = staticFieldOffsetMethod.invoke(unsafe, field).asInstanceOf [Long ]
177+
178+ // Set the field value directly
179+ putObjectMethod.invoke(unsafe, base, offset, newValue)
180+ } catch {
181+ case NonFatal (e) =>
182+ throw new IllegalStateException (s " Cannot modify final field ${field.getName}" , e)
183+ }
184+
153185}
0 commit comments