From aecff50b27d17904a7b9cb6de00df032f01425dd Mon Sep 17 00:00:00 2001 From: "A. Abram White" Date: Thu, 21 Dec 2006 17:08:38 +0000 Subject: [PATCH] Stop enhancing entity identity classes to make non-public properties public for access by the various identity object manipulation methods of the enhanced entity class. This caused problems with runtime enhancement if the identity class was loaded before the entity class. Instead, rely on reflection to access non-public identity class members. git-svn-id: https://svn.apache.org/repos/asf/incubator/openjpa/trunk@489408 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/openjpa/enhance/PCEnhancer.java | 276 ++++----- .../apache/openjpa/enhance/PCRegistry.java | 16 +- .../apache/openjpa/enhance/Reflection.java | 537 ++++++++++++++++++ .../org/apache/openjpa/kernel/Filters.java | 40 +- .../openjpa/kernel/ObjectIdStateManager.java | 56 +- .../apache/openjpa/kernel/ResultPacker.java | 5 +- .../meta/AbstractMetaDataDefaults.java | 47 +- .../apache/openjpa/meta/ClassMetaData.java | 125 ++-- .../apache/openjpa/util/ApplicationIds.java | 151 ++--- .../org/apache/openjpa/util/ImplHelper.java | 33 -- .../openjpa/enhance/localizer.properties | 9 +- .../openjpa/kernel/localizer.properties | 6 +- .../apache/openjpa/meta/localizer.properties | 12 +- .../apache/openjpa/util/localizer.properties | 2 - .../persistence/EntityManagerFactoryImpl.java | 12 +- .../PersistenceMetaDataDefaults.java | 5 +- 16 files changed, 821 insertions(+), 511 deletions(-) create mode 100644 openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java 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 1a2b78536..2c4446b47 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 @@ -101,7 +101,6 @@ public class PCEnhancer { public static final int ENHANCE_AWARE = 2 << 0; public static final int ENHANCE_INTERFACE = 2 << 1; public static final int ENHANCE_PC = 2 << 2; - public static final int ENHANCE_OID = 2 << 3; private static final String PRE = "pc"; private static final Class PCTYPE = PersistenceCapable.class; @@ -205,14 +204,6 @@ public class PCEnhancer { return _pc; } - /** - * Return the bytecode representations of any oid classes that must be - * manipulated. - */ - public Collection getObjectIdBytecode() { - return (_oids == null) ? Collections.EMPTY_LIST : _oids; - } - /** * Return the metadata for the class being manipulated, or null if not * a persistent type. @@ -311,8 +302,6 @@ public class PCEnhancer { if (interfaces[i].getName().equals(PCTYPE.getName())) { if (_log.isTraceEnabled()) _log.trace(_loc.get("pc-type", _pc.getType())); - if (_meta != null && enhanceObjectId()) - return ENHANCE_OID; return ENHANCE_NONE; } } @@ -335,8 +324,6 @@ public class PCEnhancer { addAttachDetachCode(); addSerializationCode(); addCloningCode(); - if (enhanceObjectId()) - ret |= ENHANCE_OID; runAuxiliaryEnhancers(); return ret; } @@ -1535,14 +1522,43 @@ public class PCEnhancer { FieldMetaData[] fmds = _meta.getDeclaredFields(); Class type; String name; + Field field; + Method setter; + boolean reflect; for (int i = 0; i < fmds.length; i++) { if (!fmds[i].isPrimaryKey()) continue; + code.aload().setLocal(id); name = fmds[i].getName(); type = fmds[i].getObjectIdFieldType(); + if (_meta.getAccessType() == ClassMetaData.ACCESS_FIELD) { + setter = null; + field = Reflection.findField(oidType, name, true); + reflect = !Modifier.isPublic(field.getModifiers()); + if (reflect) { + code.constant().setValue(oidType); + code.constant().setValue(name); + code.constant().setValue(true); + code.invokestatic().setMethod(Reflection.class, + "findField", Field.class, new Class[] { Class.class, + String.class, boolean.class }); + } + } else { + field = null; + setter = Reflection.findSetter(oidType, name, type, true); + reflect = !Modifier.isPublic(setter.getModifiers()); + if (reflect) { + code.constant().setValue(oidType); + code.constant().setValue(name); + setClassConstant(code, type); + code.constant().setValue(true); + code.invokestatic().setMethod(Reflection.class, + "findSetter", Method.class, new Class[] { Class.class, + String.class, Class.class, boolean.class }); + } + } - code.aload().setLocal(id); if (fieldManager) { code.aload().setParam(0); code.constant().setValue(i); @@ -1554,7 +1570,7 @@ public class PCEnhancer { // if the type of this field meta data is // non-primitive and non-string, be sure to cast // to the appropriate type. - if (!type.isPrimitive() + if (!reflect && !type.isPrimitive() && !type.getName().equals(String.class.getName())) code.checkcast().setType(type); } else { @@ -1566,12 +1582,18 @@ public class PCEnhancer { addExtractObjectIdFieldValueCode(code, fmds[i]); } - if (_meta.getAccessType() == ClassMetaData.ACCESS_FIELD) - code.putfield().setField(findDeclaredField(oidType, name)); + if (reflect && field != null) { + code.invokestatic().setMethod(Reflection.class, "set", + void.class, new Class[] { Object.class, Field.class, + (type.isPrimitive()) ? type : Object.class }); + } else if (reflect) { + code.invokestatic().setMethod(Reflection.class, "set", + void.class, new Class[] { Object.class, Method.class, + (type.isPrimitive()) ? type : Object.class }); + } else if (field != null) + code.putfield().setField(field); else - code.invokevirtual().setMethod(findDeclaredMethod - (oidType, "set" + StringUtils.capitalize(name), - new Class[]{ type })); + code.invokevirtual().setMethod(setter); } code.vreturn(); @@ -1579,6 +1601,30 @@ public class PCEnhancer { code.calculateMaxLocals(); } + /** + * Works around a bug in serp when primitive type constants. + */ + private static void setClassConstant(Code code, Class type) { + if (type == boolean.class) + code.getstatic().setField(Boolean.class, "TYPE", Class.class); + else if (type == byte.class) + code.getstatic().setField(Byte.class, "TYPE", Class.class); + else if (type == char.class) + code.getstatic().setField(Character.class, "TYPE", Class.class); + else if (type == double.class) + code.getstatic().setField(Double.class, "TYPE", Class.class); + else if (type == float.class) + code.getstatic().setField(Float.class, "TYPE", Class.class); + else if (type == int.class) + code.getstatic().setField(Integer.class, "TYPE", Class.class); + else if (type == long.class) + code.getstatic().setField(Long.class, "TYPE", Class.class); + else if (type == short.class) + code.getstatic().setField(Short.class, "TYPE", Class.class); + else + code.constant().setValue(type); + } + /** * Add code to extract the id of the given primary key relation field for * setting into an objectid instance. @@ -1788,9 +1834,11 @@ public class PCEnhancer { // this. = id. // or for single field identity: id.getId () FieldMetaData[] fmds = _meta.getDeclaredFields(); + String name; Class type; Class unwrapped; - String name; + Field field; + Method getter; for (int i = 0; i < fmds.length; i++) { if (!fmds[i].isPrimaryKey()) continue; @@ -1840,11 +1888,41 @@ public class PCEnhancer { code.invokespecial().setMethod(type, "", void.class, new Class[]{ unwrapped }); } - } else if (_meta.getAccessType() == ClassMetaData.ACCESS_FIELD) - code.getfield().setField(findDeclaredField(oidType, name)); - else // property - code.invokevirtual().setMethod(findDeclaredGetterMethod - (oidType, StringUtils.capitalize(name))); + } else if (_meta.getAccessType() == ClassMetaData.ACCESS_FIELD){ + field = Reflection.findField(oidType, name, true); + if (Modifier.isPublic(field.getModifiers())) + code.getfield().setField(field); + else { + // Reflection.getXXX(oid, Reflection.findField(...)); + code.constant().setValue(oidType); + code.constant().setValue(name); + code.constant().setValue(true); + code.invokestatic().setMethod(Reflection.class, + "findField", Field.class, new Class[] { + Class.class, String.class, boolean.class }); + code.invokestatic().setMethod + (getReflectionGetterMethod(type, Field.class)); + if (!type.isPrimitive() && type != Object.class) + code.checkcast().setType(type); + } + } else { + getter = Reflection.findGetter(oidType, name, true); + if (Modifier.isPublic(getter.getModifiers())) + code.invokevirtual().setMethod(getter); + else { + // Reflection.getXXX(oid, Reflection.findGetter(...)); + code.constant().setValue(oidType); + code.constant().setValue(name); + code.constant().setValue(true); + code.invokestatic().setMethod(Reflection.class, + "findGetter", Method.class, new Class[] { + Class.class, String.class, boolean.class }); + code.invokestatic().setMethod + (getReflectionGetterMethod(type, Method.class)); + if (!type.isPrimitive() && type != Object.class) + code.checkcast().setType(type); + } + } } if (fieldManager) @@ -1910,6 +1988,19 @@ public class PCEnhancer { } } + /** + * Return the proper getter method of the {@link Reflection} helper for + * a field or getter method of the given type. + */ + private Method getReflectionGetterMethod(Class type, Class argType) + throws NoSuchMethodException { + String name = "get"; + if (type.isPrimitive()) + name += StringUtils.capitalize(type.getName()); + return Reflection.class.getMethod(name, new Class[] { Object.class, + argType }); + } + /** * Return the proper fetch method of the ObjectIdFieldSupplier for * a field of the given type. @@ -2727,123 +2818,6 @@ public class PCEnhancer { } } - /** - * Enhance the PC's object id class. - */ - private boolean enhanceObjectId() - throws IOException { - Class cls = _meta.getObjectIdType(); - if (cls == null) - return false; - - FieldMetaData[] pks = _meta.getPrimaryKeyFields(); - int access = _meta.getAccessType(); - if (_meta.isOpenJPAIdentity()) { - if (pks[0].getDeclaredTypeCode() != JavaTypes.OID) - return false; - cls = pks[0].getDeclaredType(); - access = pks[0].getEmbeddedMetaData().getAccessType(); - pks = pks[0].getEmbeddedMetaData().getFields(); - } - - String cap; - for (int i = 0; i < pks.length; i++) { - if (access == ClassMetaData.ACCESS_FIELD) - makeObjectIdFieldPublic(findDeclaredField(cls, - pks[i].getName())); - else // property - { - cap = StringUtils.capitalize(pks[i].getName()); - makeObjectIdMethodPublic(findDeclaredGetterMethod(cls, cap)); - makeObjectIdMethodPublic(findDeclaredMethod(cls, "set" + cap, - new Class[]{ pks[i].getDeclaredType() })); - } - } - return _oids != null; - } - - /** - * Find the given (possibly private) field. - */ - private Field findDeclaredField(Class cls, String name) { - if (cls == null || cls == Object.class) - return null; - - try { - return cls.getDeclaredField(name); - } catch (NoSuchFieldException nsfe) { - return findDeclaredField(cls.getSuperclass(), name); - } catch (Exception e) { - throw new GeneralException(e); - } - } - - /** - * Return the getter method for the given capitalized property name. - */ - private Method findDeclaredGetterMethod(Class cls, String baseName) { - Method meth = findDeclaredMethod(cls, "get" + baseName, null); - if (meth != null) - return meth; - return findDeclaredMethod(_meta.getObjectIdType(), "is" + baseName, - null); - } - - /** - * Find the given (possibly private) method. - */ - private Method findDeclaredMethod(Class cls, String name, Class[] params) { - if (cls == null || cls == Object.class) - return null; - - try { - return cls.getDeclaredMethod(name, params); - } catch (NoSuchMethodException nsme) { - return findDeclaredMethod(cls.getSuperclass(), name, params); - } catch (Exception e) { - throw new GeneralException(e); - } - } - - /** - * Ensure that the given oid field is public. - */ - private void makeObjectIdFieldPublic(Field field) { - if (Modifier.isPublic(field.getModifiers())) - return; - - BCClass bc = getObjectIdBytecode(field.getDeclaringClass()); - bc.getDeclaredField(field.getName()).makePublic(); - } - - /** - * Ensure that the given oid method is public. - */ - private void makeObjectIdMethodPublic(Method meth) { - if (Modifier.isPublic(meth.getModifiers())) - return; - - BCClass bc = getObjectIdBytecode(meth.getDeclaringClass()); - bc.getDeclaredMethod(meth.getName(), meth.getParameterTypes()). - makePublic(); - } - - /** - * Return the bytecode for the given oid class, creating and caching it - * if necessary. - */ - private BCClass getObjectIdBytecode(Class cls) { - BCClass bc = _pc.getProject().loadClass(cls); - if (_oids == null) - _oids = new ArrayList(3); - if (!_oids.contains(bc)) { - if (_log.isTraceEnabled()) - _log.trace(_loc.get("enhance-oid", bc.getName())); - _oids.add(bc); - } - return bc; - } - /** * Gets the auxiliary enhancers registered as {@link Services services}. */ @@ -3716,22 +3690,8 @@ public class PCEnhancer { else if (status == ENHANCE_AWARE) { log.info(_loc.get("enhance-aware")); enhancer.record(); - } else { + } else enhancer.record(); - if ((status & ENHANCE_OID) != 0) { - if (log.isInfoEnabled()) { - Collection oids = enhancer.getObjectIdBytecode(); - StringBuffer buf = new StringBuffer(); - for (Iterator oiditr = oids.iterator(); - oiditr.hasNext();) { - buf.append(((BCClass) oiditr.next()).getName()); - if (oiditr.hasNext()) - buf.append(", "); - } - log.info(_loc.get("enhance-running-oids", buf)); - } - } - } project.clear(); } return true; diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java index dd4bb0523..c62e402aa 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java @@ -21,8 +21,10 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.Map; +import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.lib.util.ReferenceMap; import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap; +import org.apache.openjpa.util.UserException; /** * Tracks registered persistence-capable classes. @@ -33,14 +35,13 @@ import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap; public class PCRegistry { // DO NOT ADD ADDITIONAL DEPENDENCIES TO THIS CLASS - // intentionally left unlocalized to minimize dependencies - private static final String COPY_NO_ID = "Cannot copy identity for " - + "abstract class "; - private static final String NO_META = "No metadata found for class "; + private static final Localizer _loc = Localizer.forPackage + (PCRegistry.class); // map of pc classes to meta structs; weak so the VM can GC classes private static final Map _metas = new ConcurrentReferenceHashMap (ReferenceMap.WEAK, ReferenceMap.HARD); + // register class listeners private static final Collection _listeners = new LinkedList(); @@ -151,7 +152,7 @@ public class PCRegistry { Object oid) { Meta meta = getMeta(pcClass); if (meta.pc == null) - throw new IllegalStateException(COPY_NO_ID + pcClass.getName()); + throw new UserException(_loc.get("copy-no-id", pcClass)); meta.pc.pcCopyKeyFieldsToObjectId(fm, oid); } @@ -164,7 +165,7 @@ public class PCRegistry { FieldConsumer fm, Object oid) { Meta meta = getMeta(pcClass); if (meta.pc == null) - throw new IllegalStateException(COPY_NO_ID + pcClass.getName()); + throw new UserException(_loc.get("copy-no-id", pcClass)); meta.pc.pcCopyKeyFieldsFromObjectId(fm, oid); } @@ -219,7 +220,8 @@ public class PCRegistry { private static Meta getMeta(Class pcClass) { Meta ret = (Meta) _metas.get(pcClass); if (ret == null) - throw new IllegalStateException(NO_META + pcClass.getName()); + throw new IllegalStateException(_loc.get("no-meta", pcClass). + getMessage()); return ret; } 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 new file mode 100644 index 000000000..c038f74c9 --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java @@ -0,0 +1,537 @@ +package org.apache.openjpa.enhance; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.apache.commons.lang.StringUtils; +import org.apache.openjpa.lib.util.Localizer; +import org.apache.openjpa.util.GeneralException; +import org.apache.openjpa.util.UserException; + +/** + * Reflection utilities used to support and augment enhancement. Used both + * at enhancement time and at runtime. + * + * @author Abe White + */ +public class Reflection { + + private static final Localizer _loc = Localizer.forPackage + (Reflection.class); + + /** + * Return the getter method matching the given property name, optionally + * throwing an exception if none. + */ + public static Method findGetter(Class cls, String prop, boolean mustExist) { + prop = StringUtils.capitalize(prop); + String name = "get" + prop; + try { + 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) { + } + } + } + } catch (Exception e) { + throw new GeneralException(e); + } + + if (mustExist) + throw new UserException(_loc.get("bad-getter", cls, prop)); + return null; + } + + /** + * Return the setter method matching the given property name, optionally + * throwing an exception if none. The property must also have a getter. + */ + public static Method findSetter(Class cls, String prop, boolean mustExist) { + Method getter = findGetter(cls, prop, mustExist); + return (getter == null) ? null + : findSetter(cls, prop, getter.getReturnType(), mustExist); + } + + /** + * Return the setter method matching the given property name, optionally + * throwing an exception if none. + */ + public static Method findSetter(Class cls, String prop, Class param, + boolean mustExist) { + String name = "set" + StringUtils.capitalize(prop); + Class[] params = new Class[] { param }; + try { + for (Class c = cls; c != null && c != Object.class; + c = c.getSuperclass()) { + try { + return c.getDeclaredMethod(name, params); + } catch (NoSuchMethodException nsme) { + } + } + } catch (Exception e) { + throw new GeneralException(e); + } + + if (mustExist) + throw new UserException(_loc.get("bad-setter", cls, prop)); + 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; + c = c.getSuperclass()) { + try { + return c.getDeclaredField(name); + } catch (NoSuchFieldException nsfe) { + } + } + } catch (Exception e) { + throw new GeneralException(e); + } + + if (mustExist) + throw new UserException(_loc.get("bad-field", cls, name)); + return null; + } + + /** + * Return the value of the given field in the given object. + */ + public static Object get(Object target, Field field) { + if (target == null || field == null) + return null; + makeAccessible(field, field.getModifiers()); + try { + return field.get(target); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Make the given member accessible if it isn't already. + */ + private static void makeAccessible(AccessibleObject ao, int mods) { + try { + if (!Modifier.isPublic(mods) && !ao.isAccessible()) + ao.setAccessible(true); + } catch (SecurityException se) { + throw new UserException(_loc.get("reflect-security", ao)). + setFatal(true); + } + } + + /** + * Wrap the given reflection exception as a runtime exception. + */ + private static RuntimeException wrapReflectionException(Throwable t) { + if (t instanceof InvocationTargetException) + t = ((InvocationTargetException) t).getTargetException(); + if (t instanceof RuntimeException) + return (RuntimeException) t; + return new GeneralException(t); + } + + /** + * Return the value of the given field in the given object. + */ + public static boolean getBoolean(Object target, Field field) { + if (target == null || field == null) + return false; + makeAccessible(field, field.getModifiers()); + try { + return field.getBoolean(target); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Return the value of the given field in the given object. + */ + public static byte getByte(Object target, Field field) { + if (target == null || field == null) + return (byte) 0; + makeAccessible(field, field.getModifiers()); + try { + return field.getByte(target); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Return the value of the given field in the given object. + */ + public static char getChar(Object target, Field field) { + if (target == null || field == null) + return (char) 0; + makeAccessible(field, field.getModifiers()); + try { + return field.getChar(target); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Return the value of the given field in the given object. + */ + public static double getDouble(Object target, Field field) { + if (target == null || field == null) + return 0D; + makeAccessible(field, field.getModifiers()); + try { + return field.getDouble(target); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Return the value of the given field in the given object. + */ + public static float getFloat(Object target, Field field) { + if (target == null || field == null) + return 0F; + makeAccessible(field, field.getModifiers()); + try { + return field.getFloat(target); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Return the value of the given field in the given object. + */ + public static int getInt(Object target, Field field) { + if (target == null || field == null) + return 0; + makeAccessible(field, field.getModifiers()); + try { + return field.getInt(target); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Return the value of the given field in the given object. + */ + public static long getLong(Object target, Field field) { + if (target == null || field == null) + return 0L; + makeAccessible(field, field.getModifiers()); + try { + return field.getLong(target); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Return the value of the given field in the given object. + */ + public static short getShort(Object target, Field field) { + if (target == null || field == null) + return (short) 0; + makeAccessible(field, field.getModifiers()); + try { + return field.getShort(target); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Return the return value of the given getter in the given object. + */ + public static Object get(Object target, Method getter) { + if (target == null || getter == null) + return null; + makeAccessible(getter, getter.getModifiers()); + try { + return getter.invoke(target, (Object[]) null); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Return the return value of the given getter in the given object. + */ + public static boolean getBoolean(Object target, Method getter) { + Object o = get(target, getter); + return (o == null) ? false : ((Boolean) o).booleanValue(); + } + + /** + * Return the return value of the given getter in the given object. + */ + public static byte getByte(Object target, Method getter) { + Object o = get(target, getter); + return (o == null) ? (byte) 0 : ((Number) o).byteValue(); + } + + /** + * Return the return value of the given getter in the given object. + */ + public static char getChar(Object target, Method getter) { + Object o = get(target, getter); + return (o == null) ? (char) 0 : ((Character) o).charValue(); + } + + /** + * Return the return value of the given getter in the given object. + */ + public static double getDouble(Object target, Method getter) { + Object o = get(target, getter); + return (o == null) ? 0D : ((Number) o).doubleValue(); + } + + /** + * Return the return value of the given getter in the given object. + */ + public static float getFloat(Object target, Method getter) { + Object o = get(target, getter); + return (o == null) ? 0F : ((Number) o).floatValue(); + } + + /** + * Return the return value of the given getter in the given object. + */ + public static int getInt(Object target, Method getter) { + Object o = get(target, getter); + return (o == null) ? 0 : ((Number) o).intValue(); + } + + /** + * Return the return value of the given getter in the given object. + */ + public static long getLong(Object target, Method getter) { + Object o = get(target, getter); + return (o == null) ? 0L : ((Number) o).longValue(); + } + + /** + * Return the return value of the given getter in the given object. + */ + public static short getShort(Object target, Method getter) { + Object o = get(target, getter); + return (o == null) ? (short) 0 : ((Number) o).shortValue(); + } + + /** + * Set the value of the given field in the given object. + */ + public static void set(Object target, Field field, Object value) { + if (target == null || field == null) + return; + makeAccessible(field, field.getModifiers()); + try { + field.set(target, value); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Set the value of the given field in the given object. + */ + public static void set(Object target, Field field, boolean value) { + if (target == null || field == null) + return; + makeAccessible(field, field.getModifiers()); + try { + field.setBoolean(target, value); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Set the value of the given field in the given object. + */ + public static void set(Object target, Field field, byte value) { + if (target == null || field == null) + return; + makeAccessible(field, field.getModifiers()); + try { + field.setByte(target, value); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Set the value of the given field in the given object. + */ + public static void set(Object target, Field field, char value) { + if (target == null || field == null) + return; + makeAccessible(field, field.getModifiers()); + try { + field.setChar(target, value); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Set the value of the given field in the given object. + */ + public static void set(Object target, Field field, double value) { + if (target == null || field == null) + return; + makeAccessible(field, field.getModifiers()); + try { + field.setDouble(target, value); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Set the value of the given field in the given object. + */ + public static void set(Object target, Field field, float value) { + if (target == null || field == null) + return; + makeAccessible(field, field.getModifiers()); + try { + field.setFloat(target, value); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Set the value of the given field in the given object. + */ + public static void set(Object target, Field field, int value) { + if (target == null || field == null) + return; + makeAccessible(field, field.getModifiers()); + try { + field.setInt(target, value); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Set the value of the given field in the given object. + */ + public static void set(Object target, Field field, long value) { + if (target == null || field == null) + return; + makeAccessible(field, field.getModifiers()); + try { + field.setLong(target, value); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Set the value of the given field in the given object. + */ + public static void set(Object target, Field field, short value) { + if (target == null || field == null) + return; + makeAccessible(field, field.getModifiers()); + try { + field.setShort(target, value); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Invoke the given setter on the given object. + */ + public static void set(Object target, Method setter, Object value) { + if (target == null || setter == null) + return; + makeAccessible(setter, setter.getModifiers()); + try { + setter.invoke(target, new Object[] { value }); + } catch (Throwable t) { + throw wrapReflectionException(t); + } + } + + /** + * Invoke the given setter on the given object. + */ + public static void set(Object target, Method setter, boolean value) { + set(target, setter, (value) ? Boolean.TRUE : Boolean.FALSE); + } + + /** + * Invoke the given setter on the given object. + */ + public static void set(Object target, Method setter, byte value) { + set(target, setter, new Byte(value)); + } + + /** + * Invoke the given setter on the given object. + */ + public static void set(Object target, Method setter, char value) { + set(target, setter, new Character(value)); + } + + /** + * Invoke the given setter on the given object. + */ + public static void set(Object target, Method setter, double value) { + set(target, setter, new Double(value)); + } + + /** + * Invoke the given setter on the given object. + */ + public static void set(Object target, Method setter, float value) { + set(target, setter, new Float(value)); + } + + /** + * Invoke the given setter on the given object. + */ + public static void set(Object target, Method setter, int value) { + set(target, setter, new Integer(value)); + } + + /** + * Invoke the given setter on the given object. + */ + public static void set(Object target, Method setter, long value) { + set(target, setter, new Long(value)); + } + + /** + * Invoke the given setter on the given object. + */ + public static void set(Object target, Method setter, short value) { + set(target, setter, new Short(value)); + } +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Filters.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Filters.java index 6136dfe32..4afadcb7d 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Filters.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Filters.java @@ -25,6 +25,7 @@ import java.util.Collection; import java.util.Date; import java.util.List; +import org.apache.openjpa.enhance.Reflection; import org.apache.openjpa.kernel.exps.AggregateListener; import org.apache.openjpa.kernel.exps.FilterListener; import org.apache.openjpa.lib.util.Localizer; @@ -854,16 +855,8 @@ public class Filters { if (target == null || hintKey == null) return null; - Method getter = ImplHelper.getGetter(target.getClass(), hintKey); - try { - return getter.invoke(target, (Object[]) null); - } catch (Exception e) { - Throwable t = e; - if (e instanceof InvocationTargetException) - t = ((InvocationTargetException) e).getTargetException(); - throw new UserException(_loc.get("bad-getter-hint", - target.getClass(), hintKey)).setCause(t); - } + Method getter = Reflection.findGetter(target.getClass(), hintKey, true); + return Reflection.get(target, getter); } /** @@ -874,22 +867,21 @@ public class Filters { if (target == null || hintKey == null) return; - Method setter = ImplHelper.getSetter(target.getClass(), hintKey); - try { - if (value instanceof String) { - if ("null".equals(value)) - value = null; - else + Method setter = Reflection.findSetter(target.getClass(), hintKey, true); + if (value instanceof String) { + if ("null".equals(value)) + value = null; + else { + try { value = Strings.parse((String) value, setter.getParameterTypes()[0]); + } catch (Exception e) { + throw new UserException(_loc.get("bad-setter-hint-arg", + hintKey, value, setter.getParameterTypes()[0])). + setCause(e); + } } - setter.invoke(target, new Object[]{ value }); - } catch (Exception e) { - Throwable t = e; - if (e instanceof InvocationTargetException) - t = ((InvocationTargetException) e).getTargetException(); - throw new UserException(_loc.get("bad-setter-hint", - target.getClass (), hintKey, value)).setCause (t); - } + } + Reflection.set(target, setter, value); } } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java index bd293f2ea..7231d262d 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java @@ -24,6 +24,7 @@ import java.util.BitSet; import org.apache.commons.lang.StringUtils; import org.apache.openjpa.enhance.PersistenceCapable; import org.apache.openjpa.enhance.StateManager; +import org.apache.openjpa.enhance.Reflection; import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.FieldMetaData; import org.apache.openjpa.meta.JavaTypes; @@ -689,30 +690,17 @@ public class ObjectIdStateManager return null; FieldMetaData fmd = getMetaData().getField(field); - try { - if (fmd.getBackingMember() instanceof Field) - return ((Field) fmd.getBackingMember()).get(_oid); - if (fmd.getBackingMember() instanceof Method) - return ((Method) fmd.getBackingMember()). - invoke(_oid, (Object[]) null); + if (fmd.getBackingMember() instanceof Field) + return Reflection.get(_oid, (Field) fmd.getBackingMember()); + if (fmd.getBackingMember() instanceof Method) + return Reflection.get(_oid, (Method) fmd.getBackingMember()); - if (fmd.getDefiningMetaData().getAccessType() - == ClassMetaData.ACCESS_FIELD) - return _oid.getClass().getField(fmd.getName()).get(_oid); - - // property - Method meth; - try { - meth = _oid.getClass().getMethod("get" - + StringUtils.capitalize(fmd.getName()), (Class[]) null); - } catch (NoSuchMethodException nsme) { - meth = _oid.getClass().getMethod("is" - + StringUtils.capitalize(fmd.getName()), (Class[]) null); - } - return meth.invoke(_oid, (Object[]) null); - } catch (Exception e) { - throw new GeneralException(e); - } + if (fmd.getDefiningMetaData().getAccessType() + == ClassMetaData.ACCESS_FIELD) + return Reflection.get(_oid, Reflection.findField(_oid.getClass(), + fmd.getName(), true)); + return Reflection.get(_oid, Reflection.findGetter(_oid.getClass(), + fmd.getName(), true)); } /** @@ -731,18 +719,14 @@ public class ObjectIdStateManager return; FieldMetaData fmd = getMetaData().getField(field); - try { - if (fmd.getBackingMember() instanceof Field) - ((Field) fmd.getBackingMember()).set(_oid, val); - else if (fmd.getDefiningMetaData().getAccessType() - == ClassMetaData.ACCESS_FIELD) - _oid.getClass().getField(fmd.getName()).set(_oid, val); - else // property - _oid.getClass().getMethod("set" + StringUtils.capitalize - (fmd.getName()), new Class[]{ fmd.getDeclaredType() }). - invoke(_oid, new Object[]{ val }); - } catch (Exception e) { - throw new GeneralException(e); - } + if (fmd.getBackingMember() instanceof Field) + Reflection.set(_oid, (Field) fmd.getBackingMember(), val); + else if (fmd.getDefiningMetaData().getAccessType() + == ClassMetaData.ACCESS_FIELD) { + Reflection.set(_oid, Reflection.findField(_oid.getClass(), + fmd.getName(), true), val); + } else + Reflection.set(_oid, Reflection.findSetter(_oid.getClass(), + fmd.getName(), fmd.getDeclaredType(), true), val); } } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ResultPacker.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ResultPacker.java index ed9bcd22b..0323e25b5 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ResultPacker.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ResultPacker.java @@ -285,10 +285,7 @@ public class ResultPacker { } // check setter methods - String setName = "set" + Character.toUpperCase(alias.charAt(0)); - if (alias.length() > 1) - setName = setName + alias.substring(1); - + String setName = "set" + StringUtils.capitalize(alias); Method method = null; boolean eqName = false; Class[] params; diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java index c562c7ae2..b2e6d2b6c 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java @@ -22,6 +22,7 @@ import java.lang.reflect.Modifier; import org.apache.commons.lang.StringUtils; import org.apache.openjpa.enhance.PCRegistry; +import org.apache.openjpa.enhance.Reflection; import org.apache.openjpa.lib.log.Log; import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.util.InternalException; @@ -183,8 +184,8 @@ public abstract class AbstractMetaDataDefaults if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD) member = cls.getDeclaredField(fieldNames[i]); else - member = getBackingMethod(meta.getDescribedType(), - fieldNames[i], fieldTypes[i]); + member = Reflection.findGetter(meta.getDescribedType(), + fieldNames[i], true); fmd = meta.addDeclaredField(fieldNames[i], fieldTypes[i]); fmd.backingMember(member); populate(fmd); @@ -310,8 +311,8 @@ public abstract class AbstractMetaDataDefaults if (fmd.getDefiningMetaData().getAccessType() == ClassMetaData.ACCESS_FIELD) return fmd.getDeclaringType().getDeclaredField(fmd.getName()); - return getBackingMethod(fmd.getDeclaringType(), fmd.getName(), - fmd.getDeclaredType()); + return Reflection.findGetter(fmd.getDeclaringType(), fmd.getName(), + true); } catch (OpenJPAException ke) { throw ke; } catch (Exception e) { @@ -319,44 +320,6 @@ public abstract class AbstractMetaDataDefaults } } - /** - * Return the method backing the given field metadata. Looks for - * "get" and "is" methods with no parameters by default. This looks - * for elements defined in cls and its superclasses. - */ - private Method getBackingMethod(Class cls, String name, - Class methReturnType) - throws NoSuchMethodException { - String clsName = cls.getName(); - String capName = StringUtils.capitalize(name); - boolean isBoolean = methReturnType == boolean.class - || methReturnType == Boolean.class; - do { - try { - return cls.getDeclaredMethod("get" + capName, (Class[]) null); - } catch (NoSuchMethodException e) { - } - - if (isBoolean) { - try { - return cls.getDeclaredMethod("is" + capName, - (Class[]) null); - } catch (NoSuchMethodException e) { - } - } - // ### EJB3: recursion should be limited to manageable types, - // ### including embeddable and embeddable superclass - cls = cls.getSuperclass(); - } - while (cls != null); - - if (!isBoolean) - throw new UserException(_loc.get("pc-registry-no-method", - name, clsName, "get" + capName)); - throw new UserException(_loc.get("pc-registry-no-boolean-method", - new String[]{ name, clsName, "get" + capName, "is" + capName })); - } - public Class getUnimplementedExceptionType() { return UnsupportedOperationException.class; } 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 405916b25..4796d2a3e 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 @@ -36,6 +36,7 @@ import org.apache.openjpa.conf.OpenJPAConfiguration; import org.apache.openjpa.datacache.DataCache; import org.apache.openjpa.enhance.PCRegistry; import org.apache.openjpa.enhance.PersistenceCapable; +import org.apache.openjpa.enhance.Reflection; import org.apache.openjpa.lib.log.Log; import org.apache.openjpa.lib.meta.SourceTracker; import org.apache.openjpa.lib.util.Localizer; @@ -1894,95 +1895,45 @@ public class ClassMetaData throw new MetaDataException(_loc.get("no-pk", _type)); // check that the oid type contains all pk fields - try { - Field f; - Method m; - String cap; - int type; - Class c; - int access = meta.getAccessType(); - for (int i = 0; i < fmds.length; i++) { - switch (fmds[i].getDeclaredTypeCode()) { - case JavaTypes.ARRAY: - c = fmds[i].getDeclaredType().getComponentType(); - if (c == byte.class || c == Byte.class - || c == char.class || c == Character.class) { - c = fmds[i].getDeclaredType(); - break; - } - // else no break - case JavaTypes.PC_UNTYPED: - case JavaTypes.COLLECTION: - case JavaTypes.MAP: - case JavaTypes.OID: // we're validating embedded fields - throw new MetaDataException(_loc.get("bad-pk-type", - fmds[i])); - default: - c = fmds[i].getObjectIdFieldType(); - } - - if (access == ACCESS_FIELD) { - f = findField(oid, fmds[i].getName(), runtime); - if (f == null || !f.getType().isAssignableFrom(c)) - throw new MetaDataException(_loc.get("invalid-id", - _type)).setFailedObject(fmds[i].getName()); - } else if (access == ACCESS_PROPERTY) { - cap = StringUtils.capitalize(fmds[i].getName()); - type = fmds[i].getDeclaredTypeCode(); - - m = findMethod(oid, "get" + cap, null, runtime); - if (m == null && (type == JavaTypes.BOOLEAN - || type == JavaTypes.BOOLEAN_OBJ)) - m = findMethod(oid, "is" + cap, null, runtime); - if (m == null || !m.getReturnType().isAssignableFrom(c)) - throw new MetaDataException(_loc.get("invalid-id", - _type)).setFailedObject("get" + cap); - - m = findMethod(oid, "set" + cap, - new Class[]{ fmds[i].getDeclaredType() }, runtime); - if (m == null || m.getReturnType() != void.class) - throw new MetaDataException(_loc.get("invalid-id", - _type)).setFailedObject("set" + cap); - } + Field f; + Method m; + Class c; + for (int i = 0; i < fmds.length; i++) { + switch (fmds[i].getDeclaredTypeCode()) { + case JavaTypes.ARRAY: + c = fmds[i].getDeclaredType().getComponentType(); + if (c == byte.class || c == Byte.class + || c == char.class || c == Character.class) { + c = fmds[i].getDeclaredType(); + break; + } + // else no break + case JavaTypes.PC_UNTYPED: + case JavaTypes.COLLECTION: + case JavaTypes.MAP: + case JavaTypes.OID: // we're validating embedded fields + throw new MetaDataException(_loc.get("bad-pk-type", + fmds[i])); + default: + c = fmds[i].getObjectIdFieldType(); } - } catch (OpenJPAException ke) { - throw ke; - } catch (Throwable t) { - throw new MetaDataException(_loc.get("invalid-id", _type)). - setCause(t); - } - } - /** - * Find the named field, recursing to superclasses if necessary. - */ - private static Field findField(Class c, String name, boolean pub) - throws Exception { - if (c == null || c == Object.class) - return null; - - try { - return (pub) ? c.getField(name) : c.getDeclaredField(name); - } catch (NoSuchFieldException nsfe) { - return (pub) ? null : findField(c.getSuperclass(), name, false); - } - } - - /** - * Find the named method, recursing to superclasses if necessary. - */ - private static Method findMethod(Class c, String name, Class[] params, - boolean pub) - throws Exception { - if (c == null || c == Object.class) - return null; - - try { - return (pub) ? c.getMethod(name, params) - : c.getDeclaredMethod(name, params); - } catch (NoSuchMethodException nsfe) { - return (pub) ? null : findMethod(c.getSuperclass(), name, params, - false); + if (meta.getAccessType() == ACCESS_FIELD) { + f = Reflection.findField(oid, fmds[i].getName(), false); + if (f == null || !f.getType().isAssignableFrom(c)) + throw new MetaDataException(_loc.get("invalid-id", + _type, fmds[i].getName())); + } else if (meta.getAccessType() == ACCESS_PROPERTY) { + m = Reflection.findGetter(oid, fmds[i].getName(), false); + if (m == null || !m.getReturnType().isAssignableFrom(c)) + throw new MetaDataException(_loc.get("invalid-id", + _type, fmds[i].getName())); + m = Reflection.findSetter(oid, fmds[i].getName(), + fmds[i].getDeclaredType(), false); + if (m == null || m.getReturnType() != void.class) + throw new MetaDataException(_loc.get("invalid-id", + _type, fmds[i].getName())); + } } } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java index becc59ea3..d2d4db43b 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java @@ -16,7 +16,6 @@ package org.apache.openjpa.util; import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Date; @@ -24,6 +23,7 @@ import org.apache.commons.lang.StringUtils; import org.apache.openjpa.enhance.FieldManager; import org.apache.openjpa.enhance.PCRegistry; import org.apache.openjpa.enhance.PersistenceCapable; +import org.apache.openjpa.enhance.Reflection; import org.apache.openjpa.kernel.ObjectIdStateManager; import org.apache.openjpa.kernel.OpenJPAStateManager; import org.apache.openjpa.kernel.StoreManager; @@ -84,24 +84,15 @@ public class ApplicationIds { if (meta.isObjectIdTypeShared()) oid = ((ObjectId) oid).getId(); Class oidType = oid.getClass(); - try { - Field field; - Method meth; - for (int i = 0; i < fmds.length; i++) { - if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD) { - field = oidType.getField(fmds[i].getName()); - pks[i] = field.get(oid); - } else { // property - meth = ImplHelper.getGetter(oidType, fmds[i].getName()); - pks[i] = meth.invoke(oid, (Object[]) null); - } - } - return pks; - } catch (OpenJPAException ke) { - throw ke; - } catch (Throwable t) { - throw new GeneralException(t); + for (int i = 0; i < fmds.length; i++) { + if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD) + pks[i] = Reflection.get(oid, Reflection.findField(oidType, + fmds[i].getName(), true)); + else + pks[i] = Reflection.get(oid, Reflection.findGetter(oidType, + fmds[i].getName(), true)); } + return pks; } /** @@ -133,19 +124,19 @@ public class ApplicationIds { case JavaTypes.INT: case JavaTypes.INT_OBJ: if (!convert && !(val instanceof Integer)) - throw new ClassCastException("!(x instanceof Byte)"); + throw new ClassCastException("!(x instanceof Integer)"); return new IntId(meta.getDescribedType(), ((Number) val).intValue()); case JavaTypes.LONG: case JavaTypes.LONG_OBJ: if (!convert && !(val instanceof Long)) - throw new ClassCastException("!(x instanceof Byte)"); + throw new ClassCastException("!(x instanceof Long)"); return new LongId(meta.getDescribedType(), ((Number) val).longValue()); case JavaTypes.SHORT: case JavaTypes.SHORT_OBJ: if (!convert && !(val instanceof Short)) - throw new ClassCastException("!(x instanceof Byte)"); + throw new ClassCastException("!(x instanceof Short)"); return new ShortId(meta.getDescribedType(), ((Number) val).shortValue()); case JavaTypes.STRING: @@ -174,41 +165,29 @@ public class ApplicationIds { // default to reflection Class oidType = meta.getObjectIdType(); + Object copy = null; try { - // create a new id - Object copy = oidType.newInstance(); - - // set each field - FieldMetaData[] fmds = meta.getPrimaryKeyFields(); - Field field; - Method meth; - Class[] paramTypes = null; - Object[] params = null; - for (int i = 0; i < fmds.length; i++) { - if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD) { - field = oidType.getField(fmds[i].getName()); - field.set(copy, (convert) ? JavaTypes.convert(pks[i], - fmds[i].getObjectIdFieldTypeCode()) : pks[i]); - } else { // property - if (paramTypes == null) - paramTypes = new Class[1]; - paramTypes[0] = fmds[i].getDeclaredType(); - meth = oidType.getMethod("set" + StringUtils.capitalize - (fmds[i].getName()), paramTypes); - if (params == null) - params = new Object[1]; - params[0] = (convert) ? JavaTypes.convert(pks[i], - fmds[i].getObjectIdFieldTypeCode()) : pks[i]; - meth.invoke(copy, params); - } - } - - if (meta.isObjectIdTypeShared()) - copy = new ObjectId(meta.getDescribedType(), copy); - return copy; + copy = oidType.newInstance(); } catch (Throwable t) { throw new GeneralException(t); } + + FieldMetaData[] fmds = meta.getPrimaryKeyFields(); + Object val; + for (int i = 0; i < fmds.length; i++) { + val = (convert) ? JavaTypes.convert(pks[i], + fmds[i].getObjectIdFieldTypeCode()) : pks[i]; + if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD) + Reflection.set(copy, Reflection.findField(oidType, + fmds[i].getName(), true), val); + else + Reflection.set(copy, Reflection.findSetter(oidType, + fmds[i].getName(), fmds[i].getDeclaredType(), true), val); + } + + if (meta.isObjectIdTypeShared()) + copy = new ObjectId(meta.getDescribedType(), copy); + return copy; } /** @@ -306,39 +285,31 @@ public class ApplicationIds { return null; Class oidType = oid.getClass(); + Object copy = null; try { - Object copy = oidType.newInstance(); - Field field; - Method meth; - String cap; - Class[] paramTypes = null; - Object[] params = null; - for (int i = 0; i < fmds.length; i++) { - if (fmds[i].getManagement() != FieldMetaData.MANAGE_PERSISTENT) - continue; - - if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD) { - field = oidType.getField(fmds[i].getName()); - field.set(copy, field.get(oid)); - } else { // property - if (paramTypes == null) - paramTypes = new Class[1]; - paramTypes[0] = fmds[i].getObjectIdFieldType(); - cap = StringUtils.capitalize(fmds[i].getName()); - meth = oidType.getMethod("set" + cap, paramTypes); - if (params == null) - params = new Object[1]; - params[0] = ImplHelper.getGetter(oidType, cap). - invoke(oid, (Object[]) null); - meth.invoke(copy, params); - } - } - return copy; - } catch (OpenJPAException ke) { - throw ke; + copy = oidType.newInstance(); } catch (Throwable t) { throw new GeneralException(t); } + + Field field; + Object val; + for (int i = 0; i < fmds.length; i++) { + if (fmds[i].getManagement() != FieldMetaData.MANAGE_PERSISTENT) + continue; + + if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD) { + field = Reflection.findField(oidType, fmds[i].getName(), + true); + Reflection.set(copy, field, Reflection.get(oid, field)); + } else { // property + val = Reflection.get(oid, Reflection.findGetter(oidType, + fmds[i].getName(), true)); + Reflection.set(copy, Reflection.findSetter(oidType, fmds[i]. + getName(), fmds[i].getObjectIdFieldType(), true), val); + } + } + return copy; } /** @@ -352,19 +323,11 @@ public class ApplicationIds { ClassMetaData meta = fmd.getDefiningMetaData(); Class oidType = oid.getClass(); - try { - if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD) - return oidType.getField(fmd.getName()).get(oid); - - // property - String cap = StringUtils.capitalize(fmd.getName()); - return ImplHelper.getGetter(oidType, cap). - invoke(oid, (Object[]) null); - } catch (OpenJPAException ke) { - throw ke; - } catch (Throwable t) { - throw new GeneralException(t); - } + if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD) + return Reflection.get(oid, Reflection.findField(oidType, + fmd.getName(), true)); + return Reflection.get(oid, Reflection.findGetter(oidType, fmd.getName(), + true)); } /** diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java index 8830f8d83..575fa21ef 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java @@ -15,7 +15,6 @@ */ package org.apache.openjpa.util; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.BitSet; import java.util.Collection; @@ -51,38 +50,6 @@ public class ImplHelper { private static final Localizer _loc = Localizer.forPackage (ImplHelper.class); - /** - * Return the getter method matching the given property name. - */ - public static Method getGetter(Class cls, String prop) { - prop = StringUtils.capitalize(prop); - try { - return cls.getMethod("get" + prop, (Class[]) null); - } catch (Exception e) { - try { - return cls.getMethod("is" + prop, (Class[]) null); - } catch (Exception e2) { - throw new UserException(_loc.get("bad-getter", cls, - prop)).setCause(e); - } - } - } - - /** - * Return the setter method matching the given property name. - */ - public static Method getSetter(Class cls, String prop) { - Method getter = getGetter(cls, prop); - prop = StringUtils.capitalize(prop); - try { - return cls.getMethod("set" + prop, - new Class[]{ getter.getReturnType() }); - } catch (Exception e) { - throw new UserException(_loc.get("bad-setter", cls, prop)). - setCause(e); - } - } - /** * Helper for store manager implementations. This method simply delegates * to the proper singular method for each state manager. diff --git a/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties b/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties index 4a282c225..e0f32bf7e 100644 --- a/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties +++ b/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties @@ -12,6 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +copy-no-oid: Cannot copy identity for abstract type "{0}". +no-meta: No registered metadata for type "{0}". +bad-getter: Missing getter for property "{1}" in type "{0}". +bad-setter: Missing setter for property "{1}" in type "{0}". +bad-field: Missing field for property "{1}" in type "{0}". +reflect-security: Unable to access "{0}" via reflection. Make sure OpenJPA \ + has the "suppressAccessChecks" permission. needs-runtime-enhance: "{0}" requires runtime enhancement: {1} runtime-enhance-pcclasses: You have enabled runtime enhancement, but have not \ specified the set of persistent classes. OpenJPA must look for metadata \ @@ -35,7 +42,6 @@ pers-aware: Type "{0}" has no metadata; enhancing as persistence aware. \ metadata files are not named properly. See the documentation on metadata \ placement for more information. enhance-running: Enhancer running on type "{0}". -enhance-running-oids: Enhancer running on oid: {0} enhance-aware: The class does not have metadata - enhanced as persistence-aware. enhance-norun: The class is already persistence capable - no enhancement \ performed. @@ -59,7 +65,6 @@ enhance-uid-access: An IllegalAccessException occured when trying to \ bug in JDK 1.4+ when using a custom ClassLoader to enhance a \ class that implements java.io.Serializable. If compatibility with \ non-enhanced versions of "{0}" is not needed, this warning can be ignored. -enhance-oid: Enhancing object id type "{0}" to allow member access. enhance-defcons-extern: Type "{0}" requires a public constructor to support \ detach on serialize. Making default constructor public. cons-access: An error occurred trying to instantiate a custom storage class. diff --git a/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties b/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties index 29ab6af64..afd0726d2 100644 --- a/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties +++ b/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties @@ -341,10 +341,8 @@ bad-agg-listener-hint: Query hint value "{0}" ({1}) cannot be converted into \ an aggregate listener. bad-filter-listener-hint: Query hint value "{0}" ({1}) cannot be converted \ into a filter listener. -bad-getter-hint: Invoking the getter for hint key "{0}" on "{1}" caused \ - an error. -bad-setter-hint: Invoking the setter for hint key "{0}" on "{1}" with \ - value "{2}" caused an error. +bad-setter-hint-arg: In query hint "{0}", cannot convert hint value "{1}" to \ + type "{2}". detach-val-mismatch: The instance "{0}" is managed by another context and \ cannot be inspected for field values. detach-val-badsm: The instance "{0}" has an unknown state manager which \ diff --git a/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties b/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties index 79535e16b..fd14c38ac 100644 --- a/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties +++ b/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties @@ -165,9 +165,7 @@ no-pk: Concrete type "{0}" with application identity does not declare any \ primary key fields. invalid-id: The id class specified by type "{0}" does not match the \ primary key fields of the class. Make sure your identity class has the \ - same primary keys as your persistent type, that the access types are the \ - same, and if you are getting this error at runtime, that you have \ - your persistent class since last compiling your identity class. + same primary keys as your persistent type. Mismatched property: "{1}" null-cons: The id class specified by type "{0}" does not have public a \ no-args constructor. hc-method: The identity class specified by type "{0}" is not valid, as the \ @@ -242,14 +240,6 @@ val-not-one-pk: The map value type of field "{0}" a derived key must be a \ # show up with the prefix will not be included in the list of # extensions that are validated by generic tools (such as the enhancer) extension-datastore-prefix: jdbc- -pc-registry-no-method: No method was found for the persistent property "{0}" \ - declared in "{1}" or one of its superclasses. Searched for a method called \ - "{2}". -pc-registry-no-boolean-method: No method was found for the persistent property \ - "{0}" declared in "{1}" or one of its superclasses. Searched for methods \ - called "{2}" and "{3}". -pc-registry-no-field: No field was found for the persistent property "{0}" \ - declared in "{1}" or one of its superclasses. nonpc-field-orderable: Cannot order "{0}" on "{1}", because {0} is not a \ relation to another persistent type. For non-relation fields, you can \ only order on the field element values themselves, represented by \ diff --git a/openjpa-kernel/src/main/resources/org/apache/openjpa/util/localizer.properties b/openjpa-kernel/src/main/resources/org/apache/openjpa/util/localizer.properties index f3a4ab8b2..84adb8e60 100644 --- a/openjpa-kernel/src/main/resources/org/apache/openjpa/util/localizer.properties +++ b/openjpa-kernel/src/main/resources/org/apache/openjpa/util/localizer.properties @@ -67,5 +67,3 @@ dup-oid: A duplicate object id exception has occurred. Each object you \ unique: A unique constraint violation has occurred. ref-integrity: A referential integrity constraint has occurred. no-store-exts: No store-specific facade found matching "{0}". Using default. -bad-getter: Missing getter for property "{1}" in type "{0}". -bad-setter: Missing setter for property "{1}" in type "{0}". diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java index 2f6cb5a36..e836dd17e 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java @@ -28,6 +28,7 @@ import java.util.Set; import javax.persistence.EntityManagerFactory; import org.apache.openjpa.conf.OpenJPAConfiguration; +import org.apache.openjpa.enhance.Reflection; import org.apache.openjpa.kernel.AutoDetach; import org.apache.openjpa.kernel.Broker; import org.apache.openjpa.kernel.BrokerFactory; @@ -38,7 +39,6 @@ import org.apache.openjpa.lib.conf.Configurations; import org.apache.openjpa.lib.conf.ProductDerivations; import org.apache.openjpa.lib.conf.Value; import org.apache.openjpa.lib.util.Localizer; -import org.apache.openjpa.util.ImplHelper; import org.apache.openjpa.util.OpenJPAException; import serp.util.Strings; @@ -211,7 +211,7 @@ public class EntityManagerFactoryImpl continue; prop = prop.substring(prefix.length()); try { - setter = ImplHelper.getSetter(em.getClass(), prop); + setter = Reflection.findSetter(em.getClass(), prop, true); } catch (OpenJPAException ke) { if (errs == null) errs = new LinkedList(); @@ -228,11 +228,13 @@ public class EntityManagerFactoryImpl val = Strings.parse((String) val, setter.getParameterTypes()[0]); } - setter.invoke(em, new Object[]{ val }); - } catch (Exception e) { + Reflection.set(em, setter, val); + } catch (Throwable t) { + while (t.getCause() != null) + t = t.getCause(); ArgumentException err = new ArgumentException(_loc.get ("bad-em-prop", prop, entry.getValue()), - new Throwable[]{ e }, null, true); + new Throwable[]{ t }, null, true); if (errs == null) errs = new LinkedList(); errs.add(err); diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java index 907f929a3..bdce0c80a 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java @@ -43,6 +43,7 @@ import javax.persistence.PreRemove; import javax.persistence.PreUpdate; import javax.persistence.Transient; +import org.apache.commons.lang.StringUtils; import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.meta.AbstractMetaDataDefaults; import org.apache.openjpa.meta.ClassMetaData; @@ -282,8 +283,8 @@ public class PersistenceMetaDataDefaults try { // check for setters for methods Method setter = meta.getDescribedType().getDeclaredMethod("set" - + name.substring(0, 1).toUpperCase() + name.substring(1), - new Class[] { ((Method) member).getReturnType() }); + + StringUtils.capitalize(name), new Class[] { + ((Method) member).getReturnType() }); if (setter == null) return false; } catch (Exception e) {