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