At my work we use a typical heavy enterprise stack of Hibernate, Spring, and JSF to handle our application, but after learning Scala I've wanted to try to replicate much of our functionality within a more minimal Scala stack (Squeryl, Scalatra, Scalate) to see if I can decrease code and improve performance (an Achilles heal for us right now).
Often my way of doing things is influenced by our previous stack, so I'm open to advice on a way of doing things that are closer to Scala paradigms. However, I've chosen some of what I do based on previous paradigms we have in the Java code base so that other team members will hopefully be more receptive to the work I'm doing. But here is my question:
We have a domain class like so:
class Person(var firstName: String, var lastName: String)
Within a jade template I make a call like:
.section
- view(fields)
The backing class has a list of fields like so:
class PersonBean(val person: Person) {
val fields: Fields = Fields(person,
List(
Text(person.firstName),
Text(person.lastName)
))
}
Fields has a base object (person) and a list of Field objects. Its template prints all its fields templates. Text extends Field and its Jade template is supposed to print:
<label for="person:firstName">#{label}</label>: <input type="text" id="person:firstName" value="#{value}" />
Now the #{value} is simply a call to person.firstName. However, to find out the label I reference a ResourceBundle and need to produce a string key. I was thinkin开发者_运维知识库g of using a naming convention like:
person.firstName.field=First Name
So the problem then becomes, how can I within the Text class (or parent Field class) discover what the parameter being passed in is? Is there a way I can pass in person.firstName and find that it is calling firstName on class Person? And finally, am I going about this completely wrong?
If you want to take a walk on the wild side, there's a (hidden) API in Scala that allows you to grab the syntax tree for a thunk of code - at runtime.
This incantation goes something like:
scala.reflect.Code.lift(f).tree
This should contain all the information you need, and then some, but you'll have your work cut out interpreting the output.
You can also read a bit more on the subject here: Can I get AST from live scala code?
Be warned though... It's rightly classified as experimental, do this at your own risk!
You can never do this anywhere from within Java, so I'm not wholly clear as to how you are just following the idiom you are used to. The obvious reason that this is not possible is that Java is pass-by-value. So in:
public void foo(String s) { ... }
There is no sense that the parameter s
is anything other than what it is. It is not person.firstName
just because you called foo
like:
foo(person.firstName);
Because person.firstName
and s
are completely separate references!
What you could do is replacing the fields (e.g. firstname) with actual objects, which have a name attribute.
I did something similiar in a recent blog post:http://blog.schauderhaft.de/2011/05/01/binding-scala-objects-to-swing-components/
The property doesn't have a name property (yet), but it is a full object but is still just as easy to use as a field.
I would not be very surprised if the following is complete nonsense:
- Make the parameter type of type
A
that gets passed in notA
butContext[A]
- create an implicit that turns any
A
into aContext[A]
and while doing so captures the value of the parameter in a call-by-name parameter - then use reflection to inspect the call-by-name parameter that gets passed in
For this to work, you'd need very specific knowledge of how stuff gets turned into call-by-name functions; and how to extract the information you want (if it's present at all).
精彩评论