ScalaJS and MongoDB driver: Referring to non-existent class - mongodb

Learning Scala since yesterday, I've build a project to interact with a MongoDB index (which works fine) and another one using ScalaJS to do the same thing.
Here is my build.sbt :
enablePlugins(ScalaJSPlugin)
name := "demographics"
version := "1.0"
scalaVersion := "2.12.1"
libraryDependencies += "org.mongodb.scala" %% "mongo-scala-driver" % "1.2.1"
libraryDependencies += "be.doeraene" %%% "scalajs-jquery" % "0.9.1"
libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "0.9.1"
skip in packageJSDependencies := false
jsDependencies +=
"org.webjars" % "jquery" % "3.1.1" / "3.1.1/jquery.js"
and my main file:
package demographics.webapp
import org.mongodb.scala._
import scala.scalajs.js.JSApp
object DemographicsApp extends JSApp {
def main(): Unit = {
// connect to the bdd
val mongoClient: MongoClient = MongoClient()
val database: MongoDatabase = mongoClient.getDatabase("demographics")
val collection: MongoCollection[Document] = database.getCollection("demographics")
}
}
Very basic: just connect to the collection.
Sadly, when I launch a "fastOptJS" on the sbt shell, the following error appears:
[info] Compiling 1 Scala source to C:\...\target\scala-2.12\classes...
[info] Fast optimizing C:\...\target\scala-2.12\untitled1-fastopt.js
[error] Referring to non-existent class org.mongodb.scala.bson.DefaultHelper$DefaultsTo$
[error] called from demographics.webapp.DemographicsApp$.main()scala.Unit
[error] called from scala.scalajs.js.JSApp.$$js$exported$meth$main()java.lang.Object
[error] called from demographics.webapp.PrenomApp$.$$js$exported$meth$main()java.lang.Object
[error] called from demographics.webapp.DemographicsApp$.main
[error] exported to JavaScript with #JSExport
[error] involving instantiated classes:
[error] demographics.webapp.PrenomApp$
[error] Referring to non-existent class org.mongodb.scala.MongoClient$
[error] called from demographics.webapp.DemographicsApp$.main()scala.Unit
[error] called from scala.scalajs.js.JSApp.$$js$exported$meth$main()java.lang.Object
[error] called from demographics.webapp.PrenomApp$.$$js$exported$meth$main()java.lang.Object
[error] called from demographics.webapp.DemographicsApp$.main
[error] exported to JavaScript with #JSExport
[error] involving instantiated classes:
[error] demographics.webapp.DemographicsApp$
[error] Referring to non-existent class org.mongodb.scala.bson.collection.immutable.Document
[error] called from demographics.webapp.DemographicsApp$.main()scala.Unit
[error] called from scala.scalajs.js.JSApp.$$js$exported$meth$main()java.lang.Object
[error] called from demographics.webapp.PrenomApp$.$$js$exported$meth$main()java.lang.Object
[error] called from demographics.webapp.DemographicsApp$.main
[error] exported to JavaScript with #JSExport
[error] involving instantiated classes:
[error] demographics.webapp.DemographicsApp$
[error] Referring to non-existent method org.mongodb.scala.bson.DefaultHelper$DefaultsTo$.$default()org.mongodb.scala.bson.DefaultHelper$DefaultsTo
[error] called from demographics.webapp.DemographicsApp$.main()scala.Unit
[error] called from scala.scalajs.js.JSApp.$$js$exported$meth$main()java.lang.Object
[error] called from demographics.webapp.PrenomApp$.$$js$exported$meth$main()java.lang.Object
[error] called from demographics.webapp.DemographicsApp$.main
[error] exported to JavaScript with #JSExport
[error] involving instantiated classes:
[error] demographics.webapp.DemographicsApp$
[error] Referring to non-existent method org.mongodb.scala.MongoClient$.apply()org.mongodb.scala.MongoClient
[error] called from demographics.webapp.DemographicsApp$.main()scala.Unit
[error] called from scala.scalajs.js.JSApp.$$js$exported$meth$main()java.lang.Object
[error] called from demographics.webapp.PrenomApp$.$$js$exported$meth$main()java.lang.Object
[error] called from demographics.webapp.DemographicsApp$.main
[error] exported to JavaScript with #JSExport
[error] involving instantiated classes:
[error] demographics.webapp.DemographicsApp$
[trace] Stack trace suppressed: run last compile:fastOptJS for the full output.
[error] (compile:fastOptJS) There were linking errors
The same code (with adaptations in the main file) is working on the vanilla Scala project, why this error appears?

