unable to get value from JsSuccess - playframework-2.6

I am getting java.lang.ClassCastException: scala.Some cannot be cast to models.Data error when I try to get a value from JsSuccess. What is the mistake in the following code?
val dataOption = request.body.validateOpt[Data]
dataOption match {
case dataSuccess:JsSuccess[Data] => {
println("validated request body:" + dataSuccess) //I see this print
val data:Data = dataSuccess.value //PROGRAM THROWS EXCEPTION HERE
println("received data:" + data +", "+data.mydata)
I receive the following data
{"data":{"field1":"d","field2":"d","field3":["d"],"field4":["d"],"field5":[1],"field6":"d","field7":"d"}}
The JsValue.validateOpt successfully casts the data
validated request body:JsSuccess(Some(Data(MyData(None,d,List(d),List(1),d,Set(d),d,d))),/my-data)
Then when I try to get the data, the program throws an exception java.lang.ClassCastException: scala.Some cannot be cast to models.Data
val data:Data = dataSuccess.value //PROGRAM THROWS EXCEPTION HERE
println("received data:" + data +", "+data.mydata)
The model class is
case class Data(myData:MyData)
case class MyData (field1: Option[UUID],
field2: String,
field3: List[String],
field4: Seq[Byte],
field5: String,
field6: Set[String],
field7: String,
field8:String)

case dataSuccess:JsSuccess[Data] should be questionSuccess:JsSuccess[Option[Data]] because validateOpt[T] returns Option[T]

Related

JSONSerialization.jsonObject for complex array

I'm trying to take data return from an API in to an Object. However I am getting errors because the array is complex and not of the same type - it will also differ from the API according to the request made.
let json = try JSONSerialization.jsonObject(with: data!) as! Dictionary<String, Dictionary<String, String>>
The array/data it is being given is as such:
[
'heartbeatStatus' => 'ok',
'events' => [
['id' => '1', 'name' => 'Event'],
['id' => '2', 'name' => 'Event 2'],
]
]
Is there any simple way of doing this? The questions I have seen on SO so far are either for older versions of Swift (this is Swift 5) or aren't are simply different.
The errors I get are like this (different with the various attempts I have made)
Could not cast value of type '__NSSingleObjectArrayI' (0x1ed250b30) to
'NSDictionary' (0x1ed251378). 2020-04-13 18:52:23.173759+0100
removed app id [1209:472869] Could not cast value of type
'__NSSingleObjectArrayI' (0x1ed250b30) to 'NSDictionary'
(0x1ed251378).
Try to use Codable. First define a struct to be your model:
struct HeartbeatResponse: Codable { // or whatever
let heartbeatStatus: String
let events: [Event]
struct Event: Codable {
let id: String
let name: String
}
}
Then to decode:
do {
if let data = data {
let heartbeat = JSONDecoder().decode(HeartbeatResponse.self, data)
// do stuff with heartbeat
}
} catch {
print(error)
}

Contextual type 'String' cannot be used with array literal

I am getting an error while converting my code to Swift 3.0. My sample code is below:
func hexRepresentation()->String {
let dataLength:Int = self.count
let string = NSMutableString(capacity: dataLength*2)
let dataBytes:UnsafeRawPointer = (self as NSData).bytes
for idx in 0..<dataLength {
string.appendFormat("%02x", [UInt(dataBytes[idx])] as String )
}
return string as String
}
What does this line do:
string.appendFormat("%02x", [UInt(dataBytes[idx])] as String )
First of all, it takes the byte at index idx in dataBytes and wraps it in an array. This is the array literal referred to in the error message.
Next it tries to cast the array as a String - not convert: cast. This the compiler knows to be impossible, hence the error message.
Fortunately, you don't want to convert the argument to a string because your format specifier asks for a UInt (%x), so what you really want here is just
string.appendFormat("%02x", UInt(dataBytes[idx]))
As for getting the bytes, the Swift type Data has a function foreach which is handy for iterating the bytes:
self.forEach { string.appendFormat("%02x", UInt($0)) }

How to pass multiple data objects to HTML templates in Golang

I am returing all rows of a table as json to the variable pdata and unmarshaling it into an interface object.
I have an instance of the user struct which I would like to pass along with the unmarshalled json data to the render function and access it using field arguments {{.fieldname}} in the html template.
if uuid != "" {
pdata, err := getProduct()
if err != nil {
fmt.Println(err)
}
type Prdata struct {
Puid string `json:"puid"`
Pname string `json:"pname"`
Quantity string `json:"quantity"`
Price string `json:"price"`
Image string `json:"image"`
}
// Obj:= make(map[Prdata]string)
var Pr Prdata
err = json.Unmarshal(pdata , &Pr)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(pdata))
fmt.Println(Pr)
fmt.Println(u)
render(w, "internal", Pr)
}
fmt.Println(string(pdata)) gives this output
[{"image":"1Appleiphone7.jpeg","pname":"iphone7","price":"70000","puid":"d6742e4e-2ad6-43c5-97f4-e8a7b00684e2","quantity":"100"}]
I have only been successful to unmarshal the data into an interface{} object. Trying to make maps with keys of the type interface{} and values of type string but it throws the error:
"json: cannot unmarshal array into Go value of type map[interface {}]string"
The render function takes an argument of the type interface{}
func render(w http.ResponseWriter, name string, data interface{})
fmt.Println(Pr) gives this output:
[map[quantity:100 image:1Appleiphone7.jpeg pname:iphone7 price:70000 puid:d6742e4e-2ad6-43c5-97f4-e8a7b00684e2]]
u is an instance of struct User
var u = &User{}
type User struct {
Uuid string
Username string
Password string
Fname string
Email string
}
I can see the output on the html page using the pipeline {{.}}. However I am not able to access any data using the fieldname.
There must be a way of doing this. But I am not sure how?
When I pass of a json of the type below, I am able to pass it to the struct type and reference it by the key values using pipelines in my template.
str := `{
"image": "1Appleiphone7.jpeg",
"pname": "iphone7",
"price": "70000",
"puid": "d6742e4e-2ad6-43c5-97f4-e8a7b00684e2",
"quantity": "100"
}`
unmarshal function
err = json.Unmarshal([]byte(str), &Pr)
The difference in the json data of the DB record pdata and the one above str is in the use of backticks "`". It seems that though the json data shows key value pairs, it is actually a json array and not a json object. Is there a way to get around this?
You don't need a map[interface{}]string to unmarshal the json obj. Your json is equivalent to slice of maps:
[
{
"image":"1Appleiphone7.jpeg",
"pname":"iphone7",
"price":"70000",
"puid":"d6742e4e-2ad6-43c5-97f4-e8a7b00684e2",
"quantity":"100"
}
]
The object to unmarshal should be a slice of maps with string keys and values:
var Pr []map[string]string
Playground
BTW, I believe misunderstanding is hidden there:
The render function takes an argument of the type interface{}
I means not that you must pass a variable of interface{} type there but it means you CAN pass a variable of any type to render function.
I am posting a working example of unmarshalling json as bytes into a struct type which then can be referenced using the {{.}} in the template.
package main
import (
"encoding/json"
"fmt"
)
type Usrdata struct {
Uuid string
Fname string
}
type Prdata struct {
Puid string `json:"puid"`
Pname string `json:"pname"`
Quantity string `json:"quantity"`
Price string `json:"price"`
Image string `json:"image"`
}
type Data struct {
U Usrdata
P []Prdata
}
func main() {
Ur := Usrdata{Uuid: "xyz", Fname: "Somename"}
Pr := make([]Prdata, 0)
var Dt Data
Dt.U = Ur
pdata := `[{"image":"1Appleiphone7.jpeg","pname":"iphone7","price":"70000","puid":"d6742e4e-2ad6-43c5-97f4-e8a7b00684e2","quantity":"100"}]`
err := json.Unmarshal([]byte(pdata), &Pr)
if err != nil {
fmt.Println(err)
}
Dt.P = Pr
fmt.Println(Pr[0].Pname)
fmt.Println(Pr)
fmt.Println(Dt)
}

Cannot subscript a value of type '[String : PFFile]' with an index of type 'String!'

I have declared a global variable 'var recipes = String: PFFile'.
On parse.com, I created a column called "recipe" of type File and i have uploaded .txt files that contain the recipes.
I am trying to load the contents of the .txt files from parse to a UITextView.
I have tried many things and this is what I have:
let recipeFile = object["recipe"] as! PFFile
recipeFile.getDataInBackgroundWithBlock({ (recipeData, error) -> Void in
if error == nil {
let data = recipeData
} else {
print(error)
}
if let data = recipeData {
self.recipes[appetizerName] = PFFile(data: data)
// gives error: Cannot subscript a value of type '[String : PFFile]' with an index of type 'String!'
// self.myTextView.text = self.recipes[self.valuePassed]
}
})

Cannot convert value of type 'x' to expected argument type '[String : Any]'

I'm currently attempting to create a user database, with Firestore in Swift 5.
I have created a signup view controller, and I am following the Firestore documentation (this link), in order to store the user data.
In a constants file I have stored the following code.
struct userMap: Codable {
let firstName: String?
let lastName: String?
let email: String?
let profilePictureURL: String?
let UserIdentification: String?
enum CodingKeys: String, CodingKey {
case firstName
case lastName
case email
case profilePictureURL
case UserIdentification
}
}
And in my signup view controller, I have this code.
let user = Constants.userMap(firstName: firstName,
lastName: lastName,
email: email,
profilePictureURL: metaImageURL,
UserIdentification: docRefID)
do {
try dbRef.document(docRefID).setData(user)
} catch let error {
print("Error writing to Firestore: \(error)")
}
On the line try dbRef.document(docRefID).setData(user) I am getting the error, "Cannot convert value of type 'Constants.userMap' to expected argument type '[String : Any]' "
Something I feel is worth adding. In the firebase documentation, it recommends the below.
try dbRef.document(docRefID).setData(from: user)
But, I tried this, and this too and I was just asked to remove from:.
Thanks all for your help.
You are using an object of the struct userMap instead of using a dictionary. You can fix this by creating a dictionary inside the userMap struct and providing that dictionary as the parameter. Since your struct already conforms to Codable you can create Data from object of userMap using JSONEncoder. Then you can convert the data to a JSON dictionary to use as a parameter. Here the code:
struct userMap: Codable {
//...
var dictionary: [String: Any] {
let data = (try? JSONEncoder().encode(self)) ?? Data()
return (try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any]) ?? [:]
}
}
And for the setData:
try dbRef.document(docRefID).setData(from: user.dictionary)
Note: Main struct names capitalized for consistency So, convert userMap to UserMap.
For reference, another reason why someone may see the following error:
Cannot convert value of type 'x' to expected argument type '[String : Any]'
when working with Firestore's setData command is because they haven't added the line:
import FirebaseFirestoreSwift

Resources