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
023package org.granite.generator.as3.reflect;
024
025import java.lang.annotation.Annotation;
026import java.lang.reflect.Field;
027import java.lang.reflect.Modifier;
028import java.lang.reflect.ParameterizedType;
029import java.lang.reflect.Type;
030import java.lang.reflect.TypeVariable;
031import java.util.ArrayList;
032import java.util.Arrays;
033import java.util.List;
034
035import org.granite.generator.as3.ClientType;
036import org.granite.generator.as3.PropertyType;
037
038
039/**
040 * @author Franck WOLFF
041 */
042public 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}