|
5 | 5 | import java.lang.invoke.MethodHandle; |
6 | 6 | import java.lang.invoke.MethodHandles; |
7 | 7 | import java.lang.reflect.Field; |
| 8 | +import java.lang.reflect.Method; |
8 | 9 | import java.lang.reflect.Modifier; |
9 | 10 |
|
10 | 11 | public class ReflectionHelper { |
11 | 12 |
|
12 | 13 | private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); |
13 | | - private static Field modifiersField; |
| 14 | + private static Field fieldModifiersField; |
| 15 | + private static Field methodModifiersField; |
| 16 | + private static MethodHandle fieldModifiersSetter; |
| 17 | + private static MethodHandle methodModifiersSetter; |
14 | 18 |
|
15 | | - public static boolean setFinal(Field field, boolean isFinal) throws Throwable { |
| 19 | + public static Field getFieldModifiersField() { |
| 20 | + if (fieldModifiersField == null) { |
| 21 | + try { |
| 22 | + fieldModifiersField = Field.class.getDeclaredField("modifiers"); |
| 23 | + } catch (NoSuchFieldException e) { |
| 24 | + // something is very wrong if this crashes |
| 25 | + throw new RuntimeException(e); |
| 26 | + } |
| 27 | + fieldModifiersField.setAccessible(true); |
| 28 | + } |
| 29 | + return fieldModifiersField; |
| 30 | + } |
| 31 | + |
| 32 | + public static Field getMethodModifiersField() { |
| 33 | + if (methodModifiersField == null) { |
| 34 | + try { |
| 35 | + methodModifiersField = Method.class.getDeclaredField("modifiers"); |
| 36 | + } catch (NoSuchFieldException e) { |
| 37 | + // something is very wrong if this crashes |
| 38 | + throw new RuntimeException(e); |
| 39 | + } |
| 40 | + methodModifiersField.setAccessible(true); |
| 41 | + } |
| 42 | + return methodModifiersField; |
| 43 | + } |
| 44 | + |
| 45 | + private static MethodHandle getFieldModifiersSetter() { |
| 46 | + if (fieldModifiersSetter == null) { |
| 47 | + try { |
| 48 | + fieldModifiersSetter = LOOKUP.unreflectSetter(getFieldModifiersField()); |
| 49 | + } catch (IllegalAccessException e) { |
| 50 | + // something is very wrong if this crashes |
| 51 | + throw new RuntimeException(e); |
| 52 | + } |
| 53 | + } |
| 54 | + return fieldModifiersSetter; |
| 55 | + } |
| 56 | + |
| 57 | + public static MethodHandle getMethodModifiersSetter() { |
| 58 | + if (methodModifiersSetter == null) { |
| 59 | + try { |
| 60 | + methodModifiersSetter = LOOKUP.unreflectSetter(getMethodModifiersField()); |
| 61 | + } catch (IllegalAccessException e) { |
| 62 | + // something is very wrong if this crashes |
| 63 | + throw new RuntimeException(e); |
| 64 | + } |
| 65 | + } |
| 66 | + return methodModifiersSetter; |
| 67 | + } |
| 68 | + |
| 69 | + public static void setModifiers(Field field, int modifiers) { |
| 70 | + try { |
| 71 | + getFieldModifiersSetter().invokeExact(field, modifiers); |
| 72 | + } catch (Throwable e) { |
| 73 | + // unlikely to crash |
| 74 | + throw new RuntimeException(e); |
| 75 | + } |
| 76 | + } |
| 77 | + |
| 78 | + public static void setModifiers(Method method, int modifiers) { |
| 79 | + try { |
| 80 | + getMethodModifiersSetter().invokeExact(method, modifiers); |
| 81 | + } catch (Throwable e) { |
| 82 | + // unlikely to crash |
| 83 | + throw new RuntimeException(e); |
| 84 | + } |
| 85 | + } |
| 86 | + |
| 87 | + public static boolean setFinal(Field field, boolean isFinal) { |
16 | 88 | int m = field.getModifiers(); |
17 | 89 | if (Modifier.isFinal(m) == isFinal) return false; |
18 | | - if (modifiersField == null) { |
19 | | - modifiersField = Field.class.getDeclaredField("modifiers"); |
20 | | - modifiersField.setAccessible(true); |
21 | | - } |
22 | 90 | if (isFinal) m |= Modifier.FINAL; |
23 | 91 | else m &= ~Modifier.FINAL; |
24 | | - LOOKUP.unreflectSetter(modifiersField).invokeExact(field, m); |
| 92 | + setModifiers(field, m); |
25 | 93 | return true; |
26 | 94 | } |
27 | 95 |
|
@@ -77,4 +145,23 @@ public static Object getField(Object owner, String name) { |
77 | 145 | return null; |
78 | 146 | } |
79 | 147 | } |
| 148 | + |
| 149 | + public static int makeModifiersPublic(int modifiers) { |
| 150 | + if (!Modifier.isPublic(modifiers)) modifiers |= Modifier.PUBLIC; |
| 151 | + if (Modifier.isProtected(modifiers)) modifiers &= ~Modifier.PROTECTED; |
| 152 | + if (Modifier.isPrivate(modifiers)) modifiers &= ~Modifier.PRIVATE; |
| 153 | + return modifiers; |
| 154 | + } |
| 155 | + |
| 156 | + public static void makeFieldPublic(Field field) { |
| 157 | + int mod = field.getModifiers(); |
| 158 | + int newMod = makeModifiersPublic(mod); |
| 159 | + if (mod != newMod) setModifiers(field, newMod); |
| 160 | + } |
| 161 | + |
| 162 | + public static void makeMethodPublic(Method method) { |
| 163 | + int mod = method.getModifiers(); |
| 164 | + int newMod = makeModifiersPublic(mod); |
| 165 | + if (mod != newMod) setModifiers(method, newMod); |
| 166 | + } |
80 | 167 | } |
0 commit comments