【问题标题】:Get name of class-attribute or class-function as String以字符串形式获取类属性或类函数的名称
【发布时间】:2010-06-10 18:39:50
【问题描述】:

假设我有以下课程:

class Person {
  @BeanProperty
  var firstName: String = _
}

是否可以通过反射或其他方式以类型安全的方式获取“firstName”的字符串表示形式?还是生成的“getFirstName”-Function 的字符串表示形式?

如果它看起来像这样就好了:

val p = new Person
p.getFunction(p.getFirstName).toString // "getFirstName"
p.getAttribute(p.firstName).toString   // "firstName"

编辑

好的,需要更多解释;)

假设我想构建一个这样的 SQL 查询:

val jpql = "select p from Person p where p.age > 20";

所以我想让它尽可能的类型安全并写这样的东西:

val jpql = "select p from " + classOf[Person].getName + " where p." + 
  Person.getAttName(p.age) + " > 20";

这样,如果将来可以重构Scala代码,我可以在不破坏我的代码的情况下更改Person的属性名称。

【问题讨论】:

  • 你找到不用 Squeryl 的方法了吗?
  • @GermainGum 不。这不能回答最初的问题,但是如果我现在仍然必须使用 Scala,我只会使用较新的 Scala SQL 库之一,例如 slick slick.typesafe.com 来处理这个问题。

标签: scala scala-2.8


【解决方案1】:

坏消息是 Scala 并没有这样引用成员的能力。您可以获得这样的“方法参考”:

scala> class Person(val firstName:String)         
defined class Person

scala> val methodRef = new Person("i").firstName _
methodRef: () => String = <function0>

scala> methodRef()                                
res1: String = i

但它并没有给你想要的反射性东西。好消息是有几个库可以为您提供这种类型安全的 JDBC。这是您使用 Squeryl 的代码:

import org.squeryl.Schema
import org.squeryl.Session
import org.squeryl.PrimitiveTypeMode._
import org.squeryl.adapters.H2Adapter
import org.squeryl.SessionFactory

object Sample {
case class Person(val firstName:String, val age:Int)

object AppSchema extends Schema {
  val people = table[Person]("People")
}

def main(args:Array[String]) { 
  import AppSchema.people
  Class.forName("org.h2.Driver")
  SessionFactory.concreteFactory = Some(()=> Session.create(java.sql.DriverManager.getConnection("jdbc:h2:~/temp/db", "sa", ""), new H2Adapter))

  transaction {
    AppSchema.create
    people.insert(new Person("ifischer", 92)) 
    people.insert(new Person("baby", 2)) 
    for (olderPerson <- from(people)(p=> where(p.age gt 20) select(p))) {
      println(olderPerson) //wont return "baby"!
    }
  } 
}
}

这有多酷?例如,如果您尝试将年龄与字符串进行比较,则不会编译。当然,如果您使用 p.ssn 或其他一些未知字段,它也不会编译。

【讨论】:

  • 谢谢!我的 jdbc-example 只是一个示例 ;) 是的,有一些很好的库可以做这样的事情......但如果总体上可以按照我的要求去做,我会更加好奇和感兴趣。也许我应该查看 Squeryl 的来源......顺便说一句,目前我正在使用 JPA Criteria Query 进行查询,这也是类型安全的,但对于小型应用程序来说有点麻烦......
  • Squeryl 使用 cglib 和 asm 来实现这一点。
  • 好的,很高兴知道。所以这只能通过 JVM/bytecode-magic 和 -frameworks 实现。嗯,我希望 Scala 能在语言层面支持这样的东西。
【解决方案2】:

我假设您不知道要检查的类中的方法和属性名称(否则为什么要获取它们的名称而不仅仅是输入它们?)。此示例说明如何获取 java.lang.String 类中所有方法的名称。

scala> classOf[String].getMethods.map(_.getName)
res4: Array[java.lang.String] = Array(equals, hashCode, toString, charAt, compareTo, 
compareToIgnoreCase, concat, endsWith, equalsIgnoreCase, getBytes, getBytes, getBytes, 
getChars, indexOf, indexOf, indexOf, indexOf, intern, lastIndexOf, lastIndexOf, 
lastIndexOf, lastIndexOf, length, regionMatches, regionMatches, replace, startsWith, 
startsWith, substring, substring, toCharArray, toL...

【讨论】:

  • 谢谢!但我需要一个特定字段的字符串,而不是所有字段!就像在我的示例中一样:'p.getAttributeName(p.firstName).toString' 我也很高兴听到它不可能,然后我可以停止搜索 ;)
  • 也许我没抓住重点,但如果您已经在p.getAttributeName(p.firstName).toString 中输入了字段的名称,那么为什么不直接输入firstName
  • 好的,我在帖子中添加了一些解释来澄清我的问题。
猜你喜欢
  • 2015-03-18
  • 1970-01-01
  • 2011-09-30
  • 2012-11-16
  • 2014-05-23
  • 2010-09-15
  • 2011-04-12
相关资源
最近更新 更多