我目前正在使用Scala和JSF,其中两者在一起玩得很好。但有时JSF需要重新实例化(通过Class.newInstance)数据结构,如列表。例如,在托管bean中我有:
@BeanProperty
var countries: java.util.List[String] = List("US").asJava
在您进入JSF的流程验证阶段之前,它会运行到java.lang.InstantiationException:
java.lang.InstantiationException: scala.collection.JavaConversions$SeqWrapper
at java.lang.Class.newInstance0(Class.java:340)
at java.lang.Class.newInstance(Class.java:308)
at com.sun.faces.renderkit.html_basic.MenuRenderer.createCollection(MenuRenderer.java:906)
at com.sun.faces.renderkit.html_basic.MenuRenderer.convertSelectManyValuesForModel(MenuRenderer.java:366)
at com.sun.faces.renderkit.html_basic.MenuRenderer.convertSelectManyValue(MenuRenderer.java:128)
at com.sun.faces.renderkit.html_basic.MenuRenderer.getConvertedValue(MenuRenderer.java:314)
at org.primefaces.component.selectcheckboxmenu.SelectCheckboxMenuRenderer.getConvertedValue(SelectCheckboxMenuRenderer.java:34)
...
从基础层面来看,Wrappers可能无法从头开始重新实例化,因此使用JavaConverters在这里工作得不好。我的问题是那里的库已经提供了一个完整的数据结构映射/转换而没有包装器?如果不是,我只会写自己的内部。
答案 0 :(得分:4)
使用Java ArrayList
作为var
,然后在代码中使用JavaConverters
/ JavaConversions
进行操作。这是我用于需要Java集合的Hibernate,JAX-WS,JSR-303等API的常用方法。
import collection.JavaConversions._
@BeanProperty
var countries: java.util.List[String] = new java.util.ArrayList[String] += "US"
或
import collection.JavaConverters._
@BeanProperty
var countries: java.util.List[String] = new java.util.ArrayList[String]
countries.asScala += "US"
countries.asScala ++= List("US", "MX")
如果您真的想要来回转换而不是在不创建自己的类的情况下将其包装起来很容易:
import collection.JavaConverters._
import collection.mutable.ArrayBuffer
@BeanProperty
var countries: java.util.List[String] = new java.util.ArrayList[String]
val countriesBuff = new ArrayBuffer.empty[String]
countriesBuff ++= countries.asScala // Convert from ArrayList to ArrayBuffer
// ...
countries.addAll(countriesBuff.asJava) // Convert the other direction
但是你必须担心复制的成本以及何时需要同步。包装/装饰更方便。