001: //$Id: BasicPropertyAccessor.java 7516 2005-07-16 22:20:48Z oneovthafew $
002: package org.hibernate.property;
003:
004: import java.beans.Introspector;
005: import java.lang.reflect.InvocationTargetException;
006: import java.lang.reflect.Method;
007: import java.util.Map;
008:
009: import org.apache.commons.logging.Log;
010: import org.apache.commons.logging.LogFactory;
011:
012: import org.hibernate.HibernateException;
013: import org.hibernate.PropertyAccessException;
014: import org.hibernate.PropertyNotFoundException;
015: import org.hibernate.engine.SessionFactoryImplementor;
016: import org.hibernate.engine.SessionImplementor;
017: import org.hibernate.util.ReflectHelper;
018:
019: /**
020: * Accesses property values via a get/set pair, which may be nonpublic.
021: * The default (and recommended strategy).
022: * @author Gavin King
023: */
024: public class BasicPropertyAccessor implements PropertyAccessor {
025:
026: private static final Log log = LogFactory
027: .getLog(BasicPropertyAccessor.class);
028:
029: public static final class BasicSetter implements Setter {
030: private Class clazz;
031: private final transient Method method;
032: private final String propertyName;
033:
034: private BasicSetter(Class clazz, Method method,
035: String propertyName) {
036: this .clazz = clazz;
037: this .method = method;
038: this .propertyName = propertyName;
039: }
040:
041: public void set(Object target, Object value,
042: SessionFactoryImplementor factory)
043: throws HibernateException {
044: try {
045: method.invoke(target, new Object[] { value });
046: } catch (NullPointerException npe) {
047: if (value == null
048: && method.getParameterTypes()[0].isPrimitive()) {
049: throw new PropertyAccessException(
050: npe,
051: "Null value was assigned to a property of primitive type",
052: true, clazz, propertyName);
053: } else {
054: throw new PropertyAccessException(
055: npe,
056: "NullPointerException occurred while calling",
057: true, clazz, propertyName);
058: }
059: } catch (InvocationTargetException ite) {
060: throw new PropertyAccessException(ite,
061: "Exception occurred inside", true, clazz,
062: propertyName);
063: } catch (IllegalAccessException iae) {
064: throw new PropertyAccessException(
065: iae,
066: "IllegalAccessException occurred while calling",
067: true, clazz, propertyName);
068: //cannot occur
069: } catch (IllegalArgumentException iae) {
070: if (value == null
071: && method.getParameterTypes()[0].isPrimitive()) {
072: throw new PropertyAccessException(
073: iae,
074: "Null value was assigned to a property of primitive type",
075: true, clazz, propertyName);
076: } else {
077: log.error("IllegalArgumentException in class: "
078: + clazz.getName()
079: + ", setter method of property: "
080: + propertyName);
081: log.error("expected type: "
082: + method.getParameterTypes()[0].getName()
083: + ", actual value: "
084: + (value == null ? null : value.getClass()
085: .getName()));
086: throw new PropertyAccessException(
087: iae,
088: "IllegalArgumentException occurred while calling",
089: true, clazz, propertyName);
090: }
091: }
092: }
093:
094: public Method getMethod() {
095: return method;
096: }
097:
098: public String getMethodName() {
099: return method.getName();
100: }
101:
102: Object readResolve() {
103: return createSetter(clazz, propertyName);
104: }
105:
106: public String toString() {
107: return "BasicSetter(" + clazz.getName() + '.'
108: + propertyName + ')';
109: }
110: }
111:
112: public static final class BasicGetter implements Getter {
113: private Class clazz;
114: private final transient Method method;
115: private final String propertyName;
116:
117: private BasicGetter(Class clazz, Method method,
118: String propertyName) {
119: this .clazz = clazz;
120: this .method = method;
121: this .propertyName = propertyName;
122: }
123:
124: public Object get(Object target) throws HibernateException {
125: try {
126: return method.invoke(target, null);
127: } catch (InvocationTargetException ite) {
128: throw new PropertyAccessException(ite,
129: "Exception occurred inside", false, clazz,
130: propertyName);
131: } catch (IllegalAccessException iae) {
132: throw new PropertyAccessException(
133: iae,
134: "IllegalAccessException occurred while calling",
135: false, clazz, propertyName);
136: //cannot occur
137: } catch (IllegalArgumentException iae) {
138: log.error("IllegalArgumentException in class: "
139: + clazz.getName()
140: + ", getter method of property: "
141: + propertyName);
142: throw new PropertyAccessException(iae,
143: "IllegalArgumentException occurred calling",
144: false, clazz, propertyName);
145: }
146: }
147:
148: public Object getForInsert(Object target, Map mergeMap,
149: SessionImplementor session) {
150: return get(target);
151: }
152:
153: public Class getReturnType() {
154: return method.getReturnType();
155: }
156:
157: public Method getMethod() {
158: return method;
159: }
160:
161: public String getMethodName() {
162: return method.getName();
163: }
164:
165: public String toString() {
166: return "BasicGetter(" + clazz.getName() + '.'
167: + propertyName + ')';
168: }
169:
170: Object readResolve() {
171: return createGetter(clazz, propertyName);
172: }
173: }
174:
175: public Setter getSetter(Class theClass, String propertyName)
176: throws PropertyNotFoundException {
177: return createSetter(theClass, propertyName);
178: }
179:
180: private static Setter createSetter(Class theClass,
181: String propertyName) throws PropertyNotFoundException {
182: BasicSetter result = getSetterOrNull(theClass, propertyName);
183: if (result == null) {
184: throw new PropertyNotFoundException(
185: "Could not find a setter for property "
186: + propertyName + " in class "
187: + theClass.getName());
188: }
189: return result;
190: }
191:
192: private static BasicSetter getSetterOrNull(Class theClass,
193: String propertyName) {
194:
195: if (theClass == Object.class || theClass == null)
196: return null;
197:
198: Method method = setterMethod(theClass, propertyName);
199:
200: if (method != null) {
201: if (!ReflectHelper.isPublic(theClass, method))
202: method.setAccessible(true);
203: return new BasicSetter(theClass, method, propertyName);
204: } else {
205: BasicSetter setter = getSetterOrNull(theClass
206: .getSuperclass(), propertyName);
207: if (setter == null) {
208: Class[] interfaces = theClass.getInterfaces();
209: for (int i = 0; setter == null && i < interfaces.length; i++) {
210: setter = getSetterOrNull(interfaces[i],
211: propertyName);
212: }
213: }
214: return setter;
215: }
216:
217: }
218:
219: private static Method setterMethod(Class theClass,
220: String propertyName) {
221:
222: BasicGetter getter = getGetterOrNull(theClass, propertyName);
223: Class returnType = (getter == null) ? null : getter
224: .getReturnType();
225:
226: Method[] methods = theClass.getDeclaredMethods();
227: Method potentialSetter = null;
228: for (int i = 0; i < methods.length; i++) {
229: String methodName = methods[i].getName();
230:
231: if (methods[i].getParameterTypes().length == 1
232: && methodName.startsWith("set")) {
233: String testStdMethod = Introspector
234: .decapitalize(methodName.substring(3));
235: String testOldMethod = methodName.substring(3);
236: if (testStdMethod.equals(propertyName)
237: || testOldMethod.equals(propertyName)) {
238: potentialSetter = methods[i];
239: if (returnType == null
240: || methods[i].getParameterTypes()[0]
241: .equals(returnType)) {
242: return potentialSetter;
243: }
244: }
245: }
246: }
247: return potentialSetter;
248: }
249:
250: public Getter getGetter(Class theClass, String propertyName)
251: throws PropertyNotFoundException {
252: return createGetter(theClass, propertyName);
253: }
254:
255: public static Getter createGetter(Class theClass,
256: String propertyName) throws PropertyNotFoundException {
257: BasicGetter result = getGetterOrNull(theClass, propertyName);
258: if (result == null) {
259: throw new PropertyNotFoundException(
260: "Could not find a getter for " + propertyName
261: + " in class " + theClass.getName());
262: }
263: return result;
264:
265: }
266:
267: private static BasicGetter getGetterOrNull(Class theClass,
268: String propertyName) {
269:
270: if (theClass == Object.class || theClass == null)
271: return null;
272:
273: Method method = getterMethod(theClass, propertyName);
274:
275: if (method != null) {
276: if (!ReflectHelper.isPublic(theClass, method))
277: method.setAccessible(true);
278: return new BasicGetter(theClass, method, propertyName);
279: } else {
280: BasicGetter getter = getGetterOrNull(theClass
281: .getSuperclass(), propertyName);
282: if (getter == null) {
283: Class[] interfaces = theClass.getInterfaces();
284: for (int i = 0; getter == null && i < interfaces.length; i++) {
285: getter = getGetterOrNull(interfaces[i],
286: propertyName);
287: }
288: }
289: return getter;
290: }
291: }
292:
293: private static Method getterMethod(Class theClass,
294: String propertyName) {
295:
296: Method[] methods = theClass.getDeclaredMethods();
297: for (int i = 0; i < methods.length; i++) {
298: // only carry on if the method has no parameters
299: if (methods[i].getParameterTypes().length == 0) {
300: String methodName = methods[i].getName();
301:
302: // try "get"
303: if (methodName.startsWith("get")) {
304: String testStdMethod = Introspector
305: .decapitalize(methodName.substring(3));
306: String testOldMethod = methodName.substring(3);
307: if (testStdMethod.equals(propertyName)
308: || testOldMethod.equals(propertyName)) {
309: return methods[i];
310: }
311:
312: }
313:
314: // if not "get" then try "is"
315: /*boolean isBoolean = methods[i].getReturnType().equals(Boolean.class) ||
316: methods[i].getReturnType().equals(boolean.class);*/
317: if (methodName.startsWith("is")) {
318: String testStdMethod = Introspector
319: .decapitalize(methodName.substring(2));
320: String testOldMethod = methodName.substring(2);
321: if (testStdMethod.equals(propertyName)
322: || testOldMethod.equals(propertyName)) {
323: return methods[i];
324: }
325: }
326: }
327: }
328: return null;
329: }
330:
331: }
|