0

I'm very new to Argonaut (which I'm forced to use since the codebase is older, using an old version of scalaz, and we have no intentions to update it since we're rewriting this outdated code from scratch), and I'm trying to find a way to dump some data into JSON.

I have an case class called Magnitude. For simplicity, define it as:

case class Magnitude(bandname: String)

What I want is a function that takes in a List[Magnitude] and outputs Json that I can chain together with other Json.

Right now, I'm doing:

  def magnitudeFields(magnitudes: List[Magnitude]): Json =
    magnitudes.foldLeft(jEmptyObject) { case (j, m) =>
      ("bandName" := m.bandname) ->: j
    }

and then say I have an instantiation of List[Magnitude]:

val magList = List(Magnitude("R"), Magnitude("J"), Magnitude("_uc"), Magnitude("K"))

when I call magnitudeFields(magList) in a call like:

... previousJsonData ->: ('magnitudes' := magnitudeFields(magList)) ->: nextJsonData ...

I only receive the bandName: K and the other three preceding entries are not part of the JSON output by the function:

"magnitudes" : {
                    "bandName" : "K"
                  },

instead of what I want, which is:

"magnitudes" : {
                    "bandName" : "R"
                    "bandName" : "J"
                    "bandName" : "_uc"
                    "bandName" : "K"
                  },

Any help would be greatly appreciated. I suspect I'm doing something wrong by using jEmptyObject as the default to the foldLeft and may need to use something like jArray at some point (with the function returning List[Json] instead, but I'm not sure how I should be doing this.

Sebastian
  • 715
  • 6
  • 13
  • 4
    What you want is not valid JSON. You indeed want to use an array at some point. – Gaël J Jun 24 '21 at 18:55
  • Are there any examples of this anywhere? This is some throwaway code that we need ASAP. – Sebastian Jun 24 '21 at 19:55
  • I should add this is a one-time servlet that we want to eventually eliminate for use in a prototype, so elegance isn't as important as functionality. – Sebastian Jun 24 '21 at 19:58
  • Thanks for pointing that out, @GaëlJ. I know the idea behind JSON but have never actually used it directly before, so now I see that yes, my syntax is completely wrong here. – Sebastian Jun 26 '21 at 01:28

1 Answers1

1

You should just define an EncodeJson instance for Magnitude and let Argonaut deal with the rest of the logic:

import argonaut._, Argonaut._

case class Magnitude(bandname: String)

object Magnitude {
  implicit val encode: EncodeJson[Magnitude] =
    EncodeJson { m =>
      jSingleObject("bandName", jString(m.bandname))
    }
}

object Main {
  val magList = List(Magnitude("R"), Magnitude("J"), Magnitude("_uc"), Magnitude("K"))

  def main(args: Array[String]): Unit = {
    val prefix = "prefix" := "prefix"
    val suffix = "suffix" := "suffix"
    val json = prefix ->: ("magnitudes" := magList) ->: suffix ->: jEmptyObject

    println(json.asJson.spaces2)
    //{
    //  "prefix" : "prefix",
    //  "magnitudes" : [
    //  {
    //    "bandName" : "R"
    //  },
    //  {
    //    "bandName" : "J"
    //  },
    //  {
    //    "bandName" : "_uc"
    //  },
    //  {
    //    "bandName" : "K"
    //  }
    //  ],
    //  "suffix" : "suffix"
    //}
  }
}
Ionuț G. Stan
  • 176,118
  • 18
  • 189
  • 202
  • Thanks. I've never used Argonaut before so this taught me a lot I didn't know. I really appreciate it! – Sebastian Jun 26 '21 at 01:30
  • @Sebastian, glad it helped you. Circe, which is one of the more popular JSON libs in Scala nowadays, is actually a fork of Argonaut. Argonaut is not a bad library at all actually. – Ionuț G. Stan Jun 26 '21 at 11:42
  • Thanks! We're using Circe and Cats (instead of Argonaut and scalaz) with our rewrite, but this is ancient spaghetti code with a codebase that's over 20 years old now and we're not upgrading libs or adding new dependencies. The data model is absurdly complicated, which is why this has been so laborious. – Sebastian Jun 30 '21 at 12:59