001: // $Id$
002:
003: package net.sf.persist;
004:
005: import java.lang.reflect.Method;
006: import java.sql.DatabaseMetaData;
007: import java.sql.SQLException;
008: import java.util.HashMap;
009: import java.util.Map;
010:
011: public abstract class Mapping {
012:
013: public abstract Method getGetterForColumn(String columnName);
014:
015: public abstract Method getSetterForColumn(String columnName);
016:
017: // ---------- utility methods ----------
018:
019: /**
020: * Factory method to create a Mapping based on a Class. Will return a
021: * NoTableAnnotation if the class has a NoTable annotation set, or
022: * TableAnnotation otherwise.
023: */
024: public static final Mapping getMapping(
025: final DatabaseMetaData metaData, final Class objectClass,
026: final NameGuesser nameGuesser) {
027:
028: // get @NoTable annotation
029: final net.sf.persist.annotations.NoTable noTableAnnotation = (net.sf.persist.annotations.NoTable) objectClass
030: .getAnnotation(net.sf.persist.annotations.NoTable.class);
031:
032: // if @NoTable is set, build a NoTableAnnotation
033: if (noTableAnnotation != null) {
034: return new NoTableMapping(objectClass, nameGuesser);
035: }
036:
037: // otherwise, build a TableAnnotation
038: else {
039: try {
040: return new TableMapping(metaData, objectClass,
041: nameGuesser);
042: } catch (SQLException e) {
043: throw new PersistException(e);
044: }
045: }
046: }
047:
048: /**
049: * Returns an array with maps for annotations, getters and setters. Keys in
050: * each map are field names.
051: */
052: protected static final Map[] getFieldsMaps(final Class objectClass) {
053: final Method[] methods = objectClass.getMethods();
054:
055: // create map with all getters and setters
056:
057: final Map<String, Method[]> allMethods = new HashMap();
058: for (Method method : methods) {
059: final String name = method.getName();
060: final String suffix = name.substring(3);
061:
062: Method[] getterSetter = allMethods.get(suffix);
063: if (getterSetter == null) {
064: getterSetter = new Method[2];
065: allMethods.put(suffix, getterSetter);
066: }
067:
068: if (name.startsWith("get")) {
069: getterSetter[0] = method;
070: } else if (name.startsWith("set")) {
071: getterSetter[1] = method;
072: }
073: }
074:
075: // assemble annotations, getters and setters maps
076: // a field is only taken into consideration if it has a getter and a
077: // setter
078:
079: final Map<String, net.sf.persist.annotations.Column> annotationsMap = new HashMap();
080: final Map<String, Method> gettersMap = new HashMap();
081: final Map<String, Method> settersMap = new HashMap();
082:
083: for (String suffix : allMethods.keySet()) {
084:
085: final Method[] getterSetter = allMethods.get(suffix);
086:
087: // only consider fields to have both getters and setters
088: if (getterSetter[0] != null && getterSetter[1] != null) {
089:
090: // field name (prefix with first char in lower case)
091: final String fieldName = suffix.substring(0, 1)
092: .toLowerCase()
093: + suffix.substring(1);
094:
095: // column annotation
096: final net.sf.persist.annotations.Column getterAnnotation = getterSetter[0]
097: .getAnnotation(net.sf.persist.annotations.Column.class);
098: final net.sf.persist.annotations.Column setterAnnotation = getterSetter[1]
099: .getAnnotation(net.sf.persist.annotations.Column.class);
100:
101: // if NoColumn is specified, don't use the field
102: final net.sf.persist.annotations.NoColumn noPersistGetter = getterSetter[0]
103: .getAnnotation(net.sf.persist.annotations.NoColumn.class);
104:
105: final net.sf.persist.annotations.NoColumn noPersistSetter = getterSetter[1]
106: .getAnnotation(net.sf.persist.annotations.NoColumn.class);
107:
108: // check conflicting NoColumn and Column annotations
109: if (noPersistGetter != null || noPersistSetter != null) {
110: if (getterAnnotation != null
111: || setterAnnotation != null) {
112: throw new PersistException(
113: "Field ["
114: + fieldName
115: + "] from class ["
116: + objectClass.getName()
117: + "] has conflicting NoColumn and Column annotations");
118: }
119: continue;
120: }
121:
122: // assert that getters and setters have valid and compatible
123: // types
124: if (getterSetter[1].getParameterTypes().length != 1) {
125: throw new PersistException(
126: "Setter ["
127: + getterSetter[1]
128: + "] should have a single parameter but has "
129: + getterSetter[1]
130: .getParameterTypes().length);
131: }
132: if (getterSetter[0].getReturnType() == void.class) {
133: throw new PersistException("Getter ["
134: + getterSetter[0]
135: + "] must have a return parameter");
136: }
137: if (getterSetter[0].getReturnType() != getterSetter[1]
138: .getParameterTypes()[0]) {
139: throw new PersistException("Getter ["
140: + getterSetter[0] + "] and setter ["
141: + getterSetter[1]
142: + "] have incompatible types");
143: }
144:
145: // check for annotations on the getter/setter
146: net.sf.persist.annotations.Column annotation = null;
147:
148: if (getterAnnotation != null
149: && setterAnnotation != null) {
150:
151: // if both getter and setter have annotations, make sure
152: // they are equals
153: if (!getterAnnotation.equals(setterAnnotation)) {
154:
155: final String getterAnn = getterAnnotation
156: .toString().substring(
157: getterAnnotation.toString()
158: .indexOf('(') + 1,
159: getterAnnotation.toString()
160: .lastIndexOf(')'));
161:
162: final String setterAnn = setterAnnotation
163: .toString().substring(
164: setterAnnotation.toString()
165: .indexOf('(') + 1,
166: setterAnnotation.toString()
167: .lastIndexOf(')'));
168:
169: throw new PersistException(
170: "Annotations for getter ["
171: + getterSetter[0]
172: + "] and setter ["
173: + getterSetter[1]
174: + "] have different annotations ["
175: + getterAnn + "] [" + setterAnn
176: + "]");
177: }
178:
179: annotation = getterAnnotation;
180: } else if (getterAnnotation != null) {
181: annotation = getterAnnotation;
182: } else if (setterAnnotation != null) {
183: annotation = setterAnnotation;
184: }
185:
186: // make getter and setter accessible
187: getterSetter[0].setAccessible(true);
188: getterSetter[1].setAccessible(true);
189:
190: annotationsMap.put(fieldName, annotation);
191: gettersMap.put(fieldName, getterSetter[0]);
192: settersMap.put(fieldName, getterSetter[1]);
193: }
194: }
195:
196: return new Map[] { annotationsMap, gettersMap, settersMap };
197: }
198:
199: }
|