diff --git a/akka-actor-tests/src/test/java/akka/actor/ActorCreationTest.java b/akka-actor-tests/src/test/java/akka/actor/ActorCreationTest.java index 55b6a74eb3..63e73a2c5b 100644 --- a/akka-actor-tests/src/test/java/akka/actor/ActorCreationTest.java +++ b/akka-actor-tests/src/test/java/akka/actor/ActorCreationTest.java @@ -54,19 +54,38 @@ public class ActorCreationTest { return null; } } - + + + static class G implements Creator { + public Object create() { + return null; + } + } + + @Test + @SuppressWarnings("unchecked") + public void testErasedCreator() { + try { + Props.create(new G()); + assert false; + } catch(IllegalArgumentException e) { + assertEquals("erased Creator types are unsupported, use Props.create(actorClass, creator) instead", e.getMessage()); + } + Props.create(UntypedActor.class, new G()); + } + @Test public void testRightCreator() { final Props p = Props.create(new C()); assertEquals(UntypedActor.class, p.actorClass()); } - @Test - public void testTopLevelNonStaticCreator() { - final Props p = Props.create(new NonStaticCreator()); - assertEquals(UntypedActor.class, p.actorClass()); - } - + @Test + public void testTopLevelNonStaticCreator() { + final Props p = Props.create(new NonStaticCreator()); + assertEquals(UntypedActor.class, p.actorClass()); + } + @Test public void testParametricCreator() { final Props p = Props.create(new D()); diff --git a/akka-actor-tests/src/test/java/akka/actor/JavaAPI.java b/akka-actor-tests/src/test/java/akka/actor/JavaAPI.java index f81c10ceb5..8dced3d447 100644 --- a/akka-actor-tests/src/test/java/akka/actor/JavaAPI.java +++ b/akka-actor-tests/src/test/java/akka/actor/JavaAPI.java @@ -57,12 +57,27 @@ public class JavaAPI { }); } + @SuppressWarnings("unchecked") + public static Props mkErasedProps() { + return Props.create(JavaAPITestActor.class, new Creator() { + public Object create() { + return new JavaAPITestActor(); + } + }); + } + @Test public void mustBeAbleToCreateActorRefFromFactory() { ActorRef ref = system.actorOf(mkProps()); assertNotNull(ref); } + @Test + public void mustBeAbleToCreateActorRefFromErasedFactory() { + ActorRef ref = system.actorOf(mkErasedProps()); + assertNotNull(ref); + } + @Test public void mustBeAbleToCreateActorWIthConstructorParams() { ActorRef ref = system.actorOf(Props.create(ActorWithConstructorParams.class, "a", "b", new Integer(17), 18)); diff --git a/akka-actor/src/main/scala/akka/actor/Props.scala b/akka-actor/src/main/scala/akka/actor/Props.scala index 10f9ca5e1a..8e39bfbd13 100644 --- a/akka-actor/src/main/scala/akka/actor/Props.scala +++ b/akka-actor/src/main/scala/akka/actor/Props.scala @@ -100,12 +100,19 @@ object Props { /** * Create new Props from the given [[akka.japi.Creator]]. + * + * You can not use a Java 8 lambda with this method since the generated classes + * don't carry enough type information. + * + * Use the Props.create(actorClass, creator) instead. */ def create[T <: Actor](creator: Creator[T]): Props = { - if ((creator.getClass.getEnclosingClass ne null) && (creator.getClass.getModifiers & Modifier.STATIC) == 0) + val cc = creator.getClass + if ((cc.getEnclosingClass ne null) && (cc.getModifiers & Modifier.STATIC) == 0) throw new IllegalArgumentException("cannot use non-static local Creator to create actors; make it static (e.g. local to a static method) or top-level") val ac = classOf[Actor] - val actorClass = Reflect.findMarker(creator.getClass, classOf[Creator[_]]) match { + val coc = classOf[Creator[_]] + val actorClass = Reflect.findMarker(cc, coc) match { case t: ParameterizedType ⇒ t.getActualTypeArguments.head match { case c: Class[_] ⇒ c // since T <: Actor @@ -113,9 +120,18 @@ object Props { v.getBounds collectFirst { case c: Class[_] if ac.isAssignableFrom(c) && c != ac ⇒ c } getOrElse ac case x ⇒ throw new IllegalArgumentException(s"unsupported type found in Creator argument [$x]") } + case c: Class[_] if (c == coc) ⇒ + throw new IllegalArgumentException(s"erased Creator types are unsupported, use Props.create(actorClass, creator) instead") } apply(defaultDeploy, classOf[CreatorConsumer], actorClass :: creator :: Nil) } + + /** + * Create new Props from the given [[akka.japi.Creator]] with the type set to the given actorClass. + */ + def create[T <: Actor](actorClass: Class[T], creator: Creator[T]): Props = { + apply(defaultDeploy, classOf[CreatorConsumer], actorClass :: creator :: Nil) + } } /**