Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Java 12+ compatibility #291

Merged
merged 1 commit into from Dec 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -7,6 +7,7 @@
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;
Expand Down Expand Up @@ -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);
}
Expand Down
Expand Up @@ -7,6 +7,7 @@
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;
Expand Down Expand Up @@ -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);
}
Expand Down
Expand Up @@ -7,6 +7,7 @@
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;
Expand All @@ -18,7 +19,6 @@
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;
Expand Down Expand Up @@ -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);

Expand Down
Expand Up @@ -141,7 +141,7 @@ public BlockVector2 next() {

@Override
public Object[] toArray() {
return toArray(null);
return toArray((Object[]) null);
}

@Override
Expand Down
Expand Up @@ -160,7 +160,7 @@ public BlockVector3 next() {

@NotNull @Override
public Object[] toArray() {
return toArray(null);
return toArray((Object[]) null);
}

@NotNull @Override
Expand Down
Expand Up @@ -78,7 +78,7 @@ public static <T extends Enum<?>> T addEnum(Class<T> enumType, String enumName,
}

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;
Expand All @@ -96,25 +96,44 @@ private static ConstructorAccessor getConstructorAccessor(Class<?> enumClass,
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);

// 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 {
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);
} 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);
Expand All @@ -124,7 +143,7 @@ public static void setFailsafeFieldValue(Field field, Object target, Object valu
}

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);
Expand All @@ -134,8 +153,8 @@ private static void blankField(Class<?> enumClass, String fieldName)
}
}

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
}
Expand Down
Expand Up @@ -2,7 +2,10 @@

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;
Expand Down Expand Up @@ -41,15 +44,15 @@ public static <T extends Enum<?>> T addEnum(Class<T> enumType, String enumName)

// 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();
Expand All @@ -64,55 +67,11 @@ public static Object makeEnum(Class<?> enumClass, String value, int ordinal) thr
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
}
}