001: /*
002: $Header: /cvsroot/xorm/xorm/src/org/xorm/util/FieldDescriptor.java,v 1.6 2004/04/13 08:43:07 radzimir Exp $
003:
004: This file is part of XORM.
005:
006: XORM is free software; you can redistribute it and/or modify
007: it under the terms of the GNU General Public License as published by
008: the Free Software Foundation; either version 2 of the License, or
009: (at your option) any later version.
010:
011: XORM is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: GNU General Public License for more details.
015:
016: You should have received a copy of the GNU General Public License
017: along with XORM; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020: package org.xorm.util;
021:
022: import java.beans.IndexedPropertyDescriptor;
023: import java.beans.Introspector;
024: import java.beans.PropertyDescriptor;
025: import java.lang.reflect.Method;
026: import java.lang.reflect.Modifier;
027: import java.util.Collection;
028: import java.util.HashMap;
029: import java.util.Iterator;
030: import java.util.Map;
031:
032: import javax.jdo.JDOFatalUserException;
033:
034: import org.xorm.I15d;
035: import org.xorm.ModelMapping;
036: import org.xorm.util.jdoxml.JDOExtension;
037: import org.xorm.util.jdoxml.JDOField;
038:
039: /** Similar to PropertyDescriptor, but may reflect non-public methods. */
040: public class FieldDescriptor implements I15d {
041: public String name;
042: public Class type;
043: public Class abstractClass;
044: public Method readMethod;
045: public Method writeMethod;
046:
047: public FieldDescriptor(String name, Class type) {
048: this .name = name;
049: this .type = type;
050: }
051:
052: public FieldDescriptor(PropertyDescriptor propDesc) {
053: name = propDesc.getName();
054: if (propDesc instanceof IndexedPropertyDescriptor) {
055: type = ((IndexedPropertyDescriptor) propDesc)
056: .getIndexedPropertyType();
057: } else {
058: type = propDesc.getPropertyType();
059: }
060:
061: readMethod = propDesc.getReadMethod();
062: writeMethod = propDesc.getWriteMethod();
063: }
064:
065: public boolean equals(Object o) {
066: if ((o == null) || (!(o instanceof FieldDescriptor)))
067: return false;
068: FieldDescriptor other = (FieldDescriptor) o;
069: return ((other.name.equals(name)) && (other.type.equals(type)));
070: }
071:
072: public int hashCode() {
073: return name.hashCode() + type.hashCode();
074: }
075:
076: /**
077: * Returns a Collection of all FieldDescriptors that are eligible for
078: * persistence. The Class argument may be an interface or an abstract
079: * class.
080: *
081: * @return a Collection<FieldDescriptor>
082: */
083: public static Collection getFieldDescriptors(Class clazz) {
084: Map nameToDescriptor = new HashMap();
085: findLocalFieldDescriptors(clazz, nameToDescriptor);
086:
087: // Remove the "null" fake entry
088: Collection values = nameToDescriptor.values();
089: while (values.contains(null)) {
090: values.remove(null);
091: }
092: return values;
093: }
094:
095: /**
096: * Iteratively derives all get/set methods for the class, by examining
097: * its superclass, its interfaces, and itself.
098: */
099: private static void findLocalFieldDescriptors(Class clazz,
100: Map nameToDescriptor) {
101: Class temp = clazz.getSuperclass();
102: if (temp != null && !temp.equals(Object.class)) {
103: findLocalFieldDescriptors(temp, nameToDescriptor);
104: }
105: Class[] faces = clazz.getInterfaces();
106: for (int i = 0; i < faces.length; i++) {
107: findLocalFieldDescriptors(faces[i], nameToDescriptor);
108: }
109:
110: Method[] methods = clazz.getDeclaredMethods();
111: for (int i = 0; i < methods.length; i++) {
112: Method m = methods[i];
113: /*
114: Because there can be abstract methods in superclasses
115: that should not be viewed as XORM properties, we need
116: to keep track of both abstract and non-abstract
117: accessors and mutators as we walk the class hierarchy.
118: */
119: int mods = m.getModifiers();
120:
121: // Methods that are private, static or native will never be
122: // available for use by XORM.
123:
124: if (!(Modifier.isPrivate(mods) || Modifier.isStatic(mods) || Modifier
125: .isNative(mods))) {
126: Class type = m.getReturnType();
127: boolean getter = false;
128: String methodName = m.getName();
129: String field = null;
130: if (!type.equals(Void.TYPE)) {
131: /*
132: if (m.getParameterTypes().length == 0) {
133: */
134: if (methodName.startsWith("get")) {
135: getter = true;
136: field = methodName.substring(3);
137: } else if ((type.equals(Boolean.TYPE) || type
138: .equals(Boolean.class))
139: && methodName.startsWith("is")) {
140: getter = true;
141: field = methodName.substring(2);
142: }
143: /*
144: } // else other non-void-type method
145: */
146: } else if (m.getParameterTypes().length == 1) {
147: if (methodName.startsWith("set")) {
148: type = m.getParameterTypes()[0];
149: getter = false;
150: field = methodName.substring(3);
151: }
152: }
153: if (field != null) {
154: // Need to properly decapitalize
155: field = Introspector.decapitalize(field);
156:
157: // If it's non-abstract, exclude it from the possibilities
158: if (!Modifier.isAbstract(mods)) {
159: // Mark the method as not persistable
160: nameToDescriptor.put(field, null);
161: } else {
162: FieldDescriptor fd = null;
163: if (nameToDescriptor.containsKey(field)) {
164: fd = (FieldDescriptor) nameToDescriptor
165: .get(field);
166: if (fd != null) {
167: if (getter) {
168: fd.readMethod = m;
169: } else {
170: fd.writeMethod = m;
171: }
172: } // else it's blacklisted
173: } else {
174: // New field
175: fd = new FieldDescriptor(field, type);
176: if (getter) {
177: fd.readMethod = m;
178: } else {
179: fd.writeMethod = m;
180: }
181: nameToDescriptor.put(field, fd);
182: }
183: } // if an abstract method
184: } // if get or set
185: } // if method modifiers eligible
186: } // for each declared method
187: }
188:
189: }
|