ไลบรารี JSON ใดที่จะใช้ใน Scala [ปิด]


126

ฉันต้องการสร้างสตริง JSON สิ่งนี้:

[
  { 'id': 1, 'name': 'John'},
  { 'id': 2, 'name': 'Dani'}
]

val jArray = JsArray();
jArray += (("id", "1"), ("name", "John"))
jArray += (("id", "2"), ("name", "Dani"))
println(jArray.dump)

ฉันต้องสามารถเพิ่มแถวในjArrayสิ่งที่ต้องการjArray += ...

ห้องสมุด / วิธีแก้ปัญหาที่ใกล้เคียงที่สุดคืออะไร?


คำตอบ:


219

น่าเสียดายที่การเขียนไลบรารี JSON เป็นเวอร์ชันของชุมชน Scala ในการเข้ารหัสแอปรายการสิ่งที่ต้องทำ

มีทางเลือกค่อนข้างหลากหลาย ฉันไม่เรียงลำดับตามลำดับโดยเฉพาะพร้อมหมายเหตุ:

  1. parsing.json.JSON - คำเตือนไลบรารีนี้สามารถใช้ได้ถึง Scala เวอร์ชัน 2.9.x เท่านั้น (ลบออกในเวอร์ชันที่ใหม่กว่า)
  2. spray-json - สกัดจากโครงการ Spray
  3. Jerkson ± - เตือนไลบรารีที่ดี (สร้างขึ้นบน Java Jackson) แต่ตอนนี้ละทิ้ง หากคุณจะใช้สิ่งนี้ให้ทำตามตัวอย่างของโครงการScaldingและใช้ส้อม backchat.io
  4. sjson - โดย Debasish Ghosh
  5. lift-json - สามารถใช้แยกจากโครงการ Lift
  6. json4s 💣§ ± - การดึงข้อมูลจาก lift-json ซึ่งพยายามสร้าง JSON AST มาตรฐานซึ่งไลบรารี JSON อื่น ๆ สามารถใช้ได้ รวมถึงการใช้งานที่สนับสนุนโดยแจ็คสัน
  7. Argonaut 💣§ - ไลบรารี JSON แบบ FP สำหรับ Scala จากผู้ที่อยู่เบื้องหลัง Scalaz
  8. play-json ± - พร้อมใช้งานแบบสแตนด์อโลนแล้วโปรดดูรายละเอียดคำตอบนี้
  9. dijon - ไลบรารี JSON ที่สะดวกปลอดภัยและมีประสิทธิภาพใช้jsoniter-scalaภายใต้ประทุน
  10. sonofjson - ไลบรารี JSON มีเป้าหมายเพื่อ API ที่เรียบง่ายสุด ๆ
  11. Jawn - ไลบรารี JSON โดย Erik Osheim มุ่งเป้าไปที่ความเร็วของแจ็คสันหรือเร็วกว่า
  12. Rapture JSON ± - ฟรอนต์เอนด์ JSON ซึ่งสามารถใช้ 2, 4, 5, 6, 7, 11 หรือ Jackson เป็นแบ็คเอนด์
  13. Circe 💣 - ส้อมของ Argonaut ที่สร้างขึ้นบนตัวแมวแทนที่จะเป็น scalaz
  14. jsoniter-scala - มาโคร Scala สำหรับการสร้างตัวแปลงสัญญาณ JSON ที่รวดเร็วเป็นพิเศษในเวลาคอมไพล์
  15. jackson-module-scala - โมดูลเสริมสำหรับJacksonเพื่อรองรับประเภทข้อมูลเฉพาะของ Scala
  16. หนอนเจาะ - CBOR มีประสิทธิภาพและ JSON (DE) อนุกรมที่สกาล่า

💣 = ไม่ได้แก้ไขช่องโหว่ด้านความปลอดภัย, § = มีการรวม Scalaz, ± = รองรับการทำงานร่วมกับ Jackson JsonNode

