Circe: Json object to Custom Object - arrays

I've go this json node
...
"businessKeys": [
"product://color?product_code",
"product://?code"
]
...
after a sequence of computation I have a Json istance but I'm not able to understand how I can transform that object into a List of my object. So Json (istance) to List[MyClass].
MyClass(root: ParameterType, children: List[ParameterType] = List.empty)
ParameterType(parameter: String)
I have a method that transform a String into a MyClass istance, so I need to decode Json into List[String] and then call my function or there is a direct method?
Thanks

You need implement our own io.circe.Decoder, in your case it can be converted from decoder for string.
Please, find some example code below:
import io.circe._
import io.circe.generic.auto._
object CirceExample {
class ParameterType(parameter: String) {
override def toString: String = parameter
}
class MyClass(root: ParameterType, children: List[ParameterType] = List.empty) {
override def toString: String = s"MyClass($root, $children)"
}
object MyClass {
/**
* Parsing logic from string goes here, for sake of example, it just returns empty result
*/
def parse(product: String): Either[String, MyClass] = {
Right(new MyClass(new ParameterType("example")))
}
// This is what need - just declare own decoder, so the rest of circe infrastructure can use it to parse json to your own class.
implicit val decoder: Decoder[MyClass] = Decoder[String].emap(parse)
}
case class BusinessKeys(businessKeys: List[MyClass])
def main(args: Array[String]): Unit = {
val json = "{ \"businessKeys\": [\n \"product://color?product_code\",\n \"product://?code\"\n ] }"
println(parser.parse(json).map(_.as[BusinessKeys]))
}
}
Which in my case produced next output:
Right(Right(BusinessKeys(List(MyClass(example, List()), MyClass(example, List())))))
Hope this will help you!

Related

Data Class Either Object or Array

I have a Kotlin data class that has an arg that can either be an Object or Array. Is there a way to de-serialize a string into this class and not care if not an Array but somehow get it into an array of one?
data class Game(var name:List<NameItem>)
data class NameItem(var title: String, var id: Int)
data can come back as both ways a single object or an array of objects( I have no control over the data as it is 3rd party data.
jsonString = "{"game":{"name":{"title":"GameName","id":22}}}"
jsonString = "{"game":{"name":[{"title":"GameName","id":22},{"title":"GameName2","id":23}]}}"
game: Game? = Gson().fromJson(jsonString Game::class.java)
You have to write a custom JsonDeserializer. Both or your class should have the same parent class. Then, write a custom JsonDeserializer for this specific type.
For example:
sealed class GameParent() {
data class Game(val name: String): GameParent()
data class GameList(val games: List<Game>): GameParent()
}
class GameDeserializer : JsonDeserializer<GameParent> {
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): GameParent {
with(json) {
if(isJsonObject) {
// parse as Game
}
if(isJsonArray) {
// parse as GameList
}
}
}
}
Then, in your GsonBuilder you have to register this custom JsonDeserializer:
gsonBuilder.registerTypeAdapter(GameParent::class.java, GameDeserializer());
Now, whenever your Gson expect GameParent will use registered deserializer.
my suggestions for solving your task
my solution if name is object, replace it with arrays
data class Game(var name:List<NameItem> )
data class NameItem(var title: String, var id: Int)
fun main(args: Array<String>) {
var json = "{\"game\":{\"name\":[{\"title\":\"game 1\",\"id\":1},{\"title\":\"game 2\",\"id\":2}]}}"
println(useJsonParser(json)) //Game(name=[NameItem(title=game 1, id=1), NameItem(title=game 2, id=2)])
json = "{\"game\":{\"name\":[{\"title\":\"game 1\",\"id\":1}]}}"
println(useJsonParser(json)) //Game(name=[NameItem(title=game 1, id=1), NameItem(title=game 2, id=2)])
json = "{\"game\":{\"name\":{\"title\":\"game 1\",\"id\":1}}}" // not array
println(useJsonParser(json)) //Game(name=[NameItem(title=game 1, id=1)])
}
version 1 -- created and registry adapter link #Cililing
fun useJsonParser(json: String): Game? {
val gson = GsonBuilder().registerTypeAdapter(Game::class.java, GameDeserializer()).create()
return gson.fromJson(json, Game::class.java)
}
class GameDeserializer : JsonDeserializer<Game?> {
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): Game? {
val gameJson = json!!.asJsonObject.get("game")
if (gameJson.isJsonObject) {
val jsonName = gameJson.asJsonObject["name"]
val list = if (jsonName.isJsonObject) {
arrayOf(Gson().fromJson(jsonName, NameItem::class.java))
} else {
val fromJson = Gson().fromJson(jsonName, Array<NameItem>::class.java)
fromJson
}.toList()
return Game(list)
}
return null
}
}
version 2 -- manipulating the response
fun useJsonParser(json:String):Game?{
val jsonObject = JsonParser().parse(json).asJsonObject.get("game")
if(jsonObject.asJsonObject["name"].isJsonObject){
val jsonName = jsonObject.asJsonObject["name"].asJsonObject
val array = JsonArray()
array.add(jsonName)
jsonObject.asJsonObject.add("name", array) // rewrite origin JSON
}
return Gson().fromJson(jsonObject, Game::class.java)
}
vesrion 3 -- add adapter TypeToken>()
fun useJsonParser(json: String): Game? {
val type = object : TypeToken<MutableList<NameItem>>() {}.type
val gson = GsonBuilder().registerTypeAdapter(type, NameItemDeserializer()).create()
return gson.fromJson(JsonParser().parse(json).asJsonObject.get("game"), Game::class.java)
}
class NameItemDeserializer : JsonDeserializer<List<NameItem>?> {
override fun deserialize(json: JsonElement, type: Type, context: JsonDeserializationContext?): List<NameItem>? {
with(json){
return if(isJsonObject){
arrayListOf(Gson().fromJson(this,NameItem::class.java))
}else{
Gson().fromJson(this,Array<NameItem>::class.java).toList()
}
}
}
}

