Can't unitialize it well, as
val topicAsCollection: util.Collection[String] = util.List[String]
isn't highlighted as an error, but compliation fails on
Error:(126, 59) class java.util.List is not a value
val topicAsCollection: util.Collection[String] = util.List[String]
The right way here is to initalize empty list the following way:
val topicAsCollection: util.Collection[String] = Collections.emptyList()
However, then it causes one more error:
This question already has answers here:
I have a code with Java collection in Scala
val topicAsCollection: util.List[String] = Collections.emptyList()
topicAsCollection.add("recipes")
that fails in runtime
java.lang.UnsupportedOperationException was thrown.
java.lang.UnsupportedOperationException
at java.base/java.util.AbstractList.add(AbstractList.java:153)
at java.base/java.util.AbstractList.add(AbstractList.java:111)
So to initalize the java ArrayList collection in scala coirrectly, the correct initialization needs the explicit type and new:
val topicAsCollection: util.ArrayList[String] = new util.ArrayList[String]()
Related
I'm trying to use a Jackson's ObjectMapper() function: convertValue.
It takes 2 parameters (3 overloads):
(Object, Call)
(Object, TypeReference)
(Object, JavaType)
I have the following code:
val m = new ObjectMapper()
val map: Map[String, Object] = m.convertValue(bean, classOf[Map])
which doesn't work with error Type Mismatch. Expected JavaType actual Class[Map].
I tested with classOf[java.util.Map], Map.getClass, etc. but can't make it work.
How should I send that parameter?
Step 1: look at https://fasterxml.github.io/jackson-databind/javadoc/2.8/com/fasterxml/jackson/databind/JavaType.html. See
Instances can (only) be constructed by com.fasterxml.jackson.databind.type.TypeFactory.
Step 2: look at https://fasterxml.github.io/jackson-databind/javadoc/2.8/com/fasterxml/jackson/databind/type/TypeFactory.html.
Then you can see it can be used as e.g.
m.getTypeFactory.constructMapType(classOf[java.util.Map[_, _]], classOf[YourKey], classOf[YourValue])
You can use the mapper to get the JavaType, for example:
val stringType:JavaType = mapper.constructType(String.class);
You can try the following for your problem:
val m = new ObjectMapper()
val mapType:JavaType = mapper.constructType(java.util.Map.class)
val map: Map[String, Object] = m.convertValue(bean, mapType)
IntelliJ complains about this code:
val document: Node // (initialized further up in the code)
val s: String = (new scala.xml.PrettyPrinter(80, 4)).format(document))
With the error:
Cannot resolve reference format with such signature
However - such a function exists. It has a default value for the second parameter and it seems IntelliJ isn't identifying it correctly.
I am not sure about that specific error you mention, but you have one parenthesis too many. You have:
val s: String = (new scala.xml.PrettyPrinter(80, 4)).format(document))
It should be:
val s: String = (new scala.xml.PrettyPrinter(80, 4)).format(document)
I just tried you code in sbt (once I made that correction) and it seems fine:
scala> import scala.xml._
import scala.xml._
scala> val document : Node = <test>blah</test>
document: scala.xml.Node = <test>blah</test>
scala> val s: String = (new PrettyPrinter(80, 4)).format(document)
s: String = <test>blah</test>
Given an anonymous object:
val anon = new {
val a = BigDecimal(1)
}
How can I use scala reflection to get value of a ?
I have tried using java reflection, it is trivial. But with scala reflection, it is not obvious.
Here is what I have tried:
package test
object ReflectTest extends App {
val anon = new {
val a = BigDecimal(1)
}
val instanceMirror = currentMirror.reflect(anon)
val anonType = typeOf[anon.type]
val anonTermSymbol = anonType.member(newTermName("a")).asTerm
val anonFieldMirror = instanceMirror.reflectField(anonTermSymbol)
val result = anonFieldMirror.get
println(result)
}
But encountered an exception:
Exception in thread "main" scala.ScalaReflectionException: expected a member of anonymous class $anon$1, you provided value test.ReflectTest.<refinement>.a
at scala.reflect.runtime.JavaMirrors$JavaMirror.scala$reflect$runtime$JavaMirrors$JavaMirror$$ErrorNotMember(JavaMirrors.scala:130)
at scala.reflect.runtime.JavaMirrors$JavaMirror$$anonfun$scala$reflect$runtime$JavaMirrors$JavaMirror$$checkMemberOf$1.apply(JavaMirrors.scala:225)
at scala.reflect.runtime.JavaMirrors$JavaMirror.ensuringNotFree(JavaMirrors.scala:214)
at scala.reflect.runtime.JavaMirrors$JavaMirror.scala$reflect$runtime$JavaMirrors$JavaMirror$$checkMemberOf(JavaMirrors.scala:224)
at scala.reflect.runtime.JavaMirrors$JavaMirror$JavaInstanceMirror.reflectField(JavaMirrors.scala:247)
at scala.reflect.runtime.JavaMirrors$JavaMirror$JavaInstanceMirror.reflectField(JavaMirrors.scala:243)
It seems that the runtime type is not the one recognized by scala reflection.
testOnly play.api.weibo.StatusesShowBatchSpec
[error] Could not create an instance of play.api.weibo.StatusesShowBatchSpec
[error] caused by java.lang.Exception: Could not instantiate class play.api.weibo.StatusesShowBatchSpec: null
[error] org.specs2.reflect.Classes$class.tryToCreateObjectEither(Classes.scala:93)
[error] org.specs2.reflect.Classes$.tryToCreateObjectEither(Classes.scala:211)
[error] org.specs2.specification.SpecificationStructure$$anonfun$createSpecificationEither$2.apply(BaseSpecification.scala:119)
[error] org.specs2.specification.SpecificationStructure$$anonfun$createSpecificationEither$2.apply(BaseSpecification.scala:119)
...
The spec
package play.api.weibo
import org.junit.runner.RunWith
import org.specs2.runner.JUnitRunner
class StatusesShowBatchSpec extends ApiSpec {
"'statuses show batch' api" should {
"read statuses" in {
val api = StatusesShowBatch(
accessToken = testAdvancedToken,
ids = "3677163356078857")
val res = awaitApi(api)
res.statuses must have size (1)
}
}
}
See full code here https://github.com/jilen/play-weibo/tree/spec2_error
Full stacktrace
https://gist.github.com/jilen/9050548
In the ApiSpec class you have a few variables which might be null at instantiation time:
val cfg = ConfigFactory.load("http.conf")
val testToken = cfg.getString("token.normal")
val testAdvancedToken = cfg.getString("token.advanced")
implicit val http = new SprayHttp {
val config = new SprayHttpConfig {
val system = ActorSystem("test")
val gzipEnable = true
}
val context = config.system.dispatcher
}
You can turn those vals into lazy vals to avoid this situation:
lazy val cfg = ConfigFactory.load("http.conf")
lazy val testToken = cfg.getString("token.normal")
lazy val testAdvancedToken = cfg.getString("token.advanced")
implicit lazy val http = new SprayHttp {
lazy val config = new SprayHttpConfig {
val system = ActorSystem("test")
val gzipEnable = true
}
val context = config.system.dispatcher
}
I was getting a very similar error using specs2 version 2.3.10 on Scala 2.10. Upgrading to 2.3.13 makes the error messages much more informative and provides an extra stacktrace to the root cause. This newer version was released very recently (8 days before this post!), so hopefully you're able to accommodate an update...
Some of my issues ended up being related the val vs. lazy val problem like in the accepted answer; however, I'm now able to pinpoint the exact line that these errors are occurring on in addition to debugging other initialization problems as well.
I have java API which returns java.util.set, I want to iterate over the set till the size-1 and create new java.util.hashset in scala
I tried following :
val keys = CalltoJavaAPI()
val newHashSet = new java.util.HashSet()
val size = keys.size();
newHashSet.add(keys.take(keys.size() - 1))
But I am getting following error:
Caused by: java.lang.UnsupportedOperationException
at java.util.AbstractCollection.add(AbstractCollection.java:221)
Tried Following but still not working
val keys = CalltoJavaAPI().asScala
var newHashSet = new scala.collection.mutable.HashSet[Any]()
newHashSet.add(keys.take(keys.size - 1))
Use scala.collection.JavaConversions for implicit conversions between Scala and Java collections.
In the following approach we convert a Java HashSet onto a Scala Set, extract keys of interest, and convert the result onto a new Java HashSet:
import scala.collection.JavaConversions._
val javaKeys = new java.util.HashSet[Any](CalltoJavaAPI())
val n = javaKeys.size
val scalaSet = javaKeys.toSet.take(n-1)
val newJavaHashSet = new java.util.HashSet[Any]()
newJavaHashSet.addAll(scalaSet)
I think you should use newHashSet.addAll(...) instead of newHashSet.add(...) since keys.take(...) returns a List.
From the docs:
public boolean add(E e): Adds the specified element to this set if it is not already present.
public boolean addAll(Collection c): Adds all of the elements in the specified collection to this collection