When running the following as as scala script I get an InstantiationException. But when put it inside an class extending App and then compiling with scalac and running with scala it works. Any ideas?
class A
val foo = classOf[A]
foo.newInstance()
When running the following as as scala script I get an InstantiationException. But when put it inside an class extending App and then compiling with scalac and running with scala it works. Any ideas?
class A
val foo = classOf[A]
foo.newInstance()
TL;DR Try foo.getConstructors()(0).newInstance(this)
, or use your own multiline shebang
The InstantiationException suggests that your call newInstance() is invoking a non-existent constructor.
Here is a similar script, printing your constructors:
#!/bin/sh
exec scala "$0" "$@"
!#
class A
val foo = classOf[A]
foo.getConstructors.foreach(c => println("Constructor: " + c))
Producing:
Constructor: public Main$$anon$1$A(Main$$anon$1)
Thus, an instance of an anonymous class must be passed to A's constructor.
It turns out, Scala scripts are run by a ScriptRunner, that wraps your script with an anonymous object (adapted from scala source, and Programming Scala):
object Main {
def main(args: Array[String]): Unit = {
new AnyRef {
// Your script code is inserted here.
}
}
}
Thus passing the instance of your outer anonymous class, this
, to A's constructor allows instantiation of your new instance of inner class A.
As far as I know, there's no way to create a static inner class within the scala language. Any constructors (created by the scala compiler) in a basic script will require the outer instance. The other options, that I'm aware of, include bytecode manipulation to dynamically create a new constructor for the class (way overkill, imho), or reimplementing the ScriptRunner.
During the single exec line in the shell script, Scala's implementation of ScriptRunner:
#!
You could write your own external bit of code that also does the same, in any language you want, and then exec
your external code on one line, also. Or you can embed the functionality inside the script itself using multiline shebang syntax, like this example adapted from the Go sample on this page:
Debug version, printing commands via sh -x
, and not actually deleting anything:
#!/bin/sh -x
scriptfile=`basename $0`
classname="${scriptfile%.*}"
scalafile="${classname}.scala"
sed -e '1,12d' -e "s/%scala_class_name%/${classname}/" < "$0" > $scalafile
scalac $scalafile
echo todo: rm $scalafile
scala $classname "$@"
STATUS=$?
echo todo: rm "${classname}*.class"
exit $STATUS
######## Scala code starts on line 13
object %scala_class_name% {
def main(args: Array[String]) {
class A
val foo = classOf[A]
println(foo.newInstance())
}
}
The reason I included a debug version is that you probably want to just use this as a starting point. For example, one might want to do more setup or cleanup depending on what else is in the script, including:
That said here's a "it should just work, but I make no guarantees" version of the above, that cleans up after itself:
#!/bin/sh
scriptfile=`basename $0`
classname="${scriptfile%.*}"
scalafile="${classname}.scala"
sed -e '1,12d' -e "s/%scala_class_name%/${classname}/" < "$0" > $scalafile
scalac $scalafile
rm $scalafile
scala $classname "$@"
STATUS=$?
rm "${classname}*.class"
exit $STATUS
######## Scala code starts on line 13
object %scala_class_name% {
def main(args: Array[String]) {
class A
val foo = classOf[A]
println(foo.newInstance())
}
}
Original answerer does not work for Oreilly, but is an avid consumer. ;)