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    
021    package org.granite.generator.javafx;
022    
023    import java.lang.reflect.GenericArrayType;
024    import java.lang.reflect.ParameterizedType;
025    import java.lang.reflect.Type;
026    import java.lang.reflect.TypeVariable;
027    import java.lang.reflect.WildcardType;
028    import java.util.HashMap;
029    import java.util.List;
030    import java.util.Map;
031    import java.util.Set;
032    
033    import org.granite.generator.as3.As3TypeFactory;
034    import org.granite.generator.as3.ClientType;
035    import org.granite.generator.util.GenericTypeUtil;
036    import org.granite.util.ClassUtil;
037    
038    /**
039     * @author Franck WOLFF
040     */
041    public class DefaultJavaFXTypeFactory implements As3TypeFactory {
042    
043        ///////////////////////////////////////////////////////////////////////////
044        // Fields.
045    
046        private final Map<Type, ClientType> simpleJava2JavaFXType = new HashMap<Type, ClientType>();
047        private final Map<Type, ClientType> propertyJava2JavaFXType = new HashMap<Type, ClientType>();
048        
049        
050        ///////////////////////////////////////////////////////////////////////////
051        // Constructors.
052    
053        public DefaultJavaFXTypeFactory() {
054            simpleJava2JavaFXType.put(Boolean.TYPE, JavaFXType.BOOLEAN);
055            simpleJava2JavaFXType.put(Integer.TYPE, JavaFXType.INT);
056            simpleJava2JavaFXType.put(Long.TYPE, JavaFXType.LONG);
057            simpleJava2JavaFXType.put(Float.TYPE, JavaFXType.FLOAT);
058            simpleJava2JavaFXType.put(Double.TYPE, JavaFXType.DOUBLE);
059            simpleJava2JavaFXType.put(String.class, JavaFXType.STRING);
060            
061            propertyJava2JavaFXType.put(Boolean.TYPE, JavaFXType.BOOLEAN_PROPERTY);
062            propertyJava2JavaFXType.put(Double.TYPE, JavaFXType.DOUBLE_PROPERTY);
063            propertyJava2JavaFXType.put(Float.TYPE, JavaFXType.FLOAT_PROPERTY);
064            propertyJava2JavaFXType.put(Long.TYPE, JavaFXType.LONG_PROPERTY);
065            propertyJava2JavaFXType.put(Integer.TYPE, JavaFXType.INT_PROPERTY);
066            propertyJava2JavaFXType.put(String.class, JavaFXType.STRING_PROPERTY);
067        }
068    
069        ///////////////////////////////////////////////////////////////////////////
070        // Fields.
071    
072        @Override
073            public void configure(boolean externalizeLong, boolean externalizeBigInteger, boolean externalizeBigDecimal) {
074            }
075    
076            @Override
077            public ClientType getClientType(Type jType, Class<?> declaringClass, ParameterizedType[] declaringTypes, boolean property) {
078            ClientType javafxType = getFromCache(jType, property);
079    
080            if (javafxType == null) {
081                    if (jType instanceof GenericArrayType) {
082                            Type componentType = ((GenericArrayType)jType).getGenericComponentType();
083                            javafxType = getClientType(componentType, declaringClass, declaringTypes, false).toArrayType();
084                    }
085                    else if (jType instanceof Class<?> && ((Class<?>)jType).isArray()) {
086                            javafxType = getClientType(((Class<?>)jType).getComponentType(), declaringClass, declaringTypes, false).toArrayType();
087                    }
088                    else {
089                            Class<?> jClass = ClassUtil.classOfType(jType);
090                            String genericType = "";
091                            if (jType instanceof ParameterizedType) {
092                                    for (Type t : ((ParameterizedType)jType).getActualTypeArguments()) {
093                                            if (genericType.length() > 0)
094                                                    genericType += ", ";
095                                            genericType += ClassUtil.classOfType(t).getSimpleName();
096                                    }
097                                    genericType = "<" + genericType + ">";
098                            }
099                        if (property && List.class.isAssignableFrom(jClass)) {
100                            javafxType = new JavaFXType("javafx.collections", "ObservableList" + genericType, null, "org.granite.client.persistence.javafx.PersistentList" + genericType, null);
101                        }
102                        else if (property && Set.class.isAssignableFrom(jClass)) {
103                            javafxType = new JavaFXType("javafx.collections", "ObservableList" + genericType, null, "org.granite.client.persistence.javafx.PersistentSet" + genericType, null);
104                        }
105                        else if (property && Map.class.isAssignableFrom(jClass)) {
106                            javafxType = new JavaFXType("javafx.collections", "ObservableMap" + genericType, null, "org.granite.client.persistence.javafx.PersistentMap" + genericType, null);
107                        }
108                        else if (jClass.getName().equals("com.google.appengine.api.datastore.Key")) {
109                            javafxType = JavaFXType.STRING;
110                        }
111                        else if (jClass.getName().equals("org.springframework.data.domain.Page")) {
112                            javafxType = new JavaFXType("org.granite.tide.data.model", "Page" + genericType, null);
113                        }
114                        else if (jClass.getName().equals("org.springframework.data.domain.Pageable")) {
115                            javafxType = JavaFXType.PAGE_INFO;
116                        }
117                        else if (jClass.getName().equals("org.springframework.data.domain.Sort")) {
118                            javafxType = JavaFXType.SORT_INFO;
119                        }
120                        else {
121                            javafxType = createJavaFXType(jType, declaringClass, declaringTypes, property);
122                        }
123                    }
124    
125                putInCache(jType, property, javafxType);
126            }
127    
128            return javafxType;
129        }
130    
131            @Override
132            public ClientType getAs3Type(Class<?> jType) {
133                    return getClientType(jType, null, null, false);
134            }
135    
136        protected JavaFXType createJavaFXType(Type jType, Class<?> declaringClass, ParameterizedType[] declaringTypes, boolean property) {
137            Class<?> jClass = ClassUtil.classOfType(jType);
138            String name = jClass.getSimpleName();
139            if (jClass.isMemberClass())
140                    name = jClass.getEnclosingClass().getSimpleName() + '$' + jClass.getSimpleName();
141            else if (jType instanceof ParameterizedType) {
142                    ParameterizedType type = (ParameterizedType)jType;
143                    name = name + "<";
144                    boolean first = true;
145                    for (Type ata : type.getActualTypeArguments()) {
146                            if (first)
147                                    first = false;
148                            else
149                                    name = name + ", ";
150                            if (ata instanceof TypeVariable<?>) {
151                                    Type resolved = GenericTypeUtil.resolveTypeVariable(ata, declaringClass, declaringTypes);
152                                    if (resolved instanceof TypeVariable<?>)
153                                            name = name + "?";
154                                    else
155                                            name = name + ClassUtil.classOfType(resolved).getSimpleName();
156                            }
157                            else if (ata instanceof WildcardType) {
158                                    name = name + "?";
159                                    if (((WildcardType)ata).getLowerBounds().length > 0) {
160                                            String bounds = "";
161                                            for (Type t : ((WildcardType)ata).getLowerBounds()) {
162                                                    Type resolved = GenericTypeUtil.resolveTypeVariable(t, declaringClass, declaringTypes);
163                                                    if (resolved instanceof TypeVariable<?>) {
164                                                            bounds = "";
165                                                            break;
166                                                    }
167                                                    if (bounds.length() > 0)
168                                                            bounds = bounds + ", ";
169                                                    bounds = bounds + ClassUtil.classOfType(resolved).getSimpleName();
170                                            }
171                                            if (bounds.length() > 0)
172                                                    name = name + " super " + bounds;
173                                    }
174                                    if (((WildcardType)ata).getUpperBounds().length > 0) {
175                                            String bounds = "";
176                                            for (Type t : ((WildcardType)ata).getUpperBounds()) {
177                                                    Type resolved = GenericTypeUtil.resolveTypeVariable(t, declaringClass, declaringTypes);
178                                                    if (resolved instanceof TypeVariable<?>) {
179                                                            bounds = "";
180                                                            break;
181                                                    }
182                                                    if (bounds.length() > 0)
183                                                            bounds = bounds + ", ";
184                                                    bounds = bounds + ClassUtil.classOfType(resolved).getSimpleName();
185                                            }
186                                            if (bounds.length() > 0)
187                                                    name = name + " extends " + bounds;
188                                    }
189                            }
190                            else
191                                    name = name + ClassUtil.classOfType(ata).getSimpleName();
192                    }
193                    name = name + ">";
194            }
195            
196            if (property)
197                    return new JavaFXType(ClassUtil.getPackageName(jClass), name, "javafx.beans.property.ObjectProperty<" + name + ">", "javafx.beans.property.SimpleObjectProperty<" + name + ">", null);
198            return new JavaFXType(ClassUtil.getPackageName(jClass), name, null);
199        }
200    
201        protected ClientType getFromCache(Type jType, boolean property) {
202            if (jType == null)
203                throw new NullPointerException("jType must be non null");
204            if (property)
205                    return propertyJava2JavaFXType.get(jType);
206            return simpleJava2JavaFXType.get(jType);
207        }
208    
209        protected void putInCache(Type jType, boolean property, ClientType javafxType) {
210            if (jType == null || javafxType == null)
211                throw new NullPointerException("jType and JavaFXType must be non null");
212            if (property)
213                    propertyJava2JavaFXType.put(jType, javafxType);
214            else
215                    simpleJava2JavaFXType.put(jType, javafxType);
216        }
217    }