guicedee-jpms-shade

Convert an automatic-module (or non-modular) JAR dependency into a GuicedEE shaded JPMS service module so the GuicedEE/jlink pipeline stays clean. Use when a GuicedEE module requires an automatic module (a JAR with only an Automatic-Module-Name or none), when jlink/jpms complains about automatic modules on the module path, or when adding a new `com.guicedee.modules.services` shade under `services/Libraries`. Covers the maven-shade + moditect module-info pattern, version + BOM registration (Versioner, StandaloneBOM, guicedee-bom), dev-suite build registration, and rewiring the consuming module.

5 stars

Best use case

guicedee-jpms-shade is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Convert an automatic-module (or non-modular) JAR dependency into a GuicedEE shaded JPMS service module so the GuicedEE/jlink pipeline stays clean. Use when a GuicedEE module requires an automatic module (a JAR with only an Automatic-Module-Name or none), when jlink/jpms complains about automatic modules on the module path, or when adding a new `com.guicedee.modules.services` shade under `services/Libraries`. Covers the maven-shade + moditect module-info pattern, version + BOM registration (Versioner, StandaloneBOM, guicedee-bom), dev-suite build registration, and rewiring the consuming module.

Teams using guicedee-jpms-shade should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/guicedee-jpms-shade/SKILL.md --create-dirs "https://raw.githubusercontent.com/GuicedEE/ai-rules/main/skills/.system/guicedee-jpms-shade/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/guicedee-jpms-shade/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How guicedee-jpms-shade Compares

Feature / Agentguicedee-jpms-shadeStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Convert an automatic-module (or non-modular) JAR dependency into a GuicedEE shaded JPMS service module so the GuicedEE/jlink pipeline stays clean. Use when a GuicedEE module requires an automatic module (a JAR with only an Automatic-Module-Name or none), when jlink/jpms complains about automatic modules on the module path, or when adding a new `com.guicedee.modules.services` shade under `services/Libraries`. Covers the maven-shade + moditect module-info pattern, version + BOM registration (Versioner, StandaloneBOM, guicedee-bom), dev-suite build registration, and rewiring the consuming module.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# GuicedEE JPMS Shade

Turn an automatic-module dependency into a proper, named JPMS module published as a
`com.guicedee.modules.services` artifact, then make the consuming GuicedEE module require the
shaded module instead of the automatic one. This yields a clean `jlink` image (no automatic
modules on the module path).

## When This Applies
- A GuicedEE module `requires <some.automatic.module>` that resolves to a plain JAR.
- `jlink` / `jpms` rejects or warns about automatic modules.
- Goal: a fully-named module graph for a reliable runtime image.

## Inputs To Gather First
1. The upstream coordinates and resolved version (e.g. `com.graphql-java:graphql-java:26.0`).
   Resolve the EXACT version the parent already pulls (check the dependency's own POM, the BOM
   that imports it, or `mvn dependency:tree`). Pin to that version — do not guess.
2. The **module name** the JAR advertises. Read it from the JAR manifest
   `Automatic-Module-Name`; if absent, derive a stable name from the root package.
   See `references/inspect-jar.md` for ready-to-run commands to read the manifest and enumerate
   packages (needed for accurate `exports`).
3. The dependency's own external module dependencies (its compile deps that are NOT already
   bundled/relocated inside the JAR). Each becomes a `requires` in the module-info.
   Annotation-only deps (jspecify, jsr305, checker, error_prone) become `requires static`.

> Many libraries already relocate their transitives internally (e.g. graphql-java bundles ANTLR
> and Guava under `graphql.*`). Inspect the package list — only NON-relocated, externally-visible
> dependencies need a `requires`.

## Workflow

### 1. Create the shade module
Create `GuicedEE/services/Libraries/<artifactId>/` (mirror the `json` / `kafka-client` modules):
- `pom.xml` — parent `com.guicedee:parent`, groupId `com.guicedee.modules.services`, the shade
  `artifactSet` pinned to the single upstream artifact, and the standard plugin chain
  (shade → antrun → moditect → flatten → copy-rename → javadoc). Exclude transitives that you
  re-add as their own proper modules.
- `src/moditect/module-info.java` — the named module descriptor.

Use the exact templates in `references/templates.md`.

### 2. Write the moditect module-info
- `module <module-name> { ... }` using the manifest's Automatic-Module-Name.
- `exports` every public package found in the JAR EXCEPT internally-relocated/shaded packages
  (e.g. `*.com.google.*`, `*.org.antlr.*`).
- `requires transitive` for deps whose types appear in the exported API (e.g. `org.reactivestreams`).
- `requires static` for annotation-only deps.
- Add `provides ... with ...` for any `META-INF/services` the JAR ships (the SPI needs explicit
  `provides` in the descriptor, even though the shade keeps the service files).

