importing static javascript functions into scala.js - scala

In a third party library react-native-fbsdk-next I have a file FBAccessToken.ts
The class below has a few ordinary members and a static member function.
class FBAccessToken {
accessToken: string;
permissions: Array<string>;
static getCurrentAccessToken() {
return new Promise<FBAccessToken | null>((resolve) => {
...
}
}
}
export default FBAccessToken;
I need to import both the class members as well as the static function.
My strategy is to use a scala class and a companion object like so
#native
#JSImport("react-native-fbsdk-next", "FBAccessToken")
class FBAccessToken extends js.Object {
def accessToken: String = native
def permissions: Array[String] = native
}
#native
#JSImport("react-native-fbsdk-next", "FBAccessToken")
object FBAccessToken extends js.Object {
def getCurrentAccessToken: Promise[FBAccessToken | Null] = native
}
But the static function to companion object import seems to not work.
sbt fastOptJs works but on running the app in a simulator I get
TypeError: undefined is not an object (evaluating '_$$_REQUIRE(_dependencyMap[4], "react-native-fbsdk-next").FBAccessToken.getCurrentAccessToken')
What am I doing wrong?

FBAccessToken is exported under the default export in the JavaScript library:
export default FBAccessToken;
and not under its own name "FBAccessToken".
Therefore, when importing it from Scala.js, you have to use JSImport.Default as the second argument ot #JSImport:
#JSImport("react-native-fbsdk-next", JSImport.Default)
This applies both to the class and to the object

Related

Unit testing trait with object

I have the following construct, where I have a
trait DataServiceLocalImpl extends DataService {
override lazy val dataService = DataComponentLocalImpl
}
object DataComponentLocalImpl extends DataComponent {
def getData(element:String):String = GetStuffFromFile(element)
}
trait DataService {
val dataService: DataComponent
}
trait DataComponent {
def getData(element:String):String
}
The GetStuffFromFile reads a file from disk once (I only want this once, hence the object), creates a map and then returns the value for element.
This is all done in an Play Framework 2.3 surrounding and the app works as well, but when I use it in a test as an implicit I get the following error:
java.lang.NoClassDefFoundError: Could not initialize class DataComponentLocalImpl
Test suite:
class AutoCompleteSpec extends PlaySpec with Mockito with OneAppPerSuite {
val resource = new DataServiceLocalImpl {}
implicit val dataService = resource.dataService
}
If I remove the implicit it works...
You should create an object with the service overriden.
object FakeImpl extends DataServiceLocalImpl {
override dataService = //Fake or test data service here
}
You then create an anonymous class definition that allows you to test the trait.

meaning of top level private class in scala

Say in a scala file I define a class like
private class Test{}
what does the private here mean? In java you can't have a top level private class, which obviously makes sense. But private is syntactically valid in scala, hope someone can shed some light upon it.
You could specify package name for private modifier to allow access to this class only from specified package. By default (without package specified) it is visible only for other members in the enclosing package.
$ cat > test.scala <<EOF
package myPackage {
private[myPackage] class Test
private object A extends Test
}
package otherPackage {
object B extends myPackage.Test
}
EOF
$ scalac test.scala
test.scala:7: error: class Test in package myPackage cannot be accessed in package myPackage
object B extends myPackage.Test
^
one error found
For instance you can access private class from its companion object like this:
trait ITest
private class Test extends ITest
object Test {
def apply(): ITest = new Test
}
Test()
// ITest = Test#59e2abc3
Further clarification on examples:
package myPackage {
private class Test
private object A extends Test
object B extends myPackage.Test //Compile error: private class Test escapes its defining scope as part of type myPackage.Test
private object C extends myPackage.Test // works since C is also private
object Test {
def apply() = new Test //error: private class Test escapes its defining scope as part of type myPackage.Test
}
object Test2 {
def apply(): ITest = new Test //works as ITest is public
}
}
As long as instances of a private class do not escape the enclosing package scope it can be used within the package hierarchy. Companion objects accessing private classes has to be in same package hierarchy as well. With private[P] - p can be any package name that exists.

Delaying trait initialization

I need a smart mechanism for component composition which allows mixed in traits to initialize after the composed component. The following throws a NullPointerException:
class Component {
def addListener(pf: PartialFunction[Any, Unit]) {}
}
trait DynamicComponent {
protected def component: Component
component.addListener {
case x =>
}
}
class Foo extends DynamicComponent {
protected val component = new Component
}
new Foo // -> NullPointerException
The following things are not options for me:
Using protected lazy val component; that would produce an avalange of dozens of vals needing to become lazy, something I do not want.
Putting addListener in a method, e.g. initDynamic(); because I will be mixing in many traits, and I don't want to remember to call half a dozen initFoo() methods.
Using DelayedInit. This doesn't work with traits, at least according to the scaladocs.
I could live with a single init() call, but only under the following conditions:
all mixed in traits can easily declare to be invoked in this one single call
it is a compile error to forget the init() statement.
You can delay the initialization of a trait by by using early definitions. (See section 5.1.6 of the scala language specification)
class Foo extends {
protected val component = new Component
} with DynamicComponent
It's even clunkier than your solution, but you can always require the creation of a val that must be set with the init() method. You could choose to not do it last and get an error at runtime, but at least you won't forget it entirely:
class Component {
def addListener(pf: PartialFunction[Any, Unit]) {
println("Added")
}
}
trait Dyn {
protected def component: Component
protected val initialized: Init
class Init private () {}
private object Init { def apply() = new Init() }
def init() = { component.addListener{ case x => }; Init() }
}
class Foo extends Dyn {
protected val component = new Component
protected val initialized = init()
}
No cheating!:
> class Bar extends Dyn { protected val component = new Component }
<console>:12: error: class Bar needs to be abstract, since value
initialized in trait Dyn of type Bar.this.Init is not defined
class Bar extends Dyn { protected val component = new Component }
The advantage this has is if you need multiple things to be in place before you initialize all of them cooperatively, or if your Component class is final so you can't mix in anything else.
AN idea could be to use the trick described here:
Cake pattern: how to get all objects of type UserService provided by components
All your components that should be initialized could be registered in some Seq[InitializableComponent]. And then you could initialize all registered components with a foreach.
No component will be forgotten in that Seq because they are registered automatically, but you can still forget to call the foreach anyway...
Here is one idea (I am happy to read about other suggestions):
class Component {
def addListener(pf: PartialFunction[Any, Unit]) {
println("Added")
}
}
trait DynamicComponentHost {
protected def component: Component with DynamicPeer
protected trait DynamicPeer {
_: Component =>
addListener {
case x =>
}
}
}
class Foo extends DynamicComponentHost {
protected val component = new Component with DynamicPeer
}
new Foo
So basically I am forcing the component to mix in a type that can only be provided by the mixed in trait. Reasonable? Looks a bit too complicated in my eyes.

Can't access method of companion class from companion object

I thought that I can access every method of the companion class from my companion object. But I can't?
class EFCriteriaType(tag:String) extends CriteriaType
{
// implemented method of CriteriaType
def getTag = this.tag
}
object EFCriteriaType
{
var TEXT: CriteriaType = new EFCriteriaType("text")
override def toString = getTag
}
Compiler error:
not found: value getTag
What I'm doing wrong?
You are trying to call the method getTag in object EFCriteriaType. There is no such method in that object. You could do something like:
object EFCriteriaType extends EFCriteriaType("text") {
override def toString = getTag
}
Thus making the companion object a kind of template.
You can access members not normally accessible in a class from a companion object, but you still need to have an instance of the class to access them. E.g:
class Foo {
private def secret = "secret"
def visible = "visible"
}
object Foo {
def printSecret(f:Foo) = println(f.secret) // This compiles
}
object Bar {
def printSecret(f:Foo) = println(f.secret) // This does not compile
}
Here the private method secret is accessible from Foo's companion object. Bar will not compile since secret is inaccessible.
I'm not quite sure what you're trying to do here, but you need to call getTag on an instance of the class:
override def toString(x:EFCriteriaType) = x.getTag
Just to detail Matthew answer, which is the right one:
A companion object is a singleton but a class is not. a singleton. The companion
object can access the methods of the class in the sense that a private
member of the class C can be called in its companion object C.
To call a member of a given class, you need an instance of that class (even if you are not doing that from a companion object)
follow this example, please:
import scala.math._
case class Circle(radius: Double) {
import Circle._
def area: Double = calculateArea(radius)
}
object Circle {
private def calculateArea(radius: Double): Double = Pi * pow(radius, 2.0)
}
val circle1 = Circle(5.0)
circle1.area

How does one implement a Hadoop Mapper in Scala 2.9.0?

When I migrated to Scala 2.9.0 from 2.8.1, all of the code was functional except for the Hadoop mappers. Because I had some wrapper objects in the way, I distilled down to the following example:
import org.apache.hadoop.mapreduce.{Mapper, Job}
object MyJob {
def main(args:Array[String]) {
val job = new Job(new Configuration())
job.setMapperClass(classOf[MyMapper])
}
}
class MyMapper extends Mapper[LongWritable,Text,Text,Text] {
override def map(key: LongWritable, value: Text, context: Mapper[LongWritable,Text,Text,Text]#Context) {
}
}
When I run this in 2.8.1, it runs quite well (and I have plenty of production code in 2.8.1. In 2.9.0 I get the following compilation error:
error: type mismatch;
found : java.lang.Class[MyMapper](classOf[MyMapper])
required: java.lang.Class[_ <: org.apache.hadoop.mapreduce.Mapper]
job.setMapperClass(classOf[MyMapper])
The failing call is when I call setMapperClass on the Job object. Here's the definition of that method:
public void setMapperClass(java.lang.Class<? extends org.apache.hadoop.mapreduce.Mapper> cls) throws java.lang.IllegalStateException { /* compiled code */ }
The definition of the Mapper class itself is this:
public class Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>
Does anyone have a sense of what I'm doing wrong? It looks to me like the type is fundamentally correct: MyMapper does extend Mapper, and the method wants something that extends Mapper. And it works great in 2.8.1...
Silly as it seems, you can work around the problem by defining the Mapper before the Job. The following compiles:
import org.apache.hadoop._
import org.apache.hadoop.io._
import org.apache.hadoop.conf._
import org.apache.hadoop.mapreduce._
class MyMapper extends Mapper[LongWritable,Text,Text,Text] {
override def map(key: LongWritable, value: Text, context: Mapper[LongWritable,Text,Text,Text]#Context) {
}
}
object MyJob {
def main(args:Array[String]) {
val job = new Job(new Configuration())
job.setMapperClass(classOf[MyMapper])
}
}