Adding 2 characters in scala

I am new to Scala and I was working on something,
I need to implement the following code
class $(val text2d: Array[Array[Char]]) {
def +(that: $) = ...
}
But my code keeps giving me an error stating
found : Array[Array[Char]]
required: String
Here is what my code looks like:
class Point2D(val text2D : Array[Array[Char]]) {
def +(that : Point2D): Point2D =
new Point2D(text2D + that.text2D)
override def toString = {
s"${text2D}"
}
}
Any help would be appreciated.
You have to use the ++ method to join two arrays into a new one.
class Point2D(val text2D: Array[Array[Char]]) {
def +(that: Point2D): Point2D =
new Point2D(text2D ++ that.text2D)
}

JSON with array and non-array data with Groovy JsonBuilder

I need to create a JSON string in my Groovy script which has some elements that are array and some which are not. For example the below..
{
"fleet": {
"admiral":"Preston",
"cruisers": [
{"shipName":"Enterprise"},
{"shipName":"Reliant"}
]
}
}
I found this post but the answers either didn't make sense or didn't apply to my example.
I tried the below in code...
def json = new groovy.json.JsonBuilder()
def fleetStr = json.fleet {
"admiral" "Preston"
cruisers {
{shipName: "[Enterprise]"}, {shipName: "[Reliant]"}
}
}
But it gives an exception...
Ambiguous expression could be either a parameterless closure expression or an isolated open code block
In Groovy, the {} syntax is used for closures. For objects in JSON, you want to use the map syntax [:], and for lists, the list syntax []:
def json = new groovy.json.JsonBuilder()
def fleetStr = json.fleet {
"admiral" "Preston"
cruisers( [
[shipName : "[Enterprise]"],
[shipName: "[Reliant]"]
])
}
assert json.toString() ==
'{"fleet":{"admiral":"Preston","cruisers":[{"shipName":"[Enterprise]"},{"shipName":"[Reliant]"}]}}'
Update: as per your follow-up, you need to use the same list syntax [] outside the "[Enterprise]" and "[Reliant]" strings:
def json = new groovy.json.JsonBuilder()
def fleetStr = json.fleet {
"admiral" "Preston"
cruisers( [
[shipName : ["Enterprise"]],
[shipName: ["Reliant"]]
])
}
assert json.toString() ==
'{"fleet":{"admiral":"Preston","cruisers":[{"shipName":["Enterprise"]},{"shipName":["Reliant"]}]}}'

Instance member cannot be used on type Array

I have the below class and I use a function math to search the string in both SongTitle and in ESongTitle.
class KeerthanaiArray: NSObject {
var SongTitle: String = String()
var SongLyrics: String = String()
var ESongTitle: String = String()
init(SongTitle: String, SongLyrics:String, ESongTitle: String) {
self.SongTitle = SongTitle
self.SongLyrics = SongLyrics
self.ESongTitle = ESongTitle
}
class func match(string:String) -> Bool {
return SongTitle.containsString(string) || ESongTitle.containsString(string)
}
}
I get the error message 'Instance member SongTitle cannot be used on type 'Keerthanaiarray'. Please help
I need to declare the math func as class as I need to use the math function outside of its class
There are several problems here.
This class KeerthanaiArray is not an array (as suggested by the name instead)
Why are you extending NSObject?
The class method match makes no sense, it is using 2 properties (SongTitle and ESongTitle) that does not exists in this context because they belongs to an instance of the class.
So let's cleanup your code
struct Song {
let title: String
let lyrics: String
let eTitle: String
func match(keyword: String) -> Bool {
return title.containsString(keyword) || eTitle.containsString(keyword)
}
}
I make you class a struct because makes more sense. You are free to turn back to class. If you stay on structs please keep in mind they are value types.
Now given a list of Song(s)
let songs: [Song] = ...
and a keyword
let keyword = "The Great Gig In the Sky"
this is how we search the array
let results = songs.filter { $0.match(keyword) }
Case insensitive version
struct Song {
let title: String
let lyrics: String
let eTitle: String
func match(keyword: String) -> Bool {
let lowerCaseKeyword = keyword.lowercaseString
return title.lowercaseString.containsString(lowerCaseKeyword) || eTitle.lowercaseString.containsString(lowerCaseKeyword)
}
}

parse an array as a Json string using DataContractJsonSerializer WP7

How can I parse the elements of an array in a Json string using DataContractJsonSerializer?
The syntax is:
{
"array":[
{
"elementsProperies":"SomeLiteral"
}
]
}
You wouldn't necessarily "parse" a json string using DataContractJsonSerializer, but you can deserialize it into an object or list of objects using this. Here is a simple way to deserialize it to a list of objects if this is what you're after.
First you need to have an object type you plan on deserializing to:
[DataContract]
public class MyElement
{
[DataMember(Name="elementsProperties")] // this must match the json property name
public string ElementsProperties { get; set; }
}
You can then use something like the following method to deserialize your json string to a list of objects
private List<MyElement> ReadToObject(string json)
{
var deserializedElements = new List<MyElement>();
using(var ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
var ser = new DataContractJsonSerializer(deserializedElements.GetType());
deserializedElements = ser.ReadObject(ms) as List<MyElement>;
}
return deserializedUsers;
}
I suggest using Json.net.
In it you would just call:
var jsonObj = JObject.Parse(yourjsonstring);
var elPropertyValue = (string)jsonObj.SelectToken("array[0].elementsProperies");
to get the "SomeLiteral".

Resources