reading json file using jackson library in scala language - json

I am newto the scala language to i am trying to read the json file in my scala file using jackson library
my son file is like this
{
"Rice":[
{
"name":"Basmati",
"price":40
},
{
"name":"jeera",
"price":30
},
{
"name":"Indrayani",
"price":40
}
],
"Pulses":[
{
"name":"peas",
"price":60
},
{
"name":"ground nut",
"price":60
},
{
"name":"dal",
"price":80
}
],
"Wheats":[
{
"name":"atta",
"price":40
},
{
"name":"bread",
"price":45
},
{
"name":"bun",
"price":50
}
]
}
I tried with the case classes to store and print the data
code sample like this
case class Inventory(var name:String,var price:String)
object InventoryDataManagement {
def main(args: Array[String]): Unit = {
val mapper = JsonMapper.builder()
.addModule(DefaultScalaModule)
.build()
val src = new File("src/main/json/inventary.json")
val myMap = mapper.readValue(src,classOf[Inventory])
println(myMap.name)
}
}
but I am getting error like below
Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "Rice" (class Inventory), not marked as ignorable (2 known properties: "price",
"name"])
please help to understand this
thanks in advance!!!

Unrecognized field "Rice" (class Inventory)
This error should make you notice that Jackson is looking for a field Rice on the Inventory class, which doesn't make sense.
Why so?
Because you are telling Jackson to read your JSON file as a single Inventory instance.
This is not what your JSON file contains, it contains something that can be represented as a Map[String, Seq[Inventory]].
You should try something like this instead:
mapper.readValue(src,classOf[Map[String, Seq[Inventory]]])

Related

Suggestions for creating a Scalaz Tree out of a polymorphic set of Nodes in a JSON tree

