Eclipse-Plugin has class path problems

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Eclipse-Plugin has class path problems

Stefan Matthias Aust
I wounder, why I get an exception. I'm using the Eclipse plugin 2.1.3.

Example code:

  package test;

  object test {
    class A(as: Array[S])
    case class S(s: String)

    def main(args: Array[String]): Unit = {
      Console.println(new A(Array()))
    }
  }

Error message:

  Exception in thread "main" java.lang.ClassNotFoundException: test/test$S
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:169)
        at scala.runtime.BoxedAnyArray.unbox(BoxedAnyArray.scala:150)
        at scala.runtime.ScalaRunTime$.arrayValue(ScalaRunTime.scala:107)
        at test.test$.main(test.scala:8)
        at test.test.main(test.scala)

I decompiled the generated code and it looks like

  Object obj = ScalaRunTime$.MODULE$.arrayValue(
    Predef$.MODULE$.Array(
      new BoxedObjectArray((Object[])new test.S[0])), "test.test$S");
  test.A a = new test.A((test.S[])(
    (obj instanceof BoxedArray)
      ? ScalaRunTime$.MODULE$.arrayValue((BoxedArray)obj, "test.test$S")
      : obj));
  Console$.MODULE$.println(a);

Line 150 of BoxedAnyArray.scala is

  unboxed = java.lang.reflect.Array.newInstance(
   Class.forName(elemTag), length);

which also looks good.

I tried the Eclipse-compiled code with scala 2.1.3 from sbaz and that
worked just fine.

--
Stefan Matthias Aust

Reply | Threaded
Open this post in threaded view
|

Re: Eclipse-Plugin has class path problems

Lex Spoon
In general it does work to create a class in the plugin and then run
it directly from Eclipse.  Can you describe the sequence you tried in
more detail?


Incidentally, the easiest thing to do is to create the class using
"New -> Scala Application" instead of "New -> Scala Object".  If you
do it that way, the plugin will create a run profile for you
automatically.

-Lex

Reply | Threaded
Open this post in threaded view
|

Re: Eclipse-Plugin has class path problems

Stefan Matthias Aust
Lex Spoon schrieb:
> In general it does work to create a class in the plugin and then run
> it directly from Eclipse. [...]

Not for my example... because that is what I did.  I just tried it also
with a fresh Eclipse 3.2 RC1 plus plugin 2.3.1 and got the same effect.

The java.class.path accordingly to the System property is
"$ECLIPSE\plugins\ch.epfl.lamp.sdt.compiler_2.1.2.7046\lib\scala-library.jar;C:\Dokumente
und Einstellungen\sma\workspace\scala\bin" (with $ECLIPSE expanded of
course) and that looks perfectly okay.  And if I run the example via the
command line version of scala, it works.

--
Stefan Matthias Aust

Reply | Threaded
Open this post in threaded view
|

Re: Eclipse-Plugin has class path problems

sean.mcdirmid
In reply to this post by Stefan Matthias Aust
Hi Stefan,

Ah! This bug is so wicked. The following code works until the last line:

package test;
object test {
  class A(as: Array[S])
  case class S(s: String)

  def main(args : Array[String]) : Unit = {
    Console.println("hello world");
   
    val xxx = S("hello");
    Console.println(xxx.s);
    val clazz = Class.forName("test.test$S");
    Console.println("clazz: " + clazz);
    val unbox = java.lang.reflect.Array.newInstance(clazz, 10);
    Console.println("array: " + unbox);
   // crash: next line  
    Console.println(new A(Array()))
  }
}

And the reason why: the JDT launcher loads library classes from a
different more privledged class loader than the application.  This means
that the code in the library will load only from the library's class
loader and not the application's, which means our use of reflection to
get at application classes in the Scala run-time will not work with the
JDT launcher. Actually this is a pretty common setup for security
reasons as far as I understand it (prevents trojan string attacks: its
probably true in web browsers - should test). When invoked from the
command line, the Scala library is treated like part of the application
rather than a privledged system library, so it is loaded from the
application's class loader and hence forName between the library and the
application will behave the same. In Eclipse, this isn't true, and as a
result we get a crash.

As for the fix, I think we shouldn't depend on the Scala library and
application class loaders being the same. But we are going to have to

Thanks for finding this!

Sean

Stefan Matthias Aust wrote:

> I wounder, why I get an exception. I'm using the Eclipse plugin 2.1.3.
>
> Example code:
>
>  package test;
>
>  object test {
>    class A(as: Array[S])
>    case class S(s: String)
>
>    def main(args: Array[String]): Unit = {
>      Console.println(new A(Array()))
>    }
>  }
>
> Error message:
>
>  Exception in thread "main" java.lang.ClassNotFoundException: test/test$S
>     at java.lang.Class.forName0(Native Method)
>     at java.lang.Class.forName(Class.java:169)
>     at scala.runtime.BoxedAnyArray.unbox(BoxedAnyArray.scala:150)
>     at scala.runtime.ScalaRunTime$.arrayValue(ScalaRunTime.scala:107)
>     at test.test$.main(test.scala:8)
>     at test.test.main(test.scala)
>
> I decompiled the generated code and it looks like
>
>  Object obj = ScalaRunTime$.MODULE$.arrayValue(
>    Predef$.MODULE$.Array(
>      new BoxedObjectArray((Object[])new test.S[0])), "test.test$S");
>  test.A a = new test.A((test.S[])(
>    (obj instanceof BoxedArray)
>      ? ScalaRunTime$.MODULE$.arrayValue((BoxedArray)obj, "test.test$S")
>      : obj));
>  Console$.MODULE$.println(a);
>
> Line 150 of BoxedAnyArray.scala is
>
>  unboxed = java.lang.reflect.Array.newInstance(
>   Class.forName(elemTag), length);
>
> which also looks good.
>
> I tried the Eclipse-compiled code with scala 2.1.3 from sbaz and that
> worked just fine.
>