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]().
Related
I am trying to build a generic tool that finds a hibernate class and uses its methods by means of metadata.
So from the database I get 1: "TABLENAME" 2. "methodname"
Step 1. Finding the hibernate is done.
Class<?> result = generator.getClassFromTableName("TABLENAME");
Step 2. using the methods that are in the class that is returned is something I do not get.
Do i need to use classloader or finding it through result.getConstructors?
Easiest would be if I end up with an instance of 'TableName' and be able to acces all its methods. Hope it is clear!
Thanks #rsp for the reassurance to look within Reflection. First time to dive into it and in the end it was pretty straightforward.
Classloader to load class from string parameter
getConstructor to
find the right constructor and use it with newInstance()
getDeclaredMethod to find the right method and use it with Invoke and
the object instance
Class< ? > testdataClass = getClass().getClassLoader().loadClass(testDataClassname);
Constructor<?> tesdataClassConstructor = Objects.requireNonNull(testdataClass).getConstructor(datacontext);
Object testdataClassObject = tesdataClassConstructor.newInstance(dc);
Method buildMethod = testdataClass.getDeclaredMethod("build");
return buildMethod.invoke(testdataClassObject);
I have a class that, in essence, looks like this:
class Checkpointer {
public <Input,Output> Output runFunction(Input input, Function<Input,Output> function) {
Output output;
// Sometimes run the function, sometimes return an Output from a cache
return output
}
}
I would like to mock this class using Mockito doAnswer:
Checkpointer checkpointer; // mocked via #Mock annotation
Mockito
.doAnswer(/* ??? */)
.when(checkpointer)
.runFunction(Mockito.any(), Mockito.any());
The function I want to mock needs to be generic. Can this be done?
For example, my first attempt produced the following. Not only did I resort to Object as the type arguments for Function, but the compiler was still unhappy with unchecked casting:
Mockito.doAnswer((invocation) ->
{
// compiler is not happy with this cast V
Function<Object,Object> function = (Function<Object,Object>)invocation.getArguments()[1];
return function.apply(invocation.getArgument(0));
}).when(checkpointer).runFunction(Mockito.any(), Mockito.any());
If this can't be done, I think can try writing my own mock class extending the first and use Mockito.spy.
The problem here is that you insist on using getArguments, which returns an Object[]
Since you know the index of the Function argument, you can use getArgument(index), as you're doing the line after that.
final Function<String, String> argument = invocation.getArgument(1);
Is this what you're looking for? Type inference for the getArgument generic type is working fine.
If not, can you provide a more elaborate example?
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$
The method in JavaSparkContext.newAPIHadoopRDD takes class as a parameter.
In scala I was able to use the method like so:
sc.newAPIHadoopRDD(job.getConfiguration,
classOf[AvroKeyInputFormat[AvroFlumeEvent]],
classOf[AvroKey[AvroFlumeEvent]],
classOf[NullWritable])
How do i do that in java?
How do I pass the class of AvroKeyInputFormat<AvroFlumeEvent> into the method.
The closest I got was:
Class<AvroKeyInputFormat<AvroFlumeEvent>> inputFormatClass;
Class<AvroKey<AvroFlumeEvent>> keyClass;
JavaPairRDD<AvroKey<AvroFlumeEvent>, NullWritable> flumeEvents = sc.newAPIHadoopRDD(hadoopConf,
inputFormatClass,
keyClass,
NullWritable.class);
However, now it is complaining that inputFormatClass may not have been initialized. I think I'm missing something...
Variables in Java are either null, or an instance. Your variable inputFormatClass is neither null nor an instance, so you can't do anything to it until you initialize it. That's what it's complaining about.
As for passing the class in, you can do:
Class<AvroKeyInputFormat> clazz = AvroKeyInputFormat.class
Generic types are not stored at runtime - they are only used for verification. That's why you can't have a class of AvroKeyInputFormat<AvroFlumeEvent>
I am trying to introduce Scala into my Android project, which uses Guice for DI. For Guide to work, I need to add the #Inject annotation to the constructor I would like Guice to use. In my case I created a Scala class and I need to use it in my Java code.
scala:
class scalaClass1(a: String) {
var myA = a
#Inject
def this() = { this("test") }
}
This looks alright, correct? But in another case the constructor does not have any parameters, so I tried
scala:
class scalaClass2() {
var myA: String = null
#Inject
def this() = { this() }
}
And I got an syntax error. Something like recursive definition. Then I tried this:
scala:
class scalaClass2() {
var myA: String = null
#Inject
def scalaClass2() = { this }
}
The code compiled and the app works well on my phone. I have no idea why. I browsed in google, but I could not find any definition/explanation about having a method that has the same name as the class. Why this works? Is there any better solution to my problem?
If you need to to apply #Inject to a constructor without parameters you can use this:
class scalaClass2 #Inject () {
// whatever
}
Note the mandatory empty parentheses. You need them to apply an annotation on the primary constructor. But in this particular case you don't even need #Inject; see below.
In your second example (when you define def this() = { this() }) you are getting an error because you can't define multiple constructors with the same signature, and that's exactly what you are doing - you define primary constructor without parameters and immediately you define secondary constructor, again without parameters.
And in the third example you're really defining a method named scalaClass2 which returns this. It is perfectly valid, but it is not a constructor. As far as I remember, Guice does not need #Inject annotation on parameterless constructor when it is the only constructor in the class, so you can inject scalaClass2 or ask it from Guice, who will create it for you. But you don't really need scalaClass2 method; Guice may call it as a part of method injection procedure but it won't do anything.
Firstly, according to convention class names should start with upper case and methods with lower. But if we would not follow them I would say it is not safe.
Consider having a companion object to the class with apply method defined.
class Person(val name: String, val age: Int)
object Person {
def apply(name: String, age: Int) = new Person(name, age) }
and then create a method with same name and list parameters:
def Person(lastName: String, score: Int): String = s"${lastName} got ${score} points in last game"
Now if you want to make use of object apply method you cannot do it in regular way:
Person("McKenzie", 1000)
will yield McKenzie got 1000 points in last game