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    }