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.util.Map;
026    
027    import org.granite.generator.as3.As3Type;
028    import org.granite.messaging.service.annotations.Param;
029    import org.granite.tide.data.Lazy;
030    
031    /**
032     * @author Franck WOLFF
033     */
034    public class JavaMethod extends JavaMember<Method> {
035    
036        public enum MethodType {
037            GETTER,
038            SETTER,
039            OTHER
040        }
041    
042        private final String name;
043        private final boolean override;
044        private final MethodType type;
045        private final String options;
046        private final Class<?>[] parameterTypes;
047        private final As3Type[] as3ParameterTypes;
048        private final String[] as3ParameterNames;
049        private final String[] as3ParameterOptions;
050        
051        public JavaMethod(Method method, MethodType type) {
052            this(method, type, null);
053        }
054        
055        public JavaMethod(Method method, MethodType type, JavaTypeFactory provider) {
056            super(method);
057    
058            Class<?> objectClass = Object.class;
059            try {
060                    objectClass = method.getDeclaringClass().getClassLoader().loadClass(Object.class.getCanonicalName());
061            }
062            catch (Exception e) {
063            }
064            
065            this.name = method.getName();
066    
067            // This part figure out if an ActionScript3 accessor should be marked as override.
068            Class<?> superclass = method.getDeclaringClass().getSuperclass();
069            boolean override = false;
070            if (superclass != null && superclass != objectClass) {
071                try {
072                    Method superMethod = superclass.getMethod(method.getName(), method.getParameterTypes());
073    
074                    // if the super method is declared by an interface, check if we have a superclass that
075                    // implements this interface.
076                    if (superMethod.getDeclaringClass().isInterface())
077                            override = superMethod.getDeclaringClass().isAssignableFrom(superclass);
078                    // if the super method is declared by a class, check if its declaring class implements,
079                    // directly or not, an interface with a method with the same signature.
080                    else {
081                            for (Class<?> sc = superMethod.getDeclaringClass(); sc != null; sc = sc.getSuperclass()) {
082                                    for (Class<?> interfaze : sc.getInterfaces()) {
083                                                    try {
084                                                            interfaze.getMethod(method.getName(), method.getParameterTypes());
085                                                            override = true;
086                                                            break;
087                                                    }
088                                                    catch (NoSuchMethodException e) {
089                                                            // continue...
090                                                    }
091                                            }
092                                    if (override)
093                                            break;
094                            }
095                    }
096                } catch (NoSuchMethodException e) {
097                    // continue...
098                }
099            }
100            this.override = override;
101    
102            this.type = type;
103            
104            if (method.isAnnotationPresent(Lazy.class))
105                    this.options = "Lazy";
106            else
107                    this.options = null;
108            
109                    if (type == MethodType.OTHER && provider != null) {
110                            this.parameterTypes = method.getParameterTypes();
111                            this.as3ParameterTypes = new As3Type[this.parameterTypes.length];
112                            this.as3ParameterNames = new String[this.parameterTypes.length];
113                            this.as3ParameterOptions = new String[this.parameterTypes.length];
114                            for (int i = 0; i < this.parameterTypes.length; i++) {
115                                    as3ParameterNames[i] = getParamName(method, i);
116                                    if (Map.class.isAssignableFrom(parameterTypes[i]))
117                                            as3ParameterTypes[i] = As3Type.OBJECT;
118                                    else
119                                            as3ParameterTypes[i] = provider.getAs3Type(this.parameterTypes[i]);
120                                    
121                                    Annotation[] annotations = method.getParameterAnnotations()[i];
122                                    for (Annotation annotation : annotations) {
123                                            if (annotation.annotationType().equals(Lazy.class)) {
124                                                    as3ParameterOptions[i] = "Lazy";
125                                                    break;
126                                            }
127                                    }                               
128                            }
129                    } 
130                    else {
131                            this.parameterTypes = null;
132                            this.as3ParameterTypes = null;
133                            this.as3ParameterNames = null;
134                            this.as3ParameterOptions = null;
135                    }
136        }
137        
138        private String getParamName(Method method, int paramIndex) {
139            Annotation[][] annotations = method.getParameterAnnotations();
140            if (annotations != null && annotations.length > paramIndex && annotations[paramIndex] != null) {
141                    for (Annotation annotation : annotations[paramIndex]) {
142                            if (annotation.annotationType().equals(Param.class))
143                                    return ((Param)annotation).value();
144                    }
145            }
146            return "arg" + paramIndex;
147        }
148    
149        public boolean isOverride() {
150            return override;
151        }
152    
153        public MethodType getType() {
154            return type;
155        }
156        
157        public String getOptions() {
158            return options;
159        }
160    
161        public String getTypeName() {
162            return type.name();
163        }
164        
165        @Override
166            public String getName() {
167            return name;
168        }
169       
170        public Class<?>[] getParameterTypes() {
171            return parameterTypes;
172        }
173    
174            public As3Type[] getAs3ParameterTypes() {
175                    return as3ParameterTypes;
176            }
177    
178            public String[] getAs3ParameterNames() {
179                    return as3ParameterNames;
180            }
181    
182            public String[] getAs3ParameterOptions() {
183                    return as3ParameterOptions;
184            }
185    }