diff --git a/src/java/com/samskivert/depot/util/RuntimeUtil.java b/src/java/com/samskivert/depot/util/RuntimeUtil.java
index 8744207..bb3ea50 100644
--- a/src/java/com/samskivert/depot/util/RuntimeUtil.java
+++ b/src/java/com/samskivert/depot/util/RuntimeUtil.java
@@ -21,35 +21,68 @@
package com.samskivert.depot.util;
import java.lang.reflect.Field;
+import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.sql.Timestamp;
+import java.util.Date;
import java.util.List;
+import java.util.Map;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import com.samskivert.depot.PersistentRecord;
+import com.samskivert.util.Tuple;
/**
- * Creates functions that map persistent records to runtime counterparts and vice versa.
+ * Creates functions that map persistent records to runtime counterparts and vice versa. A few bits
+ * of magic are provided to help in mapping from the persistent world to the runtime work. Namely:
+ *
+ *
{@link Timestamp} and {@link java.sql.Date} are automatically converted to and from {@link
+ * Date} if necessary.
+ *
+ *
You can define custom getter and setter methods in your persistent class like so:
+ *
+ * public class FooRecord extends PersistentRecord
+ * {
+ * public long monkeyStamp;
+ *
+ * public Date getMonkeyStamp ()
+ * {
+ * return new Date(monkeyStamp);
+ * }
+ *
+ * public void setMonkeyStamp (Date value)
+ * {
+ * monkeyStamp = value.getTime();
+ * }
+ * }
+ *
+ *
+ *
The conversion methods must be named get and set followed by the
+ * name of your field with the first letter changed to a capital and their type signatures must
+ * exactly match those of the persistent and runtime types.
*/
public class RuntimeUtil
{
/**
* Creates a function that creates an instance of R and initializes all accessible (ie. public)
* fields of R from fields of P with matching name. Fields of P that do not exist in R will be
- * ignored. Note: the types of the fields must match exactly.
+ * ignored. See the class documentation for a list of field conversions that will be made
+ * automatically and the mechanism for performing other conversions.
*/
public static
Function
makeToRuntime (
Class
pclass, final Class rclass)
{
final Field[] rfields = getRuntimeFields(rclass);
- final Field[] pfields = getPersistentFields(pclass, rfields);
+ final Getter[] getters = getPersistentGetters(pclass, rfields);
return new Function
() {
public R apply (P record) {
try {
R object = rclass.newInstance();
for (int ii = 0, ll = rfields.length; ii < ll; ii++) {
- rfields[ii].set(object, pfields[ii].get(record));
+ rfields[ii].set(object, getters[ii].get(record));
}
return object;
} catch (Exception e) {
@@ -68,13 +101,13 @@ public class RuntimeUtil
Class rclass, final Class
pclass)
{
final Field[] rfields = getRuntimeFields(rclass);
- final Field[] pfields = getPersistentFields(pclass, rfields);
+ final Setter[] setters = getPersistentSetters(pclass, rfields);
return new Function() {
public P apply (R object) {
try {
P record = pclass.newInstance();
for (int ii = 0, ll = rfields.length; ii < ll; ii++) {
- pfields[ii].set(record, rfields[ii].get(object));
+ setters[ii].set(record, rfields[ii].get(object));
}
return record;
} catch (Exception e) {
@@ -96,8 +129,104 @@ public class RuntimeUtil
return fields.toArray(new Field[fields.size()]);
}
- protected static Field[] getPersistentFields (
- Class extends PersistentRecord> pclass, Field[] rfields)
+ protected static Getter[] getPersistentGetters (Class> pclass, Field[] rfields)
+ {
+ Field[] pfields = getPersistentFields(pclass, rfields);
+ Getter[] getters = new Getter[rfields.length];
+ for (int ii = 0; ii < rfields.length; ii++) {
+ getters[ii] = makeGetter(pclass, pfields[ii], rfields[ii]);
+ }
+ return getters;
+ }
+
+ protected static Setter[] getPersistentSetters (Class> pclass, Field[] rfields)
+ {
+ Field[] pfields = getPersistentFields(pclass, rfields);
+ Setter[] setters = new Setter[rfields.length];
+ for (int ii = 0; ii < rfields.length; ii++) {
+ setters[ii] = makeSetter(pclass, pfields[ii], rfields[ii]);
+ }
+ return setters;
+ }
+
+ protected static Getter makeGetter (Class> pclass, final Field pfield, Field rfield)
+ {
+ // if there's a custom getter method for the field, use that foremost
+ try {
+ final Method method = pclass.getMethod(makeMethodName("get", pfield.getName()));
+ if (method.getReturnType().equals(rfield.getType())) {
+ return new Getter() {
+ public Object get (Object object) throws Exception {
+ return method.invoke(object);
+ }
+ };
+ }
+ } catch (NoSuchMethodException nsme) {
+ // no problem, keep on truckin'
+ }
+
+ // if the fields match exactly, return a getter that just gets the field
+ if (rfield.getType().equals(pfield.getType())) {
+ return new Getter() {
+ public Object get (Object object) throws Exception {
+ return pfield.get(object);
+ }
+ };
+ }
+
+ // if we can convert from the persistent type to the runtime type, do that
+ final Function