I'm trying to convert this Java code into Scala, and I am failing:
Java (which compiles without error):
Validation.byProvider(HibernateValidator.class).configure().
buildValidatorFactory().getValidator().unwrap(MethodValidator.class);
Scala:
Validation.byProvider(classOf[HibernateValidator]).configure.
buildValidatorFactory.getValidator.unwrap( classOf[MethodValidator] )
Scala error:
inferred type arguments [Nothing,org.hibernate.validator.HibernateValidator] do
not conform to method byProvider's type parameter bounds [T <:
javax.validation.Configuration[T],U <:
javax.validation.spi.ValidationProvider[T]]
What am I doing wrong?
I am using Scala 2.10 and have JBoss 7.1.0 on the classpath.
It looks like scala is having a little trouble infering some types. This should work:
Validation.byProvider[HibernateValidatorConfiguration, HibernateValidator](classOf[HibernateValidator])
.configure.buildValidatorFactory.getValidator.unwrap(classOf[MethodValidator])
If you look at the source of byProvider you'll find this:
public static <T extends javax.validation.Configuration<T>,
U extends javax.validation.spi.ValidationProvider<T>>
javax.validation.bootstrap.ProviderSpecificBootstrap<T>
byProvider(java.lang.Class<U> providerType)
So scala should pick up that HibernateValidator has HibernateValidatorConfiguration implemented, but it doesn't.
Related
Here is a dependency service:
public class Service1 {}
Scala code that uses it via reader:
object TupleEx {
type FailFast[A] = Either[List[String], A]
type Env[A] = ReaderT[FailFast, Service1, A]
import cats.syntax.applicative._
import cats.instances.either._
def f:Env[Int] = 10.pure[Env]
}
Java test where I try to inject Service1:
#Test
public void testf() {
Service1 s = new Service1();
TupleEx.f().run(s);
}
I am getting an exception:
Error:(10, 16) java: method run in class cats.data.Kleisli
cannot be applied to given types; required: no arguments found:
com.savdev.Service1 reason: actual and formal argument lists differ
in length
Although in Scala I would be able to run it as:
TupleEx.f().run(s);
Try:
TupleEx.f().run().apply(s);
run() is the "getter" method of the val inside Kleisli
apply() is what is usually hidden by Scala's syntactic sugar
General advice:
Write down an interface in Java
Implement the interface in Scala
Use whatever you've written only through Java interfaces when writing code in Java.
Do not attempt to use Scala interfaces directly when writing code in Java.
Remember: Scala compiler understands Java. Java does not know anything about Scala. Implementing Java interfaces in Scala is trivial. Using Scala interfaces from Java is awkward.
import scala.reflect.runtime.{universe => ru}
trait someTrait{
def getType[T: ru.TypeTag](obj: T) = ru.typeOf[T]
def reflect()={
println(getType(this)) // got someTrait type, not A type.
}
}
class A extends someTrait{
}
main(){
new A().reflect()
}
When I run main function, I got someTrait type printed out.
How can I get A type in reflect function?
Using TypeTags or ClassTags, you can't (without doing extra work in every subtype, as Ramesh's answer does). Because the compiler inserts them based on static types only.
When it sees getType(this), it first infers type parameter to getType[someTrait](this), and then turns into getType[someTrait](this)(typeTag[someTrait]). You can see A is never considered and it can't be.
As the scala document says, we cant use java reflectoin since it might cause problem.
No, Scala documentation certainly doesn't say you can't use Java reflection for this. You need to understand its limitations but exactly the same applies to Scala reflection.
I am new to Scala, and I'm running into this problem when I'm trying to unit test some of my interfaces.
I have an InputService trait with method
def poll(parameters: HashMap[String, String]): Option[T]
where T is generic, so InputService has a type parameter [T].
In my module, I have
val inputService: InputService[String] = mock(classOf[InputService[String]])
bind[InputService[String]].toInstance(inputService)
and in my InputServiceTest, I have
var inputService: InputService[String] = _
before {
inputService = Guice.createInjector(new MockWatcherModule).getInstance(classOf[InputService[String]])
}
But the issue is when I run it, it gives me this error
Exception encountered when invoking run on a nested suite - Guice configuration errors:
1) No implementation for services.InputService was bound.
while locating services.InputService
I think it's because it's looking for services.InputService to bound, but it only has services.InputService[String]. However, when I just use InputService instead of InputService[String], I get the error Trait missing Type Parameter.
Any suggestions?
EDIT:
Turns out that I can use typeLiteral from scala-guice and KeyExtensions to solve my issue. Thanks Tavian!
Due to type erasure, in the getInstance(classOf[InputService[String]]) call, you're just passing InputService.class. You need to pass a TypeLiteral instead to encode the generic type information. From a quick Google it looks like
import net.codingwell.scalaguice._
import net.codingwell.scalaguice.InjectorExtensions._
Guice.createInjector(new MockWatcherModule).instance[InputService[String]]
will work.
I'm trying to read some data from hadoop into an RDD in Spark using the interactive Scala shell but I'm having trouble accessing some of the classes I need to deserialise the data.
I start by importing the necessary class
import com.example.ClassA
Which works fine. ClassA is located in a jar in the 'jars' path and has ClassB as a public static nested class
I'm then trying to use ClassB like so:
val rawData = sc.newAPIHadoopFile(dataPath, classOf[com.exmple.mapreduce.input.Format[com.example.ClassA$ClassB]], classOf[org.apache.hadoop.io.LongWritable], classOf[com.example.ClassA$ClassB])
This is slightly complicated by one of the other classes taking ClassB as a type, but I think that should be fine.
When I execute this line, I get the following error:
<console>:17: error: type ClassA$ClassB is not a member of package com.example
I have also tried using the import statement
import com.example.ClassA$ClassB
and it also seems fine with that.
Any advice as to how I could proceed to debug this would be appreciated
Thanks for reading.
update:
Changing the '$' to a '.' to reference the nested class seems to get past this problem, although I then got the following syntax error:
'<console>:17: error: inferred type arguments [org.apache.hadoop.io.LongWritable,com.example.ClassA.ClassB,com.example.mapreduce.input.Format[com.example.ClassA.ClassB]] do not conform to method newAPIHadoopFile's type parameter bounds [K,V,F <: org.apache.hadoop.mapreduce.InputFormat[K,V]]
Notice the types that the newAPIHadoopFile expects:
K,V,F <: org.apache.hadoop.mapreduce.InputFormat[K,V]
the important part here is that the generic type InputFormat expects the types K and V, i.e. the exact types of the first two parameters to the method.
In your case, the third parameter should be of type
F <: org.apache.hadoop.mapreduce.InputFormat[LongWritable, ClassA.ClassB]
does your class extend FileInputFormat<LongWritable, V>?
I'm writing a wrapper that takes a Scala ObservableBuffer and fires events compatible with the Eclipse/JFace Databinding framework.
In the Databinding framework, there is an abstract ObservableList that decorates a normal Java list. I wanted to reuse this base class, but even this simple code fails:
val list = new java.util.ArrayList[Int]
val obsList = new ObservableList(list, null) {}
with errors:
illegal inheritance; anonymous class $anon inherits different type instances of trait Collection: java.util.Collection[E] and java.util.Collection[E]
illegal inheritance; anonymous class $anon inherits different type instances of trait Iterable: java.lang.Iterable[E] and java.lang.Iterable[E]
Why? Does it have to do with raw types? ObservableList implements IObservableList, which extends the raw type java.util.List. Is this expected behavior, and how can I work around it?
Having a Java raw type in the inheritance hierarchy causes this kind of problem. One solution is to write a tiny bit of Java to fix up the raw type as in the answer for Scala class cant override compare method from Java Interface which extends java.util.comparator
For more about why raw types are problematic for scala see this bug http://lampsvn.epfl.ch/trac/scala/ticket/1737 . That bug has a workaround using existential types that probably won't work for this particular case, at least not without a lot of casting, because the java.util.List type parameter is in both co and contra variant positions.
From looking at the javadoc the argument of the constructor isn't parameterized.
I'd try this:
val list = new java.util.ArrayList[_]
val obsList = new ObservableList(list, null) {}