Say i have the following class:
class Person {
@BeanProperty
var firstName: String = _
}
Is it possible to get the String representation of "firstName" in a type-safe way, by reflection or something? Or the String representation of the generated "getFirstName"-Function?
It would be nice if it would somehow loo开发者_如何学Pythonk like:
val p = new Person
p.getFunction(p.getFirstName).toString // "getFirstName"
p.getAttribute(p.firstName).toString // "firstName"
EDIT
Ok, more explanation is needed ;)
Say i want to build a SQL query like this:
val jpql = "select p from Person p where p.age > 20";
So i want to make it as typesafe as possible and write something like this:
val jpql = "select p from " + classOf[Person].getName + " where p." +
Person.getAttName(p.age) + " > 20";
In this way, if it's possible to refactor Scala code in the future, i could change the attribute name of Person without breaking my code.
The bad news is Scala doesn't really have the ability to reference members like that. You can get a "method reference" like this:
scala> class Person(val firstName:String)
defined class Person
scala> val methodRef = new Person("i").firstName _
methodRef: () => String = <function0>
scala> methodRef()
res1: String = i
But it doesn't give you the reflective stuff that you want. The good news is there are a couple of libraries out there that give you this type of type-safe JDBC. Here's your code using 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"!
}
}
}
}
How cool is that? This won't compile if, for example, you try to compare age to a String. Of course it also won't compile if you use p.ssn or some other unknown field.
I am assuming that you don't know the method and attribute names in the class you want to inspect (otherwise why would you want to get their names rather than just typing them in?). This example shows how to get names of all the methods on the java.lang.String
class.
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...
精彩评论