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