{"id":"70e0f7704eec7118","repo":"google/gson","slug":"failed-parsing-s-as-currency-at-path","errorCode":null,"errorMessage":"Failed parsing '\" + s + \"' as Currency; at path \" + in.getPreviousPath()","messagePattern":"Failed parsing '\" \\+ s \\+ \"' as Currency; at path \" \\+ in\\.getPreviousPath\\(\\)","errorType":"exception","errorClass":"JsonSyntaxException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java","lineNumber":813,"sourceCode":"        }\n\n        @Override\n        public void write(JsonWriter out, UUID value) throws IOException {\n          out.value(value == null ? null : value.toString());\n        }\n      };\n\n  public static final TypeAdapterFactory UUID_FACTORY = newFactory(UUID.class, UUID);\n\n  public static final TypeAdapter<Currency> CURRENCY =\n      new TypeAdapter<Currency>() {\n        @Override\n        public Currency read(JsonReader in) throws IOException {\n          String s = in.nextString();\n          try {\n            return Currency.getInstance(s);\n          } catch (IllegalArgumentException e) {\n            throw new JsonSyntaxException(\n                \"Failed parsing '\" + s + \"' as Currency; at path \" + in.getPreviousPath(), e);\n          }\n        }\n\n        @Override\n        public void write(JsonWriter out, Currency value) throws IOException {\n          out.value(value.getCurrencyCode());\n        }\n      }.nullSafe();\n  public static final TypeAdapterFactory CURRENCY_FACTORY = newFactory(Currency.class, CURRENCY);\n\n  /**\n   * An abstract {@link TypeAdapter} for classes whose JSON serialization consists of a fixed set of\n   * integer fields. That is the case for {@link Calendar} and the legacy serialization of various\n   * {@code java.time} types.\n   */\n  abstract static class IntegerFieldsTypeAdapter<T> extends TypeAdapter<T> {\n    private final List<String> fields;","sourceCodeStart":795,"sourceCodeEnd":831,"githubUrl":"https://github.com/google/gson/blob/8b8628c65699bc4421696183c62ae0c1b9b281dc/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java#L795-L831","documentation":"Gson's Currency TypeAdapter calls Currency.getInstance(s), which only accepts ISO 4217 currency codes. Any string that is not a recognized 3-letter code throws IllegalArgumentException, wrapped as JsonSyntaxException. The adapter is nullSafe so null is handled, but malformed strings are not.","triggerScenarios":"Deserializing a JSON string into a Currency field where the value is not a valid ISO 4217 code (wrong length, lowercase, deprecated code like 'ITL', or a symbol like '$').","commonSituations":"Producer emits lowercase 'usd', a locale-specific symbol, a deprecated/legacy currency code, or a custom code that Currency.getInstance does not recognize.","solutions":["Normalize the value to an uppercase ISO 4217 code before deserialization.","Register a custom TypeAdapter<Currency> that uppercases the string and maps legacy codes to their successors.","Correct the upstream producer to emit valid ISO 4217 codes."],"exampleFix":"// before\nCurrency c = gson.fromJson(\"\\\"usd\\\"\", Currency.class);\n\n// after\nGson gson = new GsonBuilder().registerTypeHierarchyAdapter(Currency.class, new JsonDeserializer<Currency>() {\n    @Override public Currency deserialize(JsonElement j, Type t, JsonDeserializationContext c) {\n        return Currency.getInstance(j.getAsString().toUpperCase(Locale.ROOT));\n    }\n}).create();","handlingStrategy":"validation","validationCode":"boolean isParsableCurrency(String s) {\n  if (s == null || s.length() != 3) return false;\n  try { Currency.getInstance(s.toUpperCase(Locale.ROOT)); return true; } catch (IllegalArgumentException e) { return false; }\n}","typeGuard":"static boolean isIsoCurrency(String s) {\n  return s != null && s.matches(\"[A-Za-z]{3}\") && Currency.getAvailableCurrencies().stream().anyMatch(c -> c.getCurrencyCode().equalsIgnoreCase(s));\n}","tryCatchPattern":"try {\n  Currency c = gson.fromJson(json, Currency.class);\n} catch (JsonSyntaxException e) {\n  // map legacy/custom codes, or reject the record\n}","preventionTips":["Upper-case and length-check currency strings at the boundary.","Maintain a mapping table for legacy currency codes if your data contains them.","Register a normalization TypeAdapter<Currency> globally."],"tags":["gson","deserialization","currency","i18n","json"],"analyzedSha":"8b8628c65699bc4421696183c62ae0c1b9b281dc","analyzedAt":"2026-08-04T19:12:22.202Z","schemaVersion":2}