Objects initialized through property paths are now deproxied
authorn.hoffmann <n.hoffmann@localhost>
Fri, 12 Mar 2010 14:22:22 +0000 (14:22 +0000)
committern.hoffmann <n.hoffmann@localhost>
Fri, 12 Mar 2010 14:22:22 +0000 (14:22 +0000)
.gitattributes
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/AbstractBeanInitializer.java
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/IMethodCache.java [new file with mode: 0644]
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/MethodCacheImpl.java [new file with mode: 0644]

index 11955514682f91889b1c23420bba503821b11c9b..2096dfd4c12ab837db9e83055e78506d4ff22540 100644 (file)
@@ -2020,6 +2020,8 @@ cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/types/SybaseDatabaseT
 cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/AbstractBeanInitializer.java -text
 cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/BeanInitializer.java -text
 cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/IAlternativeSpellingSuggestionParser.java -text
+cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/IMethodCache.java -text
+cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/MethodCacheImpl.java -text
 cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/QueryParseException.java -text
 cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/agent/IAgentDao.java -text
 cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/common/AuditEventSort.java -text
index a5409ab1ec29fb880c3286832aad5b3b4bdff8fb..0ae0cae19f9a4de8321f43c92283e909741367e1 100644 (file)
@@ -11,6 +11,7 @@ package eu.etaxonomy.cdm.persistence.dao;
 \r
 import java.beans.PropertyDescriptor;\r
 import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
 import java.util.Collection;\r
 import java.util.Collections;\r
 import java.util.HashSet;\r
@@ -19,7 +20,9 @@ import java.util.Map;
 import java.util.Set;\r
 \r
 import org.apache.commons.beanutils.PropertyUtils;\r
+import org.apache.commons.lang.StringUtils;\r
 import org.apache.log4j.Logger;\r
+import org.springframework.beans.factory.annotation.Autowired;\r
 \r
 import eu.etaxonomy.cdm.model.common.CdmBase;\r
 \r