ในSnowplowเราใช้ json4s กับส่วนหลังของ Jackson เรามีประสบการณ์ที่ดีกับ Argonaut เช่นกัน


8
ไม่เป็นความจริงที่ว่า lift-json รวมอยู่ในโปรเจ็กต์ LIft ที่ใหญ่กว่าคุณสามารถพึ่งพาลิฟท์ - เจสันได้และไม่มีอะไรอื่นจากโปรเจ็กต์ลิฟต์ที่จะมาถึงโปรเจ็กต์ของคุณ
fmpwizard

3
@AlexDean: อะไรที่แย่มากเกี่ยวกับ parsing.json.JSON?
Matthias Braun

ดูเหมือนว่า play-json จะออกพร้อมกับ Play 2.2 และคุณสามารถใช้งานได้แล้ว: mandubian.com/2013/02/21/play-json-stand-alone
Christiaan

2
@BjornTipling - จุดที่ดีไม่พบการกล่าวถึงใด ๆ ในตอนนี้ว่ามันถูกเลิกใช้ใน 2.11 ลบความคิดเห็นนั้นออก
Alex Dean

2
รายการควรใส่แจ็คสันโมดูล - สกาล่าไว้ด้านบนซึ่งมีประสิทธิภาพที่ดีที่สุดสำหรับประสิทธิภาพความเรียบง่ายการบำรุงรักษาและการสนับสนุน
lyomi

17

