views:

126

answers:

2

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 look 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.

+1  A: 

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...
abhin4v
Thanks! But i need the String of one SPECIFIC field, not ALL of the fields! Like in my example: 'p.getAttributeName(p.firstName).toString' I would also be happy to hear that its NOT possible, then i can stop searching ;)
ifischer
Maybe I am missing the point but if you are already typing the name of the field in `p.getAttributeName(p.firstName).toString` then why not just put it as `firstName`?
abhin4v
Ok, i added some explanation to my post to clearify my problem.
ifischer
+2  A: 

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.

Adam Rabung
Thanks! My jdbc-example was just an example ;) yes there are some good libraries out there to do things like that... but i'm more kind of curious and interested if it is possible in general to do what i asked. Maybe i should look into the source of Squeryl... BTW Currently i'm using JPA Criteria Query for my queries, which is also typesafe, but kind of cumbersome for small apps...
ifischer
Squeryl uses cglib and asm to achieve this.
Adam Rabung
Ok, good to know. So this only possible with JVM/bytecode-magic and -frameworks. Hmm i hoped that Scala would support stuff like this on language level.
ifischer