type mismatch; found : Int required: String when trying to persist the form data in play framework - scala

I have a model as follows:
case class User(username: String, email: String) {
var id:Int = User.nextId
}
object User {
protected var currentId = 0
def nextId: Int = {
currentId += 1
currentId
}
}
And my Controller looks like this:
object Users extends Controller {
val users: scala.collection.mutable.Map[String, User] = new HashMap
val form = Form(
mapping(
"username" -> text,
"email" -> text
)(User.apply)(User.unapply))
def add = Action {
Ok(views.html.users.add(form))
}
def save = Action{
implicit request =>
val user = form.bindFromRequest.get
users.put(user.id, user)
Ok("contact saved")
}
}
But when I compile the code my browser throws an error telling there is a miss match in the type that is accepted by the users.put(user.id, user).
The error message looks as follows:
When I change the type of the id as string then it will work but I want to keep my id as integer and not string.
Is there any way I can achieve this. I am using play framework 2.11.1.
What is that I am missing. Any help would be greatly appreciated since I am new to play framework.

users is a map from String to User.
val users: scala.collection.mutable.Map[String, User] = new HashMap
The put method expects a key of type String and a value of type User, but you tried to use it with a key of type Int.
You need to change your map to the type
scala.collection.mutable.Map[Int, User]
or instead you could use a value of type String as key.

Related

Fields of type Record are inserted as null in BigQuery

I have a Scala job where I need to insert nested JSON file to BigQuery. The solution for that is to create a BQ table with field type as Record for the nested fields.
I wrote a case class that looks like this:
case class AvailabilityRecord(
nestedField: NestedRecord,
timezone: String,
) {
def toMap(): java.util.Map[String, Any] = {
val map = new java.util.HashMap[String, Any]
map.put("nestedField", nestedField)
map.put("timezone", timezone)
map
}
}
case class NestedRecord(
from: String,
to: String
)
I'm using the Java dependency "com.google.cloud" % "google-cloud-bigquery" % "2.11.0", in my program.
When I try to insert the JSON value that I parsed to the case class, into BQ, the value of field timezone of tpye String is inserted, however the nested field of type Record is inserted as null.
For insertion, I'm using the following code:
def insertData(records: Seq[AvailabilityRecord], gcpService: GcpServiceImpl): Task[Unit] = Task.defer {
val recordsToInsert = records.map(record => InsertBigQueryRecord("XY", record.toMap()))
gcpService.insertIntoBq(recordsToInsert, TableId.of("dataset", "table"))
}
override def insertIntoBq(records: Iterable[InsertBigQueryRecord],
tableId: TableId): Task[Unit] = Task {
val builder = InsertAllRequest.newBuilder(tableId)
records.foreach(record => builder.addRow(record.key, record.record))
bqContext.insertAll(builder.build)
}
What might be the issue of fields of Record type are inserted as null?
The issue was that I needed to map the sub case class too, because to the java API, the case class object is not known.
For that, this helped me to solve the issue:
case class NestedRecord(
from: String,
to: String
) {
def toMap(): java.util.Map[String, String] = {
val map = new java.util.HashMap[String, Any]
map.put("from", from)
map.put("to", to)
map
}
}
And in the parent case class, the edit would take place in the toMap method:
map.put("nestedField", nestedField.toMap)
map.put("timezone", timezone)

Scala functional programming and mutability

Let's say I have the following code:
class Pet(name: String) {
def getName: String = {
name match {
case "" => generateRandomName
case _ => name
}
}
}
object Pet {
def apply(name: String) = new Pet(name)
}
where creating a Pet with an empty name would create a Pet with a random name. How would I save the state of the newly generated random name, so calling this method twice would return the same name generated from the first call?
val pet = Pet("")
// Let's say this prints "bob"
println(pet.getName)
// I want this to still print "bob". This would generate a new random name because the state isn't saved from the previous call.
println(pet.getName)
I'd like to avoid var because it's considered bad practice -- how do you go about doing something like this? Is the best way to create a new copy of the class? That doesn't seem very efficient to me
Using a default value in the constructor, you can do something like this...
class Pet(name: String = generateRandomName) {
def getName: String = name
}
Then when you do this...
val pet = new Pet()
...getName will always return the same generated name, but this...
val pet = new Pet("")
...will populate name as an empty String.

Map key not found error despite using option classes

