One or many argument in Scala [duplicate] - java

Why do all scala vararg methods, when used from java, seem to accept a Seq of variables, and can't be used as java native vararg methods. Is this a bug?
For instance, Buffer has method def append(elems: A*): Unit. But in java it has another signature: void append(Seq<A>).

If you control the scala code you can use #varargs to make it generate a java-compatible varags method, e.g. #varargs def append(elems: A*): Unit = {}

It is not a bug. It is a design choice that favors vararg use within Scala over interoperability with Java. For example, it allows you to pass a List into a Scala varargs method without having to convert it to an Array on the way.
If you need to use Scala varargs from Java, you should create some scala Seq instead. You can, for example, write a Java wrapper to get an array automatically created, and then use the genericWrapArray method from the Predef object.

you can easily cast a Seq in varargs using :_*. For example :
val b = collection.mutable.ListBuffer.empty[Int]
b.append(List(1, 2):_*)
so this avoid code duplication in the collection API.
You can also simply use appendAll :
b.appendAll((List(1, 2))

Related

Get delegate function for arbitrary java method

Is there an easy way to get an arbitrary Function version of a method on a POJO?
For example:
FluentIterable.from(myCollection).uniqueIndex(Functions.for(Item.class).getId)
.first(Predicates.equalTo(id)).get();
Where Functions.for ideally behaves like Mockito.mock
Actually you can use lambdaj which is
a library that makes easier to address this issue by allowing to
manipulate collections in a pseudo-functional and statically typed
way.
Lambdaj does similar tricks as Mockito, so you should read its limitations (most important is that your POJO must not be final).
With lambdaj, your code could be something like this (note that uniqueIndex from your example returns Map, which does not have first method, so I'll guess here):
import ch.lambdaj.Lambda.*; // for all static methods used below
// just items indexed by their ids
Map<Intgeger, Item> indexed = index(myCollection, on(Item.class).getId());
// or more likely you want
Item foundItem = selectFirst(
myCollection, having(on(Item.class).getId(), equalTo(id)));
That's not how Java works.
However, with Java 8, you can use a method reference to create a lambda:
FluentIterable.from(myCollection).uniqueIndex(Item::getId)
.first(Predicates.equalTo(id)).get();

Using scala object inside java?

In my java code, I am calling a method, from a class which is defined in Scala, and I want to use one of its methods in java. Here is how I call it and it works fine.
Seq<SomeObjectType> variableName = ScalaClass.MethodInTheScalaClass();
I can call this function in java in this form, but since I am calling this method from a compiled package, I can't see what it going on (and therefore I can't change it).
The problem now is that, I don't know how to iterate over the "variableName" in java (since Seq is a scala type).
How can I iterate over variableName or convert it to a Java object (e.g. List)?
Try this:
java.util.List<SomeObjectType> res =
scala.collection.JavaConverters$.MODULE$.seqAsJavaListConverter(variableName).asJava();
You could get converters list in JavaConverters documentation.
You should use JavaConverters$.MODULE$ to get JavaConverters object from Java.

How to cast explicitly in clojure when interfacing with java

In trying to use weka from clojure, I'm trying to convert this howto guide from the weka wiki to clojure using the java interop features of clojure.
This has worked well so far, except in one case, where the clojure reflection mechanism can't seem to find the right method to invoke - I have:
(def c-model (doto (NaiveBayes.) (.buildClassifier is-training-set)))
Later this will be invoked by the .evaluateModel method of the Evaluation class:
(.evaluateModel e-test c-model is-testing-set)
where e-test is of type weka.classifiers.Evaluation and, according to their api documentation the method takes two parameters of types Classifier and Instances
What I get from clojure though is IllegalArgumentException No matching method found: evaluateModel for class weka.classifiers.Evaluation clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:53) - I guess that this is because c-model is actually of type NaiveBayes, although it should also be a Classifier - which it is, according to instance?.
I tried casting with cast to no avail, and from what I understand this is more of a type assertion (and passes without problems, of course) than a real cast in clojure. Is there another way of explicitly telling clojure which types to cast to in java interop method calls? (Note that the original guide I linked above also uses an explicit cast from NaiveBayes to Classifier)
Full code here: /http://paste.lisp.org/display/129250
The linked javadoc contradicts your claim that there is a method taking a Classifier and an Instances - what there is, is a method taking a Classifier, an Instances, and a variable number of Objects. As discussed in a number of SO questions (the only one of which I can find at the moment is Why Is String Formatting Causing a Casting Exception?), Clojure does not provide implicit support for varargs, which are basically fictions created by the javac compiler. At the JVM level, it is simply an additional required parameter of type Object[]. If you pass a third parameter, an empty object-array, into your method, it will work fine.
IllegalArgumentException No matching method found happens anytime the arguments don't match the class. They can fail to match because no method exists with that name and number of arguments or because no method exists with that name in the called class. so also check the number and type of the arguments.
I basically always resort to repl-utils/show in these cases

Java equivalent of python's getattr?

