summaryrefslogtreecommitdiffstats
path: root/src/com/vaadin
diff options
context:
space:
mode:
authorArtur Signell <artur@vaadin.com>2012-02-28 18:28:59 +0200
committerArtur Signell <artur@vaadin.com>2012-02-28 18:28:59 +0200
commite9882b1b664446c855b7b6c04468b4bfbbf314da (patch)
treee03756c4e8a4a1f9854a5efa5e444f912237ccf9 /src/com/vaadin
parentd718b7ce765fb8173d1465c63ad3f36d980b7938 (diff)
downloadvaadin-framework-e9882b1b664446c855b7b6c04468b4bfbbf314da.tar.gz
vaadin-framework-e9882b1b664446c855b7b6c04468b4bfbbf314da.zip
#8442 Serialize also nested beans, #8441 Allow using static inner
classes for communication
Diffstat (limited to 'src/com/vaadin')
-rw-r--r--src/com/vaadin/terminal/gwt/server/JsonCodec.java11
-rw-r--r--src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java109
-rw-r--r--src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java115
3 files changed, 178 insertions, 57 deletions
diff --git a/src/com/vaadin/terminal/gwt/server/JsonCodec.java b/src/com/vaadin/terminal/gwt/server/JsonCodec.java
index d8964f85a6..09afea3f74 100644
--- a/src/com/vaadin/terminal/gwt/server/JsonCodec.java
+++ b/src/com/vaadin/terminal/gwt/server/JsonCodec.java
@@ -19,7 +19,6 @@ import com.vaadin.external.json.JSONException;
import com.vaadin.external.json.JSONObject;
import com.vaadin.terminal.Paintable;
import com.vaadin.terminal.gwt.client.communication.JsonEncoder;
-import com.vaadin.terminal.gwt.client.communication.SharedState;
/**
* Decoder for converting RPC parameters and other values from JSON in transfer
@@ -153,9 +152,6 @@ public class JsonCodec implements Serializable {
// TODO as undefined type?
return combineTypeAndValue(JsonEncoder.VTYPE_UNDEFINED,
JSONObject.NULL);
- } else if (value instanceof SharedState) {
- return combineTypeAndValue(value.getClass().getName(),
- encodeObject(value, idMapper));
} else if (value instanceof String[]) {
String[] array = (String[]) value;
JSONArray jsonArray = new JSONArray();
@@ -181,9 +177,14 @@ public class JsonCodec implements Serializable {
Paintable paintable = (Paintable) value;
return combineTypeAndValue(JsonEncoder.VTYPE_PAINTABLE,
idMapper.getPaintableId(paintable));
- } else {
+ } else if (getTransportType(value) != JsonEncoder.VTYPE_UNDEFINED) {
return combineTypeAndValue(getTransportType(value),
String.valueOf(value));
+ } else {
+ // Any object that we do not know how to encode we encode by looping
+ // through fields
+ return combineTypeAndValue(value.getClass().getCanonicalName(),
+ encodeObject(value, idMapper));
}
}
diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java
index d7af52b10d..0beed2abf0 100644
--- a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java
+++ b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java
@@ -5,7 +5,9 @@
package com.vaadin.terminal.gwt.widgetsetutils;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.List;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.ext.Generator;
@@ -24,6 +26,7 @@ import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.vaadin.terminal.gwt.client.ConnectorMap;
import com.vaadin.terminal.gwt.client.communication.JsonDecoder;
+import com.vaadin.terminal.gwt.client.communication.SerializerMap;
import com.vaadin.terminal.gwt.client.communication.VaadinSerializer;
/**
@@ -36,29 +39,27 @@ import com.vaadin.terminal.gwt.client.communication.VaadinSerializer;
*/
public class SerializerGenerator extends Generator {
- private String packageName;
- private String beanSerializerClassName;
+ private static final String SUBTYPE_SEPARATOR = "___";
+ private static String beanSerializerPackageName = SerializerMap.class
+ .getPackage().getName();
@Override
public String generate(TreeLogger logger, GeneratorContext context,
String beanTypeName) throws UnableToCompleteException {
- String beanSerializerTypeName = beanTypeName + "_Serializer";
+ JClassType beanType = context.getTypeOracle().findType(beanTypeName);
+ String beanSerializerClassName = getSerializerSimpleClassName(beanType);
try {
- TypeOracle typeOracle = context.getTypeOracle();
-
- // get classType and save instance variables
- JClassType classType = typeOracle.getType(beanTypeName);
- packageName = classType.getPackage().getName();
- beanSerializerClassName = classType.getSimpleSourceName()
- + "_Serializer";
// Generate class source code
- generateClass(logger, context, beanTypeName, beanSerializerTypeName);
+ generateClass(logger, context, beanType, beanSerializerPackageName,
+ beanSerializerClassName);
} catch (Exception e) {
logger.log(TreeLogger.ERROR, "SerializerGenerator failed for "
- + beanTypeName, e);
+ + beanType.getQualifiedSourceName(), e);
}
// return the fully qualifed name of the class generated
- return packageName + "." + beanSerializerClassName;
+ logger.log(TreeLogger.INFO, "Generated Serializer class "
+ + getFullyQualifiedSerializerClassName(beanType));
+ return getFullyQualifiedSerializerClassName(beanType);
}
/**
@@ -68,17 +69,19 @@ public class SerializerGenerator extends Generator {
* Logger object
* @param context
* Generator context
+ * @param beanType
* @param beanTypeName
* bean type for which the serializer is to be generated
* @param beanSerializerTypeName
* name of the serializer class to generate
*/
private void generateClass(TreeLogger logger, GeneratorContext context,
- String beanTypeName, String beanSerializerTypeName) {
+ JClassType beanType, String serializerPackageName,
+ String serializerClassName) {
// get print writer that receives the source code
PrintWriter printWriter = null;
- printWriter = context.tryCreate(logger, packageName,
- beanSerializerClassName);
+ printWriter = context.tryCreate(logger, serializerPackageName,
+ serializerClassName);
// print writer if null, source code has ALREADY been generated
if (printWriter == null) {
@@ -86,13 +89,14 @@ public class SerializerGenerator extends Generator {
}
Date date = new Date();
TypeOracle typeOracle = context.getTypeOracle();
- logger.log(Type.DEBUG, "Processing serializable type " + beanTypeName
- + "...");
+ String beanQualifiedSourceName = beanType.getQualifiedSourceName();
+ logger.log(Type.DEBUG, "Processing serializable type "
+ + beanQualifiedSourceName + "...");
// init composer, set class properties, create source writer
ClassSourceFileComposerFactory composer = null;
- composer = new ClassSourceFileComposerFactory(packageName,
- beanSerializerClassName);
+ composer = new ClassSourceFileComposerFactory(serializerPackageName,
+ serializerClassName);
composer.addImport(GWT.class.getName());
composer.addImport(JSONArray.class.getName());
// composer.addImport(JSONObject.class.getName());
@@ -106,34 +110,27 @@ public class SerializerGenerator extends Generator {
printWriter);
sourceWriter.indent();
- sourceWriter.println("public " + beanTypeName + " deserialize("
- + JSONObject.class.getName() + " jsonValue, "
+ sourceWriter.println("public " + beanQualifiedSourceName
+ + " deserialize(" + JSONObject.class.getName() + " jsonValue, "
+ ConnectorMap.class.getName() + " idMapper) {");
sourceWriter.indent();
// VButtonState state = GWT.create(VButtonState.class);
- sourceWriter.println(beanTypeName + " state = GWT.create("
- + beanTypeName + ".class);");
- JClassType beanType = typeOracle.findType(beanTypeName);
+ sourceWriter.println(beanQualifiedSourceName + " state = GWT.create("
+ + beanQualifiedSourceName + ".class);");
JClassType objectType = typeOracle.findType("java.lang.Object");
while (!objectType.equals(beanType)) {
- for (JMethod method : beanType.getMethods()) {
- // Process all setters that have corresponding fields
- if (!method.isPublic() || method.isStatic()
- || !method.getName().startsWith("set")
- || method.getParameterTypes().length != 1) {
- // Not setter, skip to next method
- continue;
-
- }
+ for (JMethod method : getSetters(beanType)) {
String setterName = method.getName();
String capitalizedFieldName = setterName.substring(3);
String fieldName = decapitalize(capitalizedFieldName);
JType setterParameterType = method.getParameterTypes()[0];
- logger.log(Type.DEBUG, "* Processing field " + fieldName
- + " in " + beanTypeName + " (" + beanType.getName()
- + ")");
+ logger.log(
+ Type.INFO,
+ "* Processing field " + fieldName + " in "
+ + beanQualifiedSourceName + " ("
+ + beanType.getName() + ")");
String jsonFieldName = "json" + capitalizedFieldName;
// JSONArray jsonHeight = (JSONArray) jsonValue.get("height");
@@ -178,7 +175,45 @@ public class SerializerGenerator extends Generator {
}
+ protected static List<JMethod> getSetters(JClassType beanType) {
+
+ List<JMethod> setterMethods = new ArrayList<JMethod>();
+
+ for (JMethod method : beanType.getMethods()) {
+ // Process all setters that have corresponding fields
+ if (!method.isPublic() || method.isStatic()
+ || !method.getName().startsWith("set")
+ || method.getParameterTypes().length != 1) {
+ // Not setter, skip to next method
+ continue;
+ }
+ setterMethods.add(method);
+ }
+
+ return setterMethods;
+ }
+
private String decapitalize(String name) {
return name.substring(0, 1).toLowerCase() + name.substring(1);
}
+
+ private static String getSerializerSimpleClassName(JClassType beanType) {
+ return getSimpleClassName(beanType) + "_Serializer";
+ }
+
+ private static String getSimpleClassName(JClassType type) {
+ if (type.isMemberType()) {
+ // Assumed to be static sub class
+ String baseName = getSimpleClassName(type.getEnclosingType());
+ String name = baseName + SUBTYPE_SEPARATOR
+ + type.getSimpleSourceName();
+ return name;
+ }
+ return type.getSimpleSourceName();
+ }
+
+ public static String getFullyQualifiedSerializerClassName(JClassType type) {
+ return beanSerializerPackageName + "."
+ + getSerializerSimpleClassName(type);
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java
index 3536cbd117..2d5e2b704f 100644
--- a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java
+++ b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java
@@ -6,6 +6,9 @@ package com.vaadin.terminal.gwt.widgetsetutils;
import java.io.PrintWriter;
import java.util.Date;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
@@ -13,6 +16,8 @@ import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JMethod;
+import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
@@ -38,20 +43,18 @@ public class SerializerMapGenerator extends Generator {
try {
TypeOracle typeOracle = context.getTypeOracle();
+ Set<JClassType> typesNeedingSerializers = findTypesNeedingSerializers(
+ typeOracle, logger);
// get classType and save instance variables
JClassType classType = typeOracle.getType(typeName);
packageName = classType.getPackage().getName();
className = classType.getSimpleSourceName() + "Impl";
// Generate class source code for SerializerMapImpl
- generateClass(logger, context);
+ generateSerializerMap(typesNeedingSerializers, logger, context);
- // Generate serializer classes for each subclass of SharedState
- JClassType serializerType = typeOracle.findType(SharedState.class
- .getName());
- JClassType[] serializerSubtypes = serializerType.getSubtypes();
SerializerGenerator sg = new SerializerGenerator();
- for (JClassType type : serializerSubtypes) {
+ for (JClassType type : typesNeedingSerializers) {
sg.generate(logger, context, type.getQualifiedSourceName());
}
} catch (Exception e) {
@@ -65,12 +68,15 @@ public class SerializerMapGenerator extends Generator {
/**
* Generate source code for WidgetMapImpl
*
+ * @param typesNeedingSerializers
+ *
* @param logger
* Logger object
* @param context
* Generator context
*/
- private void generateClass(TreeLogger logger, GeneratorContext context) {
+ private void generateSerializerMap(Set<JClassType> typesNeedingSerializers,
+ TreeLogger logger, GeneratorContext context) {
// get print writer that receives the source code
PrintWriter printWriter = null;
printWriter = context.tryCreate(logger, packageName, className);
@@ -79,12 +85,8 @@ public class SerializerMapGenerator extends Generator {
if (printWriter == null) {
return;
}
- logger.log(Type.INFO, "Detecting serializable data types...");
Date date = new Date();
TypeOracle typeOracle = context.getTypeOracle();
- JClassType serializerType = typeOracle.findType(SharedState.class
- .getName());
- JClassType[] serializerSubtypes = serializerType.getSubtypes();
// init composer, set class properties, create source writer
ClassSourceFileComposerFactory composer = null;
@@ -100,15 +102,18 @@ public class SerializerMapGenerator extends Generator {
sourceWriter.indent();
// TODO cache serializer instances in a map
- for (JClassType type : serializerSubtypes) {
+ for (JClassType type : typesNeedingSerializers) {
sourceWriter.println("if (type.equals(\""
+ type.getQualifiedSourceName() + "\")) {");
sourceWriter.indent();
- sourceWriter.println("return GWT.create("
- + type.getQualifiedSourceName() + "_Serializer.class);");
+ String serializerName = SerializerGenerator
+ .getFullyQualifiedSerializerClassName(type);
+ sourceWriter.println("return GWT.create(" + serializerName
+ + ".class);");
sourceWriter.outdent();
sourceWriter.println("}");
- logger.log(Type.INFO, "Configured serializer for " + type.getName());
+ logger.log(Type.INFO, "Configured serializer (" + serializerName
+ + ") for " + type.getName());
}
sourceWriter
.println("throw new RuntimeException(\"No serializer found for class \"+type);");
@@ -125,4 +130,84 @@ public class SerializerMapGenerator extends Generator {
+ "seconds)");
}
+
+ public Set<JClassType> findTypesNeedingSerializers(TypeOracle typeOracle,
+ TreeLogger logger) {
+ logger.log(Type.INFO, "Detecting serializable data types...");
+
+ HashSet<JClassType> types = new HashSet<JClassType>();
+
+ // Generate serializer classes for each subclass of SharedState
+ JClassType serializerType = typeOracle.findType(SharedState.class
+ .getName());
+ JClassType[] serializerSubtypes = serializerType.getSubtypes();
+ for (JClassType type : serializerSubtypes) {
+ types.add(type);
+ }
+
+ // Add all types used from/in the determined types
+ for (Object t : types.toArray()) {
+ findSubTypesNeedingSerializers((JClassType) t, types);
+ }
+ logger.log(Type.INFO, "Serializable data types: " + types.toString());
+
+ return types;
+ }
+
+ public void findSubTypesNeedingSerializers(JClassType type,
+ Set<JClassType> serializableTypes) {
+ // Find all setters and look at their parameter type to determine if a
+ // new serializer is needed
+ for (JMethod setterMethod : SerializerGenerator.getSetters(type)) {
+ // The one and only parameter for the setter
+ JType setterType = setterMethod.getParameterTypes()[0];
+
+ if (serializableTypes.contains(setterType)) {
+ continue;
+ }
+ if (serializationHandledByFramework(setterType)) {
+ continue;
+ }
+
+ serializableTypes.add(setterType.isClass());
+ }
+ }
+
+ Set<Class<?>> frameworkHandledTypes = new HashSet<Class<?>>();
+ {
+ frameworkHandledTypes.add(String.class);
+ frameworkHandledTypes.add(Boolean.class);
+ frameworkHandledTypes.add(Integer.class);
+ frameworkHandledTypes.add(Float.class);
+ frameworkHandledTypes.add(Double.class);
+ frameworkHandledTypes.add(Long.class);
+ frameworkHandledTypes.add(Enum.class);
+ frameworkHandledTypes.add(String[].class);
+ frameworkHandledTypes.add(Object[].class);
+ frameworkHandledTypes.add(Map.class);
+
+ }
+
+ private boolean serializationHandledByFramework(JType setterType) {
+ // Some types are handled by the framework at the moment. See #8449
+ // This method should be removed at some point.
+ if (setterType.isArray() != null) {
+ return true;
+ }
+ if (setterType.isEnum() != null) {
+ return true;
+ }
+ if (setterType.isPrimitive() != null) {
+ return true;
+ }
+
+ String qualifiedName = setterType.getQualifiedSourceName();
+ for (Class<?> cls : frameworkHandledTypes) {
+ if (qualifiedName.equals(cls.getName())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
}