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 }