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
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      */

48     protected AnnotatedMethod(Serialization ser)
49     {
50         super(nullnullnull);
51         _method = null;
52         _serialization = ser;
53     }
54
55     @Override
56     public AnnotatedMethod withAnnotations(AnnotationMap ann) {
57         return new AnnotatedMethod(_typeContext, _method, ann, _paramAnnotations);
58     }
59
60     @Override
61     public Method getAnnotated() { return _method; }
62
63     @Override
64     public int getModifiers() { return _method.getModifiers(); }
65
66     @Override
67     public String getName() { return _method.getName(); }
68
69     /**
70      * For methods, this returns declared return type, which is only
71      * useful with getters (setters do not return anything; hence `Void`
72      * would be returned here)
73      */

74     @Override
75     public JavaType getType() {
76         return _typeContext.resolveType(_method.getGenericReturnType());
77     }
78
79     /**
80      * For methods, this returns declared return type, which is only
81      * useful with getters (setters do not usually return anything;
82      * hence "void" type is returned here)
83      */

84     @Override
85     public Class<?> getRawType() {
86         return _method.getReturnType();
87     }
88
89     /*
90     /*****************************************************
91     /* AnnotatedWithParams
92     /*****************************************************
93      */

94     
95     @Override
96     public final Object call() throws Exception {
97         return _method.invoke(null);
98     }
99
100     @Override
101     public final Object call(Object[] args) throws Exception {
102         return _method.invoke(null, args);
103     }
104
105     @Override
106     public final Object call1(Object arg) throws Exception {
107         return _method.invoke(null, arg);
108     }
109
110     public final Object callOn(Object pojo) throws Exception {
111         return _method.invoke(pojo, (Object[]) null);
112     }
113
114     public final Object callOnWith(Object pojo, Object... args) throws Exception {
115         return _method.invoke(pojo, args);
116     }
117
118     /*
119     /********************************************************
120     /* AnnotatedMember impl
121     /********************************************************
122      */

123
124     @Override
125     public int getParameterCount() {
126         return getRawParameterTypes().length;
127     }
128     
129     @Override
130     public Class<?> getRawParameterType(int index)
131     {
132         Class<?>[] types = getRawParameterTypes();
133         return (index >= types.length) ? null : types[index];
134     }
135
136     @Override
137     public JavaType getParameterType(int index) {
138         Type[] types = _method.getGenericParameterTypes();
139         if (index >= types.length) {
140             return null;
141         }
142         return _typeContext.resolveType(types[index]);
143     }
144
145     @Override
146     @Deprecated // since 2.7
147     public Type getGenericParameterType(int index) {
148         Type[] types = getGenericParameterTypes();
149         if (index >= types.length) {
150             return null;
151         }
152         return types[index];
153     }
154     
155     @Override
156     public Class<?> getDeclaringClass() { return _method.getDeclaringClass(); }
157
158     @Override
159     public Method getMember() { return _method; }
160
161     @Override
162     public void setValue(Object pojo, Object value) throws IllegalArgumentException
163     {
164         try {
165             _method.invoke(pojo, value);
166         } catch (IllegalAccessException | InvocationTargetException e) {
167             throw new IllegalArgumentException("Failed to setValue() with method "
168                     +getFullName()+": "+e.getMessage(), e);
169         }
170     }
171
172     @Override
173     public Object getValue(Object pojo) throws IllegalArgumentException
174     {
175         try {
176             return _method.invoke(pojo, (Object[]) null);
177         } catch (IllegalAccessException | InvocationTargetException e) {
178             throw new IllegalArgumentException("Failed to getValue() with method "
179                     +getFullName()+": "+e.getMessage(), e);
180         }
181     }
182
183     /*
184     /*****************************************************
185     /* Extended API, generic
186     /*****************************************************
187      */

188
189     @Override
190     public String getFullName() {
191         return String.format("%s(%d params)"super.getFullName(), getParameterCount());
192     }
193
194     public Class<?>[] getRawParameterTypes()
195     {
196         if (_paramClasses == null) {
197             _paramClasses = _method.getParameterTypes();
198         }
199         return _paramClasses;
200     }
201
202     @Deprecated // since 2.7
203     public Type[] getGenericParameterTypes() {
204         return _method.getGenericParameterTypes();
205     }
206
207     public Class<?> getRawReturnType() {
208         return _method.getReturnType();
209     }
210
211     /**
212      * Helper method that can be used to check whether method returns
213      * a value or not; if return type declared as <code>void</code>, returns
214      * false, otherwise true
215      * 
216      * @since 2.4
217      */

218     public boolean hasReturnType() {
219         Class<?> rt = getRawReturnType();
220         return (rt != Void.TYPE && rt != Void.class);
221     }
222
223     /*
224     /********************************************************
225     /* Other
226     /********************************************************
227      */

228
229     @Override
230     public String toString() {
231         return "[method "+getFullName()+"]";
232     }
233
234     @Override
235     public int hashCode() {
236         return _method.getName().hashCode();
237     }
238     
239     @Override
240     public boolean equals(Object o) {
241         if (o == thisreturn true;
242         return ClassUtil.hasClass(o, getClass())
243                 && (((AnnotatedMethod) o)._method == _method);
244     }
245
246     /*
247     /**********************************************************
248     /* JDK serialization handling
249     /**********************************************************
250      */

251
252     Object writeReplace() {
253         return new AnnotatedMethod(new Serialization(_method));
254     }
255
256     Object readResolve() {
257         Class<?> clazz = _serialization.clazz;
258         try {
259             Method m = clazz.getDeclaredMethod(_serialization.name,
260                     _serialization.args);
261             // 06-Oct-2012, tatu: Has "lost" its security override, may need to force back
262             if (!m.isAccessible()) {
263                 ClassUtil.checkAndFixAccess(m, false);
264             }
265             return new AnnotatedMethod(null, m, nullnull);
266         } catch (Exception e) {
267             throw new IllegalArgumentException("Could not find method '"+_serialization.name
268                         +"' from Class '"+clazz.getName());
269         }
270     }
271     
272     /**
273      * Helper class that is used as the workaround to persist
274      * Field references. It basically just stores declaring class
275      * and field name.
276      */

277     private final static class Serialization
278         implements java.io.Serializable
279     {
280         private static final long serialVersionUID = 1L;
281         protected Class<?> clazz;
282         protected String name;
283         protected Class<?>[] args;
284
285         public Serialization(Method setter) {
286             clazz = setter.getDeclaringClass();
287             name = setter.getName();
288             args = setter.getParameterTypes();
289         }
290     }
291 }
292