Scala: Proper way to get name of class for an object? - scala

I have a class that contains a main method, and I wish to start a new process that runs this class.
But when I try to use Scala to get the name of this class, it gives me the wrong name. For example:
object Test {
def main(args: Array[String]) = {
println(Test.getClass.getCanonicalName)
}
}
Then:
roei#roei-main:~/Java$ scalac Test.scala
roei#roei-main:~/Java$ scala Test
Test$
roei#roei-main:~/Java$ javap Test*.class
Compiled from "Test.scala"
public final class Test {
public static void main(java.lang.String[]);
}
Compiled from "Test.scala"
public final class Test$ {
public static final Test$ MODULE$;
public static {};
public void main(java.lang.String[]);
}
Test.getClass.getCanonicalName gives me Test$, not Test. But the static main method is inside of a class named Test, whereas Test$ contains a non-static main. Obviously I can do the workaround of just deleting the $ at the end, but I'm looking for a more satisfying/reliable solution.

A possible solution would be using ClassTag of scala.reflect (see API). I mean something like the following:
import scala.reflect.ClassTag
import scala.reflect.classTag
class Test
object Test {
def main(args: Array[String]) = {
println(Test.getClass.getCanonicalName)
println(classTag[Test].runtimeClass.getCanonicalName)
}
}
it will print:
Test$
Test

Related

Check what the method of mocked object receives

