On Mon, Dec 7, 2009 at 2:04 AM, Marius Bogoevici <mariusb(a)redhat.com> wrote:
Overall, it seems like there are two competing restrictions at play:
that a
decorator can decorate only methods defined on the decorated types (so
methods which are not on the decorated types will be ignored) and it can
decorate only beans which are injectable as delegates.
I don't understand how these restrictions are competing, and I don't
understand your doubt. The decorated types identify the methods that
are intercepted. The delegate injection point identifies the beans
that are decorated. There is no overlap here. These are orthogonal
things.
It should be noted that, according to Mark, quoting Pete (and I can
see the
same in the code) - Weld does not look at the interfaces implemented by the
@Decorator bean in order to retrieve the decorated types, but it infers them
from the type of the delegate.
That definitely doesn't sound right to me. That's not what the spec
says. The delegate might implement some interface that is not
implemented by the decorator, and is hence not a decorated type.
Now, it may happen that a method is defined on the decorator and the
target
class, but not on any type implemented by the decorator - according to a)
and 8.1.3, it won't be used to decorate anything. But in Weld, for example,
since the decorated types are inferred from the @Delegate, it will be used
for decoration anyway,.
If true, that would be a bug. That is not what the spec says. The spec
is the source of truth here, not Weld!
The main question raised by Mark during the discussion was what is
the use
for having the Decorator implement an interface, when for practical
purposes, the decorated types are indicated by the delegate type.
No, they are not. The delegate attribute may implement additional
types that are not decorated types. And this is *useful*.
Furthermore, if a decorator decorates more than one type/interface,
what is
the type of the injected delegate?
It must be a subtype of all the decorated types. The spec says this
*explicitly*.
The only possible solution now is a type
which implements/extends both interfaces, which means that only a bean of
that class or a subclass of it (including implementors if we're talking
about an interface) can be decorated. Apparently, this is possible because
of the gap in the specification that Gavin mentioned yesterday, which allows
concrete types to be delegates.
An interface can be a subtype of other interface types. I really don't
get your point.
If the gap was closed by eliminating
concrete classes, then you can't have a decorator that decorates more than
one interface.
Definitely not true.
interface X extends A,B {}
The delegate type restricts the eligible beans anyway (only beans
that
implement/extend this class are eligible), but why is then necessary to
indicate a number of interface types which can be decorated? My take on this
is that you may not want to decorate all methods on the delegate, only
certain methods and requiring the decorator bean to state the interfaces it
wants to decorate can be used for that purpose.
Right.
But Mark has a point here,
that you can achieve the same result by just not implementing those methods,
so the requirement for the decorator to implement certain interfaces could
be considered superfluous.
You've really, really lost me here. WTF would I not want to implement
the interface? Aside from this just being a totally normal and natural
thing to do, this makes my code typesafe (when I add @Override), and
lets my IDE fill in the method signature for me.
Suppose the interface X declares a method void foo(), and I'm going to
implement that same method on a class D (my decorator). Why would I
not want to say D implements X? How the hell can the CDI impl be sure
that this method named foo() is actually the method X.foo(), and not
some other method that just happens to have the same name? This is not
fucking Ruby. Java is a statically typed language. We identify methods
by type+name+signature. Not by name alone.
What exactly are you trying to achieve here? What is wrong with having
a decorator implement the interface it is intercepting? Why would I
ever want to do it any differently?
c) Samples
Let's look at an example provided by Mark:
class Cat { String getName() {return "";}};
class AngoraCat extends Cat { boolean getHairLength() {return true}}
class SiamCat extends Cat { };
@Decorator CatDecorator { @Delegate Cat c; String getName() {
log.info("something"); return c.getName(); } }
Now, looking at this sample it seems like:
(ASSERTION 1) In the sample above there are no decorated types, therefore no
actual decoration takes place.
Correct.
Let's add Pet, an interface and have Cat implement it
class Pet { String getRegistrationNumber()};
(ASSERTION 2) The set of decorated types consists of the interface Pet.
Not correct. Not unless CatDecorator implements Pet.
Now let's consider the following two decorators:
@Decorator PetDecorator implements Pet {@Delegate Pet p; String getName() {
log.info("something"); return c.getName(); }}
@Decorator CatDecorator { @Delegate Cat c; String getName() {
log.info("something"); return c.getName(); } }
(ASSERTION 3) With the modification above, both PetDecorator and
CatDecorator apply to all types of cats, but PetDecorator also applies to
Pets which are not Cats
Correct. But note that CatDecorator has no decorated types.
Now, if we had:
interface Cat { String getName();};
class SiamCat implements Cat, Pet { };
class RussianForestCat implements Cat, Pet { };
@Decorator PetCatDecorator implements Cat,Pet {@Delegate SiamCat c; String
getName() { log.info("something"); return c.getName(); }}
(ASSERTION 4) PetCat will decorate SiamCat but not RussianForestCat (won't
even be picked up as a decorator since it does not meet 8.3 wrt
RussianForestCat
Correct.
--
Gavin King
gavin.king(a)gmail.com
http://in.relation.to/Bloggers/Gavin
http://hibernate.org
http://seamframework.org