From 0e7feca04a29f354abc476d55252bab968a87f3f Mon Sep 17 00:00:00 2001 From: Patrick Linskey Date: Tue, 24 Apr 2007 23:34:46 +0000 Subject: [PATCH] OPENJPA-219. Avoid Class.getDeclaredField() / Class.getDeclaredMethod() in Reflection, since they throw exceptions as a side-effect. Also contains assorted clean-up in ClassMetaData. git-svn-id: https://svn.apache.org/repos/asf/incubator/openjpa/trunk@532137 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/openjpa/enhance/PCEnhancer.java | 11 +-- .../apache/openjpa/enhance/Reflection.java | 87 ++++++++++++++----- .../apache/openjpa/meta/ClassMetaData.java | 33 +++---- 3 files changed, 82 insertions(+), 49 deletions(-) diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java index 991c463b1..64c5b759f 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java @@ -687,15 +687,8 @@ public class PCEnhancer { Class owner) { // find the actual ancestor class that declares the field, then // check if the class is persistent, and if the field is managed - for (; !owner.getName().equals(Object.class.getName()); - owner = owner.getSuperclass()) { - try { - owner.getDeclaredField(fieldName); - break; - } catch (Exception e) { - } - } - if (owner.getName().equals(Object.class.getName())) + Field f = Reflection.findField(owner, fieldName, false); + if (f == null) return null; // managed interface diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java index 30e6d92b6..414e453ff 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java @@ -47,20 +47,20 @@ public class Reflection { public static Method findGetter(Class cls, String prop, boolean mustExist) { prop = StringUtils.capitalize(prop); String name = "get" + prop; + Method m; try { - for (Class c = cls; c != null && c != Object.class; + // this algorithm searches for a get or is method in + // a breadth-first manner. + for (Class c = cls; c != null && c != Object.class; c = c.getSuperclass()) { - try { - return c.getDeclaredMethod(name, (Class[]) null); - } catch (NoSuchMethodException nsme) { - try { - Method m = c.getDeclaredMethod("is" + prop, - (Class[]) null); - if (m != null && (m.getReturnType() == boolean.class - || m.getReturnType() == Boolean.class)) - return m; - } catch (NoSuchMethodException nsme2) { - } + m = getDeclaredMethod(c, name, null); + if (m != null) { + return m; + } else { + m = getDeclaredMethod(c, "is" + prop, null); + if (m != null && (m.getReturnType() == boolean.class + || m.getReturnType() == Boolean.class)) + return m; } } } catch (Exception e) { @@ -89,14 +89,13 @@ public class Reflection { public static Method findSetter(Class cls, String prop, Class param, boolean mustExist) { String name = "set" + StringUtils.capitalize(prop); - Class[] params = new Class[] { param }; + Method m; try { - for (Class c = cls; c != null && c != Object.class; + for (Class c = cls; c != null && c != Object.class; c = c.getSuperclass()) { - try { - return c.getDeclaredMethod(name, params); - } catch (NoSuchMethodException nsme) { - } + m = getDeclaredMethod(c, name, param); + if (m != null) + return m; } } catch (Exception e) { throw new GeneralException(e); @@ -108,17 +107,41 @@ public class Reflection { } /** - * Return the field with the given name, optionally throwing an exception + * Invokes cls.getDeclaredMethods(), and returns the method + * that matches the name and param arguments. + * Avoids the exception thrown by Class.getDeclaredMethod() + * for performance reasons. param may be null. + * + * @since 0.9.8 + */ + private static Method getDeclaredMethod(Class cls, String name, + Class param) { + Method[] methods = cls.getDeclaredMethods(); + for (int i = 0 ; i < methods.length; i++) { + if (name.equals(methods[i].getName())) { + Class[] methodParams = methods[i].getParameterTypes(); + if (param == null && methodParams.length == 0) + return methods[i]; + if (param != null && methodParams.length == 1 + && param.equals(methodParams[0])) + return methods[i]; + } + } + return null; + } + + /** + * Return the field with the given name, optionally throwing an exception * if none. */ public static Field findField(Class cls, String name, boolean mustExist) { try { - for (Class c = cls; c != null && c != Object.class; + Field f; + for (Class c = cls; c != null && c != Object.class; c = c.getSuperclass()) { - try { - return c.getDeclaredField(name); - } catch (NoSuchFieldException nsfe) { - } + f = getDeclaredField(c, name); + if (f != null) + return f; } } catch (Exception e) { throw new GeneralException(e); @@ -129,6 +152,22 @@ public class Reflection { return null; } + /** + * Invokes cls.getDeclaredFields(), and returns the field + * that matches the name argument. Avoids the exception + * thrown by Class.getDeclaredField() for performance reasons. + * + * @since 0.9.8 + */ + private static Field getDeclaredField(Class cls, String name) { + Field[] fields = cls.getDeclaredFields(); + for (int i = 0 ; i < fields.length; i++) { + if (name.equals(fields[i].getName())) + return fields[i]; + } + return null; + } + /** * Return the value of the given field in the given object. */ diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java index e3cbd0d31..ada6e9a3a 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java @@ -55,7 +55,6 @@ import org.apache.openjpa.util.InternalException; import org.apache.openjpa.util.LongId; import org.apache.openjpa.util.MetaDataException; import org.apache.openjpa.util.ObjectId; -import org.apache.openjpa.util.OpenJPAException; import org.apache.openjpa.util.OpenJPAId; import org.apache.openjpa.util.ShortId; import org.apache.openjpa.util.StringId; @@ -117,6 +116,10 @@ public class ClassMetaData private static final Localizer _loc = Localizer.forPackage (ClassMetaData.class); + private static final FetchGroup[] EMPTY_FETCH_GROUP_ARRAY + = new FetchGroup[0]; + private static final String[] EMPTY_STRING_ARRAY = new String[0]; + private MetaDataRepository _repos; private transient ClassLoader _loader = null; @@ -784,8 +787,9 @@ public class ClassMetaData synchronized (_ifaceMap) { Map fields = (Map) _ifaceMap.get(iface); if (fields == null) - return new String[0]; - return (String[]) fields.keySet().toArray(new String[0]); + return EMPTY_STRING_ARRAY; + return (String[]) fields.keySet().toArray( + new String[fields.size()]); } } @@ -1397,15 +1401,12 @@ public class ClassMetaData if (fieldName == null || SYNTHETIC.equals(fieldName)) return null; - for (Class type = _type; type != null && type != Object.class; - type = type.getSuperclass()) { - try { - return type.getDeclaredField(fieldName); - } catch (Exception e) { - } - } - throw new MetaDataException(_loc.get("no-detach-state", fieldName, - _type)); + Field f = Reflection.findField(_type, fieldName, false); + if (f != null) + return f; + else + throw new MetaDataException( + _loc.get("no-detach-state", fieldName, _type)); } /** @@ -1823,7 +1824,7 @@ public class ClassMetaData ClassMetaData embed = pks[0].getEmbeddedMetaData(); validateAppIdClassMethods(embed.getDescribedType()); validateAppIdClassPKs(embed, embed.getFields(), - embed.getDescribedType(), runtime); + embed.getDescribedType()); } return; } @@ -1850,7 +1851,7 @@ public class ClassMetaData validateAppIdClassMethods(_objectId); // make sure the app id class has all pk fields - validateAppIdClassPKs(this, pks, _objectId, runtime); + validateAppIdClassPKs(this, pks, _objectId); } } @@ -1904,7 +1905,7 @@ public class ClassMetaData * Validate that the primary key class has all pk fields. */ private void validateAppIdClassPKs(ClassMetaData meta, - FieldMetaData[] fmds, Class oid, boolean runtime) { + FieldMetaData[] fmds, Class oid) { if (fmds.length == 0 && !Modifier.isAbstract(meta.getDescribedType(). getModifiers())) throw new MetaDataException(_loc.get("no-pk", _type)); @@ -2012,7 +2013,7 @@ public class ClassMetaData */ public FetchGroup[] getDeclaredFetchGroups() { if (_fgs == null) - _fgs = (_fgMap == null) ? new FetchGroup[0] : (FetchGroup[]) + _fgs = (_fgMap == null) ? EMPTY_FETCH_GROUP_ARRAY : (FetchGroup[]) _fgMap.values().toArray(new FetchGroup[_fgMap.size()]); return _fgs; }