Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSON parse nil error #982

Closed
mfpiccolo opened this issue Jul 14, 2015 · 3 comments
Closed

JSON parse nil error #982

mfpiccolo opened this issue Jul 14, 2015 · 3 comments

Comments

@mfpiccolo
Copy link

Crystal 0.7.4
I am trying to parse an escaped json string.

response_hash = JSON::Parser.new("{\"response\":{\"domain_data\":\"somedata\"}}").parse
# this works
pp response_hash # response_hash = {"response" => {"domain_data" => "somedata"}}
pp response_hash.class # response_hash.class = Hash(String, JSON::Type)
# these break
response_hash["response"] # undefined method '[]' for Nil
response_hash.to_h # undefined method 'to_h' for Nil

http://play.crystal-lang.org/#/r/72m

@jhass
Copy link
Member

jhass commented Jul 14, 2015

That is expected, the compiler has no way of figuring out what the parser will return at runtime, everything is possible, including nil.

require "json"

json = JSON.parse("{\"response\":{\"domain_data\":\"somedata\"}}")
p typeof(json) #=> (Nil | String | Int64 | Float64 | Bool | Hash(String, JSON::Type) | Array(JSON::Type))

http://play.crystal-lang.org/#/r/72n

If you're sure about the structure you can cast:

require "json"

json = JSON.parse("{\"response\":{\"domain_data\":\"somedata\"}}")

casted = json as Hash
p casted["response"]

http://play.crystal-lang.org/#/r/72o

Or better yet use json_mapping:

require "json"

class DomainData
  json_mapping({
    domain_data: String
  })
end

class Response
  json_mapping({
    response: DomainData
   })
end

response = Response.from_json("{\"response\":{\"domain_data\":\"somedata\"}}")
p response.response.domain_data

http://play.crystal-lang.org/#/r/72p

If you're unsure you have to use runtime checks:

require "json"

json = JSON.parse("{\"response\":{\"domain_data\":\"somedata\"}}")

if json.is_a? Hash
  data = json["response"]
  if data.is_a? Hash
    p data["domain_data"]
  end
end

http://play.crystal-lang.org/#/r/72q

@jhass
Copy link
Member

jhass commented Jul 14, 2015

Oh and your working examples work because all elements in the union respond to the .inspect method as well as the .class method.

@mfpiccolo
Copy link
Author

👍 Thanks @jhass

asterite added a commit that referenced this issue Jul 19, 2015
…ype is different than the type that's missing the method. Related to #1008. Related to #982.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants