• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.google.gson.internal;
2 
3 import java.lang.reflect.AccessibleObject;
4 import java.lang.reflect.Method;
5 import java.util.List;
6 
7 import com.google.gson.ReflectionAccessFilter;
8 import com.google.gson.ReflectionAccessFilter.FilterResult;
9 
10 /**
11  * Internal helper class for {@link ReflectionAccessFilter}.
12  */
13 public class ReflectionAccessFilterHelper {
ReflectionAccessFilterHelper()14   private ReflectionAccessFilterHelper() { }
15 
16   // Platform type detection is based on Moshi's Util.isPlatformType(Class)
17   // See https://github.com/square/moshi/blob/3c108919ee1cce88a433ffda04eeeddc0341eae7/moshi/src/main/java/com/squareup/moshi/internal/Util.java#L141
18 
isJavaType(Class<?> c)19   public static boolean isJavaType(Class<?> c) {
20     return isJavaType(c.getName());
21   }
22 
isJavaType(String className)23   private static boolean isJavaType(String className) {
24     return className.startsWith("java.") || className.startsWith("javax.");
25   }
26 
isAndroidType(Class<?> c)27   public static boolean isAndroidType(Class<?> c) {
28     return isAndroidType(c.getName());
29   }
30 
isAndroidType(String className)31   private static boolean isAndroidType(String className) {
32     return className.startsWith("android.")
33         || className.startsWith("androidx.")
34         || isJavaType(className);
35   }
36 
isAnyPlatformType(Class<?> c)37   public static boolean isAnyPlatformType(Class<?> c) {
38     String className = c.getName();
39     return isAndroidType(className) // Covers Android and Java
40       || className.startsWith("kotlin.")
41       || className.startsWith("kotlinx.")
42       || className.startsWith("scala.");
43   }
44 
45   /**
46    * Gets the result of applying all filters until the first one returns a result
47    * other than {@link FilterResult#INDECISIVE}, or {@link FilterResult#ALLOW} if
48    * the list of filters is empty or all returned {@code INDECISIVE}.
49    */
getFilterResult(List<ReflectionAccessFilter> reflectionFilters, Class<?> c)50   public static FilterResult getFilterResult(List<ReflectionAccessFilter> reflectionFilters, Class<?> c) {
51     for (ReflectionAccessFilter filter : reflectionFilters) {
52       FilterResult result = filter.check(c);
53       if (result != FilterResult.INDECISIVE) {
54         return result;
55       }
56     }
57     return FilterResult.ALLOW;
58   }
59 
60   /**
61    * See {@link AccessibleObject#canAccess(Object)} (Java >= 9)
62    */
canAccess(AccessibleObject accessibleObject, Object object)63   public static boolean canAccess(AccessibleObject accessibleObject, Object object) {
64     return AccessChecker.INSTANCE.canAccess(accessibleObject, object);
65   }
66 
67   private static abstract class AccessChecker {
68     public static final AccessChecker INSTANCE;
69     static {
70       AccessChecker accessChecker = null;
71       // TODO: Ideally should use Multi-Release JAR for this version specific code
72       if (JavaVersion.isJava9OrLater()) {
73         try {
74           final Method canAccessMethod = AccessibleObject.class.getDeclaredMethod("canAccess", Object.class);
75           accessChecker = new AccessChecker() {
76             @Override public boolean canAccess(AccessibleObject accessibleObject, Object object) {
77               try {
78                 return (Boolean) canAccessMethod.invoke(accessibleObject, object);
79               } catch (Exception e) {
80                 throw new RuntimeException("Failed invoking canAccess", e);
81               }
82             }
83           };
84         } catch (NoSuchMethodException ignored) {
85         }
86       }
87 
88       if (accessChecker == null) {
89         accessChecker = new AccessChecker() {
90           @Override public boolean canAccess(AccessibleObject accessibleObject, Object object) {
91             // Cannot determine whether object can be accessed, so assume it can be accessed
92             return true;
93           }
94         };
95       }
96       INSTANCE = accessChecker;
97     }
98 
canAccess(AccessibleObject accessibleObject, Object object)99     public abstract boolean canAccess(AccessibleObject accessibleObject, Object object);
100   }
101 }
102