{"record":{"id":"b0696511cd9bb954","repo":"HMCL-dev/HMCL","slug":"json-tostring","errorCode":null,"errorMessage":"json.toString()","messagePattern":"json\\.toString\\(\\)","errorType":"validation","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/java/JavaLocalFiles.java","lineNumber":98,"sourceCode":"    public static class Serializer implements JsonSerializer<Local>, JsonDeserializer<Local> {\n\n        @Override\n        public JsonElement serialize(Local src, Type typeOfSrc, JsonSerializationContext context) {\n            JsonObject obj = new JsonObject();\n            obj.addProperty(\"type\", src.getType());\n            if (src instanceof LocalFile) {\n                obj.addProperty(\"sha1\", ((LocalFile) src).getSha1());\n                obj.addProperty(\"size\", ((LocalFile) src).getSize());\n            } else if (src instanceof LocalLink) {\n                obj.addProperty(\"target\", ((LocalLink) src).getTarget());\n            }\n            return obj;\n        }\n\n        @Override\n        public Local deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {\n            if (!json.isJsonObject())\n                throw new JsonParseException(json.toString());\n\n            JsonObject obj = json.getAsJsonObject();\n            if (!obj.has(\"type\"))\n                throw new JsonParseException(json.toString());\n\n            String type = obj.getAsJsonPrimitive(\"type\").getAsString();\n\n            try {\n                switch (type) {\n                    case \"file\": {\n                        String sha1 = obj.getAsJsonPrimitive(\"sha1\").getAsString();\n                        long size = obj.getAsJsonPrimitive(\"size\").getAsLong();\n                        return new LocalFile(sha1, size);\n                    }\n                    case \"directory\": {\n                        return new LocalDirectory();\n                    }\n                    case \"link\": {","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/java/JavaLocalFiles.java#L80-L116","documentation":"The Gson deserializer for JavaLocalFiles.Local requires the JSON element to be an object; a JsonParseException wrapping json.toString() is thrown when the element is an array, string, number, boolean, or null. This is a shape guard before reading the polymorphic `type` discriminator. It indicates corrupt or malformed data in a file describing a local Java installation entry.","triggerScenarios":"Gson deserializing a JSON value that is not an object (e.g. a bare string, array, or null literal) into type JavaLocalFiles.Local via the Serializer.deserialize adapter.","commonSituations":"A hand-edited or corrupted java-related JSON file (java repositories / custom runtime lists) where an entry was replaced by a scalar or array; an older schema version that stored entries differently; a truncation or merge conflict that broke the JSON structure.","solutions":["Open the JSON file and fix the malformed entry so it is an object with a `type` field (\"file\", \"directory\", or \"link\").","Restore the file from backup or delete it so the library regenerates defaults.","Validate the whole file with a JSON linter/schema check before loading it in the app.","If generating such files programmatically, always serialize through JavaLocalFiles.Serializer rather than writing raw JSON."],"exampleFix":"// before\n\"java\": \"path/to/jdk\"\n// after\n\"java\": { \"type\": \"file\", \"sha1\": \"...\", \"size\": 12345 }","handlingStrategy":"validation","validationCode":"JsonElement el = JsonParser.parseString(raw);\nif (!el.isJsonObject()) {\n    throw new IllegalArgumentException(\"entry must be a JSON object, got: \" + el);\n}","typeGuard":null,"tryCatchPattern":"try {\n    Local local = gson.fromJson(raw, JavaLocalFiles.Local.class);\n} catch (JsonParseException e) {\n    LOG.warning(\"Malformed local-java entry (must be an object with type): \" + e.getMessage());\n    // skip entry or restore from backup\n}","preventionTips":["Validate JSON files with a schema/linter before loading.","Only produce these entries via JavaLocalFiles.Serializer.serialize, never raw string building.","Back up java metadata files before hand-editing.","Handle null/array/string JSON gracefully when pre-processing unknown input."],"tags":["gson","json","deserialization","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}