Lift-json อยู่ที่เวอร์ชัน 2.6 และใช้งานได้ดีมาก (และได้รับการสนับสนุนเป็นอย่างดีผู้ดูแลระบบพร้อมที่จะแก้ไขข้อบกพร่องที่ผู้ใช้อาจพบเสมอคุณสามารถดูตัวอย่างการใช้งานได้ในที่เก็บ github

ผู้ดูแล (Joni Freeman) สามารถเข้าถึงได้ตลอดเวลาในรายชื่อผู้รับจดหมายของ Lift นอกจากนี้ยังมีผู้ใช้รายอื่นในรายชื่อผู้รับจดหมายที่มีประโยชน์มากเช่นกัน

ดังที่ @Alexey ชี้ให้เห็นหากคุณต้องการใช้ไลบรารีกับ Scala เวอร์ชันอื่นให้พูด2.11.xเปลี่ยนscalaVersionและใช้%%ดังนี้:

scalaVersion := "2.11.5" 

"net.liftweb" %% "lift-json" % "2.6"

คุณสามารถตรวจสอบเว็บไซต์liftweb.netเพื่อค้นหาเวอร์ชันล่าสุดเมื่อเวลาผ่านไป


3
ฉันใช้ lift-json ด้วยและสามารถรับรองได้ว่าเป็นห้องสมุดที่ยอดเยี่ยม ทำให้ทั้งการแยกวิเคราะห์และสร้าง / ซีเรียลไลซ์ JSON ทำได้ง่ายมาก
Dan Simon

1
+1 สำหรับ "net.liftweb"% "lift-json_2.10"% "2.5.1"
Dylan Hogg

2
และสำหรับ Scala 2.11: "net.liftweb"% "lift-json_2.11"% "2.6-M4"
Alexey

15

ฉันขอแนะนำให้ใช้jerksonซึ่งรองรับการแปลงประเภทพื้นฐานส่วนใหญ่:

scala> import com.codahale.jerkson.Json._

scala> val l = List( 
                 Map( "id" -> 1, "name" -> "John" ),
                 Map( "id" -> 2, "name" -> "Dani")
               )

scala> generate( l )

res1: String = [{"id":1,"name":"John"},{"id":2,"name":"Dani"}]

2
นอกจากนี้ยังมีการสนับสนุนที่ยอดเยี่ยมสำหรับคลาสเคสที่สามารถจัดการ JSON ที่สวยงามและปลอดภัยได้
Thomas Lockney

9
ห้องสมุดนี้ถูกละทิ้งโดยผู้เขียนมีทางเลือกอื่นหรือไม่?
zjffdu

1
อย่าลืมเกี่ยวกับrapture.ioซึ่ง "เป็นกลุ่มของไลบรารี Scala ที่ให้บริการ Scala API ที่สวยงามสำหรับงานเขียนโปรแกรมทั่วไปเช่นการทำงานกับ I / O การเข้ารหัสและการประมวลผล JSON & XML"
Piohen

12

หมายเลข 7 ในรายการคือแจ็คสันไม่ใช้ Jerkson มีการสนับสนุนวัตถุ Scala (คลาสเคส ฯลฯ )

ด้านล่างนี้เป็นตัวอย่างวิธีการใช้งาน

object MyJacksonMapper extends JacksonMapper
val jsonString = MyJacksonMapper.serializeJson(myObject)
val myNewObject = MyJacksonMapper.deserializeJson[MyCaseClass](jsonString)

สิ่งนี้ทำให้ง่ายมาก นอกจากนี้ XmlSerializer และการรองรับ JAXB Annotations นั้นมีประโยชน์มาก

โพสต์บล็อกนี้อธิบายถึงการใช้งานกับ JAXB Annotations และ Play Framework

http://krasserm.blogspot.co.uk/2012/02/using-jaxb-for-xml-and-json-apis-in.html

นี่คือ JacksonMapper ปัจจุบันของฉัน

trait JacksonMapper {

  def jsonSerializer = {
    val m = new ObjectMapper()
    m.registerModule(DefaultScalaModule)
    m
  }

  def xmlSerializer = {
    val m = new XmlMapper()
    m.registerModule(DefaultScalaModule)
    m
  }

  def deserializeJson[T: Manifest](value: String): T = jsonSerializer.readValue(value, typeReference[T])
  def serializeJson(value: Any) = jsonSerializer.writerWithDefaultPrettyPrinter().writeValueAsString(value)
  def deserializeXml[T: Manifest](value: String): T = xmlSerializer.readValue(value, typeReference[T])
  def serializeXml(value: Any) = xmlSerializer.writeValueAsString(value)

  private[this] def typeReference[T: Manifest] = new TypeReference[T] {
    override def getType = typeFromManifest(manifest[T])
  }

  private[this] def typeFromManifest(m: Manifest[_]): Type = {
     if (m.typeArguments.isEmpty) { m.erasure }
     else new ParameterizedType {
       def getRawType = m.erasure

       def getActualTypeArguments = m.typeArguments.map(typeFromManifest).toArray

       def getOwnerType = null
     }
  }
}   

8

บางทีฉันอาจจะสายไปหน่อย แต่คุณควรลองใช้ json library จาก play framework คุณสามารถดูเอกสาร ในเวอร์ชัน 2.1.1 ปัจจุบันคุณไม่สามารถใช้แยกกันได้หากไม่มีการเล่น 2 ทั้งหมดดังนั้นการพึ่งพาจะมีลักษณะดังนี้:

val typesaferepo  = "TypeSafe Repo" at "http://repo.typesafe.com/typesafe/releases"
val play2 = "play" %% "play" % "2.1.1"

มันจะทำให้คุณมีกรอบการเล่นทั้งหมดพร้อมทุกสิ่งบนกระดาน

แต่อย่างที่ฉันรู้ว่าหนุ่ม ๆ จาก typesafe มีแผนที่จะแยกมันในรุ่น 2.2 ดังนั้นจึงมีplay-jsonแบบสแตนด์อโลนจาก 2.2-snapshot


2
FYI: ไลบรารี JSON ของ Play พร้อมใช้งานแล้วใน repo สแนปช็อตของtypesafe
Tvaroh

... ซึ่งคุณสามารถเพิ่มเช่นดังนั้น
bluenote10

ถูกใช้อย่างเป็นทางการในบทช่วยสอน sbt
serv-inc

5

คุณควรตรวจสอบGenson มันใช้งานได้และใช้งานง่ายกว่าทางเลือกอื่น ๆ ที่มีอยู่ใน Scala มันรวดเร็วมีคุณสมบัติมากมายและการทำงานร่วมกับ libs อื่น ๆ (jodatime, json4s DOM api ... )

ทั้งหมดนี้ไม่มีโค้ดที่ไม่จำเป็นเช่นนัย, ผู้อ่าน / นักเขียนที่กำหนดเองสำหรับกรณีพื้นฐาน, API ที่ไม่สามารถทำได้เนื่องจากตัวดำเนินการโอเวอร์โหลด ...

การใช้งานทำได้ง่ายเหมือน:

import com.owlike.genson.defaultGenson_

val json = toJson(Person(Some("foo"), 99))
val person = fromJson[Person]("""{"name": "foo", "age": 99}""")

case class Person(name: Option[String], age: Int)

คำเตือน: ฉันเป็นผู้เขียน Gensons แต่นั่นไม่ได้หมายความว่าฉันไม่ใช่เป้าหมาย :)


