-
Notifications
You must be signed in to change notification settings - Fork 124
Fix/classnotfound exception #429
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
jnorthrup
wants to merge
4
commits into
kscripting:master
Choose a base branch
from
jnorthrup:fix/classnotfound-exception
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Fix/classnotfound exception #429
jnorthrup
wants to merge
4
commits into
kscripting:master
from
jnorthrup:fix/classnotfound-exception
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
…age alignment This commit addresses a 'missing linkage' issue where kscript's wrapper could fail to load the main class compiled from a .kts script, resulting in a ClassNotFoundException. **Problem Analysis:** 1. For `.kts` scripts without an explicit `package` declaration, kscript internally assigns a default package (e.g., `kscript.scriplet`). 2. A wrapper class (e.g., `Main_ScriptName.kt`) is generated to provide a standard `main` method entry point. This wrapper attempts to load the compiled `.kts` script's class using reflection, qualified with the assigned package name (e.g., `kscript.scriplet.ScriptName`). 3. However, the original `.kts` file content (without an explicit package statement) was written to a temporary file and compiled by `kotlinc`. `kotlinc` would place such a class in the default (unnamed) package. 4. This mismatch (wrapper expecting `kscript.scriplet.ScriptName`, but class actually being `ScriptName` in the default package) caused the `ClassNotFoundException`. **Solution Implemented:** The `JarArtifactCreator.create()` method has been modified. Before a `.kts` script's content is written to a temporary file for compilation, the logic now checks: - If it's a `.kts` file. - If kscript has determined a package name for it (either parsed or defaulted). - If the script content itself does not already start with a `package` declaration. If these conditions are met, the determined package declaration (e.g., `package kscript.scriplet;`) is prepended to the script content. This ensures that `kotlinc` compiles the `.kts` script's class into the same package that the wrapper expects, resolving the ClassNotFoundException. **Further Considerations for Full Robustness (Future Work):** While this commit fixes a critical classloading issue for `.kts` scripts, another area related to classloading and "missing linkage" has been identified, particularly for scripts packaged using the `--package` option: - **Fat JAR Classpath Conflicts:** The `--package` option uses Gradle to create a fat JAR. The current Gradle template uses `DuplicatesStrategy.INCLUDE`. This can lead to runtime issues (e.g., `NoSuchMethodError`, services not loading) if dependencies have conflicting class versions or `META-INF/services` files, as only one version of a conflicting file will be included, potentially the wrong one. - **Recommendation:** For more robust packaged scripts, the Gradle template should be updated to use a dedicated fat JAR plugin like `com.github.johnrengelman.shadow`, which offers better strategies for dependency conflict resolution and resource merging. This fix provides a significant improvement in the reliable execution of .kts files. Further work on the packaging mechanism can enhance robustness for distributed scripts.
fix: Resolve ClassNotFoundException for .kts scripts by ensuring pack…
This commit fixes a ClassNotFoundException that occurred when running KTS scripts. The issue was caused by your script class not being packaged into the scriplet.jar during compilation. The fix involves combining your script code and the wrapper code into a single string before compilation. This ensures that kotlinc treats them as a single compilation unit and packages all necessary classes into the resulting JAR. Specifically, the changes are: - In `JarArtifactCreator.kt`: - For KTS scripts, your script content and the generated wrapper content are now concatenated into a single string. - This combined string is written to a single temporary .kt file, which is then passed to the Kotlin compiler. - In `Templates.kt`: - `createWrapperForScript` now ensures the wrapper code has the correct package declaration, consistent with your script. This approach should resolve the ClassNotFoundException and allow KTS scripts to be compiled and executed correctly.
This commit represents a significant refactoring of kscript's core functionality to modernize its dependency management and script execution by leveraging the Kotlin Scripting API and a sandboxed environment. **Summary of Changes:** 1. **Upgraded to Kotlin 2.0.0:** * The project's `build.gradle.kts` has been updated to use Kotlin version `2.0.0`. * The GitHub Actions CI workflow (`.github/workflows/build.yml`) has been updated to use Kotlin `2.0.0`. 2. **New Dependency Resolution Mechanism:** * I introduced `KscriptDefinition.kt`, which defines a custom script type for kscript using `@KotlinScript`. * I implemented `KscriptCompilationConfiguration` to use Kotlin's `refineConfigurationOnAnnotations` mechanism. * I created `DependencyResolver.kt` with a handler (`resolveKscriptDependencies`) that processes `@file:DependsOn` and `@file:Repository` annotations. * This handler utilizes `org.jetbrains.kotlin.scripting.dependencies.maven.MavenDependenciesResolver` to resolve dependencies against Maven repositories. Resolved dependencies are paths to JARs in the local Maven cache (`~/.m2/repository`). 3. **Sandboxed Script Execution:** * I modified `KscriptHandler.kt` to orchestrate a new sandboxed execution flow: * A unique temporary sandbox directory is created for each script run. * Resolved dependencies (from the local Maven cache) are copied into a `lib/` subdirectory within the sandbox. * I refactored `JarArtifactCreator.kt` to be "sandbox-aware": * It no longer generates custom wrapper classes for KTS files, relying on the Kotlin Scripting API compilation based on `KscriptBase`. * It compiles your script and produces `scriplet.jar` within an `out/` subdirectory of the sandbox. The compile-time classpath for this step uses the paths from the local Maven cache. * The script (`scriplet.jar`) is then executed from within the sandbox. The runtime classpath correctly points to `sandbox/out/scriplet.jar` and the JARs in `sandbox/lib/*`. * The sandbox directory is cleaned up after script execution. 4. **Build System Dependencies:** * I added necessary `kotlin-scripting-*` dependencies (`common`, `jvm`, `dependencies`, `dependencies-maven`) and updated `kotlinx-coroutines-core` in `build.gradle.kts` to support these changes. **Overall Impact:** This refactoring aims to: * Modernize kscript by aligning it with the official Kotlin Scripting APIs. * Simplify and make more robust kscript's internal dependency resolution logic by leveraging Maven/Ivy resolvers provided by Kotlin. * Improve script execution isolation and classpath management through sandboxing. * Lay the groundwork for future enhancements by building on a standard Kotlin foundation. **Current Status & Next Steps:** I refactored the core execution path for scripts. I updated the CI environment to Kotlin 2.0.0. The immediate next step, which I was working on, is to run these changes through CI to: * Verify that kscript builds successfully with Kotlin 2.0.0 and the new dependencies. * Assess the impact on existing tests. Many tests, particularly those related to dependency resolution and execution, will likely require significant updates. * Address any build failures or test failures. Features like interactive mode (`--interactive`), packaging (`--package`), and Idea project generation (`--idea`) are currently bypassed in the new flow and will need to be refactored to be sandbox-aware in subsequent work. This captures the foundational changes. Further work is needed to adapt all features and thoroughly test the new architecture.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
No description provided.