mgttlinger
mgttlinger

Reputation: 1435

Create an actor

This is probably an extremely simple error but I can't get it to work properly. I am using akka 2.2.3 to create an actor based application in scala.

The simplified setup is the following:

object Main {
  def main(args: Array[String]) = {
    val system = ActorSystem("Test")
    val discoverer = system.actorOf(Props[Discoverer], "discoverer")

    implicit val timeout = Timeout(5.seconds)

    val not = discoverer ? Messages.Find(something)

    not.onComplete {
      case Success(va) => println(va)
      case Failure(err) => println(err)
    }
    ...
  }
}

And the main actor

class Discoverer extends Actor {
  override def preStart() = {
    val refresher = context.actorOf(Props[Refresher], "refresher")
    refresher ! Refresh
  }

  def receive = {
    case _ => sender ! Answer
  }
}

And the Refresher actor

 class Refresher extends Actor {
   ...
 }

What you should take away from this is that none of my actors has parameterized constructors.

However if I try to run my application it fails with

[ERROR] [12/09/2013 13:17:06.893] [Test-akka.actor.default-dispatcher-3] 
 [akka://Test/user/discoverer] no matching constructor found on 
  class Discoverer$Refresher for arguments []

What is my error here? Am I not supposed to create my actors with .actorOf(Props[Class], "actorname")?

Upvotes: 9

Views: 3110

Answers (2)

vptheron
vptheron

Reputation: 7476

Refresher is an inner class of Discoverer, therefor, if you want to create an instance of Refresher you need to do it in the context of an instance of Discoverer.

Take this example:

class A{
  class B{}
}

I can do new A, but new B will return an error. I have to do:

val a = new A
val b = new a.B

That's why akka failed to create this actor.

Upvotes: 0

cmbaxter
cmbaxter

Reputation: 35463

If you want to make this work with nested classes, you will need to instantiate the nested actor passing in a reference to the enclosing actor as a constructor arg. The error you are seeing is saying that there is no no-args constructor, so that's a hint. The code to make things work would look like this:

object InnerTest {
  def main(args: Array[String]) {
    val sys = ActorSystem("test")
    sys.actorOf(Props[OuterActor])
  }
}

class OuterActor extends Actor{

  override def preStart = {
    context.actorOf(Props(classOf[InnerActor], this), "my-inner-actor")
  }

  def receive = {
    case _ =>
  }

  class InnerActor extends Actor{
    def receive = {
      case _ =>
    }
  }
}

My guess is that this has to do with trying to instantiate a non-static inner class (via reflection) without giving a reference to it's outer class. I determined this by reading through this post:

https://www.assembla.com/spaces/akka/tickets/3675#/activity/ticket:

Upvotes: 12

Related Questions