เขื่อนสวยมากความอัปยศมันมีปัญหาหนึ่งgithub.com/owlike/genson/issues/82
samthebest

5

นี่คือการใช้งานพื้นฐานของการเขียนแล้วอ่านjsonไฟล์โดยใช้json4s.

import org.json4s._
import org.json4s.jackson.JsonMethods._
import org.json4s.JsonDSL._
import java.io._
import scala.io.Source


object MyObject { def main(args: Array[String]) {

  val myMap = Map("a" -> List(3,4), "b" -> List(7,8))

  // writing a file 
  val jsonString = pretty(render(myMap))

  val pw = new PrintWriter(new File("my_json.json"))
  pw.write(jsonString)
  pw.close()

  // reading a file 
  val myString = Source.fromFile("my_json.json").mkString
  println(myString)

  val myJSON = parse(myString)

  println(myJSON)

  // Converting from JOjbect to plain object
  implicit val formats = DefaultFormats
  val myOldMap = myJSON.extract[Map[String, List[Int]]]

  println(myOldMap)
 }
}

4

Jawnเป็นไลบรารีตัวแยกวิเคราะห์ JSON ที่ยืดหยุ่นมากใน Scala นอกจากนี้ยังอนุญาตให้สร้าง AST แบบกำหนดเอง คุณเพียงแค่ต้องจัดหาลักษณะเล็ก ๆ น้อย ๆ เพื่อจับคู่กับ AST

ใช้งานได้ดีสำหรับโปรเจ็กต์ล่าสุดที่ต้องการการแยกวิเคราะห์ JSON เล็กน้อย


4

ดูเหมือนว่า Rapture จะหายไปในรายการคำตอบ สามารถหาได้จากhttp://rapture.io/และช่วยให้คุณ (เหนือสิ่งอื่นใด) เพื่อ:

  • เลือก JSON back-end ซึ่งมีประโยชน์มากหากคุณใช้อยู่แล้ว (ในการนำเข้า)
  • ตัดสินใจว่าคุณทำงานกับ Try, Future, Option, Either ฯลฯ หรือไม่ (รวมถึงการนำเข้าด้วย)
  • ทำงานจำนวนมากในโค้ดบรรทัดเดียว

ฉันไม่ต้องการคัดลอก / วางตัวอย่าง Rapture จากหน้านี้ Jon Pretty นำเสนอที่ดีเกี่ยวกับคุณสมบัติของ Rapture ที่ SBTB 2014: https://www.youtube.com/watch?v=ka5-OLJgybI


3

