001/** 002 * GRANITE DATA SERVICES 003 * Copyright (C) 2006-2014 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 */ 022package org.granite.generator.as3.reflect; 023 024import java.lang.annotation.Annotation; 025import java.lang.reflect.Method; 026import java.lang.reflect.ParameterizedType; 027import java.lang.reflect.Type; 028import java.util.HashSet; 029import java.util.Map; 030import java.util.Set; 031 032import org.granite.generator.as3.ClientType; 033import org.granite.generator.as3.PropertyType; 034import org.granite.generator.util.GenericTypeUtil; 035import org.granite.messaging.service.annotations.Param; 036import org.granite.tide.data.Lazy; 037import org.granite.util.ClassUtil; 038 039/** 040 * @author Franck WOLFF 041 */ 042public class JavaMethod extends JavaMember<Method> { 043 044 public enum MethodType { 045 GETTER, 046 SETTER, 047 OTHER 048 } 049 050 private final String name; 051 private final boolean override; 052 private final MethodType type; 053 private final String options; 054 private final Class<?> returnType; 055 private final Class<?>[] parameterTypes; 056 private final ClientType clientReturnType; 057 private final ClientType[] clientParameterTypes; 058 private final String[] clientParameterNames; 059 private final String[] clientParameterOptions; 060 private final Set<ClientType> clientAnnotationTypes = new HashSet<ClientType>(); 061 062 public JavaMethod(Method method, MethodType type) { 063 this(method, type, null, null); 064 } 065 066 public JavaMethod(Method method, MethodType type, JavaTypeFactory provider) { 067 this(method, type, provider, null); 068 } 069 070 public JavaMethod(Method method, MethodType type, JavaTypeFactory provider, ParameterizedType[] declaringTypes) { 071 super(method); 072 073 Class<?> objectClass = Object.class; 074 try { 075 objectClass = method.getDeclaringClass().getClassLoader().loadClass(Object.class.getCanonicalName()); 076 } 077 catch (Exception e) { 078 } 079 080 this.name = method.getName(); 081 082 // This part figure out if an ActionScript3 accessor should be marked as override. 083 Class<?> superclass = method.getDeclaringClass().getSuperclass(); 084 boolean override = false; 085 if (superclass != null && superclass != objectClass) { 086 try { 087 Method superMethod = superclass.getMethod(method.getName(), method.getParameterTypes()); 088 089 // if the super method is declared by an interface, check if we have a superclass that 090 // implements this interface. 091 if (superMethod.getDeclaringClass().isInterface()) 092 override = superMethod.getDeclaringClass().isAssignableFrom(superclass); 093 // if the super method is declared by a class, check if its declaring class implements, 094 // directly or not, an interface with a method with the same signature. 095 else { 096 for (Class<?> sc = superMethod.getDeclaringClass(); sc != null; sc = sc.getSuperclass()) { 097 for (Class<?> interfaze : sc.getInterfaces()) { 098 try { 099 interfaze.getMethod(method.getName(), method.getParameterTypes()); 100 override = true; 101 break; 102 } 103 catch (NoSuchMethodException e) { 104 // continue... 105 } 106 } 107 if (override) 108 break; 109 } 110 } 111 } catch (NoSuchMethodException e) { 112 // continue... 113 } 114 } 115 this.override = override; 116 117 this.type = type; 118 119 if (method.isAnnotationPresent(Lazy.class)) { 120 this.options = "Lazy"; 121 this.clientAnnotationTypes.add(provider.getClientType(Lazy.class, null, null, null)); 122 } 123 else 124 this.options = null; 125 126 if (type == MethodType.OTHER && provider != null) { 127 if (method.getReturnType() == void.class) { 128 this.returnType = Void.class; 129 this.clientReturnType = provider.getClientType(Void.class, null, null, PropertyType.SIMPLE); 130 } 131 else { 132 Type genericType = GenericTypeUtil.resolveTypeVariable(method.getGenericReturnType(), method.getDeclaringClass(), declaringTypes); 133 genericType = GenericTypeUtil.primitiveToWrapperType(genericType); 134 this.returnType = ClassUtil.classOfType(genericType); 135 136 ClientType returnType = provider.getClientType(genericType, method.getDeclaringClass(), declaringTypes, PropertyType.SIMPLE); 137 if (returnType == null) 138 returnType = provider.getAs3Type(this.returnType); 139 clientReturnType = returnType; 140 } 141 142 this.parameterTypes = method.getParameterTypes(); 143 this.clientParameterTypes = new ClientType[this.parameterTypes.length]; 144 this.clientParameterNames = new String[this.parameterTypes.length]; 145 this.clientParameterOptions = new String[this.parameterTypes.length]; 146 for (int i = 0; i < this.parameterTypes.length; i++) { 147 clientParameterNames[i] = getParamName(method, i); 148 if (Map.class.isAssignableFrom(parameterTypes[i])) 149 clientParameterTypes[i] = provider.getClientType(Object.class, null, null, PropertyType.SIMPLE); 150 else { 151 Type genericType = GenericTypeUtil.resolveTypeVariable(method.getGenericParameterTypes()[i], method.getDeclaringClass(), declaringTypes); 152 parameterTypes[i] = ClassUtil.classOfType(genericType); 153 154 ClientType paramType = provider.getClientType(genericType, method.getDeclaringClass(), declaringTypes, PropertyType.SIMPLE); 155 if (paramType == null) 156 paramType = provider.getAs3Type(parameterTypes[i]); 157 clientParameterTypes[i] = paramType; 158 } 159 160 Annotation[] annotations = method.getParameterAnnotations()[i]; 161 for (Annotation annotation : annotations) { 162 if (annotation.annotationType().equals(Lazy.class)) { 163 clientParameterOptions[i] = "Lazy"; 164 this.clientAnnotationTypes.add(provider.getClientType(Lazy.class, null, null, null)); 165 break; 166 } 167 } 168 } 169 } 170 else { 171 this.returnType = null; 172 this.parameterTypes = null; 173 this.clientReturnType = null; 174 this.clientParameterTypes = null; 175 this.clientParameterNames = null; 176 this.clientParameterOptions = null; 177 } 178 } 179 180 private String getParamName(Method method, int paramIndex) { 181 Annotation[][] annotations = method.getParameterAnnotations(); 182 if (annotations != null && annotations.length > paramIndex && annotations[paramIndex] != null) { 183 for (Annotation annotation : annotations[paramIndex]) { 184 if (annotation.annotationType().equals(Param.class)) 185 return ((Param)annotation).value(); 186 } 187 } 188 return "arg" + paramIndex; 189 } 190 191 public boolean isOverride() { 192 return override; 193 } 194 195 public MethodType getType() { 196 return type; 197 } 198 199 public String getOptions() { 200 return options; 201 } 202 203 public String getTypeName() { 204 return type.name(); 205 } 206 207 @Override 208 public String getName() { 209 return name; 210 } 211 212 public Class<?> getReturnType() { 213 return returnType; 214 } 215 216 public Class<?>[] getParameterTypes() { 217 return parameterTypes; 218 } 219 220 public ClientType[] getAs3ParameterTypes() { 221 return clientParameterTypes; 222 } 223 224 public String[] getAs3ParameterNames() { 225 return clientParameterNames; 226 } 227 228 public String[] getAs3ParameterOptions() { 229 return clientParameterOptions; 230 } 231 232 public ClientType getClientReturnType() { 233 return clientReturnType; 234 } 235 236 public ClientType[] getClientParameterTypes() { 237 return clientParameterTypes; 238 } 239 240 public String[] getClientParameterNames() { 241 return clientParameterNames; 242 } 243 244 public String[] getClientParameterOptions() { 245 return clientParameterOptions; 246 } 247 248 public Set<ClientType> getClientAnnotationTypes() { 249 return clientAnnotationTypes; 250 } 251}