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