คำตอบ # 7 ของ @ AlaxDean Argonautเป็นคำตอบเดียวที่ฉันสามารถทำงานกับ sbt และ intellij ได้อย่างรวดเร็ว จริงๆแล้ว json4s ก็ใช้เวลาเพียงเล็กน้อย แต่การจัดการกับ AST ดิบไม่ใช่สิ่งที่ฉันต้องการ ฉันทำให้ argonaut ทำงานโดยใส่บรรทัดเดียวใน build.st ของฉัน:

libraryDependencies += "io.argonaut" %% "argonaut" % "6.0.1"

จากนั้นทดสอบง่ายๆเพื่อดูว่าฉันสามารถรับ JSON ได้หรือไม่:

package mytest


import scalaz._, Scalaz._
import argonaut._, Argonaut._

object Mytest extends App {

  val requestJson  =
    """
    {
      "userid": "1"
    }
    """.stripMargin

  val updatedJson: Option[Json] = for {
    parsed <- requestJson.parseOption
  } yield ("name", jString("testuser")) ->: parsed

  val obj = updatedJson.get.obj
  printf("Updated user: %s\n", updatedJson.toString())
  printf("obj : %s\n", obj.toString())
  printf("userid: %s\n", obj.get.toMap("userid"))
}

แล้ว

$ sbt
> run
Updated user: Some({"userid":"1","name":"testuser"})
obj : Some(object[("userid","1"),("name","testuser")])
userid: "1"

ตรวจสอบให้แน่ใจว่าคุณคุ้นเคยกับOptionซึ่งเป็นเพียงค่าที่สามารถเป็นโมฆะได้ (ฉันเดาว่าเป็นโมฆะ) Argonaut ใช้ประโยชน์จากScalazดังนั้นหากคุณเห็นสิ่งที่คุณไม่เข้าใจเช่นสัญลักษณ์\/(an หรือการทำงาน) อาจเป็น Scalaz


2

คุณสามารถลองสิ่งนี้: https://github.com/momodi/Json4Scala

มันง่ายและมีไฟล์ scala เพียงไฟล์เดียวที่มีโค้ดน้อยกว่า 300 บรรทัด

มีตัวอย่าง:

test("base") {
    assert(Json.parse("123").asInt == 123)
    assert(Json.parse("-123").asInt == -123)
    assert(Json.parse("111111111111111").asLong == 111111111111111l)
    assert(Json.parse("true").asBoolean == true)
    assert(Json.parse("false").asBoolean == false)
    assert(Json.parse("123.123").asDouble == 123.123)
    assert(Json.parse("\"aaa\"").asString == "aaa")
    assert(Json.parse("\"aaa\"").write() == "\"aaa\"")

    val json = Json.Value(Map("a" -> Array(1,2,3), "b" -> Array(4, 5, 6)))
    assert(json("a")(0).asInt == 1)
    assert(json("b")(1).asInt == 5)
}
test("parse base") {
    val str =
        """
          {"int":-123, "long": 111111111111111, "string":"asdf", "bool_true": true, "foo":"foo", "bool_false": false}
        """
    val json = Json.parse(str)
    assert(json.asMap("int").asInt == -123)
    assert(json.asMap("long").asLong == 111111111111111l)
    assert(json.asMap("string").asString == "asdf")
    assert(json.asMap("bool_true").asBoolean == true)
    assert(json.asMap("bool_false").asBoolean == false)
    println(json.write())
    assert(json.write().length > 0)
}
test("parse obj") {
    val str =
        """
           {"asdf":[1,2,4,{"bbb":"ttt"},432]}
        """
    val json = Json.parse(str)
    assert(json.asMap("asdf").asArray(0).asInt == 1)
    assert(json.asMap("asdf").asArray(3).asMap("bbb").asString == "ttt")
}
test("parse array") {
    val str =
        """
           [1,2,3,4,{"a":[1,2,3]}]
        """
    val json = Json.parse(str)
    assert(json.asArray(0).asInt == 1)
    assert(json(4)("a")(2).asInt == 3)
    assert(json(4)("a")(2).isInt)
    assert(json(4)("a").isArray)
    assert(json(4)("a").isMap == false)
}
test("real") {
    val str = "{\"styles\":[214776380871671808,214783111085424640,214851869216866304,214829406537908224],\"group\":100,\"name\":\"AO4614【金宏达电子】现货库存 质量保证 欢迎购买@\",\"shopgrade\":8,\"price\":0.59,\"shop_id\":60095469,\"C3\":50018869,\"C2\":50024099,\"C1\":50008090,\"imguri\":\"http://img.geilicdn.com/taobao10000177139_425x360.jpg\",\"cag\":50006523,\"soldout\":0,\"C4\":50006523}"
    val json = Json.parse(str)
    println(json.write())
    assert(json.asMap.size > 0)
}

