šŸ‘½ļø Use Unsafe instead of reflection to set private field for test
authorDavid ā€˜Bombeā€™ Roden <bombe@pterodactylus.net>
Sat, 28 Sep 2024 16:33:54 +0000 (18:33 +0200)
committerDavid ā€˜Bombeā€™ Roden <bombe@pterodactylus.net>
Sat, 28 Sep 2024 20:47:30 +0000 (22:47 +0200)
This feels like a gigantic step backwards. Additionally, JEP 471 already
plans to phase out the method used in here until Java 27 or so, so at
some point I will have to fix the underlying issue of the
PageMakerInteractionFactory being non-accessible for tests.

src/test/kotlin/net/pterodactylus/sone/test/TestUtils.kt
src/test/kotlin/net/pterodactylus/sone/web/page/FreenetTemplatePageTest.kt

index ef23d62..e49663f 100644 (file)
@@ -1,22 +1,15 @@
 package net.pterodactylus.sone.test
 
-import org.junit.rules.*
-import java.lang.reflect.*
-
-private val modifiers = Field::class.java.getDeclaredField("modifiers").apply {
-       isAccessible = true
-}
-
-fun setField(instance: Any, name: String, value: Any?) {
-       generateSequence<Class<*>>(instance.javaClass) { it.superclass }
-                       .flatMap { it.declaredFields.asSequence() }
-                       .filter { it.name == name }
-                       .toList()
-                       .forEach { field ->
-                               field.isAccessible = true
-                               modifiers.setInt(field, field.modifiers and Modifier.FINAL.inv())
-                               field.set(instance, value)
-                       }
+import org.junit.rules.ExpectedException
+import sun.misc.Unsafe
+
+inline fun <reified O : Any> setField(instance: O, name: String, value: Any?) {
+       val field = O::class.java.getDeclaredField(name)
+       val unsafe = Unsafe::class.java.getDeclaredField("theUnsafe").apply {
+               isAccessible = true
+       }.get(null) as Unsafe
+       val offset = unsafe.objectFieldOffset(field)
+       unsafe.putObject(instance, offset, value)
 }
 
 inline fun <reified T : Throwable> ExpectedException.expect() = expect(T::class.java)
index 2474d08..e6fd861 100644 (file)
@@ -131,7 +131,7 @@ class FreenetTemplatePageTest {
                val request = deepMock<FreenetRequest>()
                val pageMakerInteractionFactory = deepMock<PageMakerInteractionFactory>()
                whenever(pageMakerInteractionFactory.createPageMaker(request.toadletContext, "page title").renderPage()).thenReturn("<page>")
-               setField(page, "pageMakerInteractionFactory", pageMakerInteractionFactory)
+               setField<FreenetTemplatePage>(page, "pageMakerInteractionFactory", pageMakerInteractionFactory)
                val response = page.handleRequest(request, Response(ByteArrayOutputStream()))
                assertThat(response.statusCode, equalTo(200))
                assertThat((response.content as ByteArrayOutputStream).toString(UTF_8.name()), equalTo("<page>"))