I have previously used C++ with tools like Antlr to read a DSL and convert it into an AST/symbol table and then used tree walkers to create object models which were then elaborated and then the resulting data structure was generated into yet another language(s).
I know how to traverse/transform Scala trees and graphs many different ways. I am struggling with how to create a JSON parser that will create a Tree in an elegant way.
I could use Circe to parse the JSON and then read the Circe data structure and check the type of each node during the traversal and create the corresponding case class object.I am wondering if there is a simpler way.
Using JSON to describe a high level specification of a tree with polymorphic nodes as follows what Scala libraries can convert the JSON into a Scala Tree?
The tree will be edited and nodes will be added, deleted, and moved to create a new immutable data structure.
I have looked at Scalaz but it may not be appropriate since there are different node types and I am not sure how to go directly from JSON to a Scalaz Tree.
Tree
https://scalaz.github.io/scalaz/scalaz-2.9.1-6.0.4/doc.sxr/scalaz/Tree.scala.html#40955
Example:
https://scalaz.github.io/scalaz/scalaz-2.9.1-6.0.4/doc.sxr/scalaz/example/ExampleTree.scala.html
object ExampleTree {
def main(args: Array[String]) = run
import Scalaz._
def run {
val tree: Tree[Int] =
1.node(
2.leaf,
3.node(
4.leaf))
This link Traverse tree in a functional way has an example of a Tree constructed using the same node type. See below.
package main
import scala.collection.mutable.ListBuffer
sealed trait Tree[Node] {
val node: Node
val parent: Option[Tree[Node]]
val children: ListBuffer[Tree[Node]]
def add(n: Node): Tree[Node]
def size: Int
def getOpt(p: (Node) => Boolean): Option[Tree[Node]]
override def toString = {
s"""[$node${if (children.isEmpty) "" else s", Children: $children"}]"""
}
}
case class ConcreteTree(override val node: Int) extends Tree[Int] {
override val children = ListBuffer[Tree[Int]]()
override val parent: Option[Tree[Int]] = None
override def add(n: Int): ConcreteTree = {
val newNode = new ConcreteTree(n) {override val parent: Option[Tree[Int]] = Some(this)}
children += newNode
newNode
}
}
What I am asking is for a Scala way to convert the polymorphic JSON into a Tree structure.
Each Node type in the tree has a corresponding case class.
The JSON needs to be parsed, the type matched and correct case class used for the JSON type.
If you feel that this question some how violates the policies on StackOverflow rather than giving it a minus point perhaps you can leave a comment with a suggestion(s) about how to change the question to comply with the StackOverflow rules.
Example JSON:
{
"root": {
"Container": {
"attributes": [],
"children": {
"Container": {
"attributes": [],
"children": {
"Container": {
"attributes": [],
"children": {
"circle": {
"fill": "blue",
"diameter": "4"
}
}
},
"square": {
"name": "Y",
"color": "red",
"length": "10",
"width": "4"
}
}
}
}
}
}
}

Obtaining the value from any key-value from a string representation of a json in Scala (using scala.util.parsing.json)

Imagine I have a json (in string format) that looked like:
val jsonString: String = "
{
"toys": {
"orange toys": {
"brand":"Toys-R-Us",
"price":"123.45"
}
},
"date":"05-27-1996"
}
"
My question is, how can I get the value for "brand" (Toys-R-Us), in Scala, using the scala.util.parsing.json library? I am assuming that this might require the traversing of the json or maybe even easier, a way to look up the key "brand" and from their obtaining the value.
The scala.util.parsing.json library is outdated, unsafe for open systems, and not included in the latest version of the Scala library.
Use dijon FTW!
import dijon._
import scala.language.dynamics._
val jsonString: String = """
{
"toys": {
"orange toys": {
"brand":"Toys-R-Us",
"price":"123.45"
}
},
"date":"05-27-1996"
}
"""
println(parse(jsonString).toys.`orange toys`.brand)
Here is a runnable code on Scastie that works fine with Scala 2 and Scala 3.

How to avoid unnesary naming with Kotlin native serialization?

Situation
Say I have this JSON, which I get from some server:
{
"useless_info": "useless info",
"data": {
"useless_info2": "useless info 2",
"children": [
{
"kind": "Car",
"data": {
"id": 1,
"transmission": "manual"
}
},
{
"kind": "Boat",
"data": {
"id": 2,
"isDocked": true
}
}
]
}
}
This JSON is an example. It represent a much larger and complex one, but with similar structure. I have no say in it's structure, so I must adapt to it.
What I Want
The JSON has deep inside it an array of vehicle objects. Say I only care about the ID.
I could model it like this:
#Serializable
data class VehicleResponse(
#Serializable(with = VehicleResponseSerializer::class)
#SerialName("data")
val vehicles: List<Vehicle>
)
#Serializable
data class Vehicle(val id: Int)
In order to avoid modeling the response exactly by writing many neste data classes (which would be awful with the real one, which is more nested and complex), I can use a JsonTransformingSerializer to cut right to part I want, like this:
object VehicleResponseSerializer : JsonTransformingSerializer<List<Vehicle>>(ListSerializer(Vehicle.serializer())) {
override fun transformDeserialize(element: JsonElement): JsonElement {
val vehicles = mutableListOf<JsonElement>()
val vehicleArray = element.jsonObject["children"]!!.jsonArray
// equals: [{"kind":"Car","data":{"id":1,"totalWheels":"4"}},{"kind":"Boat","data":{"id":2,"isDocked":true}}]
vehicleArray.forEach { vehicle ->
val vehicleData = vehicle.jsonObject["data"]!!
// equals: {"id":1,"totalWheels":"4"}}
vehicles.add(vehicleData)
}
return JsonArray(vehicles.toList())
}
}
Calling it from main:
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
fun main() {
val vehicles: VehicleResponse = configuredJson.decodeFromString(vehicleJson)
println(vehicles)
}
val configuredJson = Json {
ignoreUnknownKeys = true
}
Prints:
VehicleResponse(vehicles=[Vehicle(id=1), Vehicle(id=2)])
So if it works perfectly, what's even the problem
It's this part:
#Serializable
data class VehicleResponse(
#Serializable(with = VehicleResponseSerializer::class)
#SerialName("data")
val vehicles: List<Vehicle>
)
I have a problem with the #SerialName. It feels like a hack to me. All this accomplishes is give the custom serializer the data object rather than the full original object from the response. If you remember from the custom serializer, I cut right to the array I want by walking down the structure. It would be trivial to get to the data object. So, instead of
val vehicleArray = element.jsonObject["children"]!!.jsonArray
I would have to do:
val vehicleArray = element.jsonObject["data"]!!.jsonObject["children"]!!.jsonArray
Currently I feel like what I'm doing doesn't really describe the code. In my VehicleResponse data class, I write that my vehicles list does has a serial name of "data", when it doesn't at all. This could lead me to misinterpret the structure of JSON in the future, or even confuse me as to what I'm trying to do. With this simple example it's OK, but what about more complex ones?
What I Tried
Changing VehicleResponse to this:
#Serializable(with = VehicleResponseSerializer::class)
data class VehicleResponse(
val vehicles: List<Vehicle>
)
And altering the line that gets the array inside the custom serializer to this:
override fun transformDeserialize(element: JsonElement): JsonElement {
...
val vehicleArray = element.jsonObject["data"]!!.jsonObject["children"]!!.jsonArray
...
}
Running this code gives the following error:
Exception in thread "main" java.lang.ClassCastException: class java.util.ArrayList cannot be cast to class VehicleResponse (java.util.ArrayList is in module java.base of loader 'bootstrap'; VehicleResponse is in unnamed module of loader 'app')
at MainKt.main(Main.kt:5)
at MainKt.main(Main.kt)
Process finished with exit code 1
For reference, I tried to print the vehicles array inside the serializer, to see it by any chance I messed up navigating the JSON.
override fun transformDeserialize(element: JsonElement): JsonElement {
...
println(vehicles)
return JsonArray(vehicles.toList())
}
It prints:
[{"id":1,"transmission":"manual"}, {"id":2,"isDocked":true}]
So everything seems to be fine. Not sure what I'm doing wrong.

Scala - how to take json as input arguments and parse it?

I am writing a small scala practice code where my input is going to be in the fashion -
{
"code": "",
"unique ID": "",
"count": "",
"names": [
{
"Matt": {
"name": "Matt",
"properties": [
"a",
"b",
"c"
],
"fav-colour": "red"
},
"jack": {
"name": "jack",
"properties": [
"a",
"b"
],
"fav-colour": "blue"
}
}
]
}
I'll be passing this file as an command line argument.
I want to know that how do I accept the input file parse the json and use the json keys in my code?
You may use a json library such as play-json to parse the json content.
You could either operate on the json AST or you could write case classes that have the same structure as your json file and let them be parsed.
You can find the documentation of the library here.
You'll first have to add playjson as depedency to your project. If you're using sbt, just add to your build.sbt file:
libraryDependencies += "com.typesafe.play" %% "play-json" % "2.6.13"
Play json using AST
Let's read the input file:
import play.api.libs.json.Json
object Main extends App {
// first we'll need a inputstream of your json object
// this should be familiar if you know java.
val in = new FileInputStream(args(0))
// now we'll let play-json parse it
val json = Json.parse(in)
}
Let's extract some fields from the AST:
val code = (json \ "code").as[String]
val uniqueID = (json \ "unique ID").as[UUID]
for {
JsObject(nameMap) ← (json \ "names").as[Seq[JsObject]]
(name, userMeta) ← nameMap // nameMap is a Map[String, JsValue]
} println(s"User $name has the favorite color ${(userMeta \ "fav-colour").as[String]}")
Using Deserialization
As I've just described, we may create case classes that represent your structure:
case class InputFile(code: String, `unique ID`: UUID, count: String, names: Seq[Map[String, UserData]])
case class UserData(name: String, properties: Seq[String], `fav-colour`: String)
In addition you'll need to define an implicit Format e.g. in the companion object of each case class. Instead of writing it by hand you can use the Json.format macro that derives it for you:
object UserData {
implicit val format: OFormat[UserData] = Json.format[UserData]
}
object InputFile {
implicit val format: OFormat[InputFile] = Json.format[InputFile]
}
You can now deserialize your json object:
val argumentData = json.as[InputFile]
I generally prefer this approach but in your case the json structure does not fit really well. One improvement could be to add an additional getter to your InputFile class that makes accesing the fields with space and similar in the name easier:
case class InputFile(code: String, `unique ID`: UUID, count: String, names: Seq[Map[String, String]]) {
// this method is nicer to use
def uniqueId = `unique ID`
}

How to Parse this JSON with LibGDX

"components":[
{
"class":"AssetReference",
"asset":{
"class":"TextureRegionAsset",
"relativePath":"gfx/opengraph.png"
}
},
{
"class":"Layer"
},
{
"class":"ProtoVisSprite",
"width":5,
"height":5
},
{
"class":"Transform",
"x":0.13817275,
"y":2.8430145,
"scaleX":0.2,
"scaleY":0.2
},
{
"class":"Origin"
},
{
"class":"Tint"
},
{
"class":"Renderable",
"zIndex":2
},
{
"class":"VisID",
"id":"scratch"
}
]
Im having some issues in parsing the nested asset with LibGDX. Does anyone know how to assign asset to AssetReference with the relativePath from TextureRegionAsset?
I know I could strip out the "class" handling and simple parse the JSON but I need to be able to handle this with LibGDX.
Ideally Im looking to parse the data and create a sprite from the JSON.
Thanks.
You can use JsonReader and get JsonValue for that.
JsonReader json = new JsonReader();
JsonValue base = json.parse(Gdx.files.internal("file.json"));
//print json to console
System.out.println(base);
//get the component values
JsonValue component = base.get("components");
//print class value to console
System.out.println(component.getString("class"));
//array objects in json if you would have more components
for (JsonValue component : base.get("components"))
{
System.out.println(component.getString("class"));
System.out.println(component.get("asset").getString("class");
System.out.println(component.get("asset").getString("relativePath");
}
There is actually a useful libgdx wiki page for this:
https://libgdx.com/wiki/utils/reading-and-writing-json
Apparently it seems to work fine with nested classes on its own already.
The wiki page has this example:
Json json = new Json();
Person person = json.fromJson(Person.class, text);
Using the following as text:
{
class: com.example.Person,
numbers: [
{
class: com.example.PhoneNumber,
number: "206-555-1234",
name: Home
},
{
class: com.example.PhoneNumber,
number: "425-555-4321",
name: Work
}
],
name: Nate,
age: 31
}
This is using an example class "Person" with the following properties:
ArrayList numbers
String name
int age
The String text is the result of json.toJson(person). Your resulting serialized string seems the same format, which makes me assume you're already using the Json serializer, but not the unserializer.