In my project, whenever a class produces some output, instead of doing println it calls OutputStore.write, which is a class and method I defined.
I am trying to test the output of another class so I mocked OutputStore. I want to see what parameters it receives to OutputStore.write.
val mockOutputStore = mock[OutputStore]
I would like to do something like this:
val argument = ArgumentCaptor.forClass(classOf[OutputStore])
verify(mockOutputStore).write(argument.capture())
assertEquals("some parameter", argument.getValue())
However, this doesn't compile as verify is not even recognized.
The signature of my test class is this:
class SomeUnitTestSet extends org.scalatest.FunSuite with MockitoSugar with PropertyChecks
Any idea how to check what parameters a mocked object's method receives?
Here is a translation of what #JBNizet suggested into a Scala code
Assuming you have your OutputStore class
class OutputStore {
def write(msg: String) = {
println(msg)
}
}
and some OutputStoreApiUser class
class OutputStoreApiUser(val outputStore: OutputStore) {
def foo(): Unit = {
outputStore.write("some parameter")
outputStore.write("some parameter2")
}
}
Then your test might be something like this (in real life you probably #Inject outputStore but this is not relevant here):
import org.mockito.Mockito.verify // static import!
import org.scalatest.mockito.MockitoSugar
import org.scalatest.prop.PropertyChecks
class SomeUnitTestSet extends org.scalatest.FunSuite with MockitoSugar with PropertyChecks {
test("Capture calls"){
val mockOutputStore = mock[OutputStore]
val apiUser = new OutputStoreApiUser(mockOutputStore)
apiUser.foo()
verify(mockOutputStore).write("some parameter")
verify(mockOutputStore).write("some parameter2")
}
}
This one compiles and works for me as I would expect

Main method in Scala

I wrote a Scala class and defined the main() method in it. It compiled, but when I ran it, I got NoSuchMethodError:main. In all the scala examples, I have seen, the main method is defined in an object. In Java we define the main method in a class. Is it possible to define main() in a Scala class or do we always need an object for this?
To answer your question, have a look on the following :
I made a scala class, compiled and decompiled it, and what I got is interesting.
class MyScalaClass{
def main(args: Array[String]): Unit = {
println("Hello from main of class")
}
}
Compiled from "MyScalaClass.scala"
public class MyScalaClass {
public void main(java.lang.String[]);
public MyScalaClass();
}
So it means that when the scala class is converted to java class then the main method of the scala class which in turn being converted to the main method in java class is not static.
And hence we would not be able to run the program because JVM is not able to find the starting point in the program.
But if the same code is done by using the 'object' keyword then:
Compiling the following:
object MyScalaClass{
def main(args: Array[String]): Unit = {
println("Hello from main of object")
}
}
Decompiling the following:
javap MyScalaClass$.class
Compiled from "MyScalaClass.scala"
public final class MyScalaClass$ {
public static final MyScalaClass$ MODULE$;
public static {};
public void main(java.lang.String[]);
}
Decompiling the following
javap MyScalaClass.class
Compiled from "MyScalaClass.scala"
public final class MyScalaClass {
public static void main(java.lang.String[]);
}
So here we got public static void main in MyScalaClass.class therefore the main method can be executed directly by the JVM here.
I hope you got your answer.
As Eugene said in a comment, there are no static methods in Scala. But watch this:
$ cat Echo.scala
object Echo {
def main( args:Array[String] ):Unit = args foreach println
}
$ scalac Echo.scala
$ javap Echo\$.class
Compiled from "Echo.scala"
public final class Echo$ {
public static final Echo$ MODULE$;
public static {};
public void main(java.lang.String[]);
}
$ javap Echo.class
Compiled from "Echo.scala"
public final class Echo {
public static void main(java.lang.String[]);
}
Note that the classfile for the Echo class (not Echo$, the object) does indeed have a public static void main method. Scala generates static methods for methods defined in objects for compatibility with Java.
However, I consider creating a main method in a Scala program an anachronism. Use the App trait instead; it's cleaner:
object Echo extends App {
args foreach println
}
When I want to test my code in intelligent idea scala editor, I simply create a companion object just below my class and put a main method in it. That's all. see an example:
class Colon {
class Cow {
def ^ (moon:Moon): Unit ={
println("Cow jumped over the moon")
}
}
class Moon{
def ^:(cow:Cow) = println("This cow jumped over moon too")
}
}
object Colon{
def main(args: Array[String]): Unit = {
val c:Colon = new Colon
val cow = new c.Cow
val moon = new c.Moon
cow ^ moon
cow ^: moon
moon.^:(cow)
}
}

meaning of top level private class in scala

Say in a scala file I define a class like
private class Test{}
what does the private here mean? In java you can't have a top level private class, which obviously makes sense. But private is syntactically valid in scala, hope someone can shed some light upon it.
You could specify package name for private modifier to allow access to this class only from specified package. By default (without package specified) it is visible only for other members in the enclosing package.
$ cat > test.scala <<EOF
package myPackage {
private[myPackage] class Test
private object A extends Test
}
package otherPackage {
object B extends myPackage.Test
}
EOF
$ scalac test.scala
test.scala:7: error: class Test in package myPackage cannot be accessed in package myPackage
object B extends myPackage.Test
^
one error found
For instance you can access private class from its companion object like this:
trait ITest
private class Test extends ITest
object Test {
def apply(): ITest = new Test
}
Test()
// ITest = Test#59e2abc3
Further clarification on examples:
package myPackage {
private class Test
private object A extends Test
object B extends myPackage.Test //Compile error: private class Test escapes its defining scope as part of type myPackage.Test
private object C extends myPackage.Test // works since C is also private
object Test {
def apply() = new Test //error: private class Test escapes its defining scope as part of type myPackage.Test
}
object Test2 {
def apply(): ITest = new Test //works as ITest is public
}
}
As long as instances of a private class do not escape the enclosing package scope it can be used within the package hierarchy. Companion objects accessing private classes has to be in same package hierarchy as well. With private[P] - p can be any package name that exists.

Instantiating the same scala class from main

In Java I usually do something like:
class Hello {
public Hello() {
System.out.println("hello");
}
public static void main(String args[]) {
new Hello();
}
}
How do I do something similar in Scala? I start off with Hello being a Scala object like so:
object Hello {
// constructor goes here
def main(args: Array[String]): Unit = {
println("hello") // new Hello() would go here
}
}
but I can't instantiate that. If I change I change the object keyword to class then the scala compiler complains i.e.
class Hello {
println("hello")
def main(args: Array[String]): Unit = {
new Hello()
}
}
I know I'm probably on completely the wrong track here but I'd like to be put out of my misery.
Usually for this in Scala i use objects representing the application:
object Hello extends App {
println("hello")
}
I don't think you understand what a Scala object is. It is actually the equivalent of a Java singleton, where an anonymous class is created and instantiated in place.
If you would recompile the code to Java in this scenario:
object Hello {}
It would get something like:
public class Hello$ {
public static Hello$ $MODULE = new Hello$()
}
This is already a singleton, an equivalent of a val. You can even do:
val x = Hello; // x will be of type Hello.type

How do I "get" a Scala case object from Java?

I created a hierarchy of case objects in Scala that looks like the following:
package my.awesome.package
sealed abstract class PresetShapeType(val displayName: String)
case object AccelerationSensor extends PresetShapeType("Acceleration Sensor")
case object DisplacementSensor extends PresetShapeType("Displacement Sensor")
case object ForceSensor extends PresetShapeType("Force Sensor")
case object PressureSensor extends PresetShapeType("Pressure Sensor")
case object StrainSensor extends PresetShapeType("Strain Sensor")
I also have a piece of Java code in which I'd like to access PressureSensor, but the following does not work:
package my.awesome.package.subpackage;
import my.awesome.package.PressureSensor;
// Do some stuff, then...
DVShape newshape = DVShapeFactory.createPresetShape(PressureSensor, new Point3f(0,0,0));
So, how do I reference the PressureSensor case object from Java? I decompiled the byte code for both the PressureSensor and PressureSensor$ classes, which yielded the following:
Compiled from "DVShapeFactory.scala"
public final class org.nees.rpi.vis.PressureSensor extends java.lang.Object{
public static final java.lang.Object productElement(int);
public static final int productArity();
public static final java.lang.String productPrefix();
public static final int $tag();
public static final java.lang.String displayName();
}
Compiled from "DVShapeFactory.scala"
public final class org.nees.rpi.vis.PressureSensor$ extends org.nees.rpi.vis.PresetShapeType implements scala.ScalaObject,scala.Product,java.io.Serializable{
public static final org.nees.rpi.vis.PressureSensor$ MODULE$;
public static {};
public org.nees.rpi.vis.PressureSensor$();
public java.lang.Object readResolve();
public java.lang.Object productElement(int);
public int productArity();
public java.lang.String productPrefix();
public final java.lang.String toString();
public int $tag();
}
But that didn't yield any great insight.
from Java, say:
my.awesome.package.PressureSensor$.MODULE$
PressureSensor$.MODULE$ should give you the instance of the case object.
This is still a hack, but in my opinion a bit more readable in Java. Just add a method to explicitly return the reference to the singleton instance (it shows up as a static method on the class):
sealed abstract class PresetShapeType(val displayName: String)
case object AccelerationSensor extends PresetShapeType("Acceleration Sensor") { def instance = this }
case object DisplacementSensor extends PresetShapeType("Displacement Sensor") { def instance = this }
case object ForceSensor extends PresetShapeType("Force Sensor") { def instance = this }
case object PressureSensor extends PresetShapeType("Pressure Sensor") { def instance = this }
case object StrainSensor extends PresetShapeType("Strain Sensor") { def instance = this }
And then in Java:
import my.awesome.package.PressureSensor;
DVShape newshape = DVShapeFactory.createPresetShape(PressureSensor.instance(), new Point3f(0,0,0));