### 3. Register versions and BOMs
- `GuicedEE/bom/Versioner/pom.xml` — add `<...version>` properties for the upstream artifact(s).
- `GuicedEE/bom/StandaloneBOM/pom.xml` — `dependencyManagement` for the UPSTREAM artifacts (so the
  shade module's `pom.xml` and its exclusions resolve versions).
- `GuicedEE/bom/pom.xml` (guicedee-bom) — `dependencyManagement` for the new
  `com.guicedee.modules.services:<artifactId>` at `${guicedee.version}` (so consumers omit versions).

### 4. Register in the dev-suite build (the "workflows")
- Root `DevSuite/pom.xml` → `services` profile `<modules>` list. This is the module list the
  dev-suite GitHub workflows build/deploy; the reusable workflows in `GuicedEE/workflows` are generic
  templates and do NOT enumerate modules. Each shade also ships as its own GitHub repo that calls the
  reusable `Projects Builder` workflow — mention this to the user, but it is created outside DevSuite.
- Optionally document the mapping table in `GuicedEE/services/services.md`.

### 5. Rewire the consuming module
In the GuicedEE module that used the automatic module:
- Exclude the upstream automatic artifact(s) from whatever transitively brought them in
  (e.g. exclude `com.graphql-java:graphql-java` from `io.vertx:vertx-web-graphql`).
- Add a dependency on the new `com.guicedee.modules.services:<artifactId>`.
- The consumer's `module-info.java` usually needs **no change**: the shaded module keeps the same
  module name, so `requires <module-name>` already resolves — now to a real named module.

### 6. Validate
Install the updated BOMs first (they are SNAPSHOTs the shade module imports), then build:
```
mvn -B -N install        # in Versioner, then StandaloneBOM, then GuicedEE/bom
mvn -B install -DskipTests -Dmaven.javadoc.skip=true   # in each new shade module
jar --describe-module --file target/<artifactId>-<ver>.jar   # confirm requires/exports
mvn -B -o clean compile  # in the consumer module — must compile on the module path
```
Confirm `jar --describe-module` shows the expected named module with correct `requires`/`exports`,
and that the consumer compiles with `[debug release N module-path]`.

## Pitfalls
- **Build env (Windows)**: the repo `mvnw` wrapper may be broken; a system Maven 4
  (`C:\Software\maven4`) + `JAVA_HOME=c:\software\jdk\25` works. Chain PowerShell commands with `;`.
- **Relocated deps need explicit `requires` for JDK modules.** When a library internally relocates
  its dependencies (e.g. graphql-java bundles Guava under `graphql.com.google.*` and ANTLR under
  `graphql.org.antlr.*`), those classes still use JDK APIs such as `java.util.logging`. As an
  *automatic* module the jar implicitly read every module, so it worked; as a *named* module it only
  reads what it `requires`. Missing ones surface at RUNTIME, not compile time, as
  `IllegalAccessError: class X (in module M) cannot access class Y (in module java.logging) because
  module M does not read module java.logging`. Add the JDK module (e.g. `requires java.logging;`).
  Compile + `jar --describe-module` will NOT catch this — only running the code does. Always run the
  consumer's integration tests after a shade.
- **Missing version errors** in the shade module mean the updated StandaloneBOM was not installed yet.
- **Split packages**: never let the shaded module and a separately-required module both export the
  same package — exclude the transitive from one side.
- **Don't export relocated internals** — they are implementation detail and break encapsulation.

## References
- `references/templates.md` — copy-paste `pom.xml` and `module-info.java` templates + BOM snippets.
- `references/inspect-jar.md` — PowerShell snippets to read the manifest module name and package list.
- `references/worked-example.md` — the graphql-java + java-dataloader case, end to end.

Related Skills

guicedee-websockets

5
from GuicedEE/ai-rules

RFC 6455 WebSocket support for GuicedEE using Vert.x 5: call-scoped connections, action-based message routing via IWebSocketMessageReceiver SPI, group management and broadcasting, WebSocketServerOptions, and lifecycle hooks. Use when adding WebSocket messaging, implementing real-time communication, managing WebSocket groups, or creating message receivers.

guicedee-webservices

5
from GuicedEE/ai-rules

SOAP web services for GuicedEE using Apache CXF conventions: JAX-WS annotations (@WebService, @WebMethod, @WebParam, @WebResult), code-first and WSDL-first approaches, endpoint publishing, CXF interceptors and logging, MTOM, WS-Security (WSS4J), SOAP 1.1/1.2 bindings, and Guice DI integration. Use when creating SOAP services, publishing JAX-WS endpoints, configuring CXF bindings, or adding WS-Security.

guicedee-web

5
from GuicedEE/ai-rules

Bootstrap reactive HTTP/HTTPS servers with Vert.x 5 inside GuicedEE: Router setup, BodyHandler configuration, TLS/HTTPS, SPI extension points (VertxRouterConfigurator, VertxHttpServerOptionsConfigurator, VertxHttpServerConfigurator), per-verticle sub-routers, and environment-driven configuration. Use when setting up the Vert.x web server, configuring HTTP/HTTPS, adding custom routes or middleware, or managing server options.

guicedee-vertx

5
from GuicedEE/ai-rules

Build reactive services using Vert.x 5 inside the GuicedEE DI lifecycle: event-bus consumers, publishers, verticle deployment, codecs, throttling, clustering, SPI hooks, and JPMS module setup. Use when adding Vert.x event-bus messaging, deploying verticles, wiring reactive endpoints with Guice injection, configuring Vert.x runtime options, or implementing custom codecs and cluster managers.

guicedee-service-registry

5
from GuicedEE/ai-rules

Named service registry with health-aware resolution for GuicedEE. Register services by simple name, auto-construct URLs from cloud DNS suffix, monitor health status, resolve services via registry:name prefix or bare name in rest-client @Endpoint. Supports aliases, multiple external URLs, Kubernetes internal URLs, and per-service health paths. Use when registering named services, checking service health, resolving service URLs by name, or integrating with rest-client for service-to-service calls.

guicedee-rest

5
from GuicedEE/ai-rules

Build Jakarta REST (JAX-RS) services on Vert.x 5 inside GuicedEE: @Path/@GET/@POST route registration, parameter binding (@PathParam, @QueryParam, @HeaderParam, etc.), Guice-managed resource classes, response handling, content negotiation, and JPMS module setup. Use when creating REST endpoints, configuring Jakarta REST resources, or wiring JAX-RS services with Guice injection.

guicedee-rest-client

5
from GuicedEE/ai-rules

Annotation-driven REST client for GuicedEE using Vert.x 5 WebClient: @Endpoint declarations, RestClient<Send, Receive> injection, authentication strategies (Bearer, Basic, API Key, OAuth2, mTLS), path parameters, environment variable overrides, package-level endpoints, service registry integration (bare name or registry: prefix), and RestClientConfigurator SPI. Use when making outbound REST calls, configuring REST client endpoints, or wiring reactive HTTP clients with Guice injection.

guicedee-rabbitmq

5
from GuicedEE/ai-rules

Annotation-driven RabbitMQ integration for GuicedEE with Vert.x 5: @RabbitConnectionOptions, @QueueExchange, @QueueDefinition, QueueConsumer/QueuePublisher injection, exchange management, queue options (priority, TTL, prefetch), publisher confirms, environment variable overrides, and verticle-scoped connections. Use when adding RabbitMQ messaging, declaring exchanges and queues, creating consumers and publishers, or configuring AMQP topology.

guicedee-persistence

5
from GuicedEE/ai-rules

Reactive JPA persistence with Hibernate Reactive 7, Vert.x 5 SQL clients, and Mutiny sessions inside GuicedEE: DatabaseModule setup, persistence.xml configuration, multi-database support, @EntityManager scoping, and environment variable resolution. Use when adding database persistence, configuring Hibernate Reactive, creating DatabaseModule subclasses, wiring Mutiny.SessionFactory, or managing multiple persistence units.

guicedee-openapi

5
from GuicedEE/ai-rules

Automatic OpenAPI 3.1 spec generation and serving for GuicedEE with Vert.x 5: scans Jakarta REST resources at startup, serves /openapi.json and /openapi.yaml endpoints, Swagger annotations support, @OpenAPIDefinition configuration, and companion Swagger UI module. Use when generating API documentation, serving OpenAPI specs, or configuring Swagger annotations on REST resources.

guicedee-metrics

5
from GuicedEE/ai-rules

Application metrics for GuicedEE using Vert.x 5 Dropwizard Metrics and MicroProfile Metrics 5.1: @Counted, @Timed, @MetricMethod annotations, Guice AOP interceptors, Prometheus scrape endpoint, Graphite reporting, JMX exposure, @MetricsOptions configuration, environment variable overrides, and Vert.x built-in metrics (event bus, HTTP, pools). Use when adding application metrics, configuring Prometheus endpoints, creating custom counters/timers, or monitoring Vert.x internals.

guicedee-mail-client

5
from GuicedEE/ai-rules

Annotation-driven SMTP mail client for GuicedEE with Vert.x 5: @MailConnectionOptions for SMTP server configuration, MailService injection for sending text/HTML/multipart emails with attachments, connection pooling, StartTLS/SSL support, DKIM signing, environment variable overrides, and graceful shutdown. Use when sending emails via SMTP, configuring mail connections, or injecting mail services.