在Crystal语言中从JSON解析Entry类对象时出现解析错误
解决JSON解析错误:Expected BeginObject but was String
问题根源
解析失败主要有两个核心原因:
- 必填字段缺失:JSON中第二个条目缺少
isComplete、inProgress、priority字段,但你的Entry类将这些定义为必填属性,导致反序列化流程中断。 - 日期格式不兼容:JSON中的
_date是"Mon Apr 05 2021"格式的字符串,而Crystal默认的Time反序列化仅支持ISO 8601标准格式(如"2021-04-05T00:00:00Z")。
修正后的代码
require "json" enum Priority Low # 1 Medium # 2 High # 3 end class Entry include JSON::Serializable property _id : UInt32 property _date : Time property _timestamp : UInt64 property description : String property isStarred : Bool property boards : Array(String) property _isTask : Bool # 为缺失字段添加默认值,兼容JSON中无对应键的情况 property isComplete : Bool = false property inProgress : Bool = false property priority : Priority = Priority::Low # 自定义日期解析逻辑,处理非标准格式的日期字符串 def self._date_from_json(value : JSON::PullParser) : Time date_str = value.read_string Time.parse(date_str, "%a %b %d %Y", location: Time::Location::UTC) end end
解析示例
现在可以正常解析目标JSON数据:
json_data = <<-JSON { "2": { "_id": 2, "_date": "Mon Apr 05 2021", "_timestamp": 1617654662313, "description": "Some text", "isStarred": true, "boards": [ "@3.0", "@Some-day" ], "_isTask": false, "isComplete": false, "inProgress": false, "priority": 1 }, "7": { "_id": 7, "_date": "Mon Apr 05 2021", "_timestamp": 1617658197721, "description": "Some text too", "isStarred": false, "boards": [ "@Some-day" ], "_isTask": false } } JSON entries = Hash(String, Entry).from_json(json_data) entries.each do |key, entry| puts "条目#{key}:#{entry.description},日期:#{entry._date}" end
关键说明
- 默认值设置:给可选字段添加默认值,确保JSON中无对应键时仍能完成反序列化。
- 自定义日期解析:通过
_date_from_json方法手动适配非标准日期格式,将字符串转换为合法的Time对象。
内容的提问来源于stack exchange,提问作者somenxavier
相关产品推荐
相关产品推荐

