[
https://issues.jboss.org/browse/CDI-268?page=com.atlassian.jira.plugin.sy...
]
Arne Limburg edited comment on CDI-268 at 2/27/13 4:15 AM:
-----------------------------------------------------------
I discussed this problem with Mark Struberg for our implementation in OpenWebBeans some
time ago.
My proposal (which is quite similar to the handler, but feels cleaner to me):
Introduce an InjectionTargetFactory that may be called by the bean itself (i.e. in the
constructor) and receives the Bean instance:
{code}
public interface InjectionTargetFactory {
public <T> InjectionTarget<T> createInjectionTarget(Bean<T> bean);
}
{code}
This would lead to the following code for the above example:
{code}
AnnotatedType<Foo> annotatedType = manager.createAnnotatedType(Foo.class);
BeanAttributes<Foo> attributes = manager.createBeanAttributes(annotatedType);
Bean<Foo> bean = manager.createBean(attributes, Foo.class,
manager.getInjectionTargetFactory());
{code}
When the SPI implementor wants to hook into InjectionTarget creation he can wrap the
InjectionTargetFactory. The method BeanManager#createInjectionTarget would stay in the API
(although it is not used in this use case).
was (Author: arnelim):
I discussed this problem with Mark for our implementation in OpenWebBeans.
My proposal (which is quite similar to the handler, but feels cleaner to me):
Introduce an InjectionTargetFactory that may be called by the bean itself (i.e. in the
constructor) and receives the Bean instance:
{code}
public interface InjectionTargetFactory {
public <T> InjectionTarget<T> createInjectionTarget(Bean<T> bean);
}
{code}
This would lead to the following code for the above example:
{code}
AnnotatedType<Foo> annotatedType = manager.createAnnotatedType(Foo.class);
BeanAttributes<Foo> attributes = manager.createBeanAttributes(annotatedType);
Bean<Foo> bean = manager.createBean(attributes, Foo.class,
manager.getInjectionTargetFactory());
{code}
When the SPI implementor wants to hook into InjectionTarget creation he can wrap the
InjectionTargetFactory. The method BeanManager#createInjectionTarget would stay in the API
(although it is not used in this use case).
Limitations in the SPI for creating beans
-----------------------------------------
Key: CDI-268
URL:
https://issues.jboss.org/browse/CDI-268
Project: CDI Specification Issues
Issue Type: Bug
Components: Portable Extensions
Affects Versions: 1.1.EDR
Reporter: Jozef Hartinger
Assignee: Pete Muir
Priority: Critical
Fix For: 1.1.PFD
The CDI SPI provides an SPI that helps extension developers to build Bean
implementations.
An example follows:
{code:JAVA}
AnnotatedType<Foo> annotatedType = manager.createAnnotatedType(Foo.class);
BeanAttributes<Foo> attributes = manager.createBeanAttributes(annotatedType);
InjectionTarget<Foo> injectionTarget =
manager.createInjectionTarget(annotatedType);
Bean<Foo> bean = manager.createBean(attributes, Foo.class, injectionTarget);
{code}
This sequence allows an extension to easily build Bean<Foo>. Obviously, the
extension could modify the artifacts along the way to modify the behavior.
However, this SPI has limitations. There is a circular dependency between the
initialization of Bean and InjectionTarget which is not expressed by the SPI.
A Bean implemetation (be it container-provided one or not) almost always uses an
InjectionTarget to delegate bean instance creation and destruction to. So far so good as
the InjectionTarget is one of the arguments of BeanManager.createBean()
On the other hand, the InjectionTarget also needs a reference to a Bean instance at
initialization should it serve as an InjectionTarget for a Bean. This is not obvious but
there are two reasons why this is needed:
*1.) InjectionPoint.getBean() always returns null*
InjectionTarget.getInjectionPoints() returns a set of InjectionPoint instances. The
InjectionPoint has the method getBean(). This method would always return null (e.g. for
InjectionTarget<Foo> above) because there is no way to tell the container that this
InjectionTarget is an InjectionTarget of a Bean.
This causes problems since the getBean() method is used for validation of injection
points - certain types of injection points are allowed to be placed on beans only (e.g.
Bean metadata, injection point metadata).
There exists a workaround for this where the ProcessInjectionPoint is used to wrap every
such InjectionPoint with a wrapper that returns the Bean instance:
{code:JAVA}
void wrapInjectionPoints(@Observes ProcessInjectionPoint<Foo, ?> event) {
final InjectionPoint delegate = event.getInjectionPoint();
if (delegate.getBean() == null) {
event.setInjectionPoint(new ForwardingInjectionPoint() {
@Override
public Bean<?> getBean() {
return bean;
}
@Override
protected InjectionPoint delegate() {
return delegate;
}
});
}
}
{code}
*2.) Decorators cannot be applied*
Bean<Foo> in the example above would not be decorated even if there were enabled
decorators matching the bean. This is because the InjectionTarget, which takes care of
creating instances and whose produce() method is responsible for building decorators for
the instance does not know whether what it creates actually is a bean or not. Even if it
knew, it would need to know the types and qualifiers of the bean, which it does not.
To sum it up: Although BeanAttributes, Bean and InjectionTarget seem to be independent
layers out of which a Bean can be composed, there are actually circular relations which
the SPI currently fails to notice.
--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see:
http://www.atlassian.com/software/jira