@@ -32,6 +35,9 @@ public abstract class AbstractBeanInitializer implements BeanInitializer{
        \r
        public static final Logger logger = Logger.getLogger(AbstractBeanInitializer.class);\r
        \r
+       @Autowired\r
+       IMethodCache methodCache;\r
+       \r
        /**\r
         * Initialize the the proxy, unwrap the target object and return it.\r
         * \r
@@ -237,6 +243,7 @@ public abstract class AbstractBeanInitializer implements BeanInitializer{
                                        }else {\r
                                                // nested bean\r
                                                initializePropertyPath(unwrappedBean, nestedPath);\r
+                                               setProperty(bean, property, unwrappedBean);\r
                                        }\r
                                }\r
                                \r
@@ -250,6 +257,23 @@ public abstract class AbstractBeanInitializer implements BeanInitializer{
                }\r
        }\r
 \r
+       private void setProperty(Object object, String property, Object value){\r
+               Method method = methodCache.getMethod(object.getClass(), "set" + StringUtils.capitalize(property), value.getClass()); \r
+               if(method != null){\r
+                       try {\r
+                               method.invoke(object, value);\r
+                       } catch (IllegalArgumentException e) {\r
+                               // TODO Auto-generated catch block\r
+                               e.printStackTrace();\r
+                       } catch (IllegalAccessException e) {\r
+                               // TODO Auto-generated catch block\r
+                               e.printStackTrace();\r
+                       } catch (InvocationTargetException e) {\r
+                               // TODO Auto-generated catch block\r
+                               e.printStackTrace();\r
+                       }\r
+               }               \r
+       }\r
 \r
        /**\r
         * @param collection of which all entities are to be initialized\r
diff --git a/cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/IMethodCache.java b/cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/IMethodCache.java
new file mode 100644 (file)
index 0000000..4252f49
--- /dev/null
@@ -0,0 +1,33 @@
+// $Id$
+/**
+* Copyright (C) 2007 EDIT
+* European Distributed Institute of Taxonomy 
+* http://www.e-taxonomy.eu
+* 
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+
+package eu.etaxonomy.cdm.persistence.dao;
+
+import java.lang.reflect.Method;
+
+
+/**
+ * @author n.hoffmann
+ * @created Mar 11, 2010
+ * @version 1.0
+ */
+public interface IMethodCache {
+
+       /**
+        * Returns the method that is suitable for the given class and parameter type or
+        * null if no such method exists.
+        * 
+        * @param clazz 
+        * @param methodName
+        * @param parameterType
+        * @return
+        */
+       public Method getMethod(Class clazz, String methodName, Class parameterType);
+}
diff --git a/cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/MethodCacheImpl.java b/cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/MethodCacheImpl.java
new file mode 100644 (file)
index 0000000..c8a396c
--- /dev/null
@@ -0,0 +1,190 @@
+// $Id$
+/**
+* Copyright (C) 2007 EDIT
+* European Distributed Institute of Taxonomy 
+* http://www.e-taxonomy.eu
+* 
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+
+package eu.etaxonomy.cdm.persistence.dao;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author n.hoffmann
+ * @created Mar 11, 2010
+ * @version 1.0
+ */
+@Component
+public class MethodCacheImpl implements IMethodCache {
+       
+//     MethodUtils
+       
+       private Map<MethodDescriptor, Method> methodMap = new HashMap<MethodDescriptor, Method>();
+
+       /*
+        * (non-Javadoc)
+        * @see eu.etaxonomy.cdm.persistence.dao.IMethodCache#getMethod(java.lang.Class, java.lang.String, java.lang.Class)
+        */
+       public Method getMethod(Class clazz, String methodName, Class parameterType) {
+               MethodDescriptor methodDescriptor = new MethodDescriptor(clazz, methodName, new Class[]{parameterType}); 
+               
+               if(methodMap.containsKey(methodDescriptor)){
+                       return methodMap.get(methodDescriptor);
+               }
+               
+               Method method = getMethodInternal(clazz, methodName, parameterType);
+               if(method != null){
+                       method.setAccessible(true);
+               }
+               // we also put null methods into the map to benefit from caching
+               put(methodDescriptor, method);
+               
+               return method; 
+       }
+       
+       /**
+        * Checks class hierarchy of the given class for a method that fits to the given name and parameter type
+        * 
+        * @param clazz
+        * @param methodName
+        * @param parameterType
+        * @return
+        */
+       private Method getMethodInternal(Class clazz, String methodName,
+                       Class parameterType){
+               // stop recursing when there are no more superclasses
+               if(clazz == null){
+                       return null;
+               }
+               
+               Method method = null;
+               
+               for(Class includedType : getIncludedTypes(parameterType, new ArrayList<Class>())){
+                       try {
+                               method = clazz.getDeclaredMethod(methodName, includedType);
+                       }catch (NoSuchMethodException e) {
+                               ;
+                       } 
+               }
+               
+               // if we have a method return it
+               if(method != null){
+                       return method;
+               }
+                       
+               // recurse into superclass if no method was found
+               return getMethodInternal(clazz.getSuperclass(), methodName, parameterType);
+       }
+       
+       /**
+        * Create a list containing the type and all supertypes of a given type
+        * 
+        * @param clazz
+        * @param classList
+        * @return
+        */
+       private List<Class> getIncludedTypes(Class clazz, List<Class> classList){
+               if(clazz == null){
+                       return classList;
+               }
+               classList.add(clazz);
+               Class[] interfaces = clazz.getInterfaces();
+               if(interfaces != null){
+                       classList.addAll(Arrays.asList(interfaces));
+               }
+               return getIncludedTypes(clazz.getSuperclass(), classList);
+       }
+       
+       /**
+        * Fill the cache
+        * 
+        * @param methodDescriptor
+        * @param method
+        */
+       private void put(MethodDescriptor methodDescriptor, Method method) {
+               methodMap.put(methodDescriptor, method);
+       }
+       
+       /**
+        * 
+        * @author n.hoffmann
+        * @created Mar 11, 2010
+        * @version 1.0
+        */
+       private static class MethodDescriptor{
+               private static final Logger logger = Logger
+                               .getLogger(MethodDescriptor.class);
+               
+               /** An empty class array */
+           private static final Class[] emptyClassArray = new Class[0];
+               
+               private Class clazz;
+           private String methodName;
+           private Class[] parameterTypes;
+           private int hashCode;
+
+           /**
+            * The sole constructor.
+            *
+            * @param clazz  the class to reflect, must not be null
+            * @param methodName  the method name to obtain
+            * @param paramTypes the array of classes representing the paramater types
+            * @param exact whether the match has to be exact.
+            */
+           public MethodDescriptor(Class clazz, String methodName, Class[] paramTypes) {
+               if (clazz == null) {
+                   throw new IllegalArgumentException("Class cannot be null");
+               }
+               if (methodName == null) {
+                   throw new IllegalArgumentException("Method Name cannot be null");
+               }
+               if (paramTypes == null) {
+                   paramTypes = emptyClassArray;
+               }
+
+               this.clazz = clazz;
+               this.methodName = methodName;
+               this.parameterTypes = paramTypes;
+
+               this.hashCode = methodName.length();
+           }
+           /**
+            * Checks for equality.
+            * @param object object to be tested for equality
+            * @return true, if the object describes the same Method.
+            */
+           public boolean equals(Object object) {
+               if (!(object instanceof MethodDescriptor)) {
+                   return false;
+               }
+               MethodDescriptor methodDescriptor = (MethodDescriptor)object;
+
+               return (
+                   methodName.equals(methodDescriptor.methodName) &&
+                   clazz.equals(methodDescriptor.clazz) &&
+                   java.util.Arrays.equals(parameterTypes, methodDescriptor.parameterTypes)
+               );
+           }
+           /**
+            * Returns the string length of method name. I.e. if the
+            * hashcodes are different, the objects are different. If the
+            * hashcodes are the same, need to use the equals method to
+            * determine equality.
+            * @return the string length of method name.
+            */
+           public int hashCode() {
+               return hashCode;
+           }           
+       }       
+}