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