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