001 /**
002 * GRANITE DATA SERVICES
003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 * This file is part of the Granite Data Services Platform.
006 *
007 * Granite Data Services is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * Granite Data Services is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015 * General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020 * USA, or see <http://www.gnu.org/licenses/>.
021 */
022
023 package org.granite.generator.as3.reflect;
024
025 import java.lang.annotation.Annotation;
026 import java.lang.reflect.Method;
027 import java.lang.reflect.ParameterizedType;
028 import java.lang.reflect.Type;
029 import java.util.Map;
030
031 import org.granite.generator.as3.ClientType;
032 import org.granite.generator.as3.PropertyType;
033 import org.granite.generator.util.GenericTypeUtil;
034 import org.granite.messaging.service.annotations.Param;
035 import org.granite.tide.data.Lazy;
036 import org.granite.util.ClassUtil;
037
038 /**
039 * @author Franck WOLFF
040 */
041 public class JavaMethod extends JavaMember<Method> {
042
043 public enum MethodType {
044 GETTER,
045 SETTER,
046 OTHER
047 }
048
049 private final String name;
050 private final boolean override;
051 private final MethodType type;
052 private final String options;
053 private final Class<?> returnType;
054 private final Class<?>[] parameterTypes;
055 private final ClientType clientReturnType;
056 private final ClientType[] clientParameterTypes;
057 private final String[] clientParameterNames;
058 private final String[] clientParameterOptions;
059
060 public JavaMethod(Method method, MethodType type) {
061 this(method, type, null, null);
062 }
063
064 public JavaMethod(Method method, MethodType type, JavaTypeFactory provider) {
065 this(method, type, provider, null);
066 }
067
068 public JavaMethod(Method method, MethodType type, JavaTypeFactory provider, ParameterizedType[] declaringTypes) {
069 super(method);
070
071 Class<?> objectClass = Object.class;
072 try {
073 objectClass = method.getDeclaringClass().getClassLoader().loadClass(Object.class.getCanonicalName());
074 }
075 catch (Exception e) {
076 }
077
078 this.name = method.getName();
079
080 // This part figure out if an ActionScript3 accessor should be marked as override.
081 Class<?> superclass = method.getDeclaringClass().getSuperclass();
082 boolean override = false;
083 if (superclass != null && superclass != objectClass) {
084 try {
085 Method superMethod = superclass.getMethod(method.getName(), method.getParameterTypes());
086
087 // if the super method is declared by an interface, check if we have a superclass that
088 // implements this interface.
089 if (superMethod.getDeclaringClass().isInterface())
090 override = superMethod.getDeclaringClass().isAssignableFrom(superclass);
091 // if the super method is declared by a class, check if its declaring class implements,
092 // directly or not, an interface with a method with the same signature.
093 else {
094 for (Class<?> sc = superMethod.getDeclaringClass(); sc != null; sc = sc.getSuperclass()) {
095 for (Class<?> interfaze : sc.getInterfaces()) {
096 try {
097 interfaze.getMethod(method.getName(), method.getParameterTypes());
098 override = true;
099 break;
100 }
101 catch (NoSuchMethodException e) {
102 // continue...
103 }
104 }
105 if (override)
106 break;
107 }
108 }
109 } catch (NoSuchMethodException e) {
110 // continue...
111 }
112 }
113 this.override = override;
114
115 this.type = type;
116
117 if (method.isAnnotationPresent(Lazy.class))
118 this.options = "Lazy";
119 else
120 this.options = null;
121
122 if (type == MethodType.OTHER && provider != null) {
123 if (method.getReturnType() == void.class) {
124 this.returnType = Void.class;
125 this.clientReturnType = provider.getClientType(Void.class, null, null, PropertyType.SIMPLE);
126 }
127 else {
128 Type genericType = GenericTypeUtil.resolveTypeVariable(method.getGenericReturnType(), method.getDeclaringClass(), declaringTypes);
129 genericType = GenericTypeUtil.primitiveToWrapperType(genericType);
130 this.returnType = ClassUtil.classOfType(genericType);
131
132 ClientType returnType = provider.getClientType(genericType, method.getDeclaringClass(), declaringTypes, PropertyType.SIMPLE);
133 if (returnType == null)
134 returnType = provider.getAs3Type(this.returnType);
135 clientReturnType = returnType;
136 }
137
138 this.parameterTypes = method.getParameterTypes();
139 this.clientParameterTypes = new ClientType[this.parameterTypes.length];
140 this.clientParameterNames = new String[this.parameterTypes.length];
141 this.clientParameterOptions = new String[this.parameterTypes.length];
142 for (int i = 0; i < this.parameterTypes.length; i++) {
143 clientParameterNames[i] = getParamName(method, i);
144 if (Map.class.isAssignableFrom(parameterTypes[i]))
145 clientParameterTypes[i] = provider.getClientType(Object.class, null, null, PropertyType.SIMPLE);
146 else {
147 Type genericType = GenericTypeUtil.resolveTypeVariable(method.getGenericParameterTypes()[i], method.getDeclaringClass(), declaringTypes);
148 parameterTypes[i] = ClassUtil.classOfType(genericType);
149
150 ClientType paramType = provider.getClientType(genericType, method.getDeclaringClass(), declaringTypes, PropertyType.SIMPLE);
151 if (paramType == null)
152 paramType = provider.getAs3Type(parameterTypes[i]);
153 clientParameterTypes[i] = paramType;
154 }
155
156 Annotation[] annotations = method.getParameterAnnotations()[i];
157 for (Annotation annotation : annotations) {
158 if (annotation.annotationType().equals(Lazy.class)) {
159 clientParameterOptions[i] = "Lazy";
160 break;
161 }
162 }
163 }
164 }
165 else {
166 this.returnType = null;
167 this.parameterTypes = null;
168 this.clientReturnType = null;
169 this.clientParameterTypes = null;
170 this.clientParameterNames = null;
171 this.clientParameterOptions = null;
172 }
173 }
174
175 private String getParamName(Method method, int paramIndex) {
176 Annotation[][] annotations = method.getParameterAnnotations();
177 if (annotations != null && annotations.length > paramIndex && annotations[paramIndex] != null) {
178 for (Annotation annotation : annotations[paramIndex]) {
179 if (annotation.annotationType().equals(Param.class))
180 return ((Param)annotation).value();
181 }
182 }
183 return "arg" + paramIndex;
184 }
185
186 public boolean isOverride() {
187 return override;
188 }
189
190 public MethodType getType() {
191 return type;
192 }
193
194 public String getOptions() {
195 return options;
196 }
197
198 public String getTypeName() {
199 return type.name();
200 }
201
202 @Override
203 public String getName() {
204 return name;
205 }
206
207 public Class<?> getReturnType() {
208 return returnType;
209 }
210
211 public Class<?>[] getParameterTypes() {
212 return parameterTypes;
213 }
214
215 public ClientType[] getAs3ParameterTypes() {
216 return clientParameterTypes;
217 }
218
219 public String[] getAs3ParameterNames() {
220 return clientParameterNames;
221 }
222
223 public String[] getAs3ParameterOptions() {
224 return clientParameterOptions;
225 }
226
227 public ClientType getClientReturnType() {
228 return clientReturnType;
229 }
230
231 public ClientType[] getClientParameterTypes() {
232 return clientParameterTypes;
233 }
234
235 public String[] getClientParameterNames() {
236 return clientParameterNames;
237 }
238
239 public String[] getClientParameterOptions() {
240 return clientParameterOptions;
241 }
242 }