{"id":"2b82a67a0563804f","repo":"google/gson","slug":"reflectionaccessfilter-does-not-permit-using-refle","errorCode":null,"errorMessage":"ReflectionAccessFilter does not permit using reflection for \" + raw + \". Register a TypeAdapter for this type or adjust the access filter.","messagePattern":"ReflectionAccessFilter does not permit using reflection for \" \\+ raw \\+ \"\\. 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":145,"sourceCode":"          return null;\n        }\n\n        @Override\n        public void write(JsonWriter out, T value) throws IOException {\n          out.nullValue();\n        }\n\n        @Override\n        public String toString() {\n          return \"AnonymousOrNonStaticLocalClassAdapter\";\n        }\n      };\n    }\n\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              + \". Register a TypeAdapter for this type or adjust the access filter.\");\n    }\n    boolean blockInaccessible = filterResult == FilterResult.BLOCK_INACCESSIBLE;\n\n    // If the type is actually a Java Record, we need to use the RecordAdapter instead. This will\n    // always be false on JVMs that do not support records.\n    if (ReflectionHelper.isRecord(raw)) {\n      @SuppressWarnings(\"unchecked\")\n      TypeAdapter<T> adapter =\n          (TypeAdapter<T>)\n              new RecordAdapter<>(\n                  raw, getBoundFields(gson, type, raw, blockInaccessible, true), blockInaccessible);\n      return adapter;\n    }\n\n    ObjectConstructor<T> constructor = constructorConstructor.get(type, true);","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/google/gson/blob/8b8628c65699bc4421696183c62ae0c1b9b281dc/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java#L127-L163","documentation":"Thrown by ReflectiveTypeAdapterFactory.create() as a JsonIOException when a registered ReflectionAccessFilter returns FilterResult.BLOCK_ALL for the type being adapted. Gson refuses to use reflection (field access) for that class and requires either an explicit TypeAdapter or an adjustment to the filter. This is a security-hardening mechanism to prevent reflection on sensitive types.","triggerScenarios":"Registering a ReflectionAccessFilter via GsonBuilder.addReflectionAccessFilter(...) that blocks a type, then attempting to serialize/deserialize that type (or a type whose fields reference it) without a custom TypeAdapter. The filter's filterCheck returns BLOCK_ALL and Gson has no other adapter to fall back to.","commonSituations":"Security reviews that add filters blocking platform or internal classes; blocking third-party library types that the model transitively references; overly-broad filters (e.g. blocking all java.* or a package) catching application types; upgrading Gson and adopting the reflection filter feature without providing adapters for blocked types.","solutions":["Register a custom TypeAdapter (or JsonSerializer/JsonDeserializer) for the blocked type via GsonBuilder.registerTypeAdapter(...).","Adjust the ReflectionAccessFilter to return ALLOW for this type, or BLOCK_INACCESSIBLE instead of BLOCK_ALL if partial reflection is acceptable.","Annotate the type with @JsonAdapter(SomeAdapter.class) so Gson uses your adapter without reflection.","Narrow the filter's scope so it only blocks the intended sensitive types."],"exampleFix":"// before: filter blocks java.util.Currency, no adapter registered\nGson gson = new GsonBuilder()\n  .addReflectionAccessFilter((c, t) -> t.getName().startsWith(\"java.\") ? FilterResult.BLOCK_ALL : FilterResult.ALLOW)\n  .create();\ngson.toJson(myCurrency); // throws JsonIOException\n\n// after: register an adapter for the blocked type\nGson gson = new GsonBuilder()\n  .addReflectionAccessFilter((c, t) -> t.getName().startsWith(\"java.\") ? FilterResult.BLOCK_ALL : FilterResult.ALLOW)\n  .registerTypeAdapter(Currency.class, new CurrencyAdapter())\n  .create();\ngson.toJson(myCurrency);","handlingStrategy":"fallback","validationCode":"// Provide a TypeAdapter for any type you block via ReflectionAccessFilter\nGson gson = new GsonBuilder()\n  .addReflectionAccessFilter((c, t) -> isBlocked(t) ? FilterResult.BLOCK_ALL : FilterResult.ALLOW)\n  .registerTypeAdapter(MyBlockedType.class, new MyBlockedTypeAdapter())\n  .create();","typeGuard":null,"tryCatchPattern":"try {\n  return gson.toJson(obj);\n} catch (JsonIOException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"ReflectionAccessFilter does not permit\")) {\n    // build a fresh Gson without the blocking filter, or with an adapter for the type\n    Gson fallback = buildGsonWithAdapterFor(obj.getClass());\n    return fallback.toJson(obj);\n  }\n  throw e;\n}","preventionTips":["For every type a ReflectionAccessFilter blocks, register an explicit TypeAdapter.","Prefer BLOCK_INACCESSIBLE over BLOCK_ALL when you only need to avoid setAccessible on internals.","Document the filter policy and the adapters required for blocked types in your project."],"tags":["json","gson","reflection","security","access-filter","type-adapter"],"analyzedSha":"8b8628c65699bc4421696183c62ae0c1b9b281dc","analyzedAt":"2026-08-04T19:12:22.202Z","schemaVersion":2}