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.ParameterizedType;
025    import java.lang.reflect.Type;
026    import java.lang.reflect.TypeVariable;
027    import java.util.ArrayList;
028    import java.util.Arrays;
029    import java.util.List;
030    
031    import org.granite.generator.as3.ClientType;
032    import org.granite.messaging.amf.io.util.externalizer.annotation.ExternalizedProperty;
033    import org.granite.util.ClassUtil;
034    
035    /**
036     * @author Franck WOLFF
037     */
038    public class JavaMethodProperty implements JavaProperty {
039    
040        private final String name;
041        private final JavaMethod readMethod;
042        private final JavaMethod writeMethod;
043        private final Class<?> type;
044        private final Type genericType;
045        private final ClientType clientType;
046        private final boolean externalizedProperty;
047    
048        public JavaMethodProperty(JavaTypeFactory provider, String name, JavaMethod readMethod, JavaMethod writeMethod) {
049            this(provider, name, readMethod, writeMethod, null);
050        }
051        
052        public JavaMethodProperty(JavaTypeFactory provider, String name, JavaMethod readMethod, JavaMethod writeMethod, ParameterizedType declaringType) {
053            if (name == null || (readMethod == null && writeMethod == null))
054                throw new NullPointerException("Invalid parameters");
055            this.name = name;
056            this.readMethod = readMethod;
057            this.writeMethod = writeMethod;
058            Type genericType = (
059                readMethod != null ?
060                readMethod.getMember().getGenericReturnType() :
061                writeMethod.getMember().getGenericParameterTypes()[0]
062            );
063            Class<?> declaringClass = readMethod != null ? readMethod.getMember().getDeclaringClass() : writeMethod.getMember().getDeclaringClass();
064            if (genericType instanceof TypeVariable && declaringType != null) {
065                    int index = -1;
066                    for (int i = 0; i < declaringClass.getTypeParameters().length; i++) {
067                            if (declaringClass.getTypeParameters()[i] == genericType) {
068                                    index = i;
069                                    break;
070                            }
071                    }
072                    if (index >= 0 && index < declaringType.getActualTypeArguments().length)
073                            genericType = declaringType.getActualTypeArguments()[index];
074            }
075            this.type = ClassUtil.classOfType(genericType);
076            this.genericType = genericType;
077            ClientType clientType = provider.getClientType(genericType, null, null, true);
078            if (clientType == null)
079                    clientType = provider.getAs3Type(type);
080            this.clientType = clientType;
081            this.externalizedProperty = (
082                    readMethod != null &&
083                    ClassUtil.isAnnotationPresent(readMethod.getMember(), ExternalizedProperty.class)
084            );
085        }
086    
087        @Override
088            public String getName() {
089            return name;
090        }
091        
092        @Override
093            public String getCapitalizedName() {
094            return getName().substring(0, 1).toUpperCase() + getName().substring(1);
095        }
096    
097        @Override
098            public Class<?> getType() {
099            return type;
100        }
101        
102        public Type getGenericType() {
103            return genericType;
104        }
105        
106        @Override
107            public Type[] getGenericTypes() {
108                    Type type = readMethod != null ? readMethod.getMember().getGenericReturnType() : writeMethod.getMember().getGenericParameterTypes()[0];
109                    if (!(type instanceof ParameterizedType))
110                            return null;
111                    return ((ParameterizedType)type).getActualTypeArguments();
112        }
113    
114        @Override
115            public boolean isReadable() {
116            return (readMethod != null);
117        }
118    
119        @Override
120            public boolean isWritable() {
121            return (writeMethod != null);
122        }
123    
124        @Override
125            public boolean isExternalizedProperty() {
126            return externalizedProperty;
127        }
128    
129        @Override
130            public boolean isEnum() {
131                    return (type.isEnum() || Enum.class.getName().equals(type.getName()));
132            }
133    
134            @Override
135            public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
136            return (
137                (readMethod != null && readMethod.getMember().isAnnotationPresent(annotationClass)) ||
138                (writeMethod != null && writeMethod.getMember().isAnnotationPresent(annotationClass))
139            );
140        }
141    
142        @Override
143            public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
144            T annotation = null;
145            if (readMethod != null) {
146                    annotation = readMethod.getMember().getAnnotation(annotationClass);
147                    if (annotation != null)
148                            return annotation;
149            }
150            if (writeMethod != null) {
151                    annotation = writeMethod.getMember().getAnnotation(annotationClass);
152                    if (annotation != null)
153                            return annotation;
154            }
155            return null;
156        }
157        
158        @Override
159            public Annotation[] getDeclaredAnnotations() {
160            List<Annotation> annos = new ArrayList<Annotation>();
161            if (readMethod != null)
162                    annos.addAll(Arrays.asList(readMethod.getMember().getDeclaredAnnotations()));
163            if (writeMethod != null)
164                    annos.addAll(Arrays.asList(writeMethod.getMember().getDeclaredAnnotations()));
165            return annos.toArray(new Annotation[0]);
166        }
167    
168        @Override
169            public boolean isReadOverride() {
170            return (readMethod != null && readMethod.isOverride());
171        }
172    
173        @Override
174            public boolean isWriteOverride() {
175            return (writeMethod != null && writeMethod.isOverride());
176        }
177    
178        @Override
179            public JavaMethod getReadMethod() {
180            return readMethod;
181        }
182    
183        @Override
184            public JavaMethod getWriteMethod() {
185            return writeMethod;
186        }
187    
188        public ClientType getAs3Type() {
189            return clientType;
190        }
191    
192        @Override
193            public ClientType getClientType() {
194            return clientType;
195        }
196    
197        @Override
198            public int compareTo(JavaProperty o) {
199            return name.compareTo(o.getName());
200        }
201    
202        @Override
203        public boolean equals(Object obj) {
204            if (this == obj)
205                return true;
206            if (obj instanceof JavaMethodProperty)
207                return ((JavaMethodProperty)obj).name.equals(name);
208            return false;
209        }
210    
211        @Override
212        public int hashCode() {
213            return name.hashCode();
214        }
215    }