Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* Instances are not reusable. For each synthetic bean, new instance
* must be created by {@link SyntheticComponents#addBean(Class)}.
*
* @param <T> the bean class of this synthetic bean
* @param <T> the implementation class of this synthetic bean
* @since 4.0
*/
public interface SyntheticBeanBuilder<T> {
Expand Down Expand Up @@ -451,6 +451,66 @@ public interface SyntheticBeanBuilder<T> {
*/
SyntheticBeanBuilder<T> withParam(String key, InvokerInfo[] value);

/**
* Declares that the creation or destruction function for this synthetic bean will potentially
* look up a bean of given {@code type} with given {@code qualifiers}.
* If no qualifier is passed, {@code @Default} is assumed.
* <p>
* The registered injection point will be validated. If no matching bean exists,
* the container treats it as a deployment problem.
*
* @param type the type of the bean that may be looked up in the creation/destruction function
* @param qualifiers the qualifiers of the bean that may be looked up in the creation/destruction function
* @return this {@code SyntheticBeanBuilder}
* @since 5.0
*/
SyntheticBeanBuilder<T> withInjectionPoint(Class<?> type, Annotation... qualifiers);

/**
* Declares that the creation or destruction function for this synthetic bean will potentially
* look up a bean of given {@code type} with given {@code qualifiers}.
* If no qualifier is passed, {@code @Default} is assumed.
* <p>
* The registered injection point will be validated. If no matching bean exists,
* the container treats it as a deployment problem.
*
* @param type the type of the bean that may be looked up in the creation/destruction function
* @param qualifiers the qualifiers of the bean that may be looked up in the creation/destruction function
* @return this {@code SyntheticBeanBuilder}
* @since 5.0
*/
SyntheticBeanBuilder<T> withInjectionPoint(Class<?> type, AnnotationInfo... qualifiers);

/**
* Declares that the creation or destruction function for this synthetic bean will potentially
* look up a bean of given {@code type} with given {@code qualifiers}.
* If no qualifier is passed, {@code @Default} is assumed.
* <p>
* The registered injection point will be validated. If no matching bean exists,
* the container treats it as a deployment problem.
*
* @param type the type of the bean that may be looked up in the creation/destruction function
* @param qualifiers the qualifiers of the bean that may be looked up in the creation/destruction function
* @return this {@code SyntheticBeanBuilder}
* @since 5.0
*/
SyntheticBeanBuilder<T> withInjectionPoint(Type type, Annotation... qualifiers);

/**
* Declares that the creation or destruction function for this synthetic bean will potentially
* look up a bean of given {@code type} with given {@code qualifiers}.
* If no qualifier is passed, {@code @Default} is assumed.
* <p>
* The registered injection point will be validated. If no matching bean exists,
* the container treats it as a deployment problem.
*
* @param type the type of the bean that may be looked up in the creation/destruction function
* @param qualifiers the qualifiers of the bean that may be looked up in the creation/destruction function
* @return this {@code SyntheticBeanBuilder}
* @since 5.0
*/
SyntheticBeanBuilder<T> withInjectionPoint(Type type, AnnotationInfo... qualifiers);

/**
* Sets the class of the synthetic bean {@linkplain SyntheticBeanCreator creation} function.
* CDI container will create an instance of the creation function every time when it needs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,43 @@
* CDI container will create an instance of the creation function every time when it needs
* to obtain an instance of the synthetic bean. Implementations must be {@code public}
* classes with a {@code public} zero-parameter constructor; they must not be beans.
* <p>
* Starting with CDI 5.0, the {@link #create(Instance, Parameters)} method is deprecated
* for removal; suggested replacement is {@link #create(SyntheticInjections, Parameters)}.
* Exactly one of these methods must be implemented; if not, non-portable behavior results.
* The CDI container must check which method exists and call it. The CDI container may assume
* that the {@link #create(SyntheticInjections, Parameters)} method is present directly
* on the class registered using {@link SyntheticBeanBuilder#createWith(Class)}
* and not inherited from a superclass or a superinterface.
*
* @param <T> the bean class of the synthetic bean
* @param <T> the implementation class of the synthetic bean
* @since 4.0
*/
public interface SyntheticBeanCreator<T> {
/**
* Creates an instance of the synthetic bean.
* May only return {@code null} if the synthetic bean is {@code @Dependent}.
* <p>
* The {@link SyntheticInjections} parameter may be used to simulate producer method parameter injection.
* All injectable references looked up from {@code SyntheticInjections} have to previously be registered using
* {@code SyntheticBeanBuilder.withInjectionPoint()}.
* <p>
* If the synthetic bean is {@code @Dependent}, the {@code InjectionPoint} to which it is injected
* may be obtained from the {@code SyntheticInjections} parameter, if previously registered.
* <p>
* The parameter map contains the same values that were passed to {@code SyntheticBeanBuilder.withParam()}.
*
* @param injections {@code SyntheticInjections} that can be used to obtain injectable references for
* previously registered injection points, never {@code null}
* @param params the parameter map, never {@code null}
* @return an instance of the bean, may only be {@code null} if the synthetic bean is {@code @Dependent}
* @since 5.0
*/
default T create(SyntheticInjections injections, Parameters params) {
throw new UnsupportedOperationException("Either create(SyntheticInjections, Parameters)"
+ " or create(Instance<Object>, Parameters) must be implemented");
}

/**
* Creates an instance of the synthetic bean.
* May only return {@code null} if the synthetic bean is {@code @Dependent}.
Expand All @@ -34,12 +66,17 @@ public interface SyntheticBeanCreator<T> {
* If the synthetic bean is {@code @Dependent}, the {@code InjectionPoint} to which it is injected
* may be looked up from the {@code Instance} parameter.
* <p>
* The parameter map contains the same values that were passed to the {@link SyntheticBeanBuilder}
* that defined the synthetic bean.
* The parameter map contains the same values that were passed to {@code SyntheticBeanBuilder.withParam()}.
*
* @param lookup an {@link Instance} that can be used to lookup other beans, never {@code null}
* @param params the parameter map, never {@code null}
* @return an instance of the bean, may only be {@code null} if the synthetic bean is {@code @Dependent}
* @deprecated use {@link #create(SyntheticInjections, Parameters)} and register all potentially looked up
* beans using {@code SyntheticBeanBuilder.withInjectionPoint()}
*/
T create(Instance<Object> lookup, Parameters params);
@Deprecated(forRemoval = true, since = "5.0")
default T create(Instance<Object> lookup, Parameters params) {
throw new UnsupportedOperationException("Either create(SyntheticInjections, Parameters)"
+ " or create(Instance<Object>, Parameters) must be implemented");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,41 @@
* CDI container will create an instance of the destruction function every time when it needs
* to destroy an instance of the synthetic bean. Implementations must be {@code public}
* classes with a {@code public} zero-parameter constructor; they must not be beans.
* <p>
* Starting with CDI 5.0, the {@link #dispose(Object, Instance, Parameters)} method is deprecated
* for removal; suggested replacement is {@link #dispose(Object, SyntheticInjections, Parameters)}.
* Exactly one of these methods must be implemented; if not, non-portable behavior results.
* The CDI container must check which method exists and call it. The CDI container may assume
* that the {@link #dispose(Object, SyntheticInjections, Parameters)} method is present directly
* on the class registered using {@link SyntheticBeanBuilder#disposeWith(Class)}
* and not inherited from a superclass or a superinterface.
*
* @param <T> the bean class of the synthetic bean
* @param <T> the implementation class of the synthetic bean
* @since 4.0
*/
public interface SyntheticBeanDisposer<T> {
/**
* Destroys an instance of the synthetic bean.
* <p>
* The {@link SyntheticInjections} parameter may be used to simulate disposer method parameter injection.
* All injectable references looked up from {@code SyntheticInjections} have to previously be registered using
* {@code SyntheticBeanBuilder.withInjectionPoint()}.
* <p>
* Trying to look up {@code InjectionPoint} from the {@code SyntheticInjections} parameter is invalid.
* <p>
* The parameter map contains the same values that were passed to {@code SyntheticBeanBuilder.withParam()}.
*
* @param instance the synthetic bean instance, never {@code null}
* @param injections {@code SyntheticInjections} that can be used to obtain injectable references for
* previously registered injection points, never {@code null}
* @param params the parameter map, never {@code null}
* @since 5.0
*/
default void dispose(T instance, SyntheticInjections injections, Parameters params) {
throw new UnsupportedOperationException("Either dispose(T, SyntheticInjections, Parameters)"
+ " or dispose(T, Instance<Object>, Parameters) must be implemented");
}

/**
* Destroys an instance of the synthetic bean.
* <p>
Expand All @@ -31,12 +61,17 @@ public interface SyntheticBeanDisposer<T> {
* <p>
* Trying to look up {@code InjectionPoint} from the {@code Instance} parameter is invalid.
* <p>
* The parameter map contains the same values that were passed to the {@link SyntheticBeanBuilder}
* that defined the synthetic bean.
* The parameter map contains the same values that were passed to {@code SyntheticBeanBuilder.withParam()}.
*
* @param instance the synthetic bean instance, never {@code null}
* @param lookup an {@link Instance} that can be used to lookup other beans, never {@code null}
* @param params the parameter map, never {@code null}
* @deprecated use {@link #dispose(Object, SyntheticInjections, Parameters)} and register all potentially looked up
* beans using {@code SyntheticBeanBuilder.withInjectionPoint()}
*/
void dispose(T instance, Instance<Object> lookup, Parameters params);
@Deprecated(forRemoval = true, since = "5.0")
default void dispose(T instance, Instance<Object> lookup, Parameters params) {
throw new UnsupportedOperationException("Either dispose(T, SyntheticInjections, Parameters)"
+ " or dispose(T, Instance<Object>, Parameters) must be implemented");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2025 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made available under the
* Apache Software License 2.0 which is available at:
* https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: Apache-2.0
*/

package jakarta.enterprise.inject.build.compatible.spi;

import java.lang.annotation.Annotation;

import jakarta.enterprise.util.TypeLiteral;

/**
* Provides injectable references for injection points registered for a synthetic bean.
* A synthetic bean creation/destruction function can look up beans in this container
* that were previously registered using {@code SyntheticBeanBuilder.withInjectionPoint()}.
* <p>
* All {@code @Dependent} bean instances created by {@code SyntheticInjections} are destroyed
* when the corresponding synthetic bean instance is destroyed.
*
* @since 5.0
*/
public interface SyntheticInjections {
Comment on lines +17 to +27
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Contains injectable references" suggests that the injectable references for injection points are always created prior to bean creation, which would in turn suggest that any @Dependent scoped beans are always created, even if they're never retrieved by the user.

Is this actually the case?

If not, I suggest changing the wording to "Provides injectable references".

Copy link
Copy Markdown
Member Author

@Ladicek Ladicek Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't really specify whether the injectable references are created eagerly or lazily, and I think that's on purpose. I agree that "provides" is a better verb than "contains", for sure.

/**
* Returns an injectable reference to a bean of given {@code type} with given {@code qualifiers},
* assuming an injection point with the same type and qualifiers was registered
* on the {@link SyntheticBeanBuilder}. Throws {@link IllegalArgumentException}
* if no such injection point was registered.
* <p>
* If no qualifier is passed, {@code @Default} is assumed.
*
* @param type the type of the bean to lookup, must not be {@code null}
* @param qualifiers the qualifiers of the bean to lookup, may be {@code null} or empty
* @return injectable reference to the bean; may only be {@code null} if the bean is {@code @Dependent}
* @param <T> the type of the bean to lookup
* @throws IllegalArgumentException if the type/qualifiers combination was not registered
*/
<T> T get(Class<T> type, Annotation... qualifiers);

/**
* Returns an injectable reference to a bean of given {@code type} with given {@code qualifiers},
* assuming an injection point with the same type and qualifiers was registered
* on the {@link SyntheticBeanBuilder}. Throws {@link IllegalArgumentException}
* if no such injection point was registered.
* <p>
* If no qualifier is passed, {@code @Default} is assumed.
*
* @param type the type of the bean to lookup, must not be {@code null}
* @param qualifiers the qualifiers of the bean to lookup, may be {@code null} or empty
* @return injectable reference to the bean; may only be {@code null} if the bean is {@code @Dependent}
* @param <T> the type of the bean to lookup
* @throws IllegalArgumentException if the type/qualifiers combination was not registered
*/
<T> T get(TypeLiteral<T> type, Annotation... qualifiers);
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,21 @@
*/
public interface Types {
/**
* Returns a type from given class literal.
* Returns a type from given class literal. The result may be:
* <ul>
* <li>{@link VoidType}</li>
* <li>{@link PrimitiveType}</li>
* <li>{@link ClassType}</li>
* <li>{@link ArrayType} where the element type is either {@code PrimitiveType} or {@code ClassType}</li>
* </ul>
* For example:
* <ul>
* <li>{@code of(void.class)}: same as {@link #ofVoid() ofVoid}{@code ()}</li>
* <li>{@code of(int.class)}: same as {@link #ofPrimitive(PrimitiveType.PrimitiveKind)
* ofPrimitive}{@code (PrimitiveKind.INT)}</li>
* <li>{@code of(String.class)}: same as {@link #ofClass(ClassInfo) ofClass}{@code (... ClassInfo for String ...)}</li>
* <li>{@code of(String.class)}: same as {@link #ofClass(String) ofClass}{@code ("java.lang.String")}</li>
* <li>{@code of(int[].class)}: same as {@link #ofArray(Type, int) ofArray}{@code (ofPrimitive(PrimitiveKind.INT), 1)}</li>
* <li>{@code of(String[][].class)}: same as {@code ofArray(ofClass(... ClassInfo for String ...), 2)}</li>
* <li>{@code of(String[][].class)}: same as {@code ofArray(ofClass("java.lang.String"), 2)}</li>
* </ul>
*
* @param clazz the class literal, must not be {@code null}
Expand Down
2 changes: 2 additions & 0 deletions spec/src/main/asciidoc/core/spi_lite.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -354,10 +354,12 @@ The `SyntheticBeanBuilder` and `SyntheticObserverBuilder` interfaces are used to

* bean or observer attributes, such as scope, bean types, qualifiers, or observed event type;
* class of a bean creation/destruction function or observer notification function;
* injection points (only `SyntheticBeanBuilder`);
* a string-keyed parameter map.

The container creates an instance of the bean creation/destruction function or observer notification function whenever it needs to create an instance of the bean, destroy the instance of the bean, or notify the observer.
When invoking the bean creation/destruction function or observer notification function, the container passes the parameter map to it.
When invoking the bean creation/destruction function, the container also passes an object that allows obtaining an injectable reference for each defined injection point.

The parameter map may contain values of the following types:

Expand Down