{"record":{"id":"57ca6a0613665707","repo":"google/gson","slug":"reflectionaccessfilter-does-not-permit-using-refle-57ca6a","errorCode":null,"errorMessage":"ReflectionAccessFilter does not permit using reflection for ${raw} (supertype of ${originalRaw}). Register a TypeAdapter for this type or adjust the access filter.","messagePattern":"ReflectionAccessFilter does not permit using reflection for (.+?) \\(supertype of (.+?)\\)\\. Register a TypeAdapter for this type or adjust the access filter\\.","errorType":"exception","errorClass":"JsonIOException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java","lineNumber":340,"sourceCode":"    if (raw.isInterface()) {\n      return FieldsData.EMPTY;\n    }\n\n    Map<String, BoundField> deserializedFields = new LinkedHashMap<>();\n    // For serialized fields use a Map to track duplicate field names; otherwise this could be a\n    // List<BoundField> instead\n    Map<String, BoundField> serializedFields = new LinkedHashMap<>();\n\n    Class<?> originalRaw = raw;\n    while (raw != Object.class) {\n      Field[] fields = raw.getDeclaredFields();\n\n      // For inherited fields, check if access to their declaring class is allowed\n      if (raw != originalRaw && fields.length > 0) {\n        FilterResult filterResult =\n            ReflectionAccessFilterHelper.getFilterResult(reflectionFilters, raw);\n        if (filterResult == FilterResult.BLOCK_ALL) {\n          throw new JsonIOException(\n              \"ReflectionAccessFilter does not permit using reflection for \"\n                  + raw\n                  + \" (supertype of \"\n                  + originalRaw\n                  + \"). Register a TypeAdapter for this type or adjust the access filter.\");\n        }\n        blockInaccessible = filterResult == FilterResult.BLOCK_INACCESSIBLE;\n      }\n\n      for (Field field : fields) {\n        boolean serialize = includeField(field, true);\n        boolean deserialize = includeField(field, false);\n        if (!serialize && !deserialize) {\n          continue;\n        }\n        // The accessor method is only used for records. If the type is a record, we will read out\n        // values via its accessor method instead of via reflection. This way we will bypass the\n        // accessible restrictions","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/google/gson/blob/310ac341f2f92a454b229bf21f70d2d18b2b6db7/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java#L322-L358","documentation":"Gson walks the full class hierarchy to discover inherited fields. If a ReflectionAccessFilter returns BLOCK_ALL for any supertype (not the immediate type — that is handled separately), Gson refuses to silently drop those inherited fields and throws JsonIOException instead.","triggerScenarios":"A domain class extends or implements a type blocked by a ReflectionAccessFilter (e.g., BLOCK_ALL_JAVA or a custom filter blocking java.* or platform types) and Gson needs to serialize or deserialize it reflectively.","commonSituations":"Security hardening with ReflectionAccessFilter.BLOCK_ALL_PLATFORM on a type that extends a JDK class; JPMS migration where a model class inherits from a blocked package.","solutions":["Register a custom TypeAdapter for the domain type so Gson never uses reflection for it","Adjust the ReflectionAccessFilter to return ALLOW or BLOCK_INACCESSIBLE instead of BLOCK_ALL for the specific supertype"],"exampleFix":"// before\nGson gson = new GsonBuilder()\n    .addReflectionAccessFilter(ReflectionAccessFilter.BLOCK_ALL_JAVA)\n    .create();\ngson.toJson(myType); // throws if MyType extends a java.* class\n\n// after — bypass reflection with a custom adapter\nGson gson = new GsonBuilder()\n    .registerTypeAdapter(MyType.class, new MyTypeAdapter())\n    .addReflectionAccessFilter(ReflectionAccessFilter.BLOCK_ALL_JAVA)\n    .create();","handlingStrategy":"validation","validationCode":"// Before serializing, check if any supertype would be blocked by the filter\npublic static boolean isSupertypeBlocked(Class<?> type, ReflectionAccessFilter filter) {\n    Class<?> c = type;\n    while (c != Object.class) {\n        if (filter.check(c) == FilterResult.BLOCK_ALL) return true;\n        c = c.getSuperclass();\n    }\n    return false;\n}","typeGuard":null,"tryCatchPattern":"try {\n    String json = gson.toJson(obj);\n} catch (JsonIOException e) {\n    if (e.getMessage().contains(\"ReflectionAccessFilter does not permit\")) {\n        // fall back to a manually registered TypeAdapter for this type\n    }\n}","preventionTips":["Register custom TypeAdapters for types whose supertypes are blocked by a ReflectionAccessFilter","Test serialization of all domain types after adding a ReflectionAccessFilter","Use BLOCK_INACCESSIBLE instead of BLOCK_ALL when you only need to prevent illegal-access warnings"],"tags":["reflection","access-filter","security","inheritance"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}