Client SPI library for JWebMP β defines the contracts, AJAX pipeline types, HTML component interfaces, call interceptor SPIs, and component model that all JWebMP modules program against without pulling in the full core runtime.
Provides the AjaxCall/AjaxResponse pipeline, IPage/IPageConfigurator page contracts, the SiteCallIntercepter interception chain, and the component-model interface hierarchy (IComponentHierarchyBase, IComponentHTMLBase, etc.) that higher-level modules (core, vertx, plugins) build on top of. Extension is SPI-driven via ServiceLoader.
Every interface defined here serves dual purposes:
- Compile-time contracts β higher-level modules code against the interfaces in this library, enabling strict type safety across the ecosystem without circular dependencies
- Runtime SPI discovery β implementations are discovered via
ServiceLoader(providesβ¦within JPMS orMETA-INF/services), keeping the module graph clean and extensible
Built on GuicedEE Client Β· JWebMP Β· JPMS module com.jwebmp.client Β· Java 25+
<dependency>
<groupId>com.jwebmp</groupId>
<artifactId>jwebmp-client</artifactId>
</dependency>Gradle (Kotlin DSL)
implementation("com.jwebmp:jwebmp-client:2.0.0-SNAPSHOT")Version is managed by the JWebMP BOM.
- AJAX pipeline DTOs β
AjaxCallandAjaxResponseareCallScope-scoped, JSON-serializable objects that carry request payloads and DOM update instructions between browser and server - Three interceptor SPIs β
SiteCallIntercepter,AjaxCallIntercepter,DataCallIntercepterβ each uses CRTP andIDefaultServicefor sort-ordered, pluggable request processing - Page contracts β
IPage,IPageConfigurator,IBody,IHead,IHtmldefine the full page lifecycle without depending on core rendering - Component model interfaces β
IComponentHierarchyBase,IComponentHTMLBase,IComponentHTMLAttributeBase,IComponentStyleBase,IComponentFeatureBase,IComponentEventBase,IComponentDataBindingBase,IComponentDependencyBase,IComponentThemeBase,IComponentHTMLOptionsBase, andIComponentBaseform the type-safe component tree - Databind hooks β
IOnDataBind,IOnDataBindCloak,IOnComponentAdded,IOnComponentHtmlRender,IOnComponentConfigured,IAfterRenderComplete, andIClientVariableWatcherfire at specific points in the render lifecycle - Render-ordering SPIs β
RenderBeforeLinks,RenderAfterLinks,RenderBeforeScripts,RenderAfterScripts,RenderBeforeDynamicScripts,RenderAfterDynamicScriptsβ fine-grained control over asset insertion order - User-agent detection β UADetector parser bound as a Guice singleton for browser/device detection (
Browsers,BrowserGroups,CSSVersions,HTMLVersions) - Plugin metadata annotations β
@ComponentInformation,@PluginInformation,@FeatureInformation,@PageConfigurationfor discovery and documentation - Jackson integration β
JavaScriptPartbase class provides JSON serialization for all component options viaIJsonRepresentation - CSS/JS reference types β
CSSReferenceandJavascriptReferencemodel external stylesheets and scripts with version metadata - HTML child-constraint interfaces β
GlobalChildren,GlobalFeatures,HTMLFeatures,FormChildren, and marker interfaces enforce parent/child relationships at compile time - Generics toolkit β
WebReference,Pair,XYObject,FileTemplates,CompassPoints,Direction,Positions, and more β reusable typed data structures - Exception hierarchy β
InvalidRequestException,MissingComponentException,NullComponentException,NoServletFoundException,UserSecurityExceptionβ typed error semantics for the request pipeline - Script provider SPI β
ScriptProviderallows dynamic script components to be contributed to any page - Static strings β
StaticStringscentralises well-known constants used across the framework
module my.app {
requires com.jwebmp.client;
provides com.jwebmp.core.services.IPageConfigurator
with my.app.MyPageConfigurator;
}public class MyPageConfigurator
implements IPageConfigurator<MyPageConfigurator> {
@Override
public IPage<?> configure(IPage<?> page) {
// add CSS/JS references, configure body children, etc.
return page;
}
@Override
public Integer sortOrder() {
return 100; // higher = later
}
}public class AuditInterceptor
implements AjaxCallIntercepter<AuditInterceptor> {
@Override
public void intercept(AjaxCall<?> call, AjaxResponse<?> response) {
log.info("AJAX event: {}", call.getEventType());
}
@Override
public Integer sortOrder() {
return 10;
}
}public class InlineScript implements ScriptProvider {
@Override
public IComponentHierarchyBase<?, ?> produceScript() {
// return a component that renders as a <script> block
}
}Browser event
ββ JSON payload β AjaxCall (deserialized, CallScope-scoped)
ββ SiteCallIntercepter chain (sorted by sortOrder)
ββ AjaxCallIntercepter chain (AJAX events only)
ββ DataCallIntercepter chain (startup data calls only)
ββ Event handler processes call
ββ AjaxResponse built (component updates, reactions, scripts)
ββ JSON response β Browser applies DOM updates
All SPIs are discovered via ServiceLoader. Register implementations with JPMS provides...with or META-INF/services.
Intercepts every site call (first page load). Local storage, session storage, and other client-side items are not yet available:
public class MySecurityInterceptor
implements SiteCallIntercepter<MySecurityInterceptor> {
@Override
public void intercept(AjaxCall<?> call, AjaxResponse<?> response) {
// validate session, check IP, etc.
}
@Override
public Integer sortOrder() {
return 10; // run early
}
}Intercepts AJAX event calls β extends SiteCallIntercepter so the same intercept() method applies:
public class AuditInterceptor
implements AjaxCallIntercepter<AuditInterceptor> {
@Override
public void intercept(AjaxCall<?> call, AjaxResponse<?> response) {
log.info("AJAX event: {}", call.getEventType());
}
}Intercepts startup data calls β fires immediately after page delivery:
public class InitDataInterceptor
implements DataCallIntercepter<InitDataInterceptor> {
@Override
public void intercept(AjaxCall<?> call, AjaxResponse<?> response) {
// load initial data into the response
}
}Configures pages before rendering. Implements IDefaultService (sort-ordered) and IServiceEnablement (can be toggled on/off):
public class AnalyticsConfigurator
implements IPageConfigurator<AnalyticsConfigurator> {
@Override
public IPage<?> configure(IPage<?> page) {
page.addJavaScriptReference(analyticsScript);
return page;
}
}Provides dynamic script components to the page:
public class InlineScript implements ScriptProvider {
@Override
public IComponentHierarchyBase<?, ?> produceScript() {
// return a component that renders as a <script> block
}
}| SPI | Purpose |
|---|---|
RenderBeforeLinks |
Insert content before CSS <link> tags |
RenderAfterLinks |
Insert content after CSS <link> tags |
RenderBeforeScripts |
Insert content before <script> tags |
RenderAfterScripts |
Insert content after <script> tags |
RenderBeforeDynamicScripts |
Insert content before dynamic/inline scripts |
RenderAfterDynamicScripts |
Insert content after dynamic/inline scripts |
| SPI | Purpose |
|---|---|
IOnDataBind |
Fires when a component's data-bind is processed |
IOnDataBindCloak |
Fires for cloaked data-bind components |
IOnComponentAdded |
Fires when a child is added to a component |
IOnComponentConfigured |
Fires after component configuration completes |
IOnComponentHtmlRender |
Fires during component HTML rendering |
IAfterRenderComplete |
Fires after full render completes |
IClientVariableWatcher |
Monitors client-side variable changes |
The client defines the full interface chain that core implements with concrete classes:
IComponentBase β ID, name, properties, JSON serialization
ββ IComponentHierarchyBase β parent/child tree, CSS/JS references
ββ IComponentHTMLBase β tag rendering, text, raw HTML
ββ IComponentHTMLAttributeBase β HTML attributes (typed enums)
ββ IComponentHTMLOptionsBase β JavaScript options (JavaScriptPart)
ββ IComponentStyleBase β inline CSS via the CSS builder
ββ IComponentThemeBase β theme support
ββ IComponentDataBindingBase β data-bind hooks
ββ IComponentDependencyBase β CSS/JS dependency refs
ββ IComponentFeatureBase β Feature attachment
ββ IComponentEventBase β Event attachment
These interfaces use CRTP generics so that concrete implementations in core expose fluent APIs without unchecked casts.
com.jwebmp.client
βββ com.guicedee.client (DI, lifecycle, CallScope)
βββ com.guicedee.jsonrepresentation (JSON serialization β IJsonRepresentation)
βββ jakarta.activation
βββ org.apache.commons.io
βββ io.smallrye.mutiny (reactive types)
βββ net.sf.uadetector.core (user-agent parsing)
βββ net.sf.uadetector.resources
Module name: com.jwebmp.client
The module:
- exports
com.jwebmp.core.base.ajax,com.jwebmp.core.base.client,com.jwebmp.core.base.html.attributes,com.jwebmp.core.base.html.interfaces,com.jwebmp.core.base.html.interfaces.children,com.jwebmp.core.base.html.interfaces.children.generics,com.jwebmp.core.base.html.interfaces.events,com.jwebmp.core.base.interfaces,com.jwebmp.core.base.references,com.jwebmp.core.base.servlets.enumarations,com.jwebmp.core.base.servlets.interfaces,com.jwebmp.core.generics,com.jwebmp.core.htmlbuilder.css.enumarations,com.jwebmp.core.htmlbuilder.css.themes,com.jwebmp.core.htmlbuilder.javascript,com.jwebmp.core.htmlbuilder.javascript.events.interfaces,com.jwebmp.core.services,com.jwebmp.core.annotations,com.jwebmp.core.events.services,com.jwebmp.core.databind,com.jwebmp.interception.services,com.jwebmp.core.plugins,com.jwebmp.core.exceptions - provides
IGuiceModulewithJWebMPClientBinder,IGuiceConfiguratorwithJWebMPClientConfiguration - uses
AjaxCallIntercepter,DataCallIntercepter,SiteCallIntercepter - opens all exported packages to
com.fasterxml.jackson.databindfor JSON serialization;com.jwebmp.core.events.servicesadditionally tocom.google.guice
| Class | Role |
|---|---|
AjaxCall |
Incoming AJAX request payload β deserialized from JSON, CallScope-scoped |
AjaxResponse |
Outgoing AJAX response β carries component updates, reactions, and scripts |
AjaxComponentUpdates |
Describes a single component DOM update (insert type, HTML content) |
AjaxResponseReaction |
Client-side reaction (redirect, dialog, etc.) with ReactionType |
AjaxComponentInsertType |
Enum β where to insert a component update (replace, append, prepend, etc.) |
HeadersDTO |
Typed wrapper for HTTP headers passed through the AJAX pipeline |
JavaScriptPart |
Base class for all JSON-serializable component options (via com.guicedee.jsonrepresentation) |
JWebMPClientBinder |
IGuiceModule β binds AjaxCall/AjaxResponse in CallScope, interceptor sets as singletons, UserAgentStringParser |
JWebMPClientConfiguration |
IGuiceConfigurator β enables classpath, annotation, field, and method scanning |
JWebMPInterceptionBinder |
Guice Key constants for the three interceptor sets |
CSSReference |
Models an external CSS stylesheet with version metadata |
JavascriptReference |
Models an external JavaScript file with version metadata |
IPage |
Full page abstraction β head, body, browser, document type, CSS/JS references |
IPageConfigurator |
SPI β configure a page before rendering |
IBody / IHead / IHtml |
Page-section contracts |
SiteCallIntercepter |
SPI β intercept site-level calls |
AjaxCallIntercepter |
SPI β intercept AJAX event calls (extends SiteCallIntercepter) |
DataCallIntercepter |
SPI β intercept startup data calls (extends SiteCallIntercepter) |
ScriptProvider |
SPI β provide dynamic script components |
PageConfiguration |
Annotation β maps a page to a URL path |
ComponentInformation |
Annotation β metadata for component discovery/docs |
PluginInformation |
Annotation β metadata for plugin discovery/docs |
FeatureInformation |
Annotation β metadata for feature discovery/docs |
FileTemplates |
Utility for managing and rendering file templates |
WebReference |
Base class for CSSReference and JavascriptReference |
StaticStrings |
Centralised well-known string constants |
| Interface | Purpose |
|---|---|
GlobalChildren |
Marker for elements that accept any flow/phrasing content |
GlobalFeatures |
Marker for global HTML features |
HTMLFeatures |
Marker for HTML-specific features |
FormChildren |
Marker for elements valid inside <form> |
NoClosingTag |
Marker for void elements (<br>, <img>, etc.) |
NoIDTag |
Marker for elements that should not render an id attribute |
NoClassAttribute |
Marker for elements that should not render a class attribute |
DisplayObjectType |
Enum β block, inline, inline-block rendering hint |
AttributeDefinitions |
Enum β standard HTML attributes |
ContainerType |
Enum β container classification |
| Class | Purpose |
|---|---|
Browsers |
Enum of known browsers |
BrowserGroups |
Enum grouping browsers by engine/vendor |
CSSVersions |
Enum of CSS specification levels |
HTMLVersions |
Enum of HTML specification levels |
HttpMethodTypes |
Enum of HTTP methods (GET, POST, PUT, DELETE, β¦) |
InternetExplorerCompatibilityMode |
IE-specific compatibility mode settings |
| Exception | Purpose |
|---|---|
InvalidRequestException |
Malformed or invalid AJAX request |
MissingComponentException |
Referenced component not found in the tree |
NullComponentException |
Null component passed where one is required |
NoServletFoundException |
No servlet/handler registered for the request path |
UserSecurityException |
Security violation during request processing |
JWebMPClientConfiguration enables the following IGuiceConfig settings at startup:
| Setting | Value | Purpose |
|---|---|---|
classpathScanning |
true |
Scan the classpath for SPI implementations |
allowPaths |
true |
Allow path-based scanning |
fieldInfo |
true |
Collect field-level metadata |
methodInfo |
true |
Collect method-level metadata |
annotationScanning |
true |
Enable annotation discovery |
ignoreClassVisibility |
true |
Scan non-public classes |
ignoreFieldVisibility |
true |
Scan non-public fields |
ignoreMethodVisibility |
true |
Scan non-public methods |
# Build
mvn -B -ntp -DskipTests package
# Test
mvn -B -ntp verifyPrerequisites: Java 25+, Maven 3.9+
Issues and pull requests are welcome β please add tests for new SPI implementations or interceptors.