Scala.js convert Dynamic to scala type - scala.js

Is there a way to convert a js Dynaimc type to a desired Scala type like String, Int, Double or BigDecimal?
Looking at the source code there does not appear to be a way in the companion object to do these things.

I got it. You must use asInstanceOf[T].
For example
if you have some object called data with an id of Int and name of String
val myPromise = $.ajax(url)
myPromise.done((data: js.Dynamic, textStatus: String, jqXHr: JQueryXHR) => {
val id = data.id.asInstanceOf[Int]
val name = data.name.asInstanceOf[String]
})

Related

Upickle: read an attribute that may be a String or Int as a String

I have a field that may come from a rest api as a String or Int, but when I read it I always want to read it as a String, i.e. if it comes as an Int I want to do a toString on it
case class ZoneList(
someField: Int,
targetField: String
)
object ZoneList {
implicit val rw: ReadWriter[ZoneList] = macroRW
}
targetField is the field in question
Looking at http://www.lihaoyi.com/upickle/#CustomPicklers, but still dont think I have enough of a handle to start a custom pickler
edit:
ended up doing this
implicit val anyToStringReader: Reader[Option[String]] =
reader[ujson.Value].map[Option[String]] { j =>
Try(j.toString()).toOption
}
Would have preferred if I could single out the targetField attribute only but my actual case class has a lot of fields and don't think I can do that and also utilize the default macro. If anyone knows how let me know
Solved by lihaoyi in the upickle gitter:
"if you want to single out that attribute, give it a new type that’s a wrapper around Option String and write your pickler for that type"

Shapeless lenses usage with a string definition

