{"id":"a7e0864593a73203","repo":"google/gson","slug":"reflectionaccessfilter-does-not-permit-using-refle-a7e086","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 \" \\+ raw \\+ \" \\(supertype of \" \\+ originalRaw \\+ \"\\)\\. 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/8b8628c65699bc4421696183c62ae0c1b9b281dc/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java#L322-L358","documentation":"Thrown when a ReflectionAccessFilter returns BLOCK_ALL for a supertype encountered while scanning inherited fields of a subtype. Unlike the BLOCK_INACCESSIBLE case, this fully prohibits any reflection on that supertype, so Gson cannot even enumerate its fields. Raised as a JsonIOException in getBoundFields (line 340).","triggerScenarios":"A subclass is being serialized/deserialized and Gson walks up to a parent class for which a registered ReflectionAccessFilter returns FilterResult.BLOCK_ALL. Triggered only when the supertype declares at least one field (fields.length > 0) at line 336.","commonSituations":"Security hardening that blocks reflection on framework base classes (e.g., java.*, javax.*, Spring proxies); JPMS setups blocking access to external module types in the hierarchy; serialization of generated/interceptor subclasses whose parent lives in a restricted library.","solutions":["Register a TypeAdapter for the concrete subtype so the reflective hierarchy walk is skipped.","Adjust the filter to return ALLOW or BLOCK_INACCESSIBLE instead of BLOCK_ALL for the supertype.","Move the inherited fields into a type the filter permits, or flatten the hierarchy.","Compose the object with a separate DTO instead of inheriting from a restricted base class."],"exampleFix":"// before\n.addReflectionAccessFilter((c) ->\n    c.getType().getPackage().getName().startsWith(\"com.lib.\")\n        ? FilterResult.BLOCK_ALL : FilterResult.ALLOW)\n// serializing subclass of com.lib.Base throws\n\n// after: allow or register adapter\n.registerTypeAdapter(MySub.class, new MySubAdapter())","handlingStrategy":"validation","validationCode":"// Pre-check that no supertype of T is BLOCK_ALL\nfor (Class<?> s = T.class.getSuperclass(); s != null && s != Object.class; s = s.getSuperclass()) {\n  FilterResult r = myFilter.apply(new ReflectionAccessFilter.FilterContext(s));\n  if (r == FilterResult.BLOCK_ALL && s.getDeclaredFields().length > 0) {\n    throw new IllegalStateException(\"Supertype blocked: \" + s);\n  }\n}","typeGuard":"null","tryCatchPattern":"try {\n  gson.toJson(obj);\n} catch (JsonIOException e) {\n  if (e.getMessage().contains(\"(supertype of\")) {\n    // register adapter for obj.getClass() and retry\n  } else throw e;\n}","preventionTips":["Register TypeAdapters for any subclass of a framework base class.","Document the filter policy and which packages are blocked.","Avoid inheriting from restricted third-party classes in serialized models.","Use composition (DTO wrapping) instead of inheritance from blocked types."],"tags":["gson","reflection","access-filter","inheritance","supertype"],"analyzedSha":"8b8628c65699bc4421696183c62ae0c1b9b281dc","analyzedAt":"2026-08-04T19:12:22.202Z","schemaVersion":2}