|
Vauban is at |
Vauban implements the CDI 4.1 Lite profile. Migrating therefore implies dropping Full-profile features when used (runtime portable extensions, @ConversationScoped, passivation, application-level EL).
From Quarkus ArC
ArC shares Vauban’s build-time philosophy. The port is conceptually direct; gaps are mostly tooling.
| ArC | Vauban | Note |
|---|---|---|
Full build-time CDI |
Full build-time CDI |
Identical model. No paradigm shift on the application side. |
Bytecode generation via Gizmo |
Bytecode generation via Class-File API (JEP 484) |
No ASM. Output is compatible with any JVM 25+. |
|
No direct equivalent |
Vauban currently only removes unreferenced beans. // TODO@user: confirm whether a similar annotation is planned. |
|
No equivalent |
Build-time profiling is the responsibility of the Vidocq Runtime layer. |
Quarkus Dev Mode |
|
Vauban has no dedicated Dev Mode. |
|
|
Standard CDI pattern. |
From Weld
Weld implements the Full profile; some features used by historical applications have no Lite equivalent.
Key differences:
-
No runtime
AnnotatedTypelookup — Vauban resolves everything at compile time. Code that callsBeanManager.createAnnotatedType(Class)must be rewritten as a Build Compatible Extension. -
No runtime
BeforeBeanDiscovery/AfterBeanDiscovery— replaced by the BCE phases@Discovery/@Enhancement/@Registration/@Synthesis/@Validation. -
No portable extensions — the
Extensioninterface is not loaded viaServiceLoaderat runtime. Migrate every extension to a compile-time BCE. -
No
@ConversationScoped— refactor to@SessionScoped, which Vauban supports withvauban-webcontextswhen Foy serves the requests (Web contexts), or to an explicit application mechanism.
Exhaustive Weld → Vauban table of supported / unsupported features. // TODO@user
From OpenWebBeans
OpenWebBeans is very close to Weld in API. The Weld table mostly applies. OWB-specific traits (deferred bean resolution, custom BeanArchive) are not supported: Vauban has a single, static discovery mode.
CDI 4.1 Lite pitfalls
Lite-profile specifics worth knowing before migrating:
-
@Decorator— supported in Lite, validate against your code. // TODO@user: confirm exact coverage. -
@Specializes— not supported. Refactor as composition or a prioritised@Alternative. -
@Alternative+@Priority— supported; check existing priorities. -
Producer methods with
@Disposes— supported. -
@Injectfield on a normal scope — correctly resolves the client proxy (see fix VAU-INJ-001 in BUG.md). -
InjectionPointmetadata — supported.
Upgrading from Vauban 0.3.0 NEW
What an application built on Vauban 0.3.0 may notice on the 0.4.0-SNAPSHOT line. The full list is in What’s new.
-
Recompile with the matching processor. The generated classes live in your archive, so an archive compiled by an earlier processor keeps its old client proxies and intercepted subclasses until it is recompiled. See Which methods the intercepted subclass covers.
-
More beans are intercepted. An interceptor binding on an interface default method the bean does not override now applies. A
finalbean class, or a bean with afinalmethod, bound only that way now fails with aDeploymentException. An unproxyable intercepted bean is reported as aDeploymentExceptionin every case, with why it is intercepted, where afinalclass used to raise aDefinitionException. See unproxyable intercepted beans. -
@AroundInvokeno longer wraps@PostConstruct/@PreDestroy. A class-level@Transactional,@Retryor@Timedno longer opens a transaction, retries or records a metric around the lifecycle callbacks. -
Interceptors see the inherited declaration.
InvocationContext.getMethod()returns the superclass or interface method a call runs, not the$$super$bridge, andgetInterceptorBindings()includes that declaration’s bindings. -
Default name of a nested bean class.
@Namedwithout a value onOuter.ReportServicenames the beanreportService, no longerouter$ReportService. Update any lookup by the old name. See Qualifiers. -
Disposers. A producer’s disposer runs once, no longer twice, and its qualified parameters resolve on their qualifiers. See Producers and
@Disposes. -
beans.xmldiscovery mode. WithSeContainerInitializerdefault discovery, an emptybeans.xml, or one declaringannotated, now discovers only classes with a bean-defining annotation; it used to make every concrete class a bean. Declarebean-discovery-mode="all"to keep the old behaviour, or annotate the classes. See Default discovery: bean archives. -
Injection failures propagate. A failed field injection reaches the caller instead of leaving the field
null. See Failures are reported, not swallowed.
Recommended strategy
-
Run the existing code on Vauban in a dedicated branch.
-
Build with the Vauban toolchain (
vauban-processorplus thevauban-maven-plugingenerategoal): the compile-time deployment validation surfaces unsatisfied or ambiguous dependencies, unproxyable beans and circular dependencies atprocess-classes. -
Cover your injection graph with integration tests using
vauban-junit(@VaubanTest). -
Activate the CDI 4.1 Lite TCK on the application itself via
vauban-junit. -
Iterate on BCEs to replace portable extensions.
-
If you target GraalVM
native-image, plan for reflection metadata: class loading by name still reflects, and so do the few annotation sites nothing describes. Annotation matching does not — run your tests with-Dvauban.annotations.reflection=warnto see exactly what is left (see AOT compatibility).