import com.jwebmp.core.base.angular.client.annotations.angular.NgLocale;
@NgLocale("en-ZA")Place @NgLocale on the @NgApp class or its boot component. The Angular plugin
registers locale data before bootstrap and provides the application's LOCALE_ID.
The application declaration takes precedence; declarations can be inherited.
Optional dataLocale selects an Angular locale file independently of the locale
ID, and extraData = true includes extra day-period data.
For user-selected formatting, use
@NgLocale(value = "en-ZA", supportedLocales = {"de", "fr"}) and reference
com.jwebmp.core.base.angular.client.services.LocaleService with
@NgComponentReference(LocaleService.class). The generated localeService
exposes setLocale(id), resetLocale(), defaultLocale, and the read-only
locale() signal. Pass that signal as the locale argument of Angular's formatting
pipes for immediate updates. The startup LOCALE_ID remains unchanged; save and
restore preferences through your application's user-profile flow. Text translation
is separate. See the Angular plugin README for pipe examples and limitations.
A Java annotation library that lets JWebMP components describe Angular TypeScript metadata entirely in Java. Annotate your classes with @NgComponent, @NgDataService, @NgDirective, and friends β the generator produces ready-to-compile .ts files, Angular modules, routing configs, and STOMP-backed event-bus services without you ever editing TypeScript by hand.
- Ng* annotation family β
@NgApp,@NgComponent,@NgModule,@NgDirective,@NgDataService,@NgDataType,@NgServiceProvider,@NgProvider,@NgValidator,@NgSchema - Component metadata β
@NgInput,@NgOutput,@NgComponentTagAttributefor Angular component I/O - Lifecycle hooks β
@NgOnInit,@NgOnDestroy,@NgAfterViewInit,@NgAfterViewChecked,@NgAfterContentInit,@NgAfterContentChecked - Structural code generation β
@NgField,@NgMethod,@NgConstructorParameter,@NgConstructorBody,@NgInterface,@NgSignal,@NgSignalComputed,@NgSignalEffect,@NgModel,@NgInject - Import management β
@NgImportReference,@NgImportModule,@NgImportProvider,@NgComponentReference,@NgDataTypeReference,@NgIgnoreImportReference,@NgIgnoreRender - Global annotations β
@NgGlobalField,@NgGlobalConstructorParameter,@NgGlobalComponentConstructorParameter,@NgGlobalComponentImportReferencefor cross-cutting concerns - Routing β
@NgRoutable(path, redirectTo, pathMatch, parent, sortOrder) and@NgRouteData - Boot-module annotations β
@NgBootDeclaration,@NgBootModuleImport,@NgBootImportReference,@NgBootEntryComponent,@NgBootImportProvider,@NgBootProvider,@NgBootConstructorBody,@NgBootConstructorParameter,@NgBootGlobalField,@NgBootModuleSchema - Angular CLI config β
@NgAsset,@NgScript,@NgStyleSheet,@NgPolyfillforangular.jsonintegration - TypeScript dependencies β
@TsDependency,@TsDevDependency,@NgSourceDirectoryReference - CRTP fluent interfaces β
INgApp,INgComponent,INgDirective,INgDataService,INgDataType,INgModule,INgProvider,INgServiceProvider,INgRoutable,INgValidatorDirective,INgFormControlValidatorFunction,INgFormGroupValidatorFunction - SPI extension points β
OnGetAllConstructorParameters,OnGetAllConstructorBodies,OnGetAllFields,OnGetAllImports,OnGetAllMethods,OnGetAllModuleImports - Built-in event bus β
EventBusService(STOMP over WebSocket) with auto-reconnect, listener registration, and RxJS observables - TypeScript type helpers β
any,bool,number,stringplaceholder classes for type mapping - Java β TS field mapping β
INgDataTypeintrospects Java fields (including generics, enums, dates, optionals) and emits TypeScript interface fields withjakarta.validationawareness - Classpath scanning β
AnnotationHelperscans the hierarchy of every Ng-annotated class at startup viaAngularTypeScriptPostStartup(reactiveUni-based) - Output directory control β
jwebmp.outputDirectoryenv/system property overrides the default~/.jwebmp/<appName>output location
<dependency>
<groupId>com.jwebmp.plugins</groupId>
<artifactId>typescript-client</artifactId>
</dependency>Version is managed by the
com.jwebmp:jwebmp-bomimported in the parent POM.
module com.jwebmp.core.base.angular.client {
requires transitive com.guicedee.client;
requires transitive com.jwebmp.client;
requires transitive com.guicedee.guicedinjection;
requires transitive com.guicedee.jsonrepresentation;
requires transitive org.apache.commons.lang3;
requires transitive org.apache.commons.io;
requires transitive jakarta.validation;
exports com.jwebmp.core.base.angular.client.annotations.angular;
exports com.jwebmp.core.base.angular.client.annotations.components;
exports com.jwebmp.core.base.angular.client.annotations.functions;
exports com.jwebmp.core.base.angular.client.annotations.globals;
exports com.jwebmp.core.base.angular.client.annotations.references;
exports com.jwebmp.core.base.angular.client.annotations.constructors;
exports com.jwebmp.core.base.angular.client.annotations.angularconfig;
exports com.jwebmp.core.base.angular.client.annotations.structures;
exports com.jwebmp.core.base.angular.client.annotations.routing;
exports com.jwebmp.core.base.angular.client.annotations.typescript;
exports com.jwebmp.core.base.angular.client.annotations.boot;
exports com.jwebmp.core.base.angular.client;
exports com.jwebmp.core.base.angular.client.services;
exports com.jwebmp.core.base.angular.client.services.interfaces;
exports com.jwebmp.core.base.angular.client.services.spi;
exports com.jwebmp.core.base.angular.client.services.tstypes;
provides IGuiceScanModuleInclusions with AngularTypeScriptClientModuleInclusion;
provides IGuiceModule with AngularClientModule;
provides IGuiceConfigurator with GuicedConfig;
provides IGuicePostStartup with AngularTypeScriptPostStartup;
uses OnGetAllConstructorParameters;
uses OnGetAllConstructorBodies;
uses OnGetAllFields;
uses OnGetAllImports;
uses OnGetAllMethods;
uses OnGetAllModuleImports;
}
@NgApp(value = "my-app", bootComponent = AppComponent.class)
public class MyApp extends Page<MyApp> implements INgApp<MyApp> {
@Override
public List<IComponentHierarchyBase<?, ?>> getRoutes() {
return List.of();
}
}@NgComponent("app-header")
public class HeaderComponent extends DivSimple<HeaderComponent>
implements INgComponent<HeaderComponent> { }@NgDataType
public class UserDTO implements INgDataType<UserDTO> {
private String name;
private String email;
private int age;
}@NgDataService(value = "userData", listenerName = "user.data")
public class UserDataService implements INgDataService<UserDataService> { }@NgRoutable(path = "dashboard", parent = {AppComponent.class})
@NgComponent("app-dashboard")
public class DashboardComponent extends DivSimple<DashboardComponent>
implements INgComponent<DashboardComponent> { }mvn clean installTypeScript output is written to ~/.jwebmp/<appName>/ (override with jwebmp.outputDirectory).
| Category | Annotations | Purpose |
|---|---|---|
| Angular types | @NgApp, @NgComponent, @NgModule, @NgDirective, @NgDataService, @NgDataType, @NgServiceProvider, @NgProvider, @NgValidator, @NgSchema |
Declare Angular constructs |
| Component I/O | @NgInput, @NgOutput, @NgComponentTagAttribute |
Component inputs, outputs, and host attributes |
| Lifecycle | @NgOnInit, @NgOnDestroy, @NgAfterViewInit, @NgAfterViewChecked, @NgAfterContentInit, @NgAfterContentChecked |
Angular lifecycle hook bodies |
| Structure | @NgField, @NgMethod, @NgConstructorParameter, @NgConstructorBody, @NgInterface, @NgSignal, @NgSignalComputed, @NgSignalEffect, @NgModel, @NgInject |
TypeScript class members |
| References | @NgImportReference, @NgImportModule, @NgImportProvider, @NgComponentReference, @NgDataTypeReference, @NgIgnoreImportReference, @NgIgnoreRender |
Import/export management |
| Globals | @NgGlobalField, @NgGlobalConstructorParameter, @NgGlobalComponentConstructorParameter, @NgGlobalComponentImportReference |
Cross-cutting members applied to all components |
| Boot module | @NgBootDeclaration, @NgBootModuleImport, @NgBootImportReference, @NgBootEntryComponent, @NgBootImportProvider, @NgBootProvider, @NgBootConstructorBody, @NgBootConstructorParameter, @NgBootGlobalField, @NgBootModuleSchema |
Root Angular module configuration |
| Angular CLI | @NgAsset, @NgScript, @NgStyleSheet, @NgPolyfill |
angular.json assets/scripts/styles/polyfills |
| TypeScript | @TsDependency, @TsDevDependency, @NgSourceDirectoryReference |
package.json and source directory references |
| Routing | @NgRoutable, @NgRouteData |
Angular route declarations |
IComponent<J>
βββ INgApp<J> β @NgApp
βββ INgComponent<J> β @NgComponent (selector, template, styles, standalone)
βββ INgDirective<J> β @NgDirective (selector, inputs, outputs, standalone)
βββ INgDataService<J> β @NgDataService (signal-based, event-bus listener)
βββ INgDataType<J> β @NgDataType (Java fields β TS interface fields)
βββ INgModule<J> β @NgModule
βββ INgProvider<J> β @NgProvider (injectable service)
βββ INgServiceProvider<J> β @NgServiceProvider (data service + data type bridge)
βββ INgRoutable<J> β @NgRoutable (route path, parent, guards)
IGuiceContext.instance()
ββ GuicedConfig β enables annotation/classpath/field/method scanning
ββ AngularClientModule β binds AnnotationHelper singleton
ββ AngularTypeScriptPostStartup β scans all Ng-annotated classes via AnnotationHelper.startup()
| Class | Role |
|---|---|
AnnotationHelper |
Singleton that scans class hierarchies, collects all Ng annotations (including globals and repeatables), and caches ClassAnnotationMapping results |
AnnotationsMap |
Central registry mapping single β repeatable annotation pairs, global annotations, and the set of classes to scan |
AppUtils |
File-system utilities β resolves output directories, reads/writes generated TS files, locates angular.json, package.json, tsconfig.json, etc. |
EventBusService |
Built-in Angular provider that manages a STOMP WebSocket connection with auto-reconnect, listener registration, and RxJS subjects |
TranslationService |
Runtime Transloco language selection, fallback bundles, REST/classpath overrides, direct dictionary application, race cancellation, and context reset |
DynamicData |
Generic wrapper for sending heterogeneous data payloads through INgDataService |
ComponentConfiguration |
Runtime configuration holder for a single component's generated metadata |
TypescriptIndexPageConfigurator |
SPI for customising the generated index.html |
| SPI | Purpose |
|---|---|
OnGetAllConstructorParameters |
Add/modify constructor parameters for any Ng component |
OnGetAllConstructorBodies |
Add/modify constructor body statements |
OnGetAllFields |
Add/modify class-level fields |
OnGetAllImports |
Add/modify import references |
OnGetAllMethods |
Add/modify class methods |
OnGetAllModuleImports |
Add/modify NgModule import entries |
| Environment / System Property | Default | Purpose |
|---|---|---|
jwebmp.outputDirectory |
β | Override the generated TS output directory |
jwebmp |
~ (user home) |
Base directory when jwebmp.outputDirectory is not set (output goes to <base>/.jwebmp/<appName>) |
Important: Generated TypeScript is read-only. Change Java annotations and rerun the build β never edit the output files directly.
Use @NgTranslations on @NgApp or its boot component and add
@NgTranslationSource entries for classpath defaults or runtime URLs:
@NgTranslations(defaultLanguage = "en", supportedLanguages = {"en", "de"})
@NgTranslationSource(namespace = "orders", resource = "META-INF/jwebmp/i18n/orders")
@NgTranslationSource(namespace = "orders", url = "/rest/translations/orders/{language}", priority = 200)Libraries conventionally package META-INF/jwebmp/i18n/<namespace>/<language>.json.
The Angular generator discovers selected dictionaries with ClassGraph and writes
merged public/i18n/jwebmp bundles. Library defaults use priority 0; application
sources and URL sources default to 100. Equal-priority conflicts are errors.
The generated TranslationService uses Transloco 8.4, Angular HttpClient, and
the optional ICU message-format provider. It exposes setLanguage,
setLanguageAndLocale, applyTranslations(language, namespace, data), reload,
and clearContext, plus signal state for language, loading, and errors.
Reference it using @NgComponentReference(TranslationService.class) and use
{{ 'orders.save' | transloco }} or the transloco directive. HTTP sources use the
normal Angular interceptor chain and may be optional; stale responses are ignored
after a language or context change. Persistence and user/tenant lifecycle belong to
the consumer application.
com.jwebmp.core.base.angular.client
βββ com.jwebmp.client (JWebMP client library)
βββ com.guicedee.client (GuicedEE lifecycle & SPI)
βββ com.guicedee.guicedinjection (Guice DI + classpath scanning)
βββ com.guicedee.jsonrepresentation (Jackson / JSON utilities)
βββ org.apache.commons.lang3 (StringUtils, etc.)
βββ org.apache.commons.io (FileUtils, IOUtils)
βββ jakarta.validation (@NotNull awareness in TS field generation)
βββ org.apache.logging.log4j.core (Log4j2 logging)
- Java: 25 LTS
- Maven: inherits
com.jwebmp:parent:2.0.0-SNAPSHOT - JPMS: module descriptor at
src/main/java/module-info.java
mvn clean installRun tests:
mvn testGitHub Actions workflow at .github/workflows/maven-package.yml (GuicedEE shared workflow).
Required secrets: USERNAME, USER_TOKEN, SONA_USERNAME, SONA_PASSWORD.
Example environment file: .env.example.
| Document | Path |
|---|---|
| Architecture diagrams | docs/architecture/README.md |
Issues and pull requests are welcome. Please add tests (using jwebmp-testlib) for new annotations, SPI hooks, or rendering logic.