I have a scala case class.
i'm trying to copy it with obj.copy() from java but i don't see any such method
what i did currently was a workaround as:
// Hack, copy was not visible from java code.
def doCopy(): MyCaseClass = {
return this.copy()
}
now doCopy() is visible from java.
is there a better way to do it than this hack?
There is no method copy() in case class.
Let's see all methods generated in case class:
$ echo 'case class T(a1: String, a2: Int)' > test.scala
$ scalac -Xprint:typer test.scala
You'll find this method:
<synthetic> def copy(a1: String = a1, a2: Int = a2): T = new T(a1, a2);
There are no default parameters in Java, so you have to specify all parameters. So method copy is useless in Java.
case class should be immutable, so you don't need to copy it without changing fields.
Instead of obj2= obj.copy() you can use obj2= obj.
Related
There have been some questions answered on this before.
How can I pass a scala object reference around in Java
How can I use a Scala singleton object in Java?
But my problem is that I have nested scala objects, something like:
object Criteria {
object ActionCriteria {
case class Action (parameter: String) {
def this(parameter: String) = { this(paramerter) }
}
object Action {
def apply(parameter: String): Action = { apply(parameter) }
}
}
}
In java I then need to create a list of Actions. I have tried this... to no avail:
import Criteria.ActionCriteria.Action$
....
List<Criteria.ActionCriteria.Action$.MODULE$> actions = new ArrayList<>();
As well as a bunch of other combinations like adding $.MODULE$ with every object. Right now I am getting the following error:
error: cannot find symbol Criteria.ActionCriteria
List<Criteria$ActionCriteria$Action> actions = new ArrayList<>();
Seems to work fine. Found this with Scala REPL:
scala> classOf[Criteria.ActionCriteria.Action]
res1: Class[Criteria.ActionCriteria.Action] = class Criteria$ActionCriteria$Action
If you want the type of Action object, not case class (highly unlikely, but for the sake of completeness):
scala> Criteria.ActionCriteria.Action.getClass
res2: Class[_ <: Criteria.ActionCriteria.Action.type] = class Criteria$ActionCriteria$Action$
The difference is caused by Scala expecting Action to be a type in classOf[Action], so it returns the type corresponding to the case class. When you use Action in a context where a value is expected, it returns the singleton instance instead, so you can call standard Java method getClass to get the type of object Action.
In case you need other types:
Criteria$ cm = Criteria$.MODULE$;
Criteria.ActionCriteria$ cacm = Criteria.ActionCriteria$.MODULE$;
Criteria$ActionCriteria$Action$ cacam = Criteria$ActionCriteria$Action$.MODULE$;
Criteria$ActionCriteria$Action caca = new Criteria$ActionCriteria$Action("Foo");
Criteria.ActionCriteria$ is breaking the pattern here. Why? According to Iulian Dragos' comment under bug SI-2034 this is a special case:
since objects are "the equivalent of static" in the Java world, we
wanted to make it easier for Java code to use static inner classes.
When there's only one level of nesting, there's a guaranteed
companion: every top-level object gets a mirror class (if there isn't
one) that creates static forwarders to module methods (that's how one
can run a main method defined inside an object). Therefore, a
special case for one-level nesting: those classes use the flattened
name (without a $ suffix) as outer_name. So, Java code can say new Outer.Inner.
Summary
For every level of nesting other than first you replace . with $ in your class names
If the target type is also an object you add $ at the end
If you want an instance you add .MODULE$
Here are some of my failed attempts:
import com.google.common.collect.HashMultiset
// 1. This does not work!
// val foo1:HashMultiset[Int] = HashMultiset[Int].create()
// 2. Neither does this!
// val foo2:HashMultiset[Int] = new HashMultiset[Int]()
// foo1.add(1)
In the first case it complains that HashMultiset is not a value.
In the second case it says that HashMultiset[Int] does not have a constructor.
Is there some additional magic I need to work in order to use this guava class from Scala?
UPDATE0: I'm using Scala 2.11.2 with Guava 18.0 in case that matters!
The problem with HashMultiset[Int].create() is that, though HashMultiset is a class with a type parameter, create is a static method. When you call a static method, you do not use a type parameter on the class name. Therefore, HashMultiset.create() should be enough. I assume the create method does have a type parameter, so it would be valid to write HashMultiset.create[Int]().
I have a Python file which contains a class. I need to create an instance of that class and be able to call methods in that through Java.
I came up with a solution like this:
PythonInterpreter r = new PythonInterpreter();
r.execfile("File.py");
PyObject p = r.eval("Car().begin()");
System.out.println(p.toString());
And the python code:
class Car(SomeExtendedClass):
myvar = 5
def set(self, my):
self.myvar = my;
def begin(self):
return self.myvar
Now, when I execute this, it prints 5 But if I run the following code:
PyObject p = r.eval("Car().begin()");
System.out.println(p.toString());
r.eval("Car().set(7)");
p = r.eval("Car().begin()");
System.out.println(p.toString());
It will still print 5, instead of 7
It looks like I did not create one instance of Car and it always creating a new instance instead of using the created one.
Am I right?
Is it possible to create a new instance from a class in a Python file, and invoke/get data from methods with Java?
I have tried loading PyInstance using eval() but I get cannot cast exception from it:
return (PyInstance) this.interpreter.eval(className);
I just found out the solution for this "mystery"
At first, we want to execute the python file we're going to get instances from:
r.execfile("File.py");
And then define the PyObject which will contain the class that you want to invoke:
PyObject car = r.get("Car");
And then you have to call the __call__ method in order to create a new instance of Car, and cast it to PyObjectDerived:
PyObjectDerived p = (PyObjectDerived) o.__call__();
Now you can invoke methods, like this:
Python code:
def set(self, my):
self.myvar = my;
Your java call:
p.invoke("set", Py.newInteger(5));
Hope I helped anyone.
Whenever you call Car() you create a new instance of the class. So this create a new object and calls its set method:
r.eval("Car().set(7)");
But this then creates another instance rather than manipulating the existing one:
p = r.eval("Car().begin()");
The call to r.eval("Car().begin()"); creates a new python object as you require, but it actually returns a reference to the python object containing the return value from the begin() method - not to the instance created. This isn't what you wanted.
Leaving the python class exactly as defined, this code gets a reference to a single instance of the class:
PyObject p = r.eval("Car()");
(As you already saw, an alternative is to omit the parenthesis which gets you a reference to the python class object, and then using __call__ on it to create an instance).
Then to call the method on the existing instance:
p.invoke("set", Py.newInteger(7));
To get at the modified value, since it is an attribute of the instance and is not available via a 'getter' method, the getattr method of the PyObject class can get to it (or you could add a get method to the python code):
System.out.println(p.__getattr__("myvar"));
It's a shame that once you get a reference to the object via p you can't just call the method on it with java syntax, but of course Java knows nothing of the methods and/or attributes available on the Python object and even if it did they could change at any time because of the dynamic nature of Python. So you're left with methods like invoke to bind Java/Python together.
I'm looking over some open-source code and can't wrap my head around this snippet.
class Something
def self.smart
new.smart
end
def smart
"test"
end
end
class Other < Something
println Other.smart
Is the code trying to instantiate a new instance every time smart is called?
def self.smart
new.smart
end
is equivalent to static method, which can e accessed by using class name.
... static ... smart()
and
def smart
"test"
end
is equivalent to instance method, need object to access
... smart()
new is same as the in java, created an instance of class.
and the whole thing is equivalent to.
public static .... smart(){
new ClassName().smart();
}
I could not get it to work. It's like the method is not mocked.
Are there alternative groovy testing frameworks that work better to mock static Java methods?
Update 02/Mar/2011: Adding code:
I am actually trying to mock the Scala XML.loadXml (I am trying Groovy for unit testing) class:
This is my test case:
// ContentManagementGatewayTest.groovy
class ContentManagementGatewayTest extends GMockTestCase
{
void testGetFileList()
{
// Preparing mocks code will go here, see below
play {
GetFileGateway gateway = new GetFileGateway();
gateway.getData();
}
}
}
// GetFileGateway.scala
class GetFileGateway {
def getData()
{
// ...
val xmlData = XML.loadData("file1.txt");
}
}
I tried testing using both gmock and metaClass:
// metaClass:
XML.metaClass.'static'.loadFile = {file ->
return "test"
}
// gmock:
def xmlMock = mock(XML)
xmlMock.static.loadFile().returns(stream.getText())
You can do this using Groovy (metaprogramming), you don't need any additional libraries. Here's a (stupid) example, that overrides Collections.max such that it always returns 42. Run this code in the Groovy console to test it.
// Replace the max method with one that always returns 42
Collections.metaClass.static.max = {Collection coll ->
return 42
}
// Test it out, if the replacement has been successful, the assertion will pass
def list = [1, 2, 3]
assert 42 == Collections.max(list)
Update
You mentioned in a comment that my suggestion didn't work. Here's another example that corresponds to the code you've shown in your question. I've tested it in the Groovy console and it works for me. If it doesn't work for you, tell me how your testing differs from mine.
Math.metaClass.static.random = {-> 0.5}
assert 0.5 == Math.random()
Scala doesn't have static methods, so it is no wonder you couldn't mock one -- it doesn't exist.
The method loadXml to which you refer is found on the XML object. You can get that object from Java with scala.XML$.MODULE$, but, since objects are singleton, its class is final.
Alas, loadXML is defined on the class XMLLoader, which the object XML extends, not on the object XML itself. So you can simply do a normal mock of XMLLoader. It will lack a few methods, but perhaps it will do all you need.
The documentation for GMock seems to show that you can just do:
Mocking static method calls and
property call is similar to standard
method calls, just add the static
keyword:
def mockMath = mock(Math)
mockMath.static.random().returns(0.5)
play {
assertEquals 0.5, Math.random()
}