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