From 8569359d8fa48803db83fcb60dc8b77e5291bf95 Mon Sep 17 00:00:00 2001 From: KennyTV <28825609+KennyTV@users.noreply.github.com> Date: Sat, 21 Dec 2019 21:21:25 +0100 Subject: [PATCH] Fix Java 12+ compatibility --- .../adapter/mc1_13/BukkitAdapter_1_13.java | 7 +-- .../adapter/mc1_14/BukkitAdapter_1_14.java | 7 +-- .../adapter/mc1_15/BukkitAdapter_1_15.java | 8 +-- .../collection/LocalBlockVector2DSet.java | 2 +- .../collection/LocalBlockVectorSet.java | 2 +- .../com/boydti/fawe/util/ReflectionUtils.java | 45 ++++++++++---- .../boydti/fawe/util/ReflectionUtils9.java | 59 +++---------------- 7 files changed, 49 insertions(+), 81 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_13/BukkitAdapter_1_13.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_13/BukkitAdapter_1_13.java index 3b118179b..6f948ffad 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_13/BukkitAdapter_1_13.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_13/BukkitAdapter_1_13.java @@ -7,6 +7,7 @@ import com.boydti.fawe.bukkit.adapter.NMSAdapter; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.collection.BitArray4096; import com.boydti.fawe.util.MathMan; +import com.boydti.fawe.util.ReflectionUtils; import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypesCache; @@ -83,11 +84,7 @@ public final class BukkitAdapter_1_13 extends NMSAdapter { } catch (NoSuchFieldException paper) { tmp = DataPaletteBlock.class.getDeclaredField("j"); } - Field modifiersField = Field.class.getDeclaredField("modifiers"); - modifiersField.setAccessible(true); - int modifiers = modifiersField.getInt(tmp); - int newModifiers = modifiers & (~Modifier.FINAL); - if (newModifiers != modifiers) modifiersField.setInt(tmp, newModifiers); + ReflectionUtils.setAccessibleNonFinal(tmp); fieldLock = tmp; fieldLock.setAccessible(true); } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitAdapter_1_14.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitAdapter_1_14.java index 5a845f498..3c3a2f551 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitAdapter_1_14.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitAdapter_1_14.java @@ -7,6 +7,7 @@ import com.boydti.fawe.bukkit.adapter.DelegateLock; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.collection.BitArray4096; import com.boydti.fawe.util.MathMan; +import com.boydti.fawe.util.ReflectionUtils; import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypesCache; @@ -83,11 +84,7 @@ public final class BukkitAdapter_1_14 extends NMSAdapter { } catch (NoSuchFieldException paper) { tmp = DataPaletteBlock.class.getDeclaredField("j"); } - Field modifiersField = Field.class.getDeclaredField("modifiers"); - modifiersField.setAccessible(true); - int modifiers = modifiersField.getInt(tmp); - int newModifiers = modifiers & (~Modifier.FINAL); - if (newModifiers != modifiers) modifiersField.setInt(tmp, newModifiers); + ReflectionUtils.setAccessibleNonFinal(tmp); fieldLock = tmp; fieldLock.setAccessible(true); } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15/BukkitAdapter_1_15.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15/BukkitAdapter_1_15.java index 1faa45211..b00001bd5 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15/BukkitAdapter_1_15.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15/BukkitAdapter_1_15.java @@ -7,6 +7,7 @@ import com.boydti.fawe.bukkit.adapter.NMSAdapter; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.collection.BitArray4096; import com.boydti.fawe.util.MathMan; +import com.boydti.fawe.util.ReflectionUtils; import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypesCache; @@ -18,7 +19,6 @@ import org.bukkit.craftbukkit.v1_15_R1.CraftWorld; import sun.misc.Unsafe; import java.lang.reflect.Field; -import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.concurrent.CompletableFuture; import java.util.concurrent.locks.Lock; @@ -66,11 +66,7 @@ public final class BukkitAdapter_1_15 extends NMSAdapter { fieldDirtyBits.setAccessible(true); Field tmp = DataPaletteBlock.class.getDeclaredField("j"); - Field modifiersField = Field.class.getDeclaredField("modifiers"); - modifiersField.setAccessible(true); - int modifiers = modifiersField.getInt(tmp); - int newModifiers = modifiers & (~Modifier.FINAL); - if (newModifiers != modifiers) modifiersField.setInt(tmp, newModifiers); + ReflectionUtils.setAccessibleNonFinal(tmp); fieldLock = tmp; fieldLock.setAccessible(true); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVector2DSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVector2DSet.java index 599ed7f44..899b4cfa9 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVector2DSet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVector2DSet.java @@ -141,7 +141,7 @@ public class LocalBlockVector2DSet implements Set { @Override public Object[] toArray() { - return toArray(null); + return toArray((Object[]) null); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVectorSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVectorSet.java index d89d8c5c3..bc1388ab8 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVectorSet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVectorSet.java @@ -160,7 +160,7 @@ public class LocalBlockVectorSet implements Set { @NotNull @Override public Object[] toArray() { - return toArray(null); + return toArray((Object[]) null); } @NotNull @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils.java b/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils.java index c7a4d706a..e5144d642 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils.java @@ -78,7 +78,7 @@ public class ReflectionUtils { } public static Object makeEnum(Class enumClass, String value, int ordinal, - Class[] additionalTypes, Object[] additionalValues) throws Exception { + Class[] additionalTypes, Object[] additionalValues) throws Exception { Object[] parms = new Object[additionalValues.length + 2]; parms[0] = value; parms[1] = ordinal; @@ -96,9 +96,8 @@ public class ReflectionUtils { return ReflectionFactory.getReflectionFactory().newConstructorAccessor(enumClass.getDeclaredConstructor(parameterTypes)); } - public static void setFailsafeFieldValue(Field field, Object target, Object value) - throws NoSuchFieldException, IllegalAccessException { - + public static void setAccessibleNonFinal(Field field) + throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { // let's make the field accessible field.setAccessible(true); @@ -106,15 +105,35 @@ public class ReflectionUtils { // not be final anymore, thus tricking reflection into // letting us modify the static final field if (Modifier.isFinal(field.getModifiers())) { - Field modifiersField = Field.class.getDeclaredField("modifiers"); - modifiersField.setAccessible(true); - int modifiers = modifiersField.getInt(field); + try { + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + int modifiers = modifiersField.getInt(field); - // blank out the final bit in the modifiers int - modifiers &= ~Modifier.FINAL; - modifiersField.setInt(field, modifiers); + // blank out the final bit in the modifiers int + modifiers &= ~Modifier.FINAL; + modifiersField.setInt(field, modifiers); + } catch (NoSuchFieldException e) { + // Java 12+ compatibility - search fields with hidden method for modifiers + // same concept as above, just with a more hacky way of getting to the modifiers + Method getDeclaredFields0 = Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class); + getDeclaredFields0.setAccessible(true); + Field[] fields = (Field[]) getDeclaredFields0.invoke(Field.class, false); + for (Field classField : fields) { + if ("modifiers".equals(classField.getName())) { + classField.setAccessible(true); + classField.set(field, field.getModifiers() & ~Modifier.FINAL); + break; + } + } + } } + } + public static void setFailsafeFieldValue(Field field, Object target, Object value) + throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { + + setAccessibleNonFinal(field); try { FieldAccessor fa = ReflectionFactory.getReflectionFactory().newFieldAccessor(field, false); fa.set(target, value); @@ -124,7 +143,7 @@ public class ReflectionUtils { } private static void blankField(Class enumClass, String fieldName) - throws NoSuchFieldException, IllegalAccessException { + throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { for (Field field : Class.class.getDeclaredFields()) { if (field.getName().contains(fieldName)) { AccessibleObject.setAccessible(new Field[]{field}, true); @@ -134,8 +153,8 @@ public class ReflectionUtils { } } - private static void cleanEnumCache(Class enumClass) - throws NoSuchFieldException, IllegalAccessException { + static void cleanEnumCache(Class enumClass) + throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { blankField(enumClass, "enumConstantDirectory"); // Sun (Oracle?!?) JDK 1.5/6 blankField(enumClass, "enumConstants"); // IBM JDK } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils9.java b/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils9.java index 110c1014e..7f3b44907 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils9.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils9.java @@ -2,7 +2,10 @@ package com.boydti.fawe.util; import sun.misc.Unsafe; -import java.lang.reflect.*; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -41,15 +44,15 @@ public class ReflectionUtils9 { // 5. Set new values field try { - setFailsafeFieldValue(valuesField, null, + ReflectionUtils.setFailsafeFieldValue(valuesField, null, values.toArray((T[]) Array.newInstance(enumType, 0))); } catch (Throwable e) { Field ordinalField = Enum.class.getDeclaredField("ordinal"); - setFailsafeFieldValue(ordinalField, newValue, 0); + ReflectionUtils.setFailsafeFieldValue(ordinalField, newValue, 0); } // 6. Clean enum cache - cleanEnumCache(enumType); + ReflectionUtils.cleanEnumCache(enumType); return newValue; } catch (Exception e) { e.printStackTrace(); @@ -64,55 +67,11 @@ public class ReflectionUtils9 { Object instance = unsafe.allocateInstance(enumClass); Field ordinalField = Enum.class.getDeclaredField("ordinal"); - setFailsafeFieldValue(ordinalField, instance, 0); + ReflectionUtils.setFailsafeFieldValue(ordinalField, instance, 0); Field nameField = Enum.class.getDeclaredField("name"); - setFailsafeFieldValue(nameField, instance, value); + ReflectionUtils.setFailsafeFieldValue(nameField, instance, value); return instance; } - - public static void setFailsafeFieldValue(Field field, Object target, Object value) - throws NoSuchFieldException, IllegalAccessException { - - // let's make the field accessible - field.setAccessible(true); - - // next we change the modifier in the Field instance to - // not be final anymore, thus tricking reflection into - // letting us modify the static final field - if (Modifier.isFinal(field.getModifiers())) { - Field modifiersField = Field.class.getDeclaredField("modifiers"); - modifiersField.setAccessible(true); - int modifiers = modifiersField.getInt(field); - - // blank out the final bit in the modifiers int - modifiers &= ~Modifier.FINAL; - modifiersField.setInt(field, modifiers); - } - - try { - if (target == null) field.set(null, value); - else field.set(target, value); - } catch (NoSuchMethodError error) { - field.set(target, value); - } - } - - private static void blankField(Class enumClass, String fieldName) - throws NoSuchFieldException, IllegalAccessException { - for (Field field : Class.class.getDeclaredFields()) { - if (field.getName().contains(fieldName)) { - AccessibleObject.setAccessible(new Field[]{field}, true); - setFailsafeFieldValue(field, enumClass, null); - break; - } - } - } - - private static void cleanEnumCache(Class enumClass) - throws NoSuchFieldException, IllegalAccessException { - blankField(enumClass, "enumConstantDirectory"); // Sun (Oracle?!?) JDK 1.5/6 - blankField(enumClass, "enumConstants"); // IBM JDK - } }