What I've tried:
Ensuring Scala perspective is set, disabled, set again
Ensuring that I right click on the Object that extends App
I never get 'Run as Scala application...' at this point
Defining an explicit 'main' in Object after removing 'extends App'
What I get is 'Run Configurations..." when I right-click on Object with main(). No matter what I do there, e.g. enter name of Object that extends App or has an explicit main, main() is never found and I get classloader stack trace dumps indicating that there is no main.
While I get no Scala compile errors, no matter what I try, I never get 'Run As...Scala Application'.
Code:
object fatfinger extends App {
import com.mongodb.casbah.Imports._
import Common._
import MongoFactory._ */
object Insert {
def main(args: Array[String]) {
val apple = Stock("AAPL", 600)
val google = Stock("GOOG", 650)
val netflix = Stock("NFLX", 60)
saveStock(apple)
saveStock(google)
saveStock(netflix) }
def saveStock(stock: Stock) {
val mongoObj = buildMongoDbObject(stock)
MongoFactory.collection.save(mongoObj) } }
}
Stacktrace:
Exception in thread "main" java.lang.NoClassDefFoundError: Insert
Caused by: java.lang.ClassNotFoundException: Insert
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Related
Launching following application fails with java.lang.NoSuchMethodException: dev.buildingdragons.dragon.Dragon$.<init>() (find the full stack trace below).
To me, it looks like there is a constructor missing, but which? And Why?
I do now there are projects like ScalaFX but before using them I want to fully understand what is going on so I really want to create a walking skeleton.
Environment:
Windows 10 Professional
IntelliJ IDEA Ultimate 2019.1.2
OpenJDK 64-Bit Server VM Zulu11.2+3 (build 11.0.1+13-LTS, mixed mode)
Dragon.scala:
package dev.buildingdragons.dragon
import javafx.application.{Application, Platform}
import javafx.scene.Scene
import javafx.scene.control.Button
import javafx.stage.Stage
object Dragon extends Application {
def main(args: Array[String]) = Application.launch(args: _*)
override def start(stage: Stage): Unit = {
val scene = new Scene(new Button("Test"))
stage.setTitle("Hello, Dragon!")
stage.setScene(scene)
stage.showAndWait()
Platform.exit()
}
}
build.gradle:
plugins {
id 'scala'
id 'org.openjfx.javafxplugin' version '0.0.7'
}
compileScala.targetCompatibility = 1.8
// In this section you declare where to find the dependencies of your project
repositories {
mavenCentral()
}
dependencies {
compile 'org.scala-lang:scala-library:2.12.8'
compile 'org.scalafx:scalafx_2.12:11-R16'
}
javafx {
version = "11.0.2"
modules = ['javafx.controls']
}
Full stack trace:
Exception in Application constructor
Exception in thread "main" java.lang.RuntimeException: Unable to construct Application instance: class dev.buildingdragons.dragon.Dragon$
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:890)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.NoSuchMethodException: dev.buildingdragons.dragon.Dragon$.<init>()
at java.base/java.lang.Class.getConstructor0(Class.java:3350)
at java.base/java.lang.Class.getConstructor(Class.java:2152)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:801)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
... 1 more
EDIT: As suggested by eugene-ryzhikov I modified Dragon.scala:
package dev.buildingdragons.dragon
import javafx.application.{Application, Platform}
import javafx.scene.Scene
import javafx.scene.control.Button
import javafx.stage.Stage
class Dragon extends Application {
override def start(stage: Stage): Unit = {
val scene = new Scene(new Button("Test"))
stage.setTitle("Hello, Dragon!")
stage.setScene(scene)
stage.showAndWait()
Platform.exit()
}
}
object Dragon {
def main(args: Array[String]) = Application.launch(classOf[Dragon], args: _*)
}
That solved the original problem but now I ran into the problem I was afraid of: Java's Project Jigsaw:
Exception in Application start method
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Exception in Application start method
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.IllegalAccessError: superclass access check failed: class com.sun.javafx.scene.control.ControlHelper (in unnamed module #0x4e08e183) cannot access class com.sun.javafx.scene.layout.RegionHelper (in module javafx.graphics) because module javafx.graphics does not export com.sun.javafx.scene.layout to unnamed module #0x4e08e183
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:802)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:700)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:623)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at javafx.scene.control.Control.<clinit>(Control.java:86)
at dev.buildingdragons.dragon.Dragon.start(Dragon.scala:10)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
... 1 more
Exception running application dev.buildingdragons.dragon.Dragon
I believe that is due to the fact that Scala does not enforce module restrictions at compile time but the JVM does at runtime.
That error is the consequence of having your start method within the object. Move it to the new Dragon class with main method in the companion Dragon object. Also use the launch method where you can pass the application class.
I am new with scala and I face the following problem.
import akka.actor.Actor
import akka.actor.Props
import akka.event.Logging
import akka.actor.ActorSystem
object test extends App {
val system = ActorSystem("hello-world")
val myActor = system.actorOf(Props[MyActor], "myactor2")
}
class MyActor extends Actor {
val log = Logging(context.system, this)
val props1 = Props[MyActor]
def receive = {
case "test" => log.info("received test")
case _ => log.info("received unknown message")
}
val child = context.actorOf(Props[MyActor], name = "myChild")
}
So when I run it, I receive
[error] (run-main-1) java.lang.RuntimeException: While trying to load extension [akka.actor.InstanceCountingExtension]
java.lang.RuntimeException: While trying to load extension [akka.actor.InstanceCountingExtension]
at akka.actor.ActorSystemImpl.$anonfun$loadExtensions$1(ActorSystem.scala:906)
at scala.collection.Iterator.foreach(Iterator.scala:929)
at scala.collection.Iterator.foreach$(Iterator.scala:929)
at scala.collection.AbstractIterator.foreach(Iterator.scala:1406)
at scala.collection.IterableLike.foreach(IterableLike.scala:71)
...
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
Caused by: java.lang.ClassNotFoundException: akka.actor.InstanceCountingExtension
at java.lang.ClassLoader.findClass(ClassLoader.java:530)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
[trace] Stack trace suppressed: run last compile:run for the full output.
java.lang.RuntimeException: Nonzero exit code: 1
at scala.sys.package$.error(package.scala:27)
The problem is the ActorSystem, but i can't understand why. When I delete the system an myActor everything works fine. It even works when i make it only val system = ActorSystem but then system couldn't create actorOf.
You probably have this setting in your application.conf
akka.library-extensions += "akka.actor.InstanceCountingExtension"
This is an actor system extension used by akka-actor-tests to make assertions about the number of actor instances currently running in a system.
I don't think this is intended as an extension to be used by applications, it is more like a test utility.
However, depending on what you need:
if you just want to run your program, just delete the configuration line above, and all should be fine
if you need the extension for some reason, import akka-actor-tests test jar, or alternatively make sure you got this class available at runtime.
The problem was with the test folder. When I removed the test it started working.
I'm trying to run a scala program,
class HelloWorld {
var myField = 0;
def getMyField() : Int = {
return this.myField;
}
}
I keep getting a ClassNotFoundException even though the program is named HelloWorld.scala
Full Error below
Exception in thread "main" java.lang.ClassNotFoundException: HelloWorld
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:190)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:122)
Okay, looking at the documentation of scala http://www.scala-lang.org/documentation/getting-started.html
I changed the code to this,
object HelloWorld {
def main(args: Array[String]) {
println("Hello, world!")
}
}
This is the error now
Information:24/7/15 10:55 AM - Compilation completed with 1 error and 7 warnings in 2s 32ms
Error:scalac: Error: org.jetbrains.jps.incremental.scala.remote.ServerException
Error compiling sbt component 'compiler-interface-2.8.0.final-51.0'
at sbt.compiler.AnalyzingCompiler$$anonfun$compileSources$1$$anonfun$apply$2.apply(AnalyzingCompiler.scala:145)
at sbt.compiler.AnalyzingCompiler$$anonfun$compileSources$1$$anonfun$apply$2.apply(AnalyzingCompiler.scala:142)
at sbt.IO$.withTemporaryDirectory(IO.scala:285)
at sbt.compiler.AnalyzingCompiler$$anonfun$compileSources$1.apply(AnalyzingCompiler.scala:142)
at sbt.compiler.AnalyzingCompiler$$anonfun$compileSources$1.apply(AnalyzingCompiler.scala:139)
at sbt.IO$.withTemporaryDirectory(IO.scala:285)
at sbt.compiler.AnalyzingCompiler$.compileSources(AnalyzingCompiler.scala:139)
at sbt.compiler.IC$.compileInterfaceJar(IncrementalCompiler.scala:33)
at org.jetbrains.jps.incremental.scala.local.CompilerFactoryImpl$.org$jetbrains$jps$incremental$scala$local$CompilerFactoryImpl$$getOrCompileInterfaceJar(CompilerFactoryImpl.scala:87)
at org.jetbrains.jps.incremental.scala.local.CompilerFactoryImpl$$anonfun$getScalac$1.apply(CompilerFactoryImpl.scala:44)
at org.jetbrains.jps.incremental.scala.local.CompilerFactoryImpl$$anonfun$getScalac$1.apply(CompilerFactoryImpl.scala:43)
at scala.Option.map(Option.scala:145)
at org.jetbrains.jps.incremental.scala.local.CompilerFactoryImpl.getScalac(CompilerFactoryImpl.scala:43)
at org.jetbrains.jps.incremental.scala.local.CompilerFactoryImpl.createCompiler(CompilerFactoryImpl.scala:22)
at org.jetbrains.jps.incremental.scala.local.CachingFactory$$anonfun$createCompiler$1.apply(CachingFactory.scala:24)
at org.jetbrains.jps.incremental.scala.local.CachingFactory$$anonfun$createCompiler$1.apply(CachingFactory.scala:24)
at org.jetbrains.jps.incremental.scala.local.Cache$$anonfun$getOrUpdate$2.apply(Cache.scala:20)
at scala.Option.getOrElse(Option.scala:120)
at org.jetbrains.jps.incremental.scala.local.Cache.getOrUpdate(Cache.scala:19)
at org.jetbrains.jps.incremental.scala.local.CachingFactory.createCompiler(CachingFactory.scala:23)
at org.jetbrains.jps.incremental.scala.local.LocalServer.compile(LocalServer.scala:22)
at org.jetbrains.jps.incremental.scala.remote.Main$.make(Main.scala:62)
at org.jetbrains.jps.incremental.scala.remote.Main$.nailMain(Main.scala:20)
at org.jetbrains.jps.incremental.scala.remote.Main.nailMain(Main.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.martiansoftware.nailgun.NGSession.run(NGSession.java:319)
Warning:scalac: /tmp/sbt_20e2573f/compiler-interface-sources/CompilerInterface.scala:161: error: object creation impossible, since method registerTopLevelSym in trait GlobalCompat of type (sym: this.Symbol)Unit is not defined
Warning:scalac: new Compiler() with RangePositions // unnecessary in 2.11
Warning:scalac: ^
Warning:scalac: /tmp/sbt_20e2573f/compiler-interface-sources/CompilerInterface.scala:165: error: class Compiler needs to be abstract, since method registerTopLevelSym in trait GlobalCompat of type (sym: Compiler.this.Symbol)Unit is not defined
Warning:scalac: class Compiler extends CallbackGlobal(command.settings, dreporter, output)
Warning:scalac: ^
Warning:scalac: two errors found
Your errors are not in the code but in the way you're trying to run the code.
I loaded the code into the REPL and got no error. I loaded the code into IntelliJ and got lots of style warnings but no errors. I compiled the code and ran it from the command line:
%> java HelloWorld
Error: Main method not found in class HelloWorld, please define the
main method as:
public static void main(String[] args)
Which is what one should expect.
I am not getting how you are trying to run your program. Since I am not getting any errors. Let me share you a simple way to run your code snippet.
class HelloWorld{
var myField = 0;
def getMyField() : Int = {
return this.myField;
}
}
object Test extends App{
println(new HelloWorld().getMyField())
}
Try to run Test object by right clicking inside Test. Hope I was helpful.
Assuming you are running IntelliJ, try to build the project (CTRL+F9) and then run it. I had the same issue and it worked for me.
I've got an Akka actor that reads the contents of a file in chunks of around 1500 bytes. When the actor receives a NextBlock message it replies with the next block of data wrapped in a ByteString. A couple very simple tests and manually eyeballing data indicate the actor is working correctly. I'm using Scala 2.11.5, Akka 2.3.9, ScalaTest 2.2.1 and SBT 0.13.5.
I'm having an issue setting up larger test. I want to write around 10kB or so of a test pattern data into a file then verify the Actor's output is what I expect. I'm creating the test pattern via ByteStringBuilder. When I go to write the test data to the file I'm getting NullPointerExceptions. Here is the code for a striped down version of the test that exhibits the issue:
import java.nio.ByteOrder
import java.nio.file.StandardOpenOption._
import java.nio.file.{Files, Paths}
import akka.actor.ActorSystem
import akka.testkit.TestKit
import akka.util.{ByteString, ByteStringBuilder}
import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike}
class ByteBufferTest extends TestKit(ActorSystem("ByteBufferTest"))
with WordSpecLike with Matchers with BeforeAndAfterAll {
implicit val byteOrder = ByteOrder.BIG_ENDIAN
val file = Paths.get("test.data")
Files.deleteIfExists(file)
createTestFile()
"A ByteBufferTest" must { "work" in { assert(true) } }
def createTestFile(): Unit = {
val out = Files.newByteChannel(file, CREATE, WRITE)
out.write(contents.toByteBuffer) // Here is where the NPE occurs
out.close()
}
val contents: ByteString = {
val builder = new ByteStringBuilder
(0 to 255).foreach(builder.putInt)
builder.result()
}
override protected def afterAll(): Unit = {
Files.delete(file)
system.shutdown()
}
}
I've tried getting around this a bunch of different ways
converting the ByteString to a ByteBuffer and writing it via ByteChannel (show above)
write individual bytes of the ByteString to a BufferedOutputStream
convert the ByteString to Array[Byte] and write that via BufferedOutputStream
No matter what I try I keep ending up with something along the lines of
[debug] Running TaskDef(demo.ByteBufferTest, org.scalatest.tools.Framework$$anon$1#40fbf2c, false, [SuiteSelector])
java.lang.NullPointerException at demo.ByteBufferTest.createTestFile(ByteBufferTest.scala:32)
at demo.ByteBufferTest.<init>(ByteBufferTest.scala:21)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at java.lang.Class.newInstance(Class.java:374)
at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:641)
at sbt.TestRunner.runTest$1(TestFramework.scala:84)
at sbt.TestRunner.run(TestFramework.scala:94)
at sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:219)
at sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:219)
at sbt.TestFramework$.sbt$TestFramework$$withContextLoader(TestFramework.scala:207)
at sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:219)
at sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:219)
at sbt.TestFunction.apply(TestFramework.scala:224)
at sbt.Tests$$anonfun$7.apply(Tests.scala:196)
at sbt.Tests$$anonfun$7.apply(Tests.scala:196)
at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:45)
at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:45)
at sbt.std.Transform$$anon$4.work(System.scala:64)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
at sbt.Execute.work(Execute.scala:244)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:160)
at sbt.CompletionService$$anon$2.call(CompletionService.scala:30)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Anyone have any ideas what I'm doing wrong?
I've put a example project up on github
I didn't find the exact root cause but it seems that it is related to the initialization when the test class is launched from scala test.
I suggest to put the createTestFile() in the method of beforeAll(). Tested and it works.
override def beforeAll {
createTestFile()
}
I'm running into a problem with an actor that extends Stash and which works perfectly fine when instantiating it with actorOf in a simple ActorSystem. Now I would actually like to write some tests for my stashing actors before using them in my program. But I cannot figure out a way to use an TestActorRef with this actor in my test suite.
The code that works looks like this:
import akka.actor.{Stash, Actor, ActorSystem, Props}
import com.typesafe.config.ConfigFactory
object StashTest {
val config = ConfigFactory.parseString(
"""
|akka.actor.default-mailbox {
| mailbox-type = "akka.dispatch.UnboundedDequeBasedMailbox"
|}
""".stripMargin)
}
class StashTestActor extends Stash {
def receive: Actor.Receive = {
case "unstash" =>
unstashAll()
context become print
case msg => stash()
}
def print: Actor.Receive = {
case msg => println(s"Unstashed message: $msg")
}
}
val system = ActorSystem("stashSystem", StashTest.config)
val ref = system.actorOf(Props[StashTestActor])
ref ! "stash me"
ref ! "blah"
ref ! "unstash"
Which prints
Unstashed message: stash me
Unstashed message: blah
But if I try to write a WordSpec test for this actor, it leaves me with some nasty exceptions I can't figure out what they would like me to change in my code.
The test class looks like this
import akka.testkit.{TestActorRef, TestKit}
import akka.actor.{Stash, Actor, ActorSystem}
import org.scalatest.{WordSpecLike, MustMatchers}
import com.typesafe.config.ConfigFactory
class StashTestActor extends Stash {
def receive: Actor.Receive = {
case "unstash" =>
unstashAll()
context become print
case msg => stash()
}
def print: Actor.Receive = {
case msg => println(s"Unstashed message: $msg")
}
}
class StashTest extends TestKit(ActorSystem("testSystem", StashTest.config))
with WordSpecLike
with MustMatchers {
"A simple stashing actor" must {
val actorRef = TestActorRef[StashTestActor]
"stash messages" in {
actorRef ! "stash me!"
}
"unstash all messages" in {
actorRef ! "unstash"
}
}
}
object StashTest {
val config = ConfigFactory.parseString(
"""
|akka.actor.default-mailbox {
| mailbox-type = "akka.dispatch.UnboundedDequeBasedMailbox"
|}
""".stripMargin)
}
When running the test, I get following exceptions that are thrown during the instantiation of the TestActorRef.
[ERROR] [08/20/2013 14:19:40.765] [testSystem-akka.actor.default-dispatcher-3] [akka://testSystem/user/$$a] Could not instantiate Actor
Make sure Actor is NOT defined inside a class/trait,
if so put it outside the class/trait, f.e. in a companion object,
OR try to change: 'actorOf(Props[MyActor]' to 'actorOf(Props(new MyActor)'.
akka.actor.ActorInitializationException: exception during creation
at akka.actor.ActorInitializationException$.apply(Actor.scala:218)
at akka.actor.ActorCell.create(ActorCell.scala:578)
at akka.actor.ActorCell.invokeAll$1(ActorCell.scala:425)
at akka.actor.ActorCell.systemInvoke(ActorCell.scala:447)
at akka.dispatch.Mailbox.processAllSystemMessages(Mailbox.scala:262)
at akka.testkit.CallingThreadDispatcher.process$1(CallingThreadDispatcher.scala:244)
at akka.testkit.CallingThreadDispatcher.runQueue(CallingThreadDispatcher.scala:284)
at akka.testkit.CallingThreadDispatcher.register(CallingThreadDispatcher.scala:153)
at akka.dispatch.MessageDispatcher.attach(AbstractDispatcher.scala:133)
at akka.actor.dungeon.Dispatch$class.start(Dispatch.scala:84)
at akka.actor.ActorCell.start(ActorCell.scala:338)
at akka.testkit.TestActorRef.<init>(TestActorRef.scala:50)
at akka.testkit.TestActorRef$.apply(TestActorRef.scala:141)
at akka.testkit.TestActorRef$.apply(TestActorRef.scala:137)
at akka.testkit.TestActorRef$.apply(TestActorRef.scala:146)
at akka.testkit.TestActorRef$.apply(TestActorRef.scala:144)
at stashActorTest.StashTest$$anonfun$1.apply$mcV$sp(StashTestActor.scala:29)
at stashActorTest.StashTest$$anonfun$1.apply(StashTestActor.scala:28)
at stashActorTest.StashTest$$anonfun$1.apply(StashTestActor.scala:28)
at org.scalatest.SuperEngine.registerNestedBranch(Engine.scala:613)
at org.scalatest.WordSpecLike$class.org$scalatest$WordSpecLike$$registerBranch(WordSpecLike.scala:120)
at org.scalatest.WordSpecLike$$anon$2.apply(WordSpecLike.scala:851)
at org.scalatest.words.MustVerb$StringMustWrapperForVerb$class.must(MustVerb.scala:189)
at org.scalatest.matchers.MustMatchers$StringMustWrapper.must(MustMatchers.scala:6167)
at stashActorTest.StashTest.<init>(StashTestActor.scala:28)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at java.lang.Class.newInstance(Class.java:374)
at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:444)
at sbt.TestRunner.runTest$1(TestFramework.scala:84)
at sbt.TestRunner.run(TestFramework.scala:94)
at sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:224)
at sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:224)
at sbt.TestFramework$.sbt$TestFramework$$withContextLoader(TestFramework.scala:212)
at sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:224)
at sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:224)
at sbt.TestFunction.apply(TestFramework.scala:229)
at sbt.Tests$$anonfun$7.apply(Tests.scala:196)
at sbt.Tests$$anonfun$7.apply(Tests.scala:196)
at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:45)
at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:45)
at sbt.std.Transform$$anon$4.work(System.scala:64)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
at sbt.Execute.work(Execute.scala:244)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:160)
at sbt.CompletionService$$anon$2.call(CompletionService.scala:30)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)
Caused by: akka.actor.ActorInitializationException: Could not instantiate Actor
Make sure Actor is NOT defined inside a class/trait,
if so put it outside the class/trait, f.e. in a companion object,
OR try to change: 'actorOf(Props[MyActor]' to 'actorOf(Props(new MyActor)'.
at akka.actor.ActorInitializationException$.apply(Actor.scala:218)
at akka.testkit.TestActorRef$$anonfun$apply$2$$anonfun$apply$1.applyOrElse(TestActorRef.scala:148)
at akka.testkit.TestActorRef$$anonfun$apply$2$$anonfun$apply$1.applyOrElse(TestActorRef.scala:147)
at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:33)
at scala.util.Failure$$anonfun$recover$1.apply(Try.scala:185)
at scala.util.Try$.apply(Try.scala:161)
at scala.util.Failure.recover(Try.scala:185)
at akka.testkit.TestActorRef$$anonfun$apply$2.apply(TestActorRef.scala:147)
at akka.testkit.TestActorRef$$anonfun$apply$2.apply(TestActorRef.scala:153)
at akka.actor.CreatorFunctionConsumer.produce(Props.scala:369)
at akka.actor.Props.newActor(Props.scala:323)
at akka.actor.ActorCell.newActor(ActorCell.scala:534)
at akka.actor.ActorCell.create(ActorCell.scala:560)
... 58 more
Caused by: java.lang.NullPointerException
at akka.actor.UnrestrictedStash$class.$init$(Stash.scala:82)
at stashActorTest.StashTestActor.<init>(StashTestActor.scala:9)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at akka.actor.ReflectiveDynamicAccess$$anonfun$createInstanceFor$2.apply(DynamicAccess.scala:78)
at scala.util.Try$.apply(Try.scala:161)
at akka.actor.ReflectiveDynamicAccess.createInstanceFor(DynamicAccess.scala:73)
... 64 more
I don't have any problems with using TestActorRefs with actors that don't extend Stash. So I don't know if it is a configuration error or something else I'm missing.
TestActorRef can't be used together with Stash. TestActorRef requires a CallingThreadMailbox and Stash requires DequeBasedMessageQueueSemantics. The documentation should include this limitation and the error messages should be improved.
Using the default akka dispatcher allowed me to use Stash and TestActorRef:
val myActor = TestActorRef[MyActor](Props(classOf[MyActor]).withDispatcher("akka.actor.default-dispatcher"))
Note that this means your tests will no longer use the default CallingThreadDispatcher and will lose the benefits highlighted in the akka docs
I was able to test actors with Stash like this:
val actor = TestActorRef(Props(new MyActorWithStash()).withDispatcher("deque"))