ฉันชอบสิ่งนี้ - ยอดเยี่ยมสำหรับกรณีการใช้งานขนาดเล็ก - ไม่จำเป็นต้องมีไลบรารีใด ๆ
Samik R

2

ฉันใช้uPickleซึ่งมีข้อได้เปรียบใหญ่ที่จะจัดการคลาสเคสที่ซ้อนกันโดยอัตโนมัติ:

object SerializingApp extends App {

  case class Person(name: String, address: Address)

  case class Address(street: String, town: String, zipCode: String)

  import upickle.default._

  val john = Person("John Doe", Address("Elm Street 1", "Springfield", "ABC123"))

  val johnAsJson = write(john)
  // Prints {"name":"John Doe","address":{"street":"Elm Street 1","town":"Springfield","zipCode":"ABC123"}}
  Console.println(johnAsJson)

  // Parse the JSON back into a Scala object
  Console.println(read[Person](johnAsJson))  
}

เพิ่มสิ่งนี้build.sbtเพื่อใช้ uPickle ของคุณ:

libraryDependencies += "com.lihaoyi" %% "upickle" % "0.4.3"

0

ฉันใช้ไลบรารี PLAY JSON คุณสามารถค้นหา mavn repo สำหรับไลบรารี JSON เท่านั้นไม่ใช่กรอบงานทั้งหมดที่นี่

    val json = "com.typesafe.play" %% "play-json" % version
    val typesafe = "typesafe.com" at "http://repo.typesafe.com/typesafe/releases/"

มีบทช่วยสอนที่ดีมากเกี่ยวกับการใช้งานที่นี่:

http://mandubian.com/2012/09/08/unveiling-play-2-dot-1-json-api-part1-jspath-reads-combinators/

http://mandubian.com/2012/10/01/unveiling-play-2-dot-1-json-api-part2-writes-format-combinators/

http://mandubian.com/2012/10/29/unveiling-play-2-dot-1-json-api-part3-json-transformers/


JSON Play ได้กล่าวไว้ข้างต้นแล้ว
bluenote10

0

ขอฉันให้ลูกชายของเวอร์ชันJSON :

import nl.typeset.sonofjson._

arr(
  obj(id = 1, name = "John)
  obj(id = 2, name = "Dani)
)

ฉันชอบที่จะใช้สิ่งนี้ แต่คิดไม่ออกว่าจะเพิ่มลงในการอ้างอิงของฉันได้อย่างไรเพราะมันไม่ได้อยู่ใน maven
Jason Wolosonovich

0

Play เปิดตัวโมดูลสำหรับจัดการกับ JSON โดยไม่ขึ้นกับ Play Framework, Play WS

สร้างบล็อกโพสต์เกี่ยวกับเรื่องนี้โปรดดูที่http://pedrorijo.com/blog/scala-json/

การใช้คลาสเคสและPlay WS (รวมอยู่แล้วใน Play Framework) คุณจะแปลงกรณีระหว่าง json และคลาสเคสด้วยนัยเดียวง่ายๆ

case class User(username: String, friends: Int, enemies: Int, isAlive: Boolean)

object User {
  implicit val userJsonFormat = Json.format[User]
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.