1
16 package com.google.gson.internal.reflect;
17
18 import java.lang.reflect.AccessibleObject;
19 import java.lang.reflect.Field;
20 import java.lang.reflect.Method;
21
22 import com.google.gson.JsonIOException;
23
24
30 @SuppressWarnings({"unchecked", "rawtypes"})
31 final class UnsafeReflectionAccessor extends ReflectionAccessor {
32
33 private static Class unsafeClass;
34 private final Object theUnsafe = getUnsafeInstance();
35 private final Field overrideField = getOverrideField();
36
37
38 @Override
39 public void makeAccessible(AccessibleObject ao) {
40 boolean success = makeAccessibleWithUnsafe(ao);
41 if (!success) {
42 try {
43
44 ao.setAccessible(true);
45 } catch (SecurityException e) {
46 throw new JsonIOException("Gson couldn't modify fields for " + ao
47 + "\nand sun.misc.Unsafe not found.\nEither write a custom type adapter,"
48 + " or make fields accessible, or include sun.misc.Unsafe.", e);
49 }
50 }
51 }
52
53
54 boolean makeAccessibleWithUnsafe(AccessibleObject ao) {
55 if (theUnsafe != null && overrideField != null) {
56 try {
57 Method method = unsafeClass.getMethod("objectFieldOffset", Field.class);
58 long overrideOffset = (Long) method.invoke(theUnsafe, overrideField);
59 Method putBooleanMethod = unsafeClass.getMethod("putBoolean", Object.class, long.class, boolean.class);
60 putBooleanMethod.invoke(theUnsafe, ao, overrideOffset, true);
61 return true;
62 } catch (Exception ignored) {
63 }
64 }
65 return false;
66 }
67
68 private static Object getUnsafeInstance() {
69 try {
70 unsafeClass = Class.forName("sun.misc.Unsafe");
71 Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
72 unsafeField.setAccessible(true);
73 return unsafeField.get(null);
74 } catch (Exception e) {
75 return null;
76 }
77 }
78
79 private static Field getOverrideField() {
80 try {
81 return AccessibleObject.class.getDeclaredField("override");
82 } catch (NoSuchFieldException e) {
83 return null;
84 }
85 }
86 }
87