I'm new to the concept of using the Option type but I've tried to use it multiple places in this class to avoid these errors.
The following class is used to store data.
class InTags(val tag35: Option[String], val tag11: Option[String], val tag_109: Option[String], val tag_58: Option[String])
This following code takes a string and converts it into a Int -> String map by seperating on an equals sign.
val message= FIXMessage("8=FIX.4.29=25435=D49=REDACTED56=REDACTED115=REDACTED::::::::::CENTRAL34=296952=20151112-17:11:1111=Order7203109=CENTRAL1=TestAccount63=021=155=CSCO48=CSCO.O22=5207=OQ54=160=20151112-17:11:1338=5000040=244=2815=USD59=047=A13201=CSCO.O13202=510=127
")
val tag58 = message.fields(Some(58)).getOrElse("???")
val in_messages= new InTags(message.fields(Some(35)), message.fields(Some(11)), message.fields(Some(109)), Some(tag58))
println(in_messages.tag_109.getOrElse("???"))
where the FIXMessage object is defined as follows:
class FIXMessage (flds: Map[Option[Int], Option[String]]) {
val fields = flds
def this(fixString: String) = this(FIXMessage.parseFixString(Some(fixString)))
override def toString: String = {
fields.toString
}
}
object FIXMessage{
def apply(flds: Map[Option[Int], Option[String]]) = {
new FIXMessage(flds)
}
def apply(flds: String) = {
new FIXMessage(flds)
}
def parseFixString(fixString: Option[String]): Map[Option[Int], Option[String]] = {
val str = fixString.getOrElse("str=???")
val parts = str.split(1.toChar)
(for {
part <- parts
p = part.split('=')
} yield Some(p(0).toInt) -> Some(p(1))).toMap
}
}
The error I'm getting is ERROR key not found: Some(58) but doesnt the option class handle this? Which basically means that the string passed into the FIXMessage object doesnt contain a substring of the format 58=something(which is true) What is the best way to proceed?
You are using the apply method in Map, which returns the value or throw NoSuchElementException if key is not present.
Instead you could use getOrElse like
message.fields.getOrElse(Some(58), Some("str"))

changing immutable variable values while serialization in scala

I have a case class User. I have to serialize it using kryo. here is my class.
while implementing read() of Kryo I'm having issue. my variables has val type. as we know we can't change value of val's.
case class User(name : String, age : int) extends KryoSerializable {
def this()={
this("",0)
}
//
override def read(kryo : Kryo, input : Input) {
// here i'm getting error. i can't override name because its val
name = input.readString()
age = input.readInt()
println("-----------Read method of Kryo")
}
override def write(kryo : Kryo, output : Output) {
output.writeString(name)
output.writeInt(age)
println("--------Write method of Kryo")
}
}
please guide me, how can I do that?
If you do not have any pressing reasons to use a case class for user, I would recommend to not use a case class. Because you have to declare name and age as variables. And a case class is not supposed to be mutable.
Here is something, that might accomplish, what you want without making User a case class:
class User (private var _name : String, private var _age : Int) extends KryoSerializable {
def name = _name
def age = _age
override def read(kryo : Kryo, input : Input) {
// here i'm getting error. i can't override name because its val
_name = input.readString()
_age = input.readInt()
println("-----------Read method of Kryo")
}
override def write(kryo : Kryo, output : Output) {
output.writeString(_name)
output.writeInt(_age)
println("--------Write method of Kryo")
}
}
object User {
def apply(name: String, age: Int = 0): User = new User(name, age)
}
Since User is a case class, you can use copy to create a new User while updating (some of) the values.
case class User(name: String = "", age: Int = 0)
val empty = User() // User = User(,0)
val alice = empty.copy("Alice", 40) // User = User(Alice,40)
But since with KryoSerializable you need to modify the object itself (type of read is Unit), you can not return a new User instance, so you will be better of using an external Serializer[User] if you want to continue using a case class.
class UserSerializer extends Serializer[User] {
def write (kryo: Kryo, output: Output, user: User): Unit = {
output.writeString(user.name)
output.writeInt(user.age)
}
def read(kryo: Kryo, input: Input, `type`: Class[User]): User =
User(
name = input.readString()
age = input.readInt()
)
}

How to store child objects on GAE using JDO from Scala

I'm have a parent-child relation between 2 classes, but the child objects are never stored. I do get an warning:
"org.datanucleus.store.appengine.MetaDataValidator checkForIllegalChildField: Unable to validate relation net.vermaas.kivanotify.model.UserCriteria.internalCriteria"
but it is unclear to me why this occurs. Already tried several alternatives without luck.
The parent class is "UserCriteria" which has a List of "Criteria" as children.
The classes are defined as follows (Scala):
class UserCriteria(tu: String, crit: Map[String, String]) extends LogHelper {
#PrimaryKey
#Persistent{val valueStrategy = IdGeneratorStrategy.IDENTITY}
var id = KeyFactory.createKey("UserCriteria", System.nanoTime)
#Persistent
var twitterUser = tu
#Persistent
var internalCriteria: java.util.List[Criteria] = flatten(crit)
def flatten(crits: Map[String, String]) : java.util.List[Criteria] = {
val list = new java.util.ArrayList[Criteria]
for (key <- crits.keySet) {
list.add(new Criteria(this, key, crits(key)))
}
list
}
def criteria: Map[String, String] = {
val crits = mutable.Map.empty[String, String]
for (i <- 0 to internalCriteria.size-1) {
crits(internalCriteria.get(i).name) = internalCriteria.get(i).value
}
Map.empty ++ crits
}
// Stripped the equals, canEquals, hashCode, toString code to keep the code snippet short...
}
#PersistenceCapable
#EmbeddedOnly
class Criteria(uc: UserCriteria, nm: String, vl: String) {
#Persistent
var userCriteria = uc
#Persistent
var name = nm
#Persistent
var value = vl
override def toString = {
"Criteria name: " + name + " value: " + value
}
}
Any ideas why the childs are not stored? Or why I get the error message?
Thanks,
Gero
It looks to me like you are trying to implement an owned one-to-many relationship. Also you seem to have forgotten the #Embedded annotation for the UserCriteria's internalCriteria field, though I think, that it might still not work since the field contains a list and not the embedded class itself.