diff options
author | Reinier Zwitserloot <reinier@zwitserloot.com> | 2018-10-29 23:13:52 +0100 |
---|---|---|
committer | Reinier Zwitserloot <reinier@zwitserloot.com> | 2018-10-29 23:13:59 +0100 |
commit | eca219ee6433cd964f0549a114a791ca4eb9f0fa (patch) | |
tree | 20f6fed449504fbf5dbc52bd15ff3f2458dd90f8 /src/utils/lombok/permit/Permit.java | |
parent | 182cb0cb9e8db6341fb4633c3849b5e90ba6d088 (diff) | |
download | lombok-eca219ee6433cd964f0549a114a791ca4eb9f0fa.tar.gz lombok-eca219ee6433cd964f0549a114a791ca4eb9f0fa.tar.bz2 lombok-eca219ee6433cd964f0549a114a791ca4eb9f0fa.zip |
eliminate ‘you are using private API’ warnings by streamlining all reflective access via a class that uses sun.misc.Unsafe to arrange access. From the nqzero permit-reflect library.
Diffstat (limited to 'src/utils/lombok/permit/Permit.java')
-rw-r--r-- | src/utils/lombok/permit/Permit.java | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/src/utils/lombok/permit/Permit.java b/src/utils/lombok/permit/Permit.java new file mode 100644 index 00000000..00b8274c --- /dev/null +++ b/src/utils/lombok/permit/Permit.java @@ -0,0 +1,100 @@ +package lombok.permit; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.util.List; + +// sunapi suppresses javac's warning about using Unsafe; 'all' suppresses eclipse's warning about the unspecified 'sunapi' key. Leave them both. +// Yes, javac's definition of the word 'all' is quite contrary to what the dictionary says it means. 'all' does NOT include 'sunapi' according to javac. +@SuppressWarnings({"sunapi", "all"}) +public class Permit { + private Permit() {} + + + private static final long ACCESSIBLE_OVERRIDE_FIELD_OFFSET; + private static final IllegalAccessException INIT_ERROR; + private static final sun.misc.Unsafe UNSAFE = (sun.misc.Unsafe) reflectiveStaticFieldAccess(sun.misc.Unsafe.class, "theUnsafe"); + + static { + Field f; + long g; + Throwable ex; + + try { + f = AccessibleObject.class.getDeclaredField("override"); + g = UNSAFE.objectFieldOffset(f); + ex = null; + } catch (Throwable t) { + f = null; + g = -1L; + ex = t; + } + + ACCESSIBLE_OVERRIDE_FIELD_OFFSET = g; + if (ex == null) INIT_ERROR = null; + else if (ex instanceof IllegalAccessException) INIT_ERROR = (IllegalAccessException) ex; + else { + INIT_ERROR = new IllegalAccessException("Cannot initialize Unsafe-based permit"); + INIT_ERROR.initCause(ex); + } + } + + public static <T extends AccessibleObject> T setAccessible(T accessor) { + if (INIT_ERROR == null) { + UNSAFE.putBoolean(accessor, ACCESSIBLE_OVERRIDE_FIELD_OFFSET, true); + } else { + accessor.setAccessible(true); + } + + return accessor; + } + + public static Method getMethod(Class<?> c, String mName, Class<?>... parameterTypes) throws NoSuchMethodException { + Method m = null; + Class<?> oc = c; + while (c != null) { + try { + m = c.getDeclaredMethod(mName, parameterTypes); + break; + } catch (NoSuchMethodException e) {} + c = c.getSuperclass(); + } + + if (m == null) throw new NoSuchMethodException(oc.getName() + " :: " + mName + "(args)"); + return setAccessible(m); + } + + public static Field getField(Class<?> c, String fName) throws NoSuchFieldException { + Field f = null; + Class<?> oc = c; + while (c != null) { + try { + f = c.getDeclaredField(fName); + break; + } catch (NoSuchFieldException e) {} + c = c.getSuperclass(); + } + + if (f == null) throw new NoSuchFieldException(oc.getName() + " :: " + fName); + + return setAccessible(f); + } + + public static <T> Constructor<T> getConstructor(Class<T> c, Class<?>... parameterTypes) throws NoSuchMethodException { + return setAccessible(c.getDeclaredConstructor(parameterTypes)); + } + + private static Object reflectiveStaticFieldAccess(Class<?> c, String fName) { + try { + Field f = c.getDeclaredField(fName); + f.setAccessible(true); + return f.get(null); + } catch (Exception e) { + return null; + } + } +} |