1 package com.fasterxml.jackson.databind.introspect; 2 3 import java.lang.reflect.*; 4 5 import com.fasterxml.jackson.databind.JavaType; 6 import com.fasterxml.jackson.databind.util.ClassUtil; 7 8 public final class AnnotatedMethod 9 extends AnnotatedWithParams 10 implements java.io.Serializable 11 { 12 private static final long serialVersionUID = 1L; 13 14 final protected transient Method _method; 15 16 // // Simple lazy-caching: 17 18 protected Class<?>[] _paramClasses; 19 20 /** 21 * Field that is used to make JDK serialization work with this 22 * object. 23 * 24 * @since 2.1 25 */ 26 protected Serialization _serialization; 27 28 /* 29 /***************************************************** 30 /* Life-cycle 31 /***************************************************** 32 */ 33 AnnotatedMethod(TypeResolutionContext ctxt, Method method, AnnotationMap classAnn, AnnotationMap[] paramAnnotations)34 public AnnotatedMethod(TypeResolutionContext ctxt, Method method, 35 AnnotationMap classAnn, AnnotationMap[] paramAnnotations) 36 { 37 super(ctxt, classAnn, paramAnnotations); 38 if (method == null) { 39 throw new IllegalArgumentException("Cannot construct AnnotatedMethod with null Method"); 40 } 41 _method = method; 42 } 43 44 /** 45 * Method used for JDK serialization support 46 * @since 2.1 47 */ AnnotatedMethod(Serialization ser)48 protected AnnotatedMethod(Serialization ser) 49 { 50 super(null, null, null); 51 _method = null; 52 _serialization = ser; 53 } 54 55 @Override withAnnotations(AnnotationMap ann)56 public AnnotatedMethod withAnnotations(AnnotationMap ann) { 57 return new AnnotatedMethod(_typeContext, _method, ann, _paramAnnotations); 58 } 59 60 61 @Override getAnnotated()62 public Method getAnnotated() { return _method; } 63 64 @Override getModifiers()65 public int getModifiers() { return _method.getModifiers(); } 66 67 @Override getName()68 public String getName() { return _method.getName(); } 69 70 /** 71 * For methods, this returns declared return type, which is only 72 * useful with getters (setters do not return anything; hence `Void` 73 * would be returned here) 74 */ 75 @Override getType()76 public JavaType getType() { 77 return _typeContext.resolveType(_method.getGenericReturnType()); 78 } 79 80 /** 81 * For methods, this returns declared return type, which is only 82 * useful with getters (setters do not usually return anything; 83 * hence "void" type is returned here) 84 */ 85 @Override getRawType()86 public Class<?> getRawType() { 87 return _method.getReturnType(); 88 } 89 90 /* 91 /***************************************************** 92 /* AnnotatedWithParams 93 /***************************************************** 94 */ 95 96 @Override call()97 public final Object call() throws Exception { 98 return _method.invoke(null); 99 } 100 101 @Override call(Object[] args)102 public final Object call(Object[] args) throws Exception { 103 return _method.invoke(null, args); 104 } 105 106 @Override call1(Object arg)107 public final Object call1(Object arg) throws Exception { 108 return _method.invoke(null, arg); 109 } 110 callOn(Object pojo)111 public final Object callOn(Object pojo) throws Exception { 112 return _method.invoke(pojo, (Object[]) null); 113 } 114 callOnWith(Object pojo, Object... args)115 public final Object callOnWith(Object pojo, Object... args) throws Exception { 116 return _method.invoke(pojo, args); 117 } 118 119 /* 120 /******************************************************** 121 /* AnnotatedMember impl 122 /******************************************************** 123 */ 124 125 @Override getParameterCount()126 public int getParameterCount() { 127 return getRawParameterTypes().length; 128 } 129 130 @Override getRawParameterType(int index)131 public Class<?> getRawParameterType(int index) 132 { 133 Class<?>[] types = getRawParameterTypes(); 134 return (index >= types.length) ? null : types[index]; 135 } 136 137 @Override getParameterType(int index)138 public JavaType getParameterType(int index) { 139 Type[] types = _method.getGenericParameterTypes(); 140 if (index >= types.length) { 141 return null; 142 } 143 return _typeContext.resolveType(types[index]); 144 } 145 146 @Override 147 @Deprecated // since 2.7 getGenericParameterType(int index)148 public Type getGenericParameterType(int index) { 149 Type[] types = getGenericParameterTypes(); 150 if (index >= types.length) { 151 return null; 152 } 153 return types[index]; 154 } 155 156 @Override getDeclaringClass()157 public Class<?> getDeclaringClass() { return _method.getDeclaringClass(); } 158 159 @Override getMember()160 public Method getMember() { return _method; } 161 162 @Override setValue(Object pojo, Object value)163 public void setValue(Object pojo, Object value) throws IllegalArgumentException 164 { 165 try { 166 _method.invoke(pojo, value); 167 } catch (IllegalAccessException | InvocationTargetException e) { 168 throw new IllegalArgumentException("Failed to setValue() with method " 169 +getFullName()+": "+e.getMessage(), e); 170 } 171 } 172 173 @Override getValue(Object pojo)174 public Object getValue(Object pojo) throws IllegalArgumentException 175 { 176 try { 177 return _method.invoke(pojo, (Object[]) null); 178 } catch (IllegalAccessException | InvocationTargetException e) { 179 throw new IllegalArgumentException("Failed to getValue() with method " 180 +getFullName()+": "+e.getMessage(), e); 181 } 182 } 183 184 /* 185 /***************************************************** 186 /* Extended API, generic 187 /***************************************************** 188 */ 189 190 @Override getFullName()191 public String getFullName() { 192 final String methodName = super.getFullName(); 193 switch (getParameterCount()) { 194 case 0: 195 return methodName+"()"; 196 case 1: 197 return methodName+"("+getRawParameterType(0).getName()+")"; 198 default: 199 } 200 return String.format("%s(%d params)", super.getFullName(), getParameterCount()); 201 } 202 getRawParameterTypes()203 public Class<?>[] getRawParameterTypes() 204 { 205 if (_paramClasses == null) { 206 _paramClasses = _method.getParameterTypes(); 207 } 208 return _paramClasses; 209 } 210 211 @Deprecated // since 2.7 getGenericParameterTypes()212 public Type[] getGenericParameterTypes() { 213 return _method.getGenericParameterTypes(); 214 } 215 getRawReturnType()216 public Class<?> getRawReturnType() { 217 return _method.getReturnType(); 218 } 219 220 /** 221 * Helper method that can be used to check whether method returns 222 * a value or not; if return type declared as <code>void</code>, returns 223 * false, otherwise true 224 * 225 * @since 2.4 226 * 227 * @deprecated Since 2.12 (related to [databind#2675]), needs to be configurable 228 */ 229 @Deprecated hasReturnType()230 public boolean hasReturnType() { 231 Class<?> rt = getRawReturnType(); 232 // also, as per [databind#2675], only consider `void` to be real "No return type" 233 return (rt != Void.TYPE); 234 } 235 236 /* 237 /******************************************************** 238 /* Other 239 /******************************************************** 240 */ 241 242 @Override toString()243 public String toString() { 244 return "[method "+getFullName()+"]"; 245 } 246 247 @Override hashCode()248 public int hashCode() { 249 return _method.getName().hashCode(); 250 } 251 252 @Override equals(Object o)253 public boolean equals(Object o) { 254 if (o == this) return true; 255 return ClassUtil.hasClass(o, getClass()) 256 && (((AnnotatedMethod) o)._method == _method); 257 } 258 259 /* 260 /********************************************************** 261 /* JDK serialization handling 262 /********************************************************** 263 */ 264 writeReplace()265 Object writeReplace() { 266 return new AnnotatedMethod(new Serialization(_method)); 267 } 268 readResolve()269 Object readResolve() { 270 Class<?> clazz = _serialization.clazz; 271 try { 272 Method m = clazz.getDeclaredMethod(_serialization.name, 273 _serialization.args); 274 // 06-Oct-2012, tatu: Has "lost" its security override, may need to force back 275 if (!m.isAccessible()) { 276 ClassUtil.checkAndFixAccess(m, false); 277 } 278 return new AnnotatedMethod(null, m, null, null); 279 } catch (Exception e) { 280 throw new IllegalArgumentException("Could not find method '"+_serialization.name 281 +"' from Class '"+clazz.getName()); 282 } 283 } 284 285 /** 286 * Helper class that is used as the workaround to persist 287 * Field references. It basically just stores declaring class 288 * and field name. 289 */ 290 private final static class Serialization 291 implements java.io.Serializable 292 { 293 private static final long serialVersionUID = 1L; 294 protected Class<?> clazz; 295 protected String name; 296 protected Class<?>[] args; 297 Serialization(Method setter)298 public Serialization(Method setter) { 299 clazz = setter.getDeclaringClass(); 300 name = setter.getName(); 301 args = setter.getParameterTypes(); 302 } 303 } 304 } 305