Scala: Use Java Constructor with Subclasses in Scala - java

I want to use a constructor, that is written in Java, in Scala.
The constructor is declared in that way:
public <SUBCLASS extends Node> NodeDock(Parent<? super Node> parent, Class<SUBCLASS> cls, LookupCriteria<SUBCLASS>[] criteria) {
this(parent, cls, 0, criteria);
}
So if i want to use it:
val task = new NodeDock(scene.asParent(), classOf[FXTaskStackElement].asInstanceOf[Class[_]], new LookupCriteria[FXTaskStackElement]() {...}
Scala is giving me always an error that he cannot find the appropriate constrcutor with these parameters.
So how can i get the SUBCLASS of FXTaskStackElement for the LookupCriteria?
Edit:
In Java i would call this constrcutor like that, which works fine:
task = new NodeDock(scene.asParent(), FXTaskStackElement.class, new LookupCriteria<FXTaskStackElement>() {...})

Why are you using classOf[FXTaskStackElement].asInstanceOf[Class[_]] instead of just classOf[FXTaskStackElement]? Since your second argument is a Class[_], there is no suitable SUBCLASS.

Related

How can I call a Supplier-based constructor for a recursive set of classes based on generic container?

I have seen advice that a Supplier can be used to create an instance of a parametrized class.
E.g. Here: "Instantiating object of type parameter" or here: "Create instance of generic type in Java?"
How to create the Supplier seems clear from the linked answers:
// Example of creating objects in linked answers
MyClass<StringBuilder> it = new MyClass<>(StringBuilder::new);
SomeContainer<String> stringContainer = new SomeContainer<>(String::new);
but how to use it for a recursive set of classes based on generic container doesn't seem to be clear.
My problem is that this Supplier methods itself has to be called as a parameter of the constructor for each recursive class. Example:
class SetOf<E> {
// Supplier-based code from SO Q #75175
private Supplier<E> supplier;
SetOf(Supplier<E> supplier) { this.supplier = supplier; }
createE() { return supplier.get(); }
addToContainer(key) {
E value = createE(); // I assume that's how it's used?
this.add(key, value);
}
}
The problem here is that if we are building container of containers thusly:
class SetOfThings extends SetOf<Thing> {}
class SetOfSetsOfThings extends SetOf<SetOfThings> {}
class SetOfSetOfSetsOfThings extends SetOf<SetOfSetOfThings> {}
SetOf<SetOfSetOfSetOfThings> root = new SetOf<>(SetOfSetOfThings::new);
So, what we are passing to the Supplier of outer class (SetOfSetOfSetOfThings) is the reference to constructor of inner class (SetOfSetOfThings) - BUT, when that SetOfSetOfThings() constructor will be called, it will be called with no parameters, meaning that there will be NO supplier for SetOfThings set in the SetOfSetOfThings object! (which means we can never create SetOfThings objects).
I suppose we can fix this 3-level chain somehow, by using Lambda syntax and passing a parameter (with value of SetOfThings::new) to SetOfSetOfThings::new in turn. But this only works because our chain is 3 levels deep - what if we have to instantiate 4-level deep chain with root class being SetOfSetOfSetsOfSetsOfThings?
This question is a very narrow Function/Supplier specific version of my more generic earlier question here (where comments pointed to both Supplier as an idea, and the linked answer showing how to use a supplier in general - neither of which work easily in case of recursive class hierarchy).
You're going to need some kind of supplier passed to the constructor at any level, since the Thing at the base level ultimately has to come from somewhere. However, you can use Supplier<Thing> at every level like so:
class SetOfThings extends SetOf<Thing> {
SetOfThings(Supplier<Thing> supplier) {
super(supplier);
}
}
class SetOfSetOfThings extends SetOf<SetOfThings> {
SetOfSetOfThings(Supplier<Thing> supplier) {
super(() -> new SetOfThings(supplier));
}
}
class SetOfSetOfSetOfThings extends SetOf<SetOfSetOfThings> {
SetOfSetOfSetOfThings(Supplier<Thing> supplier) {
super(() -> new SetOfSetOfThings(supplier));
}
}
Then you can do:
SetOf<SetOfSetOfSetOfThings> root = new SetOf<>(() -> new SetOfSetOfSetOfThings(Thing::new));
SetOfSetOfSetOfThings ssst = root.createE();
SetOfSetOfThings sst = ssst.createE();
SetOfThings st = sst.createE();
Thing t = st.createE();
EDIT: If you're just trying to create an instance of recursive SetOf type, you don't need subclasses:
SetOf<SetOf<SetOf<SetOf<Thing>>>> root = new SetOf<>(
() -> new SetOf<>(
() -> new SetOf<>(
() -> new SetOf<>(
Thing::new))));
And with a helper method to make it look nicer:
public static <E> Supplier<SetOf<E>> setsOf(Supplier<E> supplier) {
return () -> new SetOf<>(supplier);
}
SetOf<SetOf<SetOf<SetOf<Thing>>>> root = new SetOf<>(setsOf(setsOf(setsOf(Thing::new))));

Java newInstance of Generic Class

I am working with Java Generic classes (in this example, these are the Collection classes), and Reflection. I would like to be able to use reflection to take in a Class, check if it is an instance of a List, and then invoke the add method to it.
However, I've faced some difficulties in trying to put as the parameters to invoke the method call, and getting the declared method (shown where I put-what???). Both of those method parameter calls, require an object of type Class<?> which is the parameter type of needed for the add methods being invoked, which I don't know, since T itself is a generic.
Any help is appreciated! I apologize if the question is unclear, I tried the best I could to clarify.
static <T> void TestACollection(Class<T> clazz) {
T element=clazz.newInstance();
if(element instanceof List<?>)
Method m=clazz.getDeclaredMethod("add", what??? );
m.invoke(element, what???);
}
I'm guessing what you are trying to do is this:
public static <T> List<T> makeList() {
List<T> list = (List<T>) new ArrayList();
return list;
}
//...
{
List<String> list = makeList();
list.add( "Howdy" );
}
Which works as-is in Java 8. In earlier versions you may have to add #SuppressWarnings("unchecked") to the assignment.

Error calling generic method

I have two generic classes
class Value<T>{...}
class Parameter<T>{...}
And i want to call a method from another class (Params)
public <T> void put(Parameter<T> key, Value<T> value) {
parameters.put(key, value);
}
And from my main class i want to call it with two objects Value and Parameter but with the Type in this way:
Value<Integer> v1 = new Value<Integer>(2);
Parameter<Integer> p1 = new Parameter<Integer>(3);
Params params = new Params();
params.put(p1,v1);
And i receive this error from Eclipse:
The method put(Parameter<T>, Value<T>) in the type Parameters is not applicable for the arguments (Parameter<Integer>, Value<Integer>)
Any hint of how can i call this method without having this error? This classes were not developed by me, so I'm trying to call them without success.
The compiler cannot derive what your class is, so you have to give it a hint:
params.<Integer>put(p1,v1);
Wouldn't it make sense to make the Params class generic?

How do I disambiguate in Scala between methods with vararg and without

I'm trying to use the java jcommander library from Scala. The java JCommander class has multiple constructors:
public JCommander(Object object)
public JCommander(Object object, ResourceBundle bundle, String... args)
public JCommander(Object object, String... args)
I want to to call the first constructor that takes no varargs. I tried:
jCommander = new JCommander(cmdLineArgs)
I get the error:
error: ambiguous reference to overloaded definition,
both constructor JCommander in class JCommander of type (x$1: Any,x$2: <repeated...>[java.lang.String])com.beust.jcommander.JCommander
and constructor JCommander in class JCommander of type (x$1: Any)com.beust.jcommander.JCommander
match argument types (com.lasic.CommandLineArgs) and expected result type com.beust.jcommander.JCommander
jCommander = new JCommander(cmdLineArgs)
I've also tried using a named parameter, but got the same result:
jCommander = new JCommander(`object` = cmdLineArgs)
How do I tell Scala I want to call the constructor that doesn't take varargs?
I'm using Scala 2.8.0.
Sorry, I now realize this is a known interoperability problem with Java. See this question and the ticket. The only work around I know of is to create a small Java class just to disambiguate these calls.
The only Scala solution to this problem that I know involves reflection.
Ambiguous Methods
Let's suppose we have a Java test class:
public class Ambig {
public Ambig() {}
public String say(Object o) { return o.toString(); }
public String say(Object o, String... ss) { return o.toString()+ss.length; }
}
We can get access to the method via reflection directly:
val ambig = new Ambig
val methods = ambig.getClass.getMethods.filter(_.getName == "say")
val wanted = methods.find(_.getParameterTypes.length == 1).get
wanted.invoke(ambig, Some(5)).asInstanceOf[String]
or we can use structural types (which use reflection under the hood) to achieve the same thing with less boilerplate:
def sayer(speaker: { def say(o: Object): String }, o: Object) = speaker.say(o)
sayer(new Ambig, Some(5))
Ambiguous Constructors
Our strategy has to differ because we don't actually have an object to begin with. Let's suppose we have the Java class
public class Ambig2 {
public final String say;
public Ambig2(Object o) { say = o.toString(); }
public Ambig2(Object o, String... ss) { say = o.toString()+ss.length; }
}
The structural types approach no longer works, but we can still use reflection:
val mkAmbig2 = classOf[Ambig2].getConstructors.filter(_.getParameterTypes.length==1)
val ambig = mkAmbig2.head.newInstance(Some(5)).asInstanceOf[Ambig2]
ambig.say // Some(5)
I think your easiest option is to have a Java class with a factory method to bridge the issue:
package com.beust.jcommander;
public class JCommanderFactory {
public static createWithArgs(Object cmdLineArgs) {
return new JCommander(cmdLineArgs);
}
}
Alternatively you could use http://jewelcli.sourceforge.net/usage.html instead. JewelCli has an unambiguous factory method for the same purpose and also uses PICA (Proxied Interfaces Configured with Annotations) technique http://www.devx.com/Java/Article/42492/1954.
In fact I have an example of using JewelCLI with Scala here on Stack Overflow.
The way to avoid this ambiguity is to force the compiler to pick the overload that takes more than one argument, using Scala's collection explosion syntax to pass in a singleton collection:
import java.util.stream.Stream
val stream = Stream.of(List(1):_*)
You can call the constructor with varags, but pass an empty list of varags.
(Of course, if you know that constructing JCommander with empty varags will produce the same result as calling the overloaded constructor (or method) without vargs)
jCommander = new JCommander(cmdLineArgs, Nil: _*)

Why has my generic method stopped working?

In my project I have a factory method that loads an object that implements an interface. You pass in the class you desire and receive an instantiation of it, like so.
public class Factory {
public static <E extends SomeInterface> E load( Class<E> clss ) throws Exception {
return clss.newInstance();
}
}
You could invoke it like this:
MyObject obj = Factory.load( MyObject.class );
This code works just fine in Eclipse 3.4 with Java 6u13, however today I received a new laptop and installed Eclipse 3.5 and java 6u15 and now I am getting type mismatches everywhere.
MyObject obj = Factory.load( MyObject.class );
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Type mismatch: cannot convert from SomeInterface to MyObject
Putting a cast before Factory on that line makes it go away and all runs well, but it makes the line a bit less clean, and I didn't need it before, so what gives?
Did you recently add a type parameter to your factory class? There's a pitfall with generic methods on raw types:
public class FooFactory<UnrelatedArg> {
public <E> E load(Class<E> c) { ... }
}
FooFactory<?> f; f.load(String.class); // returns String
FooFactory f; f.load(String.class); // returns Object
Is that all the code required to get this bug? I've seen something very similar in some code I've been looking at today. There was an additional parameter being passed into the equivalent of your Factory method which had a generic type as well. This was missing it's generic definition and I think was to blame for confusing the compiler.
ie, if your factory method looked something like
public class Factory {
public static <E extends SomeInterface> E load( Class<E> class, Key key ) {
// return an instance of E
}
}
Where there is some Key class defined something like this
public class Key<Datatype> {
....
}
Giving something like this to invoke the method, note no generics on the declaration of key
Key key = new Key()
MyObject obj = Factory.load( MyObject.class, key );
Hope that helps,
I think this is related to the Java compilance level. By default a project has the default level. Which you set in the Eclipse preferences. In your old installation you will have change it.
https://bugs.eclipse.org/bugs/show_bug.cgi?id=277643

Categories