| | 85 | |
| | 86 | /** |
| | 87 | * Reset all {@link AbstractProperty} preferences to the new preference |
| | 88 | * @param pref The preference to use |
| | 89 | * @throws ReflectiveOperationException if reflection fails |
| | 90 | */ |
| | 91 | private void resetConfigVariables(Preferences pref) throws ReflectiveOperationException { |
| | 92 | final Field classField = ClassLoader.class.getDeclaredField("classes"); |
| | 93 | classField.setAccessible(true); |
| | 94 | final Field configField = AbstractProperty.class.getDeclaredField("preferences"); |
| | 95 | final boolean configIsFinal = Modifier.isFinal(configField.getModifiers()); |
| | 96 | try { |
| | 97 | if (configIsFinal) { |
| | 98 | makeFinalFieldModifiable(configField, true); |
| | 99 | } |
| | 100 | // We are pretty much requiring that this doesn't change. |
| | 101 | @SuppressWarnings("unchecked") |
| | 102 | Vector<Class<?>> classes = (Vector<Class<?>>) classField.get(this.getClass().getClassLoader()); |
| | 103 | // We need to copy to another list (ConcurrentModificationException) |
| | 104 | for (Class<?> clazz : classes.stream().collect(Collectors.toList())) { |
| | 105 | for (Field field : clazz.getDeclaredFields()) { |
| | 106 | if (Modifier.isStatic(field.getModifiers()) && AbstractProperty.class.isInstance(field.getType())) { |
| | 107 | configField.set(field.get(null), pref); |
| | 108 | } |
| | 109 | } |
| | 110 | } |
| | 111 | } finally { |
| | 112 | if (configIsFinal) { |
| | 113 | makeFinalFieldModifiable(configField, false); |
| | 114 | } |
| | 115 | } |
| | 116 | } |
| | 117 | |
| | 118 | /** |
| | 119 | * Make a final field modifiable. This should always be called twice (once prior to modification, once after) |
| | 120 | * @param field The field to make modifiable |
| | 121 | * @param modifiable {@code false} will make the field final |
| | 122 | * @throws ReflectiveOperationException If the reflection operations fail |
| | 123 | */ |
| | 124 | private static void makeFinalFieldModifiable(Field field, boolean modifiable) throws ReflectiveOperationException { |
| | 125 | Field modifiersField = Field.class.getDeclaredField("modifiers"); |
| | 126 | boolean isModifierAccessible = modifiersField.isAccessible(); |
| | 127 | try { |
| | 128 | if (!isModifierAccessible) { |
| | 129 | modifiersField.setAccessible(true); |
| | 130 | } |
| | 131 | if (modifiable) { |
| | 132 | modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); |
| | 133 | } else { |
| | 134 | modifiersField.setInt(field, field.getModifiers() | Modifier.FINAL); |
| | 135 | } |
| | 136 | } finally { |
| | 137 | if (!isModifierAccessible) { |
| | 138 | modifiersField.setAccessible(false); |
| | 139 | } |
| | 140 | } |
| | 141 | } |