Add shaded artifact (classifier "shaded") with relocated dependencies - #102
Add shaded artifact (classifier "shaded") with relocated dependencies#102bertysentry wants to merge 2 commits into
Conversation
Attach a second artifact (classifier "shaded") in which every dependency is relocated under org.metricshub.winrm.shaded.* so that embedding winrm-java cannot clash with, or leak ServiceLoader/JAXP registrations into, the host application's classpath: - All CXF/HttpClient/JAXB/SAAJ/smbj/etc. packages relocated; the ServicesResourceTransformer renames and rewrites META-INF/services entries to the relocated names. - CXF discovers its features from META-INF/cxf/bus-extensions.txt whose class names are plain text (not rewritten by relocation), so the jar ships a pre-relocated merged copy of all cxf-* entries (src/main/shade/bus-extensions.txt) and the originals are filtered out. - javax.xml.stream.* service files are dropped: the shaded jar must not claim the JVM-wide default StAX implementation in host applications (CXF falls back to the JDK StAX implementation). - org.slf4j:slf4j-api stays external so the host controls logging; jcl-over-slf4j is embedded (relocated) to back the shaded HttpClient's commons-logging. org.bouncycastle stays external: it is a signed JCE provider and must not be repackaged. Verified by running WinRMService.createInstance + executeWql with ONLY the shaded jar, slf4j and bcprov on the classpath: the full stack (WSDL parse, JAX-WS catalog, JAXB, SAAJ, NTLM encryption interceptors, async HTTP conduit) works up to the network layer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Exclude artifacts that are never used at runtime: - com.sun.xml.ws (Metro/jaxws-rt) and its satellites (gmbal, ha-api, management-api, streambuffer, FastInfoset) plus the duplicate com.sun.xml.bind JAXB flavor: CXF is the JAX-WS implementation here and winrm-java only uses the jakarta.xml.ws API. saaj-impl and its actual dependencies (stax-ex, mimepull, angus-activation) are kept. - jakarta.mail / angus-mail: only used for MTOM/attachments, which WinRM never uses. Woodstox stays in (relocated): CXF requires it for secure StAX parsing (refuses to start without it unless org.apache.cxf.stax.allowInsecureParser is set) and instantiates it by class name, so dropping its javax.xml.stream service files hides it from the host JVM without breaking CXF. Verified with the same isolated smoke test: full stack functional down to the network layer; no unrelocated classes or unshaded service registrations remain in the jar. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Trimmed the shaded artifact 14.5 MB → 10.6 MB by excluding runtime-dead artifacts: Metro ( Woodstox must stay: CXF refuses to create a secure Deliberately NOT using Same verification as before: isolated smoke test passes (full stack to the network layer), 31/31 tests, jar hygiene clean. |
Summary
Attaches a second artifact —
winrm-java-<version>-shaded.jar(classifiershaded) — in which all dependencies are relocated underorg.metricshub.winrm.shaded.*, so embedding winrm-java cannot clash with, or leakServiceLoader/JAXP registrations into, the host application's classpath. The regular thin JAR is unchanged; existing consumers are unaffected.Why
Investigating a customer-reported WinRM failure in MetricsHub Enterprise (see MetricsHub/metricshub-community#1271) showed how fragile a flat classpath is around this library:
XMLInputFactoryfor every other component on the classpath.mvn dependencyaway.The shaded artifact fixes both directions of classpath interference. Note what it does NOT fix: JAXP factory poisoning through
DocumentBuilderFactory.newInstance()(e.g. Oraclexmlparserv2, the root cause in the linked issue) is a JDK-global lookup that no amount of relocation can shield — verified experimentally. That requires the classloader isolation proposed in the linked issue (or pinning the JAXP factories via system properties).Design notes
ServicesResourceTransformerrenames and rewritesMETA-INF/servicesfiles to the relocated names (JAXB, SAAJ, JAX-WS, CXF bus factory all resolve within the shaded namespace).META-INF/cxf/bus-extensions.txtlists class names as plain text, which relocation does not rewrite — the jar ships a pre-relocated merged copy of all cxf-* module entries (src/main/shade/bus-extensions.txt); originals are filtered out. (Fun fact: cxf-rt-ws-addr's copy has no trailing newline — naive concatenation silently corrupts the merge.)javax.xml.stream.*service files are dropped — the shaded jar must not claim the JVM-wide StAX default inside host applications; CXF falls back to the JDK StAX implementation.org.slf4j:slf4j-api(host controls logging; the embedded, relocatedjcl-over-slf4jbacks the shaded HttpClient's commons-logging and routes to the host's slf4j) andorg.bouncycastle:bcprov-jdk18on(signed JCE provider — repackaging would break it).jakarta.servlet.*service files from jaxws-rt are excluded so the jar cannot register into host servlet containers.Verification
mvn verify: 31/31 tests pass, prettier/checkstyle/pmd clean.WinRMService.createInstance()(WSDL parse, JAX-WS catalog, CXF client build) succeeds, andexecuteWql()against a nonexistent host runs the full stack — JAXB serialization, SAAJ, NTLM encryption interceptors, async HTTP conduit — down to a cleanUnknownHostExceptionat the DNS layer. No unrelocated third-party classes remain in the jar.META-INF/servicesentry is either relocated or belongs to winrm-java.Usage (for MetricsHub extensions)
See the new README section: depend on the
shadedclassifier with a wildcard exclusion, plus explicitslf4j-apiandbcprov-jdk18on.🤖 Generated with Claude Code