Class 如何在带有反射的None上获得选项类[ux]
我有这样的设置,我想从XML节点SEQ填充一个对象字段。将显示我的设置的精简版本。它工作得很好,但是当我在Class 如何在带有反射的None上获得选项类[ux],class,scala,reflection,option,Class,Scala,Reflection,Option,我有这样的设置,我想从XML节点SEQ填充一个对象字段。将显示我的设置的精简版本。它工作得很好,但是当我在testObj中放入None时,我得到了一个java.util.NoSuchElementException:None.get 我认为问题在于,当选项[\u]的类为None时,我无法找到获取该类的方法。我在这件事上纠缠了很久,找不到出路。我觉得当原始值为None时,必须有一种方法来分支和填充对象字段,但是如何呢 import xml.NodeSeq object test { case
testObj
中放入None
时,我得到了一个java.util.NoSuchElementException:None.get
我认为问题在于,当选项[\u]
的类为None
时,我无法找到获取该类的方法。我在这件事上纠缠了很久,找不到出路。我觉得当原始值为None
时,必须有一种方法来分支和填充对象字段,但是如何呢
import xml.NodeSeq
object test {
case class TestObject(name: Option[String] = None, value: Option[Double] = None)
def main(args: Array[String]): Unit = {
val testObj = TestObject(Some("xxx"), Some(12.0))
// val testObj = TestObject(None, Some(12.0))
val nodeSeq = <test> <name> yyy </name> <value> 34.0 </value> </test>
val result = getObject[TestObject](nodeSeq, Option(testObj))
println("result = " + result) // result = Some(TestObject(Some(yyy),Some(34.0)))
}
def getObject[A](nodeSeq: NodeSeq, obj: Option[A]): Option[A] = {
if ((nodeSeq.isEmpty) || (!obj.isDefined)) None else {
for (field <- obj.get.getClass.getDeclaredFields) {
field.setAccessible(true)
val fieldValue = field.get(obj.get)
if (fieldValue == null || !fieldValue.isInstanceOf[Option[_]]) None
var newValue: Option[_] = None
fieldValue.asInstanceOf[Option[_]].get match { // <---- None.get is the error here
case x: Double => newValue = Some((nodeSeq \ field.getName).text.trim.toDouble)
case x: String => newValue = Some((nodeSeq \ field.getName).text.trim)
}
val decField = obj.get.getClass.getDeclaredField(field.getName)
decField.setAccessible(true)
decField.set(obj.get, newValue)
}
obj
}
}
}
import xml.NodeSeq
对象测试{
案例类TestObject(名称:Option[String]=None,值:Option[Double]=None)
def main(参数:数组[字符串]):单位={
val testObj=TestObject(一些(“xxx”),一些(12.0))
//val testObj=TestObject(无,部分(12.0))
val nodeSeq=yyy 34.0
val result=getObject[TestObject](nodeSeq,选项(testObj))
println(“result=“+result)//result=Some(TestObject(Some(yyy)),Some(34.0)))
}
def getObject[A](nodeSeq:nodeSeq,obj:Option[A]):Option[A]={
如果((nodeSeq.isEmpty)| |(!obj.isDefined))没有其他{
for(field newValue=Some((nodeSeq\field.getName).text.trim)
}
val decField=obj.get.getClass.getDeclaredField(field.getName)
decField.setAccessible(true)
decField.set(obj.get,newValue)
}
obj
}
}
}
我忽略了此代码中我不喜欢的其他部分,但是,您不能调用。在无上获取。您可以调用map,它将返回我认为您需要的内容。以下是修改后的代码:
def getObject[A](nodeSeq: NodeSeq, obj: Option[A]): Option[A] = {
if (nodeSeq.isEmpty || obj.isEmpty) {
None
}
else {
for (field <- obj.get.getClass.getDeclaredFields) {
field.setAccessible(true)
val fieldValue = field.get(obj.get)
if (fieldValue == null || !fieldValue.isInstanceOf[Option[_]]) None
val newValue = fieldValue.asInstanceOf[Option[_]].map(a => {
a match {
case x: Double => Some((nodeSeq \ field.getName).text.trim.toDouble)
case x: String => Some((nodeSeq \ field.getName).text.trim)
}
})
val decField = obj.get.getClass.getDeclaredField(field.getName)
decField.setAccessible(true)
decField.set(obj.get, newValue)
}
obj
}
}
实际上,这可能更接近您想要的:检查字段的类型
import xml.NodeSeq
object test {
case class TestObject(name: Option[String] = None, value: Option[Double] = None)
def main(args: Array[String]): Unit = {
val testObj = TestObject(Some("xxx"), Some(12.0))
// val testObj = TestObject(None, Some(12.0))
val nodeSeq = <test> <name> yyy </name> <value> 34.0 </value> </test>
val result = getObject[TestObject](nodeSeq, Option(testObj))
println("result = " + result) // result = Some(TestObject(Some(yyy),Some(34.0)))
}
def getObject[A](nodeSeq: NodeSeq, obj: Option[A]): Option[A] = {
if ((nodeSeq.isEmpty) || (!obj.isDefined)) None else {
for (field <- obj.get.getClass.getDeclaredFields) {
field.setAccessible(true)
val newValue = field.getGenericType match {
case t: ParametrizedType if (t.getActualType == classOf[Option[_]]) =>
val paramType = t.getActualTypeArguments()(0)
if (paramType == classOf[java.lang.Double]) // since Double can't be a generic type parameter on JVM
// from your original code, but it probably needs to be modified
// to handle cases where field isn't in nodeSeq or not a number
Some((nodeSeq \ field.getName).text.trim.toDouble)
else if (paramType == classOf[String])
Some((nodeSeq \ field.getName).text.trim)
else None
case _ => None
}
if (newValue.isDefined)
field.set(obj.get, newValue)
}
obj
}
}
}
然后fieldValue
是None
。一个cast(一个实例)不改变底层对象;只改变它的静态类型视图。get
方法是虚拟的/多态的,因为它是Some和None的超级类型。虽然@pst的评论是正确的,但您也可以使用Scala 2.10反射库,以这种方式改变字段很难看,很容易导致错误。相反,您的signature应该是def getObject[A:ru.TypeTag](nodeSeq:nodeSeq):选项[A]
(或者ClassManifest
,而不是2.10之前的TypeTag
)并创建一个新对象。谢谢大家,我从评论和答案中学到了很多,但是我仍然没有得到我想要的结果,尽管越来越近了。通过输入val testObj=TestObject(无,一些(12.0)),我得到了result=Some(TestObject(无,一些(34.0)),我在寻找result=Some(TestObject(一些(yyy),一些(34.0)))
import xml.NodeSeq
object test {
case class TestObject(name: Option[String] = None, value: Option[Double] = None)
def main(args: Array[String]): Unit = {
val testObj = TestObject(Some("xxx"), Some(12.0))
// val testObj = TestObject(None, Some(12.0))
val nodeSeq = <test> <name> yyy </name> <value> 34.0 </value> </test>
val result = getObject[TestObject](nodeSeq, Option(testObj))
println("result = " + result) // result = Some(TestObject(Some(yyy),Some(34.0)))
}
def getObject[A](nodeSeq: NodeSeq, obj: Option[A]): Option[A] = {
if ((nodeSeq.isEmpty) || (!obj.isDefined)) None else {
for (field <- obj.get.getClass.getDeclaredFields) {
field.setAccessible(true)
val newValue = field.getGenericType match {
case t: ParametrizedType if (t.getActualType == classOf[Option[_]]) =>
val paramType = t.getActualTypeArguments()(0)
if (paramType == classOf[java.lang.Double]) // since Double can't be a generic type parameter on JVM
// from your original code, but it probably needs to be modified
// to handle cases where field isn't in nodeSeq or not a number
Some((nodeSeq \ field.getName).text.trim.toDouble)
else if (paramType == classOf[String])
Some((nodeSeq \ field.getName).text.trim)
else None
case _ => None
}
if (newValue.isDefined)
field.set(obj.get, newValue)
}
obj
}
}
}
def getObject[A](nodeSeq: NodeSeq, objClass: Class[A]): Option[A] = {
if (nodeSeq.isEmpty) None else {
try {
val fieldValues = objClass.getDeclaredFields.flatMap { field =>
field.setAccessible(true)
field.getGenericType match {
case t: ParametrizedType if (t.getActualType == classOf[Option[_]]) =>
val paramType = t.getActualTypeArguments()(0)
if (paramType == classOf[java.lang.Double])
Some(Some((nodeSeq \ field.getName).text.trim.toDouble))
else if (paramType == classOf[String])
Some(Some((nodeSeq \ field.getName).text.trim))
else None
case _ => None
}
}
// assumes only one constructor, otherwise get the desired one
val ctor = objClass.getConstructors()(0)
Some(ctor.newInstance(fieldValues))
} catch {
case _ => None
}
}
}