Archive
Patch Accepted
Woo hoo! My patch to the maven-scala-plugin has been accepted!
That means that my GitHub pull request was accepted into the main repository. Users can get the fix by pulling down the code and building the plugin. The fix will be included in the next version of the plugin, which I will be sure to mention here!
maven-scala-plugin
Continuing from my last post: With the Scala script written, I wanted to integrate it into our Maven build as an optional step. But this didn’t go so well.
When running mvn scala:script
with a link to my script file in the configured pom.xml, I got a Fatal Error. I also couldn’t get a simple helloWorld script to run, as a separate file or scripted right into the pom.xml file. This is the error I got:
[INFO] ------------------------------------------------------------------------
[ERROR] FATAL ERROR
[INFO] ------------------------------------------------------------------------
[INFO] scala/ScalaObject
scala.ScalaObject
[INFO] ------------------------------------------------------------------------
[INFO] Trace
java.lang.NoClassDefFoundError: scala/ScalaObject
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at org_scala_tools_maven.ScalaScriptMojo.runScript(ScalaScriptMojo.java:185)
at org_scala_tools_maven.ScalaScriptMojo.doExecute(ScalaScriptMojo.java:154)
at org_scala_tools_maven.ScalaMojoSupport.execute(ScalaMojoSupport.java:340)
at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:490)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:694)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(DefaultLifecycleExecutor.java:556)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:535)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:387)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:348)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:180)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:328)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:138)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:362)
at org.apache.maven.cli.compat.CompatibleMain.main(CompatibleMain.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
Caused by: java.lang.ClassNotFoundException: scala.ScalaObject
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
... 33 more
[INFO] ------------------------------------------------------------------------
The maven-scala-plugin couldn’t even find the ScalaObject class, which is analagous to Java Object. Of course I googled the heck out of this error and found a few people suffering the same problem, but no one posted a solution. Then I found maven-scala-plugin’s repo on GitHub and discovered that this issue has been reported but not yet fixed. So I decided to download the source code and take a look.
Here’s what I found, in ScalaScriptMojo.java:
private URLClassLoader createScriptClassloader(File scriptDir, Set<String> classpath) throws MalformedURLException { List<URL> urls = new ArrayList<URL>(); // add the script directory to the classpath urls.add(scriptDir.toURI().toURL()); for (String string : classpath) { urls.add(new URL("file://" + string)); } URLClassLoader loader = new URLClassLoader(urls.toArray(new URL[urls .size()]), getClass().getClassLoader()); return loader; }
That seemed like a pretty hinky way to me to send files to the URLClassLoader. The code that generates the Set of classpath Strings uses File.getCanonicalPath()
to create the Strings. Thus they are platform-dependent Strings, and on a Windows box you can’t use them to create a valid File URL by prepending “file://” to them because the path separators are “\”. I assume that the plugin contributors are on Linux machines and couldn’t replicate the problem to fix it.
Like all the best bug fixes, this one was a one-liner:
for (String string : classpath) { urls.add(new File(string).toURI().toURL()); }
Now the URLs will be correct no matter what platform you’re on.
I forked the maven-scala-plugin repository on GitHub and checked in my fix. I was waiting to post this entry until my Pull Request was accepted by the repo owner, but I guess he is too busy working on other efforts. Until the request is accepted, please check out my forked repo.