Generic implementation von java.util.Comparator in Scala - java

I am using twirl templates with Java and Scala. So I am trying to sort a List in the template, but I do not know how to override the Comparator method.
My List contains objects of a class designed like:
class Foo extends BaseFoo<Foo>
The class BaseFoo does have a method called
public String FooName() {/*returns some Name of Foo*/}
In my scala twirl template it looks like:
source: java.util.Collection[_ <: BaseFoo[_]]
No in the twirl template I am trying to sort it:
#Collections.sort(
new util.ArrayList[_ <: BaseFoo[_]](source),
new Comparator[_ <: BaseFoo[_]] {
override def compare(o1: BaseFoo, o2: BaseFoo) = {
return o1.FooName.compareTo(o2.FooName);
}
})
But this seems not to compile:
class type required but java.util.ArrayList[_ <: BaseFoo[_]] found

Not a direct answer, but given that you state that you have a list of Foo objects, the straight forward solution seems to be to use
source: java.util.Collection[_ <: Foo[_]]
or something alike!
Meaning: when the list contains Foo objects, what does it matter if those descend from Object or from FooBase?!

You could convert your source to a Scala collection type and then just call .sortBy on it. No need for Comparators:
import collection.JavaConverters._
source.asScala.toSeq.sortBy(_.FooName)

Related

Java fails to properly infer stream type without apparently redundant typecast

I'm doing a series of streaming operations to flatten what's effectively a 2D array.
Arrays.stream(attributes)
.map(Attribute::getCommand)
.filter(Optional::isPresent)
.map(Optional::get)
.flatMap((array) -> (Arrays.stream((String[]) array)))
.toArray(String[]::new)
Where Attribute conforms to the following interface:
public interface Attribute<T> {
Optional<String[]> getCommand();
}
However, the final flatMap() call isn't operating as expected.
.flatMap((array) -> (Arrays.stream((String[]) array))) works just fine.
.flatMap((array) -> (Arrays.stream(array))) fails to compile with java: no suitable method found for stream(java.lang.Object).
.flatMap(Arrays::stream) fails to compile with java: incompatible types: cannot infer type-variable(s) T (argument mismatch; java.lang.Object cannot be converted to T[]).
It seems to me that the type should be inferred just fine though. IntelliJ agrees and marks the cast as redundant and shows no compile errors with any of the three implementations. Why does Java require this apparently redundant typecast?
I additionally tried the following minimalist implementation:
import java.util.Arrays;
import java.util.Optional;
public class Streaming {
public static void main(String[] args) {
Optional<String[]>[] myarray = new Optional[]{Optional.of(new String[]{"Hello", "world"}),
Optional.empty(), Optional.of(new String[]{"Foo"})};
System.out.println(Arrays.toString(Arrays.stream(myarray).filter(Optional::isPresent).map
(Optional::get).flatMap(Arrays::stream).toArray(String[]::new)));
}
}
And it works just fine with all three implementations, outputting the expected [Hello, world, Foo].
Edit:
This was marked as a duplicate of this question. I may be wrong, but it seems that there's a distinction since this the type is specified in a more explicit manner. Notably, IntelliJ agrees that the cast is necessary in the example provided on said post, but not for my code. If I am mistaken, please let me know.
Edit:
Per request, the declaration of attributes is Attribute[] attributes = new Attribute[]{...} where ... is a variety of implementations of Attribute.
Attribute is a generic class (I wonder why as T is not used).
If you have this error it means that you declared a raw type of that such as :
Attribute[] attributes = ...;
For a raw type, the return type of getCommand() that is declared as Optional<String[]> becomes just Optional.
Declare Attribute as a generic type, for example : Attribute<String>[] attributes = ...; and this should compile without the cast or just remove the parameterized type T if it is not required.

How to pass nested scala object reference in Java?

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$

Alternative to Collectors.groupingBy() for scala

