11package io .ebean .mocker ;
22
3+ import sun .misc .Unsafe ;
4+
35import java .lang .reflect .Field ;
4- import java .lang .reflect .Modifier ;
5- import java .security .AccessController ;
6- import java .security .PrivilegedAction ;
76
87/**
98 * Used to replace a "Finder" that is located as a static field (typically on an Model entity bean).
@@ -23,6 +22,14 @@ public class WithStaticFinder<T> {
2322
2423 Object testDouble ;
2524
25+ Field unsafeField ;
26+
27+ Unsafe unsafe ;
28+
29+ Object staticFieldBase ;
30+
31+ long staticFieldOffset ;
32+
2633 /**
2734 * Construct with a given bean type.
2835 */
@@ -48,25 +55,20 @@ public WithStaticFinder<T> as(Object testDouble) throws FinderFieldNotFoundExcep
4855 this .testDouble = testDouble ;
4956 this .field = findField ();
5057 this .field .setAccessible (true );
58+
5159 try {
52- Field modifiersField = Field .class .getDeclaredField ("modifiers" );
53- /**
54- * If the project using this library has a SecurityManager set up, permission may be denied.
55- * Therefor, running this as a privileged action.
56- */
57- AccessController .doPrivileged ((PrivilegedAction <Object >) () -> {
58- modifiersField .setAccessible (true );
59- return null ;
60- });
61- modifiersField .setInt (field , field .getModifiers () & ~Modifier .FINAL );
60+ unsafeField = Unsafe .class .getDeclaredField ("theUnsafe" );
61+ unsafeField .setAccessible (true );
62+ unsafe = (Unsafe ) unsafeField .get (null );
63+
64+ staticFieldBase = unsafe .staticFieldBase (this .field );
65+ staticFieldOffset = unsafe .staticFieldOffset (this .field );
6266 } catch (NoSuchFieldException e ) {
63- // this fails with Java 17
6467 throw new RuntimeException ("Unable to turn off final field flag for " + field , e );
6568 }
66-
6769 this .original = field .get (null );
68- return this ;
6970
71+ return this ;
7072 } catch (IllegalAccessException e ) {
7173 throw new RuntimeException (e );
7274 }
@@ -79,23 +81,14 @@ public WithStaticFinder<T> as(Object testDouble) throws FinderFieldNotFoundExcep
7981 * After this the test double will be used by calling code.
8082 */
8183 public void useTestDouble () {
82- try {
83- this .field .set (null , testDouble );
84- } catch (IllegalAccessException e ) {
85- throw new FinderIllegalAccessException (e );
86- }
84+ unsafe .putObject (staticFieldBase , staticFieldOffset , testDouble );
8785 }
8886
8987 /**
9088 * Restore the original implementation using reflection.
9189 */
9290 public void restoreOriginal () {
93-
94- try {
95- this .field .set (null , original );
96- } catch (IllegalAccessException e ) {
97- throw new FinderIllegalAccessException (e );
98- }
91+ unsafe .putObject (staticFieldBase , staticFieldOffset , original );
9992 }
10093
10194 /**
0 commit comments