diff --git a/akka-actor-tests/src/test/scala/akka/actor/DynamicAccessSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/DynamicAccessSpec.scala new file mode 100644 index 0000000000..ffc36a5577 --- /dev/null +++ b/akka-actor-tests/src/test/scala/akka/actor/DynamicAccessSpec.scala @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2019 Lightbend Inc. + */ + +package akka.actor + +import org.scalatest._ + +import scala.collection.immutable +import scala.concurrent.Await +import scala.concurrent.duration._ +import scala.util.{ Failure, Success, Try } + +abstract class TestSuperclass { + def name: String +} + +class TestClassWithStringConstructor(val name: String) extends TestSuperclass +class TestClassWithDefaultConstructor extends TestSuperclass { + override def name = "default" +} + +class DynamicAccessSpec extends WordSpec with Matchers with BeforeAndAfterAll { + val system = ActorSystem() + + "The DynamicAccess of a system" should { + val dynamicAccess = system.asInstanceOf[ExtendedActorSystem].dynamicAccess + + "instantiate an object with a default constructor" in { + val instance: Try[TestClassWithDefaultConstructor] = dynamicAccess + .createInstanceFor[TestClassWithDefaultConstructor]("akka.actor.TestClassWithDefaultConstructor", Nil) + instance match { + case Success(i) => i shouldNot be(null) + case Failure(t) => fail(t) + } + } + + "throw a ClassNotFound exception when the class is not found" in { + dynamicAccess.createInstanceFor[TestClassWithDefaultConstructor]("foo.NonExistingClass", Nil) match { + case Success(instance) => + fail(s"Expected failure, found $instance") + case Failure(e) => + e shouldBe a[ClassNotFoundException] + } + } + + "try different constructors with recoverWith" in { + instantiateWithDefaultOrStringCtor("akka.actor.TestClassWithStringConstructor").get.name shouldBe "string ctor argument" + instantiateWithDefaultOrStringCtor("akka.actor.TestClassWithDefaultConstructor").get.name shouldBe "default" + instantiateWithDefaultOrStringCtor("akka.actor.foo.NonExistingClass") match { + case Failure(t) => + t shouldBe a[ClassNotFoundException] + case Success(instance) => + fail(s"unexpected instance $instance") + } + } + + def instantiateWithDefaultOrStringCtor(fqcn: String): Try[TestSuperclass] = + // recoverWith doesn't work with scala 2.13.0-M5 + // https://github.com/scala/bug/issues/11242 + dynamicAccess.createInstanceFor[TestSuperclass](fqcn, Nil) match { + case s: Success[TestSuperclass] => s + case Failure(_: NoSuchMethodException) => + dynamicAccess + .createInstanceFor[TestSuperclass](fqcn, immutable.Seq((classOf[String], "string ctor argument"))) + case f: Failure[_] => f + } + + } + + override def afterAll() = { + Await.result(system.terminate(), 10.seconds) + super.afterAll() + } +} diff --git a/akka-coordination/src/main/scala/akka/coordination/lease/scaladsl/LeaseProvider.scala b/akka-coordination/src/main/scala/akka/coordination/lease/scaladsl/LeaseProvider.scala index 2ad301b477..555401145a 100644 --- a/akka-coordination/src/main/scala/akka/coordination/lease/scaladsl/LeaseProvider.scala +++ b/akka-coordination/src/main/scala/akka/coordination/lease/scaladsl/LeaseProvider.scala @@ -5,11 +5,10 @@ package akka.coordination.lease.scaladsl import java.util.concurrent.ConcurrentHashMap -import java.util.function.{ Function ⇒ JFunction } +import java.util.function.{ Function => JFunction } import scala.collection.immutable -import scala.util.Failure -import scala.util.Success +import scala.util.{ Failure, Success, Try } import akka.actor.ActorSystem import akka.actor.ExtendedActorSystem import akka.actor.Extension @@ -65,15 +64,17 @@ class LeaseProvider(system: ExtendedActorSystem) extends Extension { val fqcn = leaseSettings.leaseConfig.getString("lease-class") require(fqcn.nonEmpty, "lease-class must not be empty") val dynamicAccess = system.dynamicAccess - dynamicAccess - .createInstanceFor[Lease]( - fqcn, - immutable.Seq((classOf[LeaseSettings], leaseSettings), (classOf[ExtendedActorSystem], system))) - .recoverWith { - case _: NoSuchMethodException ⇒ - dynamicAccess.createInstanceFor[Lease](fqcn, immutable.Seq((classOf[LeaseSettings], leaseSettings))) - - } match { + val instance: Try[Lease] = dynamicAccess.createInstanceFor[Lease]( + fqcn, + immutable.Seq((classOf[LeaseSettings], leaseSettings), (classOf[ExtendedActorSystem], system))) match { + case s: Success[Lease] => + s + case Failure(_: NoSuchMethodException) => + dynamicAccess.createInstanceFor[Lease](fqcn, immutable.Seq((classOf[LeaseSettings], leaseSettings))) + case f: Failure[_] => + f + } + instance match { case Success(value) ⇒ value case Failure(e) ⇒ log.error(