In Java I have something like:
Collectors.groupingBy((Re r) -> return r.pName)
And it works properly. Now I'm trying to get the same thing into scala, like:
Collectors.groupingBy((r:Re) => return r.pName)
but then I get stuff like
cannot resolve reference groupingBy with such signature
cannot resolve symbol groupingBy
unspecified value parameters Collector
unspecified value parameters Supplier
Let me know if you need any more info/code, and I'll create some dummy example since I'm not allowed to post the exact code.
Update based on #Vladimir Matveev answer:
pName should be String, but if I write new java.util.function.Function[Re, java.lang.String] then I get a
type mismatch;
found : java.util.function.Function[Re,String]
required: java.util.function.Function[_ >: Re, _ <: ?0(in value x$1)(in value x$1)(in value x$1)(in value x$1)]
Java lambdas are "implementors" of arbitrary functional interfaces (in this particular case Collectors.groupingBy() accepts java.util.function.Function. Scala anonymous functions, however, are instances of some class implementing scala.FunctionX trait. Consequently, you can't use Scala functions for arbitrary functional interfaces (but there are plans to allow that, as far as I know).
You need to create an anonymous class extending java.util.function.Function explicitly:
Collectors.groupingBy(new java.util.function.Function[Re, ???] {
def apply(r: Re) = r.pName
})
(you need to put correct type of pName instead of ???, of course).
If you're doing this often, you can define an implicit conversion for Scala's T => U to java.util.function.Function[T, U]:
implicit class FunctionWrapper[T, U](f: T => U) extends java.util.function.Function[T, U] {
def apply(x: T): U = f(x)
}
Then (given that this implicit is in scope) you can use it like you tried initially:
Collectors.groupingBy((r: Re) => r.pName)
Update I have no idea why your error happens (probably because of some incompatibilities between Scala and Java generics), but if you specify all types explicitly it does work:
scala> Collectors.groupingBy[Re, String](new JFunction[Re, String] {
| def apply(r: Re) = r.pName
| })
res2: java.util.stream.Collector[Re, _, java.util.Map[String,java.util.List[Re]]] = java.util.stream.Collectors$CollectorImpl#4f83df68
(JFunction is an alias for java.util.function.Function).
The variant with an implicit adaptor looks nicer (but still requires explicit type annotations):
scala> Collectors.groupingBy[Re, String]((r: Re) => r.pName)
res4: java.util.stream.Collector[Re, _, java.util.Map[String,java.util.List[Re]]] = java.util.stream.Collectors$CollectorImpl#71075444

Programmatically assess relationship between type variables in class hierarchy

Suppose I have a Java class hierarchy defined as follow:
interface Bar<T> {}
class Foo<A,B> implements Bar<B> {}
How can I programmatically assess (using reflection) that the type parameter of Bar in Foo is the second of foo's parameters and not the first (B instead of A)?
I've tried using TypeVariable#getName() in order to compare the names, but when I apply getGenericInterfaces() to Foo<A,B> I get Bar<T> and not Bar<B>
Solution (thanks to #LouisWasserman): use Foo.class.getGeenricInterfaces()[0].getActualTypeParameters() returns the correct TypeVariable (B instead of T, in the previous example)
well using TypeVariable#getName() return the type as it appears in the source code in your case it's normal to get Bar<T>. TypeVariable Doc
Using reflection in generic Classes can't help, because of Type Erasure. Erasure of Generic Types
I've the same issue in some personal projects, I tried to change the design of my class, have a look at the example below:
Instead of this:
public class Mapper<T> {
public Mapper(){
}
}
I used this:
public class Mapper {
private Class<?> entityClazz;
public Mapper(Class<?> entity){
this.entityClazz = entity
//Here I've donne all reflection issues i want !
}
}
You can use Class#isAssignableFrom() Doc to test assignability between Class Objects.
I hope this helps, good luck !

Re-using Java generic collections in Scala without trait Object

I'm trying to re-use a Java generic collection I wrote, looks a lot like this:
public class Blah<T>
implements List<T>
{
...
public void test(T[] array) {
...
}
...
}
When consumed from a Scala generic collection that uses the above, I'm getting a compilation error, where I notice that the Blah class method expects not T, but T with java.lang.Object!
Object MyStaticObject {
def test[T](array: Array[T]) = {
val x = new Blah[T]();
x.test(array) // <- error here: Overloaded method with alternatives test[T with java.lang.Object] ... cannot be applied
}
Is there a way to avoid this situation without re-writing the Blah class in Scala? (That works, but I have too much such Java code and rather not port the whole thing...)
Maybe perhaps some kind of implicit definition could come to the rescue?
Thanks!
Restricting def test[T <: AnyRef] does the trick.
Rightly so, the generic java method should not accept , e.g., an int[] (Array[Int]) parameter.
Blah[Int] will be taken as Blah<Integer>, Array[Int] is int[], which is not Integer[].

Categories