I'm converting some python code to java, and have a situation where I need to call methods of an object but don't know which methods until runtime. In python I resolve this by using getattr on my object and passing it a string that is the name of my method. How would you do something similar in Java?
Class.getField is your friend. It probably won't be very straightforward though since Python is dynamically typed and Java is statically typed (unless you know the types of your fields in advance.)
EDIT: How to translate these examples. http://effbot.org/zone/python-getattr.htm
Attribute Lookup
Python
//normal
value = obj.attribute
//runtime
value = getattr(obj, "attribute")
Java
//normal
value = obj.attribute;
//runtime
value = obj.getClass().getField("attribute").get(obj);
Method Call
Python
//normal
result = obj.method(args)
//runtime
func = getattr(obj, "method")
result = func(args)
Java
//normal
result = obj.method(args);
//runtime
Method func = obj.getClass().getMethod("method", Object[].class);
result = func.invoke(obj, args);
In the simpler cases, you need to know whether you have a field or a method. esp as they can have the same name. Additionally methods can be overloaded, so you need to know which method signature you want.
If you don't care which method or field you get, you can implement this as a helper method fairly easily.
You can start here to learn about Java Reflection.
You can use java reflection but there is no exact equivalent of getattr.
In Java you do this with the Reflection API (and it's usually pretty cumbersome).
MethodUtils in Apache Commons BeanUtils project may make it a bit easier to work with, though it's a pretty hefty dependency for something simple like this.
You should use the Reflection API. Since the pure API is a bit ... unapproachable, you should have a look at helpers like commons beanutils or reflections.
The easiest way to handle this is to create a Map object in Java class & keep adding the name value pairs & retrieve it accordingly though it might not support different types that setAttr supports.

How to pass a typed collection from clojure to java?

I know the basics of clojure/java interop: calling java from clojure and vice versa. However, I was not able to return a typed collection from clojure to java. I am trying to see something of that nature List<TypedObject> from the java code which is calling into clojure.
Java Object:
public class TypedObject {
private OtherType1 _prop1;
public OtherType1 getProp1() {
return _prop1;
}
public void setProp1(OtherType1 prop1) {
_prop1 = prop1;
}
}
CLojure method:
(defn -createListOfTypedObjects
"Creates and returns a list of TypedObjects"
[input]
;Do work here to create and return list of TypedObjects
[typedObj1, typedObj2, typedObj3])
(:gen-class
:name some.namespace
:methods [createListofTypedObjects[String] ????])
Let us consider that I am writing an API using clojure, which is to be distributed as a jar file, to be used from java. My question was really how to what to pass in place of the ???? questions marks above inside the :gen-class for AOT, so that a programmer writing a piece of code in java using my api, can have the appropriate intellisense / code completion (i.e.: createListofTypedObjects() returns List<TypedObject>) from within eclipse for example.
The others are right that Clojure doesn't ensure the types of elements in returned collections, etc. (Actually, the JVM doesn't ensure the types of elements in collections, either – that's handled entirely by javac.)
However, I can see the value of providing an API to other Java programmers that specifies an interface that declares that return values (or parameters) parameterized in various ways; this is especially attractive if one is looking to use Clojure in an existing Java environment without making waves.
This currently requires a two step process:
define a separate interface (in Java!) that specifies the parameterized types as you like
define your gen-class namespace (or proxy or reify instance) such that it implements that interface
(Clojure does provide a definterface form that would allow you to avoid the separate Java interface definition, but definterface, just like the rest of Clojure, does not provide for specifying parameterized types. Maybe someday... :-))
e.g.
public interface IFoo {
List<TypedObject> createListOfTypedObjects ();
}
and then your gen-class namespace:
(ns your.ns.FooImpl
(:gen-class
:implements [IFoo]))
(defn -createListOfTypedObjects
[]
[typedObj1, typedObj2, typedObj3])
When your users create instances of FooImpl, they'll e.g. get code completion indicating that the method returns List<TypedObject> rather than Object or the unparameterized List type.
If you're using sane build tools (e.g. maven, gradle, or properly-configured ant), then you can put the Java interface in your Clojure project, and the cross-language dependency will be taken care of.
If you're trying to pass something like List<String> to a java method, then you don't need to worry about it. The type parameter (e.g., String) is only used to by the javac compiler, so any List will work just fine at runtime.
On the other hand if you're trying to pass an array of a particular object type (e.g., String[]), then you can use the various -array functions:
user=> (make-array String 10) ; an empty String array
#<String[] [Ljava.lang.String;#78878c4c>
user=> (into-array ["foo" "bar"]) ; array type inferred from first element
#<String[] [Ljava.lang.String;#743fbbfc>
user=> (into-array Number [1.2 5 7N]) ; explicit type array
#<Number[] [Ljava.lang.Number;#7433b121>
You don't need to worry about generics (typed collections) in Clojure. Generics are really just type hints to the Java compiler. In a running Java program, List<String> is effectively the same as List<Object>.
So, for example, a Clojure vector containing Strings is already a List<String> with no conversion needed.

Categories