I would like use shapeless lenses to access value of the case class field by a String definition.
I know this code works.
case class Test(id: String, calc: Long)
val instance = Test("123232", 3434L)
val lens = lens[Test] >> 'id
val valueOfFieldId = lens.get(instance)
But what I am trying to do is:
val fieldName = "id"
val lens = lens[Test] >> fieldName.witness
//I typed .witness because it was expecting a witness (if I am not wrong)
val valueOfFieldId = lens.get(instance)
But with this code, I am getting this error.
Could not find implicit value for parameter mkLens: shapeless.MkFieldLens[A$A148.this.Test,A$A148.this.str.type]
def get$$instance$$lll = lll;/* ###worksheet### generated $$end$$ */ lazy val lens = lens[Test] >> str.witness
Is it possible to get the value of case class field with a String definition?
Thanks.
You are supposed to use Symbol ('id) here rather than String ("id").
Creating Symbol from String
Symbol(fieldName)
is runtime operation and Shapeless operates in compile time.
Why can't you use symbols?

Scala: constructor with two paretneheses

I'm new to scala.
What does following syntax mean?
case class User(val id: Long)(val username: String)
I've read about currying in scala, but explain please how it related to construction above (if related).
Thanks.
Just like partially-applied functions, a constructor (which is a function from its arguments to the constructed type) can be partially applied, in this case:
scala> case class User(val id: Long)(val username: String)
defined class User
scala> val userBuilder = User(123L) _
userBuilder: String => User = <function1>
Note the type of the resulting userBuilder - it's a function from String (the remaining parameter) to User
Now, like partially applied functions, you can apply this result to a String and get a User instance:
scala> val user = userBuilder("a")
user: User = User(123)
scala> user.username
res1: String = a
When is this useful?
When you want to construct many instances with common values for a subset of the arguments, e.g.:
case class Person(lastName: String)(val firstName: String)
class Family(lastName: String, firstNames: List[String]) {
def getMembers: List[Person] = {
val creator = Person(lastName) _ // will be reused for each first name!
firstNames.map(creator)
}
}
When you want to use one argument as the default value of another one:
case class Measure(min: Int)(val max: Int = min*2)
Measure(5)() // max = 10
Measure(5)(12) // default overridden, max = 12
When you want to use implicit arguments, which must reside in a separate, last argument list of the function, as described int the Scala Language Specification (Chapter 7.2):
A method or constructor can have only one implicit
parameter list, and it must be the last parameter list given.
It allows you to construct the object in steps.
val user = User(123L) _ // user now has only the ID
// later on
val completeUser = user("moreo") // user now also has the username
This is generally useful when you want to have your object follow an interface, but need to pass additional parameters, so you first initialise your object with those parameters and then later you get a function that can follow the interface.

Returning a java List with a scala method

Can someone help me? I'm trying to port a Java method to Scala but I'm getting a ClassCastException.
This is the Java version that works:
private static void addCompoundRecipe(String tag, String tagAddon, AspectList creationAspects, int sizeX, int sizeY, int sizeZ, Object... recipe)
{
List<Object> compoundRecipe = Arrays.asList(new Object[] {creationAspects, Integer.valueOf(sizeX), Integer.valueOf(sizeY), Integer.valueOf(sizeZ), Arrays.asList(recipe)});
recipelist.put(tag+tagAddon, compoundRecipe);
}
recipelist is an HashMap. When the compoundRecipe is retrieved via recipelist.get("string") and casted to List, all goes fine.
Here comes the troubled conversion:
private def addCompoundRecipe(tag: String, tagAddon: String, sizeX: Int, sizeY: Int, sizeZ: Int, aspects: AspectList, recipe: AnyRef*) {
val compoundRecipe = java.util.Arrays.asList(Array(sizeX, sizeY, sizeZ, aspects, java.util.Arrays.asList(recipe)))
if(compoundRecipe.isInstanceOf[java.util.List[_]])
recipes += (tag+tagAddon -> compoundRecipe)
else
throw new IllegalArgumentException(s"$tag$tagAddon is not a valid recipe!")
}
Instead of recipelist, here I use recipes, an immutable HashMap.
Of course, when I call it with recipes.apply("string"), I have to cast it again to make it fit the method's signature, using .asInstanceOf[java.util.List[_]]
The problem is, I get a ClassCastException :
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to thaumcraft.api.aspects.AspectList
Of course I could just write a Java class to do this stuff, but it's become a challenge for me, I really want to get into Scala.
EDIT:
I already pasted line 387, it's r.get(0), and ResearchPage is a simple class which has a Constructor that takes a java.util.List paramater, which is what I'm trying to do. There's no need too look more into that, because it's an API and I can't change it, and also because it worked when I wrote my stuff in Java. However, it seems I'm having problems with conversions...here's what I've been trying: `private def addCompoundRecipe(tag: String, tagAddon: String, sizeX: Int, sizeY: Int, sizeZ: Int, aspects: AspectList, recipe: ItemStack*) {
val compoundRecipe = (Seq(aspects, sizeX, sizeY, sizeZ, recipe.toSeq))
if(recipe != null) recipes += (tag+tagAddon -> compoundRecipe) else
throw new IllegalArgumentException(s"$tag$tagAddon is not a valid recipe!")
}
Here's the exception I get now:
java.lang.ClassCastException: scala.collection.mutable.WrappedArray$ofRef cannot be cast to java.util.List
in the same line 387, of course. So I guess the problem is with implicit conversions?
EDIT: this works:
private def addCompoundRecipe(tag: String, tagAddon: String, sizeX: Int, sizeY: Int, sizeZ: Int, aspects: AspectList, recipe: AnyRef*) {
val compoundRecipe = Seq(aspects, sizeX, sizeY, sizeZ, recipe.asJava)
if(recipe != null) recipes += (tag+tagAddon -> compoundRecipe.asJava) else
throw new IllegalArgumentException(s"$tag$tagAddon is not a valid recipe!")
}
My guess is there's something wrong with the line val compoundRecipe = java.util.Arrays.asList(Array(sizeX, sizeY, sizeZ, aspects, java.util.Arrays.asList(recipe))), where you expect to get a java.util.List[Any] that contains sizeX, sizeY... but unfortunately what you get is actually java.util.List[Array[Any]] where the inside Array contains sizeX, sizeY... If you pass them on to your java method call, the types won't check.
I don't think it's a good idea to mix java types and scala types within your scala code (e.g. val compoundRecipe = java.util.Arrays.asList ..., or if (compoundRecipe.isInstanceOf[java.util.List[_])). What seems to be a better practice is to always use scala types in your code, and do the conversion only when necessary (use .asJava as #Alvaro suggested).

Scala Getting class type from string representation

I have a class name string representation
val cls = Class.forName("clsName")
def fromJson[T: Manifest](me: String): T = {
Extraction.extract[T](net.liftweb.json.parse(me))
}
I would like to use it as T:manifest i.e
JsonConverter.fromJson[cls.type](stringData)
this returns an error
tried also
val t = Manifest.classType(cls)
JsonConverter.fromJson[t](stringData) // compile error
what is the best way to it ? is there a way to avoid using reflection ?
You could try something like this:
val cls = Class.forName(myClassName)
val m = Manifest.classType(cls)
val myObj:Any = JsonConverter.fromJson(stringData)(m)
One nuance to this approach is that you have to explicitly type the object as an Any. This is because you don't have the class as compile time and the call to classType is not supplied its type param so the Manifest returned is Manifest[Nothing]. Not ideal, but it works.