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$
Related
I'm using Wicket 6/Java 8 and am adding some simple classes that make use of the lambda functionality from Java 8 (I know the later versions of Wicket have lambda support but we can't upgrade right now). I'm creating a LambdaModel that is a bit like the PropertyModel, which I'm hoping will remove the need to hardcode Strings representing the nested path to the property.
To start, I'm making a simple readonly version. Ive made Serializable versions of the Function interface to create the following:
public class LambdaModelUtils {
public static <X,R> IModel<R> ofNested( IModel<X> target, SerializableFunction<?,?>... path ) {
// creates a model that works through each function in the path in turn
}
}
My implementation works well, but the only problem is that calling this method the 'efficient' way causes compile errors:
IModel<Parent> parentModel = ...
IModel<String> model = LambdaModelUtils.ofNested( parentModel,
Parent::getChild, Child::getName ); // Compile time error
The only way I can find to call the method is by the following:
SerializableFunction<Parent,Child> path0 = Parent::getChild;
SerializableFunction<Child,String> path1 = Child::getName;
IModel<String> model = LambdaModelUtils.ofNested( parentModel,
path0, path1 ); // works
This is a bit clumsy - is there a better way?
Ive looked here but this doesnt seem to work either:
List<SerializableFunction> path = Arrays.asList( Parent::getChild, Child::getName );
Thanks
If you're using these functions to get to a nested property, but don't really use the intermediate results, I'd advice you to just use a lambda expression:
public static <X,R> IModel<R> ofNested(IModel<X> target, SerializableFunction<X, R> path)
IModel<Parent> parentModel = ...
IModel<String> model = LambdaModelUtils.ofNested(parentModel, p -> p.getChild().getName());
This works since the target type of the lambda is now known, instead of the generic SerializedFunction<?, ?>, you get SerialiedFunction<X, R> where X = Parent and R = String.
I tried something similar to your code. Casting the method references to the functional interface type solves the compilation error:
IModel<String> model =
LambdaModelUtils.ofNested(parentModel,
(SerializableFunction<Parent,Child>) Parent::getChild,
(SerializableFunction<Child,String>) Child::getName);
Not the prettiest solution, but at least it saves you the need to declare the path0 and path1 variables.
I have a generic getter trait
trait Getter[A] {
def get: A
}
and I would like to parse JSON into a List of objects implementing this trait. Two such implementations:
case class CoalesceGetter[A](getters: List[Getter[String]]) extends Getter[A] {
override def get: A = getters.map(_.get).find(_ != null).orNull
}
case class AsnGetter(ipGetter: Getter[String]) extends Getter[Long] {
override def get: Long = 99L // dummy function
}
I would like to parse JSON into the correct Getter class based upon a property called function which corresponds to the class and type which corresponds to the generic type in the case of getters which need a generic (both properties are strings in the json blob I'm parsing). I've looked at custom serializers for json4s but don't see how to work with generics. Any help is appreciated!
First of all, I don't think it is a good idea to jsonify classes with type argument. I think it is a better design to define non-typed (case) classes that are direct equivalent of your json object, and use standard read/write json as provided by many libraries.
But then, to answer your question, I'd like to return another question: how would you do it "manually"?
I.e. how would you write and read different CoalesceGetter[A] with different A?
Here is a proposition: put the type arg in a json field:
"ofInt": {"type-arg":"Int", "getters":[ ... list of getters in json ...]},
"ofDouble":{"type-arg":"Double", "getters":[ ... list of getters in json ...]}
Now, if you'd write the reader, how would you instantiate the 2 ofInt and ofDouble, knowing the type-arg "Int" and "Double" (which are string!).
I see 2 solutions:
1) Either you have a hard-coded map of arg-type string => actual scala type
argType match{
case "Int" => new CoalesceGetter[Int](...)
case "Double" => new CoalesceGetter[Double](...)
}
2) Or you store and read a generalized type as string value in the arg-type string, such as the java Class.forName (see [https://stackoverflow.com/a/7495850/1206998] for example). But this is a really really bad idea IMHO.
(note: if you want to serialize any object just to reload it later or on another computer, don't use json but dedicated serialization such as the Java Serialization or kryo that is used by spark)
Is it possible to make an Java object the prototype of a JavaScript object? Like the following:
var Person = Java.type("Person");
var hans = new Person();
hans.name = "Hans";
var employeeFactory = function() {
var F = function(){};
F.prototype = hans;
return new F();
};
var fritz = employeeFactory();
print(fritz.name);
Here Person is a Java Bean. The variable hans is set as the instance of this Java class. The line hans.name = "Hans" sets the name field in the Java object as expected. But when the object fritz is created in the factory function, it doesn't get linked to the expected prototype. Is there any reason why the Java instance isn't accepted as prototype?
It might work in Rhino, because in Rhino all beans are wrapped into JS native objects before being exposed to the JS program. Nashorn OTOH doesn't create wrappers. You can, however, use Nashorn's non-standard Object.bindProperties that adds properties from one object to another, bound to the original object's instance as its this. That's essentially as close as you can get (well, it's pretty darn close) to a wrapper. The exact specification is:
Object.bindProperties(dst, src)
creates bound properties from all properties in src object, puts them into the dst object, and returns the dst object. Since the properties are bound to src, dst.foo will delegate to src.foo for its value. bindProperties has been coded specifically so that it can handle ordinary Java objects as src.
With that in mind, I believe that if you change the line
F.prototype = hans;
to
F.prototype = Object.bindProperties({}, hans);
you'll get what you wanted. That would work with Object.create too, e.g. Object.create(Object.bindProperties({}, somePojo)).
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 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.