7

I'm using Scala & Argonaut, trying to parse the following JSON:

[
    {
        "name": "apple",
        "type": "fruit",
        "size": 3
    },
    {
        "name": "jam",
        "type": "condiment",
        "size": 5
    },
    {
        "name": "beef",
        "type": "meat",
        "size": 1
    }
]

And struggling to work out how to iterate and extract the values into a List[MyType] where MyType will have name, type and size properties.

I will post more specific code soon (i have tried many things), but basically I'm looking to understand how the cursor works, and how to iterate through arrays etc. I have tried using \\ (downArray) to move to the head of the array, then :->- to iterate through the array, then --\ (downField) is not available (at least IntelliJ doesn't think so). So the question is how do i:

  • navigate to the array
  • iterate through the array (and know when I'm done)
  • extract string, integer etc. values for each field - jdecode[String]? as[String]?
2
  • What did you try? Can you show your code? Commented Mar 18, 2014 at 15:33
  • First of all, your JSON is invalid. Maybe this causes errors? Or what's your plan? See jsonlint.com for JSON validation. Commented Mar 18, 2014 at 16:25

3 Answers 3

6

The easiest way to do this is to define a codec for MyType. The compiler will then happily construct a decoder for List[MyType], etc. I'll use a plain class here (not a case class) to make it clear what's happening:

class MyType(val name: String, val tpe: String, val size: Int)

import argonaut._, Argonaut._

implicit def MyTypeCodec: CodecJson[MyType] = codec3(
  (name: String, tpe: String, size: Int) => new MyType(name, tpe, size),
  (myType: MyType) => (myType.name, myType.tpe, myType.size)
)("name", "type", "size")

codec3 takes two parameter lists. The first has two parameters, which allow you to tell how to create an instance of MyType from a Tuple3 and vice versa. The second parameter list lets you specify the names of the fields.

Now you can just write something like the following (if json is your string):

Parse.decodeValidation[List[MyType]](json)

And you're done.

Sign up to request clarification or add additional context in comments.

1 Comment

I would suggest to use casecodec instead of codec implicit def MyTypeCodec = casecodec3(MyType.apply, MyType.unapply)("name", "type", "size")
0

Since you don't need to encode and are only looking at decoding, you can do as suggested by Travis, but by implementing another implicit: MyTypeDecodeJson

implicit def MyTypeDecodeJson: DecodeJson[MyType] = DecodeJson(
    raw => for {
    name     <- raw.get[String]("name")
    type     <- raw.get[String]("type")
    size     <- raw.get[Int]("size")
  } yield MyType(name, type, size))

Then to parse your list:

Parse.decodeValidation[List[MyType]](jsonString)

Comments

0

Assuming MyType is a case class, the following works too:

case class MyType(name: String, type: String, size: Int)

object MyType {
    implicit val createCodecJson: CodecJson[MyType] = CodecJson.casecodec3(apply, unapply)(
        "name",
        "type",
        "size"
    )
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.