improve safety of Props.create by allowing Creator<T>, see #3377
Props constructors need to be deprecated instead of being mutated because we cannot just start throwing exceptions in people’s existing code. Props.withCreator is deprecated for similar reasons, but also because Props are about the creators, so replacing that after the fact is not good style.
This commit is contained in:
parent
58756be937
commit
f8fa825e48
11 changed files with 222 additions and 45 deletions
|
|
@ -0,0 +1,68 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package akka.actor;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import akka.japi.Creator;
|
||||||
|
|
||||||
|
public class ActorCreationTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWrongCreator() {
|
||||||
|
try {
|
||||||
|
Props.create(new Creator<Actor>() {
|
||||||
|
@Override
|
||||||
|
public Actor create() throws Exception {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assert false;
|
||||||
|
} catch(IllegalArgumentException e) {
|
||||||
|
assertEquals("cannot use non-static local Creator to create actors; make it static or top-level", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class C implements Creator<UntypedActor> {
|
||||||
|
@Override
|
||||||
|
public UntypedActor create() throws Exception {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class D<T> implements Creator<T> {
|
||||||
|
@Override
|
||||||
|
public T create() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class E<T extends UntypedActor> implements Creator<T> {
|
||||||
|
@Override
|
||||||
|
public T create() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRightCreator() {
|
||||||
|
final Props p = Props.create(new C());
|
||||||
|
assertEquals(UntypedActor.class, p.actorClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParametricCreator() {
|
||||||
|
final Props p = Props.create(new D<UntypedActor>());
|
||||||
|
assertEquals(Actor.class, p.actorClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBoundedCreator() {
|
||||||
|
final Props p = Props.create(new E<UntypedActor>());
|
||||||
|
assertEquals(UntypedActor.class, p.actorClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -12,9 +12,12 @@ import akka.util.Reflect
|
||||||
import scala.annotation.varargs
|
import scala.annotation.varargs
|
||||||
import Deploy.{ NoDispatcherGiven, NoMailboxGiven }
|
import Deploy.{ NoDispatcherGiven, NoMailboxGiven }
|
||||||
import scala.collection.immutable
|
import scala.collection.immutable
|
||||||
|
|
||||||
import scala.language.existentials
|
import scala.language.existentials
|
||||||
import java.lang.reflect.Constructor
|
import java.lang.reflect.Constructor
|
||||||
|
import java.lang.reflect.Modifier
|
||||||
|
import scala.annotation.tailrec
|
||||||
|
import java.lang.reflect.ParameterizedType
|
||||||
|
import java.lang.reflect.TypeVariable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory for Props instances.
|
* Factory for Props instances.
|
||||||
|
|
@ -40,16 +43,16 @@ object Props {
|
||||||
*/
|
*/
|
||||||
final val defaultDeploy = Deploy()
|
final val defaultDeploy = Deploy()
|
||||||
|
|
||||||
/**
|
|
||||||
* The default Props instance, uses the settings from the Props object starting with default*.
|
|
||||||
*/
|
|
||||||
final val default = new Props()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Props instance whose creator will create an actor that doesn't respond to any message
|
* A Props instance whose creator will create an actor that doesn't respond to any message
|
||||||
*/
|
*/
|
||||||
final val empty = Props[EmptyActor]
|
final val empty = Props[EmptyActor]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default Props instance, uses the settings from the Props object starting with default*.
|
||||||
|
*/
|
||||||
|
final val default = new Props()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* INTERNAL API
|
* INTERNAL API
|
||||||
*
|
*
|
||||||
|
|
@ -85,7 +88,7 @@ object Props {
|
||||||
/**
|
/**
|
||||||
* The deprecated legacy constructor.
|
* The deprecated legacy constructor.
|
||||||
*/
|
*/
|
||||||
@deprecated("give class and arguments instead", "2.2")
|
@deprecated("use Props.withDispatcher and friends", "2.2")
|
||||||
def apply(
|
def apply(
|
||||||
creator: () ⇒ Actor = Props.defaultCreator,
|
creator: () ⇒ Actor = Props.defaultCreator,
|
||||||
dispatcher: String = Dispatchers.DefaultDispatcherId,
|
dispatcher: String = Dispatchers.DefaultDispatcherId,
|
||||||
|
|
@ -98,6 +101,13 @@ object Props {
|
||||||
if (d2 != Props.defaultDeploy) p.withDeploy(d2) else p
|
if (d2 != Props.defaultDeploy) p.withDeploy(d2) else p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The deprecated legacy extractor.
|
||||||
|
*/
|
||||||
|
@deprecated("use three-argument version", "2.2")
|
||||||
|
def unapply(p: Props)(dummy: Int = 0): Option[(() ⇒ Actor, String, RouterConfig, Deploy)] =
|
||||||
|
Some((p.creator, p.dispatcher, p.routerConfig, p.deploy))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scala API: create a Props given a class and its constructor arguments.
|
* Scala API: create a Props given a class and its constructor arguments.
|
||||||
*/
|
*/
|
||||||
|
|
@ -108,6 +118,30 @@ object Props {
|
||||||
*/
|
*/
|
||||||
@varargs
|
@varargs
|
||||||
def create(clazz: Class[_], args: AnyRef*): Props = apply(defaultDeploy, clazz, args.toVector)
|
def create(clazz: Class[_], args: AnyRef*): Props = apply(defaultDeploy, clazz, args.toVector)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create new Props from the given [[Creator]].
|
||||||
|
*/
|
||||||
|
def create[T <: Actor](creator: Creator[T]): Props = {
|
||||||
|
if ((creator.getClass.getModifiers & Modifier.STATIC) == 0)
|
||||||
|
throw new IllegalArgumentException("cannot use non-static local Creator to create actors; make it static or top-level")
|
||||||
|
val cc = classOf[Creator[_]]
|
||||||
|
val ac = classOf[Actor]
|
||||||
|
@tailrec def findType(c: Class[_]): Class[_] = {
|
||||||
|
c.getGenericInterfaces collectFirst {
|
||||||
|
case t: ParameterizedType if cc.isAssignableFrom(t.getRawType.asInstanceOf[Class[_]]) ⇒
|
||||||
|
t.getActualTypeArguments.head match {
|
||||||
|
case c: Class[_] ⇒ c // since T <: Actor
|
||||||
|
case v: TypeVariable[_] ⇒
|
||||||
|
v.getBounds collectFirst { case c: Class[_] if ac.isAssignableFrom(c) && c != ac ⇒ c } getOrElse ac
|
||||||
|
}
|
||||||
|
} match {
|
||||||
|
case Some(x) ⇒ x
|
||||||
|
case None ⇒ findType(c.getSuperclass)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
apply(defaultDeploy, classOf[CreatorConsumer], findType(creator.getClass) :: creator :: Nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -183,7 +217,7 @@ final case class Props(deploy: Deploy, clazz: Class[_], args: immutable.Seq[Any]
|
||||||
* non-serializable inner classes, making them also
|
* non-serializable inner classes, making them also
|
||||||
* non-serializable
|
* non-serializable
|
||||||
*/
|
*/
|
||||||
@deprecated("use Props.create", "2.2")
|
@deprecated("use Props.create()", "2.2")
|
||||||
def this(factory: UntypedActorFactory) = this(Props.defaultDeploy, classOf[UntypedActorFactoryConsumer], Vector(factory))
|
def this(factory: UntypedActorFactory) = this(Props.defaultDeploy, classOf[UntypedActorFactoryConsumer], Vector(factory))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -227,6 +261,7 @@ final case class Props(deploy: Deploy, clazz: Class[_], args: immutable.Seq[Any]
|
||||||
*
|
*
|
||||||
* The creator must not return the same instance multiple times.
|
* The creator must not return the same instance multiple times.
|
||||||
*/
|
*/
|
||||||
|
@deprecated("use Props(...).withDeploy(other.deploy)", "2.2")
|
||||||
def withCreator(c: ⇒ Actor): Props = copy(clazz = classOf[CreatorFunctionConsumer], args = (() ⇒ c) :: Nil)
|
def withCreator(c: ⇒ Actor): Props = copy(clazz = classOf[CreatorFunctionConsumer], args = (() ⇒ c) :: Nil)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -239,8 +274,8 @@ final case class Props(deploy: Deploy, clazz: Class[_], args: immutable.Seq[Any]
|
||||||
* non-serializable inner classes, making them also
|
* non-serializable inner classes, making them also
|
||||||
* non-serializable
|
* non-serializable
|
||||||
*/
|
*/
|
||||||
@deprecated("use Props.create(clazz, args ...) instead", "2.2")
|
@deprecated("use Props.create(clazz, args ...).withDeploy(other.deploy) instead", "2.2")
|
||||||
def withCreator(c: Creator[Actor]): Props = copy(clazz = classOf[CreatorConsumer], args = c :: Nil)
|
def withCreator(c: Creator[Actor]): Props = copy(clazz = classOf[CreatorConsumer], args = classOf[Actor] :: c :: Nil)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new Props with the specified creator set.
|
* Returns a new Props with the specified creator set.
|
||||||
|
|
@ -248,7 +283,7 @@ final case class Props(deploy: Deploy, clazz: Class[_], args: immutable.Seq[Any]
|
||||||
* @deprecated use Props.create(clazz) instead; deprecated since it duplicates
|
* @deprecated use Props.create(clazz) instead; deprecated since it duplicates
|
||||||
* another API
|
* another API
|
||||||
*/
|
*/
|
||||||
@deprecated("use Props(clazz, args).withDeploy(other.deploy)", "2.2")
|
@deprecated("use Props.create(clazz, args).withDeploy(other.deploy)", "2.2")
|
||||||
def withCreator(c: Class[_ <: Actor]): Props = copy(clazz = c, args = Nil)
|
def withCreator(c: Class[_ <: Actor]): Props = copy(clazz = c, args = Nil)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -342,8 +377,8 @@ private[akka] class CreatorFunctionConsumer(creator: () ⇒ Actor) extends Indir
|
||||||
/**
|
/**
|
||||||
* INTERNAL API
|
* INTERNAL API
|
||||||
*/
|
*/
|
||||||
private[akka] class CreatorConsumer(creator: Creator[Actor]) extends IndirectActorProducer {
|
private[akka] class CreatorConsumer(clazz: Class[_ <: Actor], creator: Creator[Actor]) extends IndirectActorProducer {
|
||||||
override def actorClass = classOf[Actor]
|
override def actorClass = clazz
|
||||||
override def produce() = creator.create()
|
override def produce() = creator.create()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -166,5 +166,5 @@ abstract class UntypedActor extends Actor {
|
||||||
/**
|
/**
|
||||||
* Factory closure for an UntypedActor, to be used with 'Actors.actorOf(factory)'.
|
* Factory closure for an UntypedActor, to be used with 'Actors.actorOf(factory)'.
|
||||||
*/
|
*/
|
||||||
@deprecated("use Props.create(clazz, args) instead", "2.2")
|
@deprecated("use Creator<T> instead", "2.2")
|
||||||
trait UntypedActorFactory extends Creator[Actor] with Serializable
|
trait UntypedActorFactory extends Creator[Actor] with Serializable
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ import java.util.concurrent.TimeoutException
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import akka.pattern.ask
|
import akka.pattern.ask
|
||||||
import scala.reflect.ClassTag
|
import scala.reflect.ClassTag
|
||||||
import akka.dispatch.{ UnboundedDequeBasedMailbox, RequiresMessageQueue }
|
|
||||||
|
|
||||||
trait Creators { this: ActorDSL.type ⇒
|
trait Creators { this: ActorDSL.type ⇒
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,8 @@ trait Effect {
|
||||||
/**
|
/**
|
||||||
* A constructor/factory, takes no parameters but creates a new value of type T every call.
|
* A constructor/factory, takes no parameters but creates a new value of type T every call.
|
||||||
*/
|
*/
|
||||||
trait Creator[T] {
|
@SerialVersionUID(1L)
|
||||||
|
trait Creator[T] extends Serializable {
|
||||||
/**
|
/**
|
||||||
* This method must return a different instance upon every call.
|
* This method must return a different instance upon every call.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ import akka.actor.IndirectActorProducer;
|
||||||
import akka.actor.OneForOneStrategy;
|
import akka.actor.OneForOneStrategy;
|
||||||
//#import-props
|
//#import-props
|
||||||
import akka.actor.Props;
|
import akka.actor.Props;
|
||||||
|
import akka.japi.Creator;
|
||||||
//#import-props
|
//#import-props
|
||||||
import akka.actor.SupervisorStrategy;
|
import akka.actor.SupervisorStrategy;
|
||||||
import akka.actor.SupervisorStrategy.Directive;
|
import akka.actor.SupervisorStrategy.Directive;
|
||||||
|
|
@ -88,15 +89,36 @@ public class UntypedActorDocTest {
|
||||||
|
|
||||||
private final ActorSystem system = actorSystemResource.getSystem();
|
private final ActorSystem system = actorSystemResource.getSystem();
|
||||||
|
|
||||||
|
//#creating-props-config
|
||||||
|
static class MyActorC implements Creator<MyActor> {
|
||||||
|
@Override public MyActor create() {
|
||||||
|
return new MyActor("...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#creating-props-config
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Test
|
@Test
|
||||||
public void createProps() {
|
public void createProps() {
|
||||||
//#creating-props-config
|
//#creating-props-config
|
||||||
Props props1 = Props.create(MyUntypedActor.class);
|
Props props1 = Props.create(MyUntypedActor.class);
|
||||||
Props props2 = Props.create(MyActor.class, "...");
|
Props props2 = Props.create(MyActor.class, "...");
|
||||||
|
Props props3 = Props.create(new MyActorC());
|
||||||
//#creating-props-config
|
//#creating-props-config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#parametric-creator
|
||||||
|
static class ParametricCreator<T extends MyActor> implements Creator<T> {
|
||||||
|
@Override public T create() {
|
||||||
|
// ... fabricate actor here
|
||||||
|
//#parametric-creator
|
||||||
|
return null;
|
||||||
|
//#parametric-creator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#parametric-creator
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
@Test
|
@Test
|
||||||
public void createPropsDeprecated() {
|
public void createPropsDeprecated() {
|
||||||
|
|
|
||||||
|
|
@ -51,12 +51,20 @@ dispatcher to use, see more below). Here are some examples of how to create a
|
||||||
.. includecode:: code/docs/actor/UntypedActorDocTest.java#import-props
|
.. includecode:: code/docs/actor/UntypedActorDocTest.java#import-props
|
||||||
.. includecode:: code/docs/actor/UntypedActorDocTest.java#creating-props-config
|
.. includecode:: code/docs/actor/UntypedActorDocTest.java#creating-props-config
|
||||||
|
|
||||||
The last line shows how to pass constructor arguments to the :class:`Actor`
|
The second line shows how to pass constructor arguments to the :class:`Actor`
|
||||||
being created. The presence of a matching constructor is verified during
|
being created. The presence of a matching constructor is verified during
|
||||||
construction of the :class:`Props` object, resulting in an
|
construction of the :class:`Props` object, resulting in an
|
||||||
:class:`IllegalArgumentEception` if no or multiple matching constructors are
|
:class:`IllegalArgumentEception` if no or multiple matching constructors are
|
||||||
found.
|
found.
|
||||||
|
|
||||||
|
The third line demonstrates the use of a :class:`Creator<T extends Actor>`. The
|
||||||
|
creator class must be static, which is verified during :class:`Props`
|
||||||
|
construction. The type parameter’s upper bound is used to determine the
|
||||||
|
produced actor class, falling back to :class:`Actor` if fully erased. An
|
||||||
|
example of a parametric factory could be:
|
||||||
|
|
||||||
|
.. includecode:: code/docs/actor/UntypedActorDocTest.java#parametric-creator
|
||||||
|
|
||||||
Deprecated Variants
|
Deprecated Variants
|
||||||
^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,17 +18,57 @@ Deprecated Closure-Taking Props
|
||||||
are usually created in-line and thus carry a reference to their enclosing
|
are usually created in-line and thus carry a reference to their enclosing
|
||||||
object; this is not well known among programmers, in particular it can be
|
object; this is not well known among programmers, in particular it can be
|
||||||
surprising that innocent-looking actor creation should not be serializable,
|
surprising that innocent-looking actor creation should not be serializable,
|
||||||
e.g. if the enclosing class is an actor.
|
e.g. if the enclosing class is an actor. Another issue which came up often
|
||||||
|
during reviews is that these actor creators inadvertedly close over the Actor’s
|
||||||
|
``this`` reference for calling methods on it, which is inherently unsafe.
|
||||||
|
|
||||||
Thus we have decided to deprecate ``Props(new MyActor(...))`` and
|
Another reason for changing the underlying implementation is that Props now
|
||||||
:class:`UntypedActorFactory` in favor of basing :class:`Props` on a
|
carries information about which class of actor will be created, allowing the
|
||||||
:class:`Class` and a sequence of constructor arguments. This has the added
|
extraction of mailbox type requirements (e.g. when using the Stash) before
|
||||||
benefit of allowing easier integration with dependency injection frameworks,
|
trying to create the actor. Being based on the actor class and a list of
|
||||||
see :ref:`actor-create-factory`.
|
constructor arguments also allows these arguments to be serialized according to
|
||||||
|
the configured serializer bindings instead of mandating Java serialization
|
||||||
|
(which was used previously).
|
||||||
|
|
||||||
The deprecated methods will be retained until the possibility of reintroducing
|
What changes for Java?
|
||||||
a similar syntax in a safe fashion has been properly researched (in case of
|
----------------------
|
||||||
Scala it might be possible to use macros to this effect).
|
|
||||||
|
A new method ``Props.create`` has been introduced with two overloads::
|
||||||
|
|
||||||
|
Props.create(MyActor.class, arg1, arg2, ...);
|
||||||
|
// or
|
||||||
|
Props.create(new MyActorCreator(args ...));
|
||||||
|
|
||||||
|
In the first case the existence of a constructor signature matching the
|
||||||
|
supplied arguments is verified at Props construction time. In the second case
|
||||||
|
it is verified that ``MyActorCreator`` (which must be a ``akka.japi.Creator<?
|
||||||
|
extends Actor>``) is a static class. In both cases failure is signaled by
|
||||||
|
throwing a :class:`IllegalArgumentException`.
|
||||||
|
|
||||||
|
The constructors of :class:`Props` have been deprecated to facilitate migration.
|
||||||
|
|
||||||
|
The :meth:`withCreator` methods have been deprecated. The functionality is
|
||||||
|
available by using ``Props.create(...).withDeploy(oldProps.deploy());``.
|
||||||
|
|
||||||
|
:class:`UntypedActorFactory` has been deprecated in favor of the more precisely
|
||||||
|
typed :class:`Creator<T>`.
|
||||||
|
|
||||||
|
What changes for Scala?
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
The case class signature of Props has been changed to only contain a
|
||||||
|
:class:`Deploy`, a :class:`Class[_]` and an immutable :class:`Seq[Any]` (the
|
||||||
|
constructor arguments for the class). The old factory and extractor methods
|
||||||
|
have been deprecated.
|
||||||
|
|
||||||
|
Properly serializable :class:`Props` can now be created for actors which take
|
||||||
|
constructor arguments by using ``Props(classOf[MyActor], arg1, arg2, ...)``.
|
||||||
|
In a future update—possibly within the 2.2.x timeframe—we plan to introduce a
|
||||||
|
macro which will transform the by-name argument to ``Props(new MyActor(...))``
|
||||||
|
into a call to the former.
|
||||||
|
|
||||||
|
The :meth:`withCreator` methods have been deprecated. The functionality is
|
||||||
|
available by using ``Props(...).withDeploy(oldProps.deploy)``.
|
||||||
|
|
||||||
Immutable everywhere
|
Immutable everywhere
|
||||||
====================
|
====================
|
||||||
|
|
|
||||||
|
|
@ -85,18 +85,21 @@ for a migration period):
|
||||||
|
|
||||||
.. includecode:: code/docs/actor/ActorDocSpec.scala#creating-props-deprecated
|
.. includecode:: code/docs/actor/ActorDocSpec.scala#creating-props-deprecated
|
||||||
|
|
||||||
The last one is deprecated because its functionality is available in full
|
The first one is deprecated because the case class structure changed between
|
||||||
through :meth:`Props.apply()`.
|
Akka 2.1 and 2.2.
|
||||||
|
|
||||||
The first three are deprecated because the captured closure is a local class
|
The two variants in the middle are deprecated because :class:`Props` are
|
||||||
which means that it implicitly carries a reference to the enclosing class. This
|
primarily concerned with actor creation and thus the “creator” part should be
|
||||||
can easily make the resulting :class:`Props` non-serializable, e.g. when the
|
explicitly set when creating an instance. In case you want to deploy one actor
|
||||||
enclosing class is an :class:`Actor`. Akka advocates location transparency,
|
in the same was as another, simply use
|
||||||
meaning that an application written with actors should just work when it is
|
``Props(...).withDeploy(otherProps.deploy)``.
|
||||||
deployed over multiple network nodes, and non-serializable actor factories
|
|
||||||
would break this principle. In case indirect actor creation is needed—for
|
The last one is not technically deprecated, but it is not recommended because
|
||||||
example when using dependency injection—there is the possibility to use an
|
it encourages to close over the enclosing scope, resulting in non-serializable
|
||||||
:class:`IndirectActorProducer` as described below.
|
:class:`Props` and possibly race conditions (breaking the actor encapsulation).
|
||||||
|
We will provide a macro-based solution in a future release which allows similar
|
||||||
|
syntax without the headaches, at which point this variant will be properly
|
||||||
|
deprecated.
|
||||||
|
|
||||||
There were two use-cases for these methods: passing constructor arguments to
|
There were two use-cases for these methods: passing constructor arguments to
|
||||||
the actor—which is solved by the newly introduced
|
the actor—which is solved by the newly introduced
|
||||||
|
|
|
||||||
|
|
@ -243,19 +243,19 @@ class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
|
||||||
//#creating-props
|
//#creating-props
|
||||||
|
|
||||||
//#creating-props-deprecated
|
//#creating-props-deprecated
|
||||||
// DEPRECATED: encourages to close over enclosing class
|
// DEPRECATED: old case class signature
|
||||||
val props4 = Props(
|
val props4 = Props(
|
||||||
creator = { () ⇒ new MyActor },
|
creator = { () ⇒ new MyActor },
|
||||||
dispatcher = "my-dispatcher")
|
dispatcher = "my-dispatcher")
|
||||||
|
|
||||||
// DEPRECATED: encourages to close over enclosing class
|
// DEPRECATED due to duplicate functionality with Props.apply()
|
||||||
val props5 = props1.withCreator(new MyActor)
|
val props5 = props1.withCreator(new MyActor)
|
||||||
|
|
||||||
// DEPRECATED: encourages to close over enclosing class
|
|
||||||
val props6 = Props(new MyActor)
|
|
||||||
|
|
||||||
// DEPRECATED due to duplicate functionality with Props.apply()
|
// DEPRECATED due to duplicate functionality with Props.apply()
|
||||||
val props7 = props1.withCreator(classOf[MyActor])
|
val props6 = props1.withCreator(classOf[MyActor])
|
||||||
|
|
||||||
|
// NOT RECOMMENDED: encourages to close over enclosing class
|
||||||
|
val props7 = Props(new MyActor)
|
||||||
//#creating-props-deprecated
|
//#creating-props-deprecated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,8 @@ object AkkaBuild extends Build {
|
||||||
dependencies = Seq(testkit % "compile;test->test"),
|
dependencies = Seq(testkit % "compile;test->test"),
|
||||||
settings = defaultSettings ++ scaladocSettings ++ Seq(
|
settings = defaultSettings ++ scaladocSettings ++ Seq(
|
||||||
publishArtifact in Compile := false,
|
publishArtifact in Compile := false,
|
||||||
libraryDependencies ++= Dependencies.actorTests
|
libraryDependencies ++= Dependencies.actorTests,
|
||||||
|
testOptions += Tests.Argument(TestFrameworks.JUnit, "-v", "-a")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -972,7 +973,7 @@ object Dependencies {
|
||||||
|
|
||||||
val testkit = Seq(Test.junit, Test.scalatest)
|
val testkit = Seq(Test.junit, Test.scalatest)
|
||||||
|
|
||||||
val actorTests = Seq(Test.junit, Test.scalatest, Test.commonsCodec, Test.commonsMath, Test.mockito, Test.scalacheck, protobuf)
|
val actorTests = Seq(Test.junit, Test.scalatest, Test.commonsCodec, Test.commonsMath, Test.mockito, Test.scalacheck, protobuf, Test.junitIntf)
|
||||||
|
|
||||||
val remote = Seq(netty, protobuf, uncommonsMath, Test.junit, Test.scalatest)
|
val remote = Seq(netty, protobuf, uncommonsMath, Test.junit, Test.scalatest)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue