jakartaee / jakartaee/cdi

Add methods to BeanConfigurator for applying decorators

Open
#459 4 comments 0 reactions 2 assignees Claimed by @arjantijms View on GitHub
Dominant language
Java
Stars
240
Forks
83
PR merge metrics
No merged PRs in 30d

Description

Currently when adding a `Bean` using `jakarta.enterprise.inject.spi.AfterBeanDiscovery.addBean()` or `jakarta.enterprise.inject.spi.AfterBeanDiscovery.addBean(Bean)` any decorators declared or programatically added for the types of the `Bean` are not automatically applied.

Not only is this perhaps surprising, there actually is no portable way to achieve this behaviour. Someone adding a bean must resort to SPIs and implementation specific code. For instance Soteria uses the following code:

```java
afterBeanDiscovery.addBean(
decorator.decorateBean(authenticationMechanismBean, HttpAuthenticationMechanism.class, beanManager));
```
[Source](https://github.com/eclipse-ee4j/soteria/blob/master/impl/src/main/java/org/glassfish/soteria/cdi/CdiExtension.java#L246)

Where `decorator.decorateBean` is an SPI, that for Weld uses code such as the following:

```java
public class DecorableWeldBeanWrapper extends RIBean implements Bean, PassivationCapable {

private final Bean bean;
private final CurrentInjectionPoint currentInjectionPoint;
private final boolean isProxyable;
private Class type;

private List> decorators;
private Class proxyClass;
private boolean proxyRequired;
private boolean isPassivationCapableBean;
private boolean isPassivationCapableDependency;

public DecorableWeldBeanWrapper(Bean bean, Class type, BeanManagerImpl beanManager) {
super(
bean,
new StringBeanIdentifier(BeanIdentifiers.forBuiltInBean(beanManager, type, null)),
beanManager);

this.bean = bean;
this.type = type;
this.currentInjectionPoint = beanManager.getServices().get(CurrentInjectionPoint.class);
this.isProxyable = Proxies.isTypesProxyable(getTypes(), beanManager.getServices());
}

@Override
public void initializeAfterBeanDiscovery() {
decorators = beanManager.resolveDecorators(getTypes(), getQualifiers());

if (!decorators.isEmpty()) {
proxyClass = new ProxyFactory(getBeanManager().getContextId(), getType(), getTypes(), this).getProxyClass();
}
}

@Override
protected void internalInitialize(BeanDeployerEnvironment environment) {
proxyRequired = getScope() != null && isNormalScoped();
isPassivationCapableBean = Serializable.class.isAssignableFrom(type);
isPassivationCapableDependency = isNormalScoped() || (isDependent() && isPassivationCapableBean());
}

@Override
public T create(CreationalContext creationalContext) {
T instance = bean.create(creationalContext);

if (decorators.isEmpty()) {
return instance;
}

return getOuterDelegate(this, instance, creationalContext, proxyClass, currentInjectionPoint.peek(), getBeanManager(), decorators);
}
```
[Source](https://github.com/eclipse-ee4j/soteria/blob/master/spi/bean-decorator/weld/src/main/java/org/glassfish/soteria/spi/bean/decorator/weld/DecorableWeldBeanWrapper.java#L40)

This code is difficult to come up with, difficult to maintain and error prone. The user must also make sure the right companion SPI implementation is available on the class path.

To simplify this, I'd like to propose a method for `BeanConfigurator` to signal to the runtime that enabled decorators should be applied to the instance returned from the `Bean.create` (`Contextual.create') method, just like happens for beans which implement the bean types directly and are discovered by CDI.

For instance:

```java
public void afterBean(final @Observes AfterBeanDiscovery afterBeanDiscovery) {
afterBeanDiscovery
.addBean()
.scope(ApplicationScoped.class)
.types(MyBean.class)
.id("Created by " + CdiExtension.class)
.enabledDecorators()
.createWith(e -> new MyBeanImpl("Hi!"));
}
```

Several variants could be considered, like e.g.:

* addEnabledDecorators()
* decorators(Decorator... decorators)
* addDecorators(Decorator... decorators)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.