1 16 17 package org.springframework.core; 18 19 import java.lang.reflect.Method ; 20 import java.lang.reflect.Modifier ; 21 import java.util.LinkedList ; 22 23 import org.apache.commons.logging.Log; 24 import org.apache.commons.logging.LogFactory; 25 26 import org.springframework.util.Assert; 27 import org.springframework.util.CachingMapDecorator; 28 import org.springframework.util.ReflectionUtils; 29 30 54 public final class ReflectiveVisitorHelper { 55 56 private static final String VISIT_METHOD = "visit"; 57 58 private static final String VISIT_NULL = "visitNull"; 59 60 private static final Log logger = LogFactory.getLog(ReflectiveVisitorHelper.class); 61 62 63 private CachingMapDecorator visitorClassVisitMethods = new CachingMapDecorator() { 64 public Object create(Object key) { 65 return new ClassVisitMethods((Class ) key); 66 } 67 }; 68 69 70 77 public Object invokeVisit(Object visitor, Object argument) { 78 Assert.notNull(visitor, "The visitor to visit is required"); 79 Method method = getMethod(visitor.getClass(), argument); 81 if (method == null) { 82 if (logger.isWarnEnabled()) { 83 logger.warn("No method found by reflection for visitor class [" + visitor.getClass().getName() 84 + "] and argument of type [" + (argument != null ? argument.getClass().getName() : "") + "]"); 85 } 86 return null; 87 } 88 try { 89 Object [] args = null; 90 if (argument != null) { 91 args = new Object [] { argument }; 92 } 93 if (!Modifier.isPublic(method.getModifiers()) && !method.isAccessible()) { 94 method.setAccessible(true); 95 } 96 return method.invoke(visitor, args); 97 98 } 99 catch (Exception ex) { 100 ReflectionUtils.handleReflectionException(ex); 101 throw new IllegalStateException ("Should never get here"); 102 } 103 } 104 105 109 private Method getMethod(Class visitorClass, Object argument) { 110 ClassVisitMethods visitMethods = (ClassVisitMethods) this.visitorClassVisitMethods.get(visitorClass); 111 return visitMethods.getVisitMethod(argument != null ? argument.getClass() : null); 112 } 113 114 115 118 private static class ClassVisitMethods { 119 120 private final Class visitorClass; 121 122 private CachingMapDecorator visitMethodCache = new CachingMapDecorator() { 123 public Object create(Object argumentClazz) { 124 if (argumentClazz == null) { 125 return findNullVisitorMethod(); 126 } 127 Method method = findVisitMethod((Class )argumentClazz); 128 if (method == null) { 129 method = findDefaultVisitMethod(); 130 } 131 return method; 132 } 133 }; 134 135 private ClassVisitMethods(Class visitorClass) { 136 this.visitorClass = visitorClass; 137 } 138 139 private Method findNullVisitorMethod() { 140 for (Class clazz = this.visitorClass; clazz != null; clazz = clazz.getSuperclass()) { 141 try { 142 return clazz.getDeclaredMethod(VISIT_NULL, (Class [])null); 143 } 144 catch (NoSuchMethodException e) { 145 } 146 } 147 return findDefaultVisitMethod(); 148 } 149 150 private Method findDefaultVisitMethod() { 151 final Class [] args = {Object .class}; 152 for (Class clazz = this.visitorClass; clazz != null; clazz = clazz.getSuperclass()) { 153 try { 154 return clazz.getDeclaredMethod(VISIT_METHOD, args); 155 } 156 catch (NoSuchMethodException e) { 157 } 158 } 159 if (logger.isWarnEnabled()) { 160 logger.warn("No default '" + VISIT_METHOD + "' method found. Returning <null>"); 161 } 162 return null; 163 } 164 165 168 private Method getVisitMethod(Class argumentClass) { 169 return (Method ) this.visitMethodCache.get(argumentClass); 170 } 171 172 175 private Method findVisitMethod(Class rootArgumentType) { 176 if (rootArgumentType == Object .class) { 177 return null; 178 } 179 LinkedList classQueue = new LinkedList (); 180 classQueue.addFirst(rootArgumentType); 181 182 while (!classQueue.isEmpty()) { 183 Class argumentType = (Class )classQueue.removeLast(); 184 try { 187 if (logger.isDebugEnabled()) { 188 logger.debug("Looking for method " + VISIT_METHOD + "(" + argumentType + ")"); 189 } 190 return findVisitMethod(this.visitorClass, argumentType); 191 } 192 catch (NoSuchMethodException e) { 193 if (!argumentType.isInterface() && (argumentType.getSuperclass() != Object .class)) { 195 classQueue.addFirst(argumentType.getSuperclass()); 196 } 197 198 Class [] interfaces = argumentType.getInterfaces(); 200 for (int i = 0; i < interfaces.length; i++) { 201 classQueue.addFirst(interfaces[i]); 202 } 203 } 204 } 205 return findDefaultVisitMethod(); 207 } 208 209 private Method findVisitMethod(Class visitorClass, Class argumentType) throws NoSuchMethodException { 210 try { 211 return visitorClass.getDeclaredMethod(VISIT_METHOD, new Class [] {argumentType}); 212 } 213 catch (NoSuchMethodException ex) { 214 if (visitorClass.getSuperclass() != Object .class) { 216 return findVisitMethod(visitorClass.getSuperclass(), argumentType); 217 } 218 else { 219 throw ex; 220 } 221 } 222 } 223 } 224 225 } 226 | Popular Tags |