Ceylon 1.3.3 JVM Module to Java Interop: Resolving Module Versioning and Classloader Conflicts
0 reputation · 16 Mar 2020, 00:06 UTC
0 reputation · 16 Mar 2020, 00:06 UTC
The objective is to integrate a Ceylon 1.3.3 module into a Java application by compiling the module to Java bytecode and wiring it into a standard Maven or Gradle build. The integration must preserve semantic versioning, avoid class‑loader isolation issues, and eliminate the requirement for the Ceylon runtime at runtime.
Ceylon’s module system uses a custom version scheme (major.minor.patch[-qualifier]) that has no direct mapping to Maven coordinates. Because the Herd repository is offline, any remote dependency resolution must rely on locally vendored JARs or a self‑hosted mirror. Additionally, Ceylon modules are loaded by a dedicated module classloader; when the same Java library is also loaded by the application classloader, ClassCastException can occur. Finally, the ceylon compile --java flag generates Java source that still references ceylon.language types, implying a runtime dependency that may not be desirable.
1. Is there a recommended strategy for mapping Ceylon module version strings to Maven coordinates that ensures binary compatibility across builds?
2. What configuration or classloader strategy can prevent ClassCastException when a shared Java library is loaded by both the Ceylon module classloader and the application classloader?
3. Can the Java sources produced by ceylon compile --java be used without retaining the Ceylon runtime on the classpath, or is the runtime mandatory for correct operation?
34775 reputation · 16 Mar 2020, 09:45 UTC
1. Map Ceylon module versions to Maven coordinates manually: groupId from the module namespace segments, artifactId from the final segment, and version from major.minor.patch[-qualifier]. Pin exact versions; do not use Maven version ranges because Ceylon compatibility is enforced by the Ceylon toolchain, not Maven or Gradle.
2. Prevent ClassCastException by loading shared Java libraries through a single common parent classloader and configuring the Ceylon module classloader for parent-first delegation. Do not ship duplicate copies of the same library under different loaders, and set the thread context classloader to the loader owning the shared classes before crossing into Ceylon code.
3. The Ceylon runtime is mandatory. Classes produced by ceylon compile --java still reference ceylon.language types such as Object, Sequence, and Function. Removing ceylon.language.jar causes NoClassDefFoundError when loading or invoking Ceylon-generated classes from Java. A thin Java wrapper can hide Ceylon types in public signatures, but instantiating or subclassing Ceylon classes still requires the runtime on the classpath.
This answer assumes Ceylon 1.3.3 compiler output behaves as described for the 1.3.x line and that you are compiling with ceylon compile 1.3.3. Because Ceylon 1.3.3 is legacy and largely unmaintained, treat module resolution and --java behavior as version-sensitive until verified against your installed compiler. The offline Herd repository means remote dependency resolution is unavailable; vendored JARs must be checksum-verified and license-reviewed before use.
major.minor.patch[-qualifier].ceylon.language.jar into your local repository or libs/ directory. Do not resolve from Herd.ceylon.language.jar to the application classpath alongside the Ceylon module JAR.java.* types if you want to limit Ceylon exposure to callers.# Inspect compiled Ceylon output for runtime references
javap -c -classpath build/ceylon modules/your.module.1.0.0.car.jar | grep ceylon.language
# Confirm runtime is required
java -cp app.jar:ceylon-module.jar YourJavaCaller # expect NoClassDefFoundError without ceylon.language.jar
# Confirm classloader fix
java -cp shared.jar:ceylon-module.jar:app.jar YourJavaCaller # cast should succeed when shared.jar is on the parent loader
Missing diagnostic detail: confirm which classloader loads your shared Java library in the running application. If it is already the system/application loader, moving the shared JAR to the parent loader may not change behavior; if it is a custom loader, you must align that loader with the Ceylon module loader instead.
| Item | Status | Notes |
|---|---|---|
| Ceylon-to-Maven coordinate mapping | Likely explanation | No official mapping exists; derive manually and pin exact versions. |
| ClassCastException from separate loaders | Confirmed JVM behavior | Same class loaded by two loaders produces distinct Class objects. |
| Ceylon runtime mandatory for compiled output | Likely explanation | Generated bytecode references ceylon.language; verify with javap on your build. |
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.