It appears because you use a JVM-only library. mongo-scala-driver is not published for Scala.js. It it were, you could use a %%% dependency to depend on the Scala.js version of that library, which would work with Scala.js. But you cannot use a JVM-only library in a Scala.js project.
(Conversely, you cannot use a Scala.js-only library in a Scala/JVM project, for example, scalajs-dom.)

Related

ScalaJs + ZIO: Program works with sbt 1.2.8 but not >= 1.3

I'm trying out scala.js with zio using the sample app at
https://github.com/wongelz/zio-scalajs-solarsystem
as soon as I update the sbt version from 1.2.8 to 1.3.13 or 1.4.4 I'm getting the following error:
[error] Referring to non-existent method java.time.LocalTime$.NANOS_PER_SECOND()long
[error] called from private java.time.LocalDateTime.plusWithOverflow(java.time.LocalDate,long,long,long,long,int)java.time.LocalDateTime
[error] called from java.time.LocalDateTime.plusNanos(long)java.time.LocalDateTime
[error] called from java.time.LocalDateTime.plus(long,java.time.temporal.TemporalUnit)java.time.LocalDateTime
[error] called from java.time.LocalDateTime.plus(long,java.time.temporal.TemporalUnit)java.time.temporal.Temporal
[error] called from java.time.temporal.ChronoUnit.addTo(java.time.temporal.Temporal,long)java.time.temporal.Temporal
[error] called from java.time.OffsetDateTime.plus(long,java.time.temporal.TemporalUnit)java.time.OffsetDateTime
[error] called from java.time.OffsetDateTime.plus(long,java.time.temporal.TemporalUnit)java.time.temporal.Temporal
[error] called from java.time.Duration.addTo(java.time.temporal.Temporal)java.time.temporal.Temporal
[error] called from java.time.OffsetDateTime.plus(java.time.temporal.TemporalAmount)java.time.OffsetDateTime
[error] called from private zio.Schedule$.$anonfun$fixed$2(scala.Option,java.time.OffsetDateTime,long,java.time.Duration,long,scala.runtime.LazyRef)zio.Schedule$Decision
[error] called from private zio.Schedule$.$anonfun$fixed$1(scala.Option,long,java.time.Duration,long,scala.runtime.LazyRef,java.time.OffsetDateTime,java.lang.Object)zio.ZIO
[error] called from private zio.Schedule$.loop$23(scala.Option,long,long,java.time.Duration,scala.runtime.LazyRef)scala.Function2
[error] called from zio.Schedule$.fixed(java.time.Duration)zio.Schedule
[error] called from private SolarSystemExample$.$anonfun$run$1(SolarSystemExample$SolarSystem)zio.ZIO
[error] called from SolarSystemExample$.run(scala.collection.immutable.List)zio.ZIO
[error] called from private zio.App.$anonfun$main$1([java.lang.String)zio.ZIO
[error] called from zio.App.main([java.lang.String)void
[error] called from SolarSystemExample$.main([java.lang.String)void
[error] called from static SolarSystemExample.main([java.lang.String)void
[error] called from core module module initializers
[error] involving instantiated classes:
[error] java.time.LocalDateTime
[error] java.time.temporal.ChronoUnit
[error] java.time.OffsetDateTime
[error] java.time.Duration
[error] zio.Schedule$
[error] SolarSystemExample$
Why does this bug happen? And where should I report it?
To answer my own question (for anybody strugling with the same problem):
Make sure you don't have scalajs-java-time (1.0.0) as a dependency in your classpath.
It is a incomplete library and if it is picked before scala-java-time you will receive the error posted in the question.
The reason this error occurred, was, that at least on my system, the ordering of the classpath changed from sbt 1.2.8 to sbt 1.3.x, which resulted in the scalajs-java-time library being picked before scala-java-time which resulted in the
Referring to non-existent method java.time.LocalTime$.NANOS_PER_SECOND()long
Error

what should I do to import cache,ws, jdbc and specs2 % Test

I'm upgrading my project from play 2.4.3 to 2.5.0
I have added the sbt plugin for play 2.5.0 in plugin.sbt file like this
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.0")
After adding when I compiled the code it throws me an error stating
[info] Loading project definition from /Users/ege/Sites/Aeione/greenroom6-services-v3/greenroom6-services-v3/project
[info] Compiling 1 Scala source to /Users/ege/Sites/Aeione/greenroom6-services-v3/greenroom6-services-v3/project/target/scala-2.10/sbt-0.13/classes...
[error] /Users/ege/Sites/Aeione/greenroom6-services-v3/greenroom6-services-v3/project/Common.scala:4: object PlayScala is not a member of package play
[error] import play.PlayScala
[error] ^
[error] /Users/ege/Sites/Aeione/greenroom6-services-v3/greenroom6-services-v3/project/Common.scala:49: not found: value jdbc
[error] jdbc,
[error] ^
[error] /Users/ege/Sites/Aeione/greenroom6-services-v3/greenroom6-services-v3/project/Common.scala:50: not found: value cache
[error] cache,
[error] ^
[error] /Users/ege/Sites/Aeione/greenroom6-services-v3/greenroom6-services-v3/project/Common.scala:51: not found: value ws
[error] ws,
[error] ^
[error] /Users/ege/Sites/Aeione/greenroom6-services-v3/greenroom6-services-v3/project/Common.scala:52: not found: value specs2
[error] specs2 % Test,
[error] ^
[error] 5 errors found
[error] (compile:compileIncremental) Compilation failed
can anyone help me out to import these dependencies?
I think your import is wrong. According to the documentation it should be:
import sbt._
import Keys._
import play.sbt._
import Play.autoImport._
import PlayKeys._

Calling clojure code from a scala sbt task

I am trying to call some clojure code as a sbt task.
My build.sbt looks like,
lazy val aTask = taskKey[Unit]("a task")
libraryDependencies ++= Seq(
"org.clojure" % "clojure" % "1.9.0"
)
import clojure.java.api.Clojure
import clojure.lang.IFn
aTask := {
val plus: IFn = Clojure.`var`("clojure.core", "+")
println(plus.invoke(1, 4))
}
Contents of project/build.sbt
resolvers += Resolver.mavenLocal
libraryDependencies ++= Seq(
"org.clojure" % "clojure" % "1.9.0"
)
Also I have added clojure dep in project/build.sbt of my project.
I am getting the following error when calling the task
[error] java.lang.ExceptionInInitializerError
[error] at clojure.lang.Namespace.<init>(Namespace.java:34)
[error] at clojure.lang.Namespace.findOrCreate(Namespace.java:176)
[error] at clojure.lang.Var.intern(Var.java:148)
[error] at clojure.java.api.Clojure.var(Clojure.java:82)
[error] at clojure.java.api.Clojure.<clinit>(Clojure.java:96)
[error] at $2d5a9b65ddee7e6a09cc$.$anonfun$$sbtdef$1(build.sbt:20)
[error] at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
[error] at sbt.std.Transform$$anon$3.$anonfun$apply$2(System.scala:46)
[error] at sbt.std.Transform$$anon$4.work(System.scala:66)
[error] at sbt.Execute.$anonfun$submit$2(Execute.scala:262)
[error] at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:16)
[error] at sbt.Execute.work(Execute.scala:271)
[error] at sbt.Execute.$anonfun$submit$1(Execute.scala:262)
[error] at sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:174)
[error] at sbt.CompletionService$$anon$2.call(CompletionService.scala:36)
[error] at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[error] at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
[error] at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[error] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[error] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[error] at java.lang.Thread.run(Thread.java:748)
[error] Caused by: java.io.FileNotFoundException: Could not locate clojure/core__init.class or clojure/core.clj on classpath.
[error] at clojure.lang.RT.load(RT.java:463)
[error] at clojure.lang.RT.load(RT.java:426)
[error] at clojure.lang.RT.doInit(RT.java:468)
[error] at clojure.lang.RT.<clinit>(RT.java:336)
Any pointers on what I could try would be helpful.
I think there is an issue with class loaders setup by sbt. Clojure's RT class loads Clojure namespaces/classes using class loaders API. If sbt configures the classloaders hierarchy and class loading strategy (e.g. parent first) in a way that RT's classloader doesn't find Clojure's classes via classloader it's using then it will fail with the error you are getting.
Unfortunately, I don't know sbt internals to determine how the classloaders get configured. Maybe another question would help in the investigation: How to display classpath used for run task?

Linker error in ScalaJS: "Referring to non-existent class"

I am getting a bunch of linker errors when trying to link to FastParse in a Scala project which I've just tried to build a ScalaJS web app in.
I added the ScalaJS dependency for FastParse into my build.sbt: here's approximately the relevant line (full file here):
libraryDependencies ++= Seq(
"com.lihaoyi" %%% "fastparse" % "0.4.1"
)
My errors are voluminous, but here's a representative one:
[error] Referring to non-existent class fastparse.Implicits$Repeater$
[error] called from parsers.MainParser$$anonfun$impls$1.apply()fastparse.core.Parser
[error] called from parsers.MainParser$$anonfun$impls$1.apply()java.lang.Object
[error] called from scala.Option.getOrElse(scala.Function0)java.lang.Object
[error] called from fastparse.StringReprOps$.errorMessage(fastparse.utils.ParserInput,java.lang.String,scala.Int)java.lang.String
[error] called from fastparse.core.ParseError.<init>(fastparse.core.Parsed$Failure)
[error] called from fastparse.Api.<init>(scala.reflect.ClassTag,fastparse.utils.ElemSetHelper,fastparse.utils.ReprOps,scala.math.Ordering)
[error] called from fastparse.StringApi.<init>()
[error] called from fastparse.all$.<init>()
[error] called from parsers.MainParser$.<init>()
[error] called from webapp.WebApp$.makeChoices(java.lang.String,java.lang.String)scala.collection.immutable.List
[error] called from webapp.WebApp$.$$js$exported$meth$makeChoices(java.lang.String,java.lang.String)java.lang.Object
[error] called from webapp.WebApp$.makeChoices
[error] exported to JavaScript with #JSExport
[error] involving instantiated classes:
[error] parsers.MainParser$$anonfun$impls$1
[error] scala.None$
[error] scala.Some
[error] fastparse.StringReprOps$
[error] webapp.WebApp$
What am I doing wrong?
The problem was that I was requiring the JVM version of FastParse two lines up in my build.sbt. This broke my build apparently. I removed that line and cleaned my build and now both the ScalaJS and ScalaJVM versions of the project are building nicely.
(Thanks heaps to Li Haoyi for spotting the problem for me)

Class Resolving in one namespace, but not the other

When running play compile, I get a compile-time error.
[error] test.scala:14: object BOMInputStream is not a member of package org.ap
ache.commons.io.input
[error] import org.apache.commons.io.input.BOMInputStream
[error] ^
[error] test.scala:80: not found: type BOMInputStream
[error] val bomIn = new BOMInputStream(fileInpStream, false)
[error] ^
[error] two errors found
However, I successfully ran a scalatest test using the BOMInputStream in the same play project within the /test directory.
When I comment out the offending lines in the above compile-time error, the test succeeds.
Note that I've updated my /project/Build.scala appropriately:
"org.apache.commons" % "commons-io" % "1.3.2"
After deleting a JAR, which contained the BOMInputStream class, from my PLAY-PROJECT/lib/ directory, I was able to compile.