Browse Source

Support arrays in RPC and shared state + test (#8655)

tags/7.0.0.alpha3
Leif Åstrand 12 years ago
parent
commit
a7097c68ef

+ 8
- 13
src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java View File

@@ -52,9 +52,7 @@ public class JsonDecoder {
}

String baseTypeName = type.getBaseTypeName();
if (baseTypeName.endsWith("[]")) {
return decodeArray(type, (JSONArray) jsonValue, connection);
} else if (Map.class.getName().equals(baseTypeName)
if (Map.class.getName().equals(baseTypeName)
|| HashMap.class.getName().equals(baseTypeName)) {
return decodeMap(type, jsonValue, connection);
} else if (List.class.getName().equals(baseTypeName)
@@ -78,6 +76,13 @@ public class JsonDecoder {
} else if (Boolean.class.getName().equals(baseTypeName)) {
// TODO handle properly
return Boolean.valueOf(String.valueOf(jsonValue));
} else if (Byte.class.getName().equals(baseTypeName)) {
// TODO handle properly
return Byte.valueOf(String.valueOf(jsonValue));
} else if (Character.class.getName().equals(baseTypeName)) {
// TODO handle properly
return Character.valueOf(((JSONString) jsonValue).stringValue()
.charAt(0));
} else if (Connector.class.getName().equals(baseTypeName)) {
return ConnectorMap.get(connection).getConnector(
((JSONString) jsonValue).stringValue());
@@ -180,16 +185,6 @@ public class JsonDecoder {
return map;
}

private static Object[] decodeArray(Type type, JSONArray jsonArray,
ApplicationConnection connection) {
String arrayTypeName = type.getBaseTypeName();
String chldTypeName = arrayTypeName.substring(0,
arrayTypeName.length() - 2);
List<Object> list = decodeList(new Type(chldTypeName, null), jsonArray,
connection);
return list.toArray(new Object[list.size()]);
}

private static List<Object> decodeList(Type type, JSONArray jsonArray,
ApplicationConnection connection) {
List<Object> tokens = new ArrayList<Object>();

+ 5
- 0
src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java View File

@@ -13,6 +13,7 @@ import java.util.Set;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONBoolean;
import com.google.gwt.json.client.JSONNull;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;
@@ -72,6 +73,10 @@ public class JsonEncoder {
return new JSONString((String) value);
} else if (value instanceof Boolean) {
return JSONBoolean.getInstance((Boolean) value);
} else if (value instanceof Byte) {
return new JSONNumber((Byte) value);
} else if (value instanceof Character) {
return new JSONString(String.valueOf(value));
} else if (value instanceof Object[]) {
return encodeObjectArray((Object[]) value, restrictToInternalTypes,
connection);

+ 39
- 7
src/com/vaadin/terminal/gwt/server/JsonCodec.java View File

@@ -8,6 +8,7 @@ import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
@@ -82,6 +83,10 @@ public class JsonCodec implements Serializable {

public static boolean isInternalType(Type type) {
if (type instanceof Class && ((Class<?>) type).isPrimitive()) {
if (type == byte.class || type == char.class) {
// Almost all primitive types are handled internally
return false;
}
// All primitive types are handled internally
return true;
} else if (type == UidlValue.class) {
@@ -123,6 +128,16 @@ public class JsonCodec implements Serializable {
// Try to decode object using fields
if (value == JSONObject.NULL) {
return null;
} else if (targetType == byte.class || targetType == Byte.class) {
return Byte.valueOf(String.valueOf(value));
} else if (targetType == char.class || targetType == Character.class) {
return Character.valueOf(String.valueOf(value).charAt(0));
} else if (targetType instanceof Class<?>
&& ((Class<?>) targetType).isArray()) {
// Legacy Object[] and String[] handled elsewhere, this takes care
// of generic arrays
return decodeArray((Class<?>) targetType, (JSONArray) value,
application);
} else if (targetType == JSONObject.class
|| targetType == JSONArray.class) {
return value;
@@ -131,6 +146,18 @@ public class JsonCodec implements Serializable {
}
}

private static Object decodeArray(Class<?> targetType, JSONArray value,
Application application) throws JSONException {
Class<?> componentType = targetType.getComponentType();
Object array = Array.newInstance(componentType, value.length());
for (int i = 0; i < value.length(); i++) {
Object decodedValue = decodeInternalOrCustomType(componentType,
value.get(i), application);
Array.set(array, i, decodedValue);
}
return array;
}

/**
* Decodes a value that is of an internal type.
* <p>
@@ -203,7 +230,7 @@ public class JsonCodec implements Serializable {
return application.getConnector(stringValue);
}

// Standard Java types
// Legacy types

if (JsonEncoder.VTYPE_STRING.equals(transportType)) {
return stringValue;
@@ -494,14 +521,17 @@ public class JsonCodec implements Serializable {
return value;
} else if (value instanceof Number) {
return value;
} else if (value instanceof Character) {
// Character is not a Number
return value;
} else if (value instanceof Collection) {
Collection<?> collection = (Collection<?>) value;
JSONArray jsonArray = encodeCollection(valueType, collection,
application);
return jsonArray;
} else if (value instanceof Object[]) {
Object[] array = (Object[]) value;
JSONArray jsonArray = encodeArrayContents(array, application);
} else if (valueType instanceof Class<?>
&& ((Class<?>) valueType).isArray()) {
JSONArray jsonArray = encodeArrayContents(value, application);
return jsonArray;
} else if (value instanceof Map) {
Object jsonMap = encodeMap(valueType, (Map<?, ?>) value,
@@ -604,11 +634,13 @@ public class JsonCodec implements Serializable {
return e.name();
}

private static JSONArray encodeArrayContents(Object[] array,
private static JSONArray encodeArrayContents(Object array,
Application application) throws JSONException {
JSONArray jsonArray = new JSONArray();
for (Object o : array) {
jsonArray.put(encode(o, null, null, application));
Class<?> componentType = array.getClass().getComponentType();
for (int i = 0; i < Array.getLength(array); i++) {
jsonArray.put(encode(Array.get(array, i), null, componentType,
application));
}
return jsonArray;
}

+ 12
- 9
src/com/vaadin/terminal/gwt/widgetsetutils/GeneratedRpcMethodProviderGenerator.java View File

@@ -146,8 +146,8 @@ public class GeneratedRpcMethodProviderGenerator extends Generator {
if (i != 0) {
sourceWriter.print(", ");
}
sourceWriter.print("("
+ parameterType.getQualifiedSourceName()
String parameterTypeName = getBoxedTypeName(parameterType);
sourceWriter.print("(" + parameterTypeName
+ ") parameters[" + i + "]");
}
sourceWriter.println(");");
@@ -179,13 +179,7 @@ public class GeneratedRpcMethodProviderGenerator extends Generator {
}

public static void writeTypeCreator(SourceWriter sourceWriter, JType type) {
String typeName;
if (type.isPrimitive() != null) {
// Used boxed types for primitives
typeName = type.isPrimitive().getQualifiedBoxedSourceName();
} else {
typeName = type.getErasedType().getQualifiedBinaryName();
}
String typeName = getBoxedTypeName(type);
sourceWriter.print("new Type(\"" + typeName + "\", ");
JParameterizedType parameterized = type.isParameterized();
if (parameterized != null) {
@@ -202,6 +196,15 @@ public class GeneratedRpcMethodProviderGenerator extends Generator {
sourceWriter.print(")");
}

public static String getBoxedTypeName(JType type) {
if (type.isPrimitive() != null) {
// Used boxed types for primitives
return type.isPrimitive().getQualifiedBoxedSourceName();
} else {
return type.getErasedType().getQualifiedSourceName();
}
}

private String getInvokeMethodName(JClassType type) {
return "invoke" + type.getQualifiedSourceName().replaceAll("\\.", "_");
}

+ 109
- 42
src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java View File

@@ -6,7 +6,6 @@ package com.vaadin.terminal.gwt.widgetsetutils;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;

@@ -16,13 +15,15 @@ import com.google.gwt.core.ext.GeneratorContext;
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.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JEnumConstant;
import com.google.gwt.core.ext.typeinfo.JEnumType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.core.ext.typeinfo.TypeOracleException;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;
@@ -46,26 +47,32 @@ import com.vaadin.terminal.gwt.client.communication.SerializerMap;
public class SerializerGenerator extends Generator {

private static final String SUBTYPE_SEPARATOR = "___";
private static String beanSerializerPackageName = SerializerMap.class
private static String serializerPackageName = SerializerMap.class
.getPackage().getName();

@Override
public String generate(TreeLogger logger, GeneratorContext context,
String beanTypeName) throws UnableToCompleteException {
JClassType beanType = context.getTypeOracle().findType(beanTypeName);
String beanSerializerClassName = getSerializerSimpleClassName(beanType);
String typeName) throws UnableToCompleteException {
JClassType type;
try {
type = (JClassType) context.getTypeOracle().parse(typeName);
} catch (TypeOracleException e1) {
logger.log(Type.ERROR, "Could not find type " + typeName, e1);
throw new UnableToCompleteException();
}
String serializerClassName = getSerializerSimpleClassName(type);
try {
// Generate class source code
generateClass(logger, context, beanType, beanSerializerPackageName,
beanSerializerClassName);
generateClass(logger, context, type, serializerPackageName,
serializerClassName);
} catch (Exception e) {
logger.log(TreeLogger.ERROR, "SerializerGenerator failed for "
+ beanType.getQualifiedSourceName(), e);
+ type.getQualifiedSourceName(), e);
throw new UnableToCompleteException();
}

// return the fully qualifed name of the class generated
return getFullyQualifiedSerializerClassName(beanType);
return getFullyQualifiedSerializerClassName(type);
}

/**
@@ -75,7 +82,7 @@ public class SerializerGenerator extends Generator {
* Logger object
* @param context
* Generator context
* @param beanType
* @param type
* @param beanTypeName
* bean type for which the serializer is to be generated
* @param beanSerializerTypeName
@@ -83,7 +90,7 @@ public class SerializerGenerator extends Generator {
* @throws UnableToCompleteException
*/
private void generateClass(TreeLogger logger, GeneratorContext context,
JClassType beanType, String serializerPackageName,
JClassType type, String serializerPackageName,
String serializerClassName) throws UnableToCompleteException {
// get print writer that receives the source code
PrintWriter printWriter = null;
@@ -94,13 +101,12 @@ public class SerializerGenerator extends Generator {
if (printWriter == null) {
return;
}
boolean isEnum = (beanType.isEnum() != null);
boolean isEnum = (type.isEnum() != null);
boolean isArray = (type.isArray() != null);

Date date = new Date();
TypeOracle typeOracle = context.getTypeOracle();
String beanQualifiedSourceName = beanType.getQualifiedSourceName();
String qualifiedSourceName = type.getQualifiedSourceName();
logger.log(Type.DEBUG, "Processing serializable type "
+ beanQualifiedSourceName + "...");
+ qualifiedSourceName + "...");

// init composer, set class properties, create source writer
ClassSourceFileComposerFactory composer = null;
@@ -115,12 +121,12 @@ public class SerializerGenerator extends Generator {
composer.addImport(JsonDecoder.class.getName());
// composer.addImport(VaadinSerializer.class.getName());

if (isEnum) {
if (isEnum || isArray) {
composer.addImplementedInterface(JSONSerializer.class.getName()
+ "<" + beanQualifiedSourceName + ">");
+ "<" + qualifiedSourceName + ">");
} else {
composer.addImplementedInterface(DiffJSONSerializer.class.getName()
+ "<" + beanQualifiedSourceName + ">");
+ "<" + qualifiedSourceName + ">");
}

SourceWriter sourceWriter = composer.createSourceWriter(context,
@@ -132,17 +138,19 @@ public class SerializerGenerator extends Generator {
// public JSONValue serialize(Object value,
// ApplicationConnection connection) {
sourceWriter.println("public " + JSONValue.class.getName()
+ " serialize(" + beanQualifiedSourceName + " value, "
+ " serialize(" + qualifiedSourceName + " value, "
+ ApplicationConnection.class.getName() + " connection) {");
sourceWriter.indent();
// MouseEventDetails castedValue = (MouseEventDetails) value;
sourceWriter.println(beanQualifiedSourceName + " castedValue = ("
+ beanQualifiedSourceName + ") value;");
sourceWriter.println(qualifiedSourceName + " castedValue = ("
+ qualifiedSourceName + ") value;");

if (isEnum) {
writeEnumSerializer(logger, sourceWriter, beanType);
writeEnumSerializer(logger, sourceWriter, type);
} else if (isArray) {
writeArraySerializer(logger, sourceWriter, type.isArray());
} else {
writeBeanSerializer(logger, sourceWriter, beanType);
writeBeanSerializer(logger, sourceWriter, type);
}
// }
sourceWriter.outdent();
@@ -152,14 +160,14 @@ public class SerializerGenerator extends Generator {
// Updater
// public void update(T target, Type type, JSONValue jsonValue,
// ApplicationConnection connection);
if (!isEnum) {
sourceWriter.println("public void update("
+ beanQualifiedSourceName + " target, Type type, "
+ JSONValue.class.getName() + " jsonValue, "
+ ApplicationConnection.class.getName() + " connection) {");
if (!isEnum && !isArray) {
sourceWriter.println("public void update(" + qualifiedSourceName
+ " target, Type type, " + JSONValue.class.getName()
+ " jsonValue, " + ApplicationConnection.class.getName()
+ " connection) {");
sourceWriter.indent();

writeBeanDeserializer(logger, sourceWriter, beanType);
writeBeanDeserializer(logger, sourceWriter, type);

sourceWriter.outdent();
sourceWriter.println("}");
@@ -168,18 +176,19 @@ public class SerializerGenerator extends Generator {
// Deserializer
// T deserialize(Type type, JSONValue jsonValue, ApplicationConnection
// connection);
sourceWriter.println("public " + beanQualifiedSourceName
sourceWriter.println("public " + qualifiedSourceName
+ " deserialize(Type type, " + JSONValue.class.getName()
+ " jsonValue, " + ApplicationConnection.class.getName()
+ " connection) {");
sourceWriter.indent();

if (isEnum) {
writeEnumDeserializer(logger, sourceWriter, beanType.isEnum());
writeEnumDeserializer(logger, sourceWriter, type.isEnum());
} else if (isArray) {
writeArrayDeserializer(logger, sourceWriter, type.isArray());
} else {
sourceWriter.println(beanQualifiedSourceName
+ " target = GWT.create(" + beanQualifiedSourceName
+ ".class);");
sourceWriter.println(qualifiedSourceName + " target = GWT.create("
+ qualifiedSourceName + ".class);");
sourceWriter
.println("update(target, type, jsonValue, connection);");
// return target;
@@ -195,7 +204,7 @@ public class SerializerGenerator extends Generator {
// commit generated class
context.commit(logger, printWriter);
logger.log(TreeLogger.INFO, "Generated Serializer class "
+ getFullyQualifiedSerializerClassName(beanType));
+ getFullyQualifiedSerializerClassName(type));
}

private void writeEnumDeserializer(TreeLogger logger,
@@ -214,6 +223,43 @@ public class SerializerGenerator extends Generator {
sourceWriter.println("return null;");
}

private void writeArrayDeserializer(TreeLogger logger,
SourceWriter sourceWriter, JArrayType type) {
JType leafType = type.getLeafType();
int rank = type.getRank();

sourceWriter.println(JSONArray.class.getName()
+ " jsonArray = jsonValue.isArray();");

// Type value = new Type[jsonArray.size()][][];
sourceWriter.print(type.getQualifiedSourceName() + " value = new "
+ leafType.getQualifiedSourceName() + "[jsonArray.size()]");
for (int i = 1; i < rank; i++) {
sourceWriter.print("[]");
}
sourceWriter.println(";");

sourceWriter.println("for(int i = 0 ; i < value.length; i++) {");
sourceWriter.indent();

JType componentType = type.getComponentType();

sourceWriter.print("value[i] = ("
+ GeneratedRpcMethodProviderGenerator
.getBoxedTypeName(componentType) + ") "
+ JsonDecoder.class.getName() + ".decodeValue(");
GeneratedRpcMethodProviderGenerator.writeTypeCreator(sourceWriter,
componentType);
sourceWriter.print(", jsonArray.get(i), null, connection)");

sourceWriter.println(";");

sourceWriter.outdent();
sourceWriter.println("}");

sourceWriter.println("return value;");
}

private void writeBeanDeserializer(TreeLogger logger,
SourceWriter sourceWriter, JClassType beanType) {
String beanQualifiedSourceName = beanType.getQualifiedSourceName();
@@ -281,6 +327,23 @@ public class SerializerGenerator extends Generator {
+ "(castedValue.name());");
}

private void writeArraySerializer(TreeLogger logger,
SourceWriter sourceWriter, JArrayType array) {
sourceWriter.println(JSONArray.class.getName() + " values = new "
+ JSONArray.class.getName() + "();");
JType componentType = array.getComponentType();
// JPrimitiveType primitive = componentType.isPrimitive();
sourceWriter.println("for (int i = 0; i < castedValue.length; i++) {");
sourceWriter.indent();
sourceWriter.print("values.set(i, ");
sourceWriter.print(JsonEncoder.class.getName()
+ ".encode(castedValue[i], false, connection)");
sourceWriter.println(");");
sourceWriter.outdent();
sourceWriter.println("}");
sourceWriter.println("return values;");
}

private void writeBeanSerializer(TreeLogger logger,
SourceWriter sourceWriter, JClassType beanType)
throws UnableToCompleteException {
@@ -373,10 +436,15 @@ public class SerializerGenerator extends Generator {
return getSimpleClassName(beanType) + "_Serializer";
}

private static String getSimpleClassName(JClassType type) {
if (type.isMemberType()) {
private static String getSimpleClassName(JType type) {
JArrayType arrayType = type.isArray();
if (arrayType != null) {
return "Array" + getSimpleClassName(arrayType.getComponentType());
}
JClassType classType = type.isClass();
if (classType != null && classType.isMemberType()) {
// Assumed to be static sub class
String baseName = getSimpleClassName(type.getEnclosingType());
String baseName = getSimpleClassName(classType.getEnclosingType());
String name = baseName + SUBTYPE_SEPARATOR
+ type.getSimpleSourceName();
return name;
@@ -385,7 +453,6 @@ public class SerializerGenerator extends Generator {
}

public static String getFullyQualifiedSerializerClassName(JClassType type) {
return beanSerializerPackageName + "."
+ getSerializerSimpleClassName(type);
return serializerPackageName + "." + getSerializerSimpleClassName(type);
}
}

+ 24
- 5
src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java View File

@@ -17,6 +17,7 @@ import com.google.gwt.core.ext.GeneratorContext;
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.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
@@ -96,6 +97,10 @@ public class SerializerMapGenerator extends Generator {
JClassType javaSerializable = typeOracle.findType(Serializable.class
.getName());
for (JClassType type : typesNeedingSerializers) {
if (type.isArray() != null) {
// Don't check for arrays
continue;
}
boolean serializable = type.isAssignableTo(javaSerializable);
if (!serializable) {
logger.log(
@@ -166,8 +171,15 @@ public class SerializerMapGenerator extends Generator {

// TODO cache serializer instances in a map
for (JClassType type : typesNeedingSerializers) {
sourceWriter.println("if (type.equals(\""
+ type.getQualifiedBinaryName() + "\")) {");
sourceWriter.print("if (type.equals(\""
+ type.getQualifiedSourceName() + "\")");
if (type instanceof JArrayType) {
// Also add binary name to support encoding based on
// object.getClass().getName()
sourceWriter.print("||type.equals(\"" + type.getJNISignature()
+ "\")");
}
sourceWriter.println(") {");
sourceWriter.indent();
String serializerName = SerializerGenerator
.getFullyQualifiedSerializerClassName(type);
@@ -277,6 +289,14 @@ public class SerializerMapGenerator extends Generator {
serializableTypes.add(typeClass);
findSubTypesNeedingSerializers(typeClass, serializableTypes);
}

// Generate (n-1)-dimensional array serializer for n-dimensional array
JArrayType arrayType = type.isArray();
if (arrayType != null) {
serializableTypes.add(arrayType);
addTypeIfNeeded(serializableTypes, arrayType.getComponentType());
}

}

Set<Class<?>> frameworkHandledTypes = new HashSet<Class<?>>();
@@ -293,15 +313,14 @@ public class SerializerMapGenerator extends Generator {
frameworkHandledTypes.add(Map.class);
frameworkHandledTypes.add(List.class);
frameworkHandledTypes.add(Set.class);
frameworkHandledTypes.add(Byte.class);
frameworkHandledTypes.add(Character.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.isPrimitive() != null) {
return true;
}

+ 273
- 0
tests/testbench/com/vaadin/tests/serialization/SerializerTest.java View File

@@ -0,0 +1,273 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.tests.serialization;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.vaadin.annotations.Widgetset;
import com.vaadin.terminal.WrappedRequest;
import com.vaadin.terminal.gwt.client.Connector;
import com.vaadin.tests.components.AbstractTestRoot;
import com.vaadin.tests.util.Log;
import com.vaadin.tests.widgetset.client.ComplexTestBean;
import com.vaadin.tests.widgetset.client.SerializerTestRpc;
import com.vaadin.tests.widgetset.client.SimpleTestBean;
import com.vaadin.tests.widgetset.server.SerializerTestExtension;

@Widgetset("com.vaadin.tests.widgetset.TestingWidgetSet")
public class SerializerTest extends AbstractTestRoot {

private Log log = new Log(40);

@Override
protected void setup(WrappedRequest request) {
final SerializerTestExtension testExtension = new SerializerTestExtension();
addExtension(testExtension);
addComponent(log);

SerializerTestRpc rpc = testExtension
.getRpcProxy(SerializerTestRpc.class);
rpc.sendBoolean(true, Boolean.FALSE, new boolean[] { true, true, false,
true, false, false });
rpc.sendByte((byte) 5, Byte.valueOf((byte) -12), new byte[] { 3, 1, 2 });
rpc.sendChar('∫', Character.valueOf('å'), "aBcD".toCharArray());
rpc.sendInt(Integer.MAX_VALUE, Integer.valueOf(0), new int[] { 5, 7 });
rpc.sendLong(577431841358l, Long.valueOf(0), new long[] {
-57841235865l, 57 });
rpc.sendFloat(3.14159f, Float.valueOf(Math.nextUp(1)), new float[] {
57, 0, -12 });
rpc.sendDouble(Math.PI, Double.valueOf(-Math.E), new double[] {
Double.MAX_VALUE, Double.MIN_VALUE });
rpc.sendString("This is a tesing string ‡");
rpc.sendConnector(this);
rpc.sendBean(
new ComplexTestBean(new SimpleTestBean(0),
new SimpleTestBean(1), Arrays.asList(
new SimpleTestBean(3), new SimpleTestBean(4)),
5), new SimpleTestBean(6),
new SimpleTestBean[] { new SimpleTestBean(7) });
rpc.sendNull("Not null", null);
rpc.sendNestedArray(new int[][] { { 5 }, { 7 } },
new SimpleTestBean[][] { { new SimpleTestBean(4),
new SimpleTestBean(2) } });
rpc.sendList(Arrays.asList(5, 8, -234), Arrays.<Connector> asList(this,
testExtension), Arrays.asList(new SimpleTestBean(234),
new SimpleTestBean(-568)));
// Disabled because of #8861
// rpc.sendArrayList(
// Arrays.asList(new int[] { 1, 2 }, new int[] { 3, 4 }),
// Arrays.asList(new Integer[] { 5, 6 }, new Integer[] { 7, 8 }),
// Collections
// .singletonList(new SimpleTestBean[] { new SimpleTestBean(
// 7) }));
// Disabled because of #8861
// rpc.sendListArray(
// new List[] { Arrays.asList(1, 2), Arrays.asList(3, 4) },
// new List[] { Collections.singletonList(new SimpleTestBean(-1)) });
rpc.sendSet(new HashSet<Integer>(Arrays.asList(4, 7, 12)), Collections
.singleton((Connector) this), new HashSet<SimpleTestBean>(
Arrays.asList(new SimpleTestBean(1), new SimpleTestBean(2))));

rpc.sendMap(new HashMap<String, SimpleTestBean>() {
{
put("1", new SimpleTestBean(1));
put("2", new SimpleTestBean(2));
}
}, new HashMap<Connector, Boolean>() {
{
put(testExtension, true);
put(getRoot(), false);
}
}, new HashMap<Integer, Connector>() {
{
put(5, testExtension);
put(10, getRoot());
}
}, new HashMap<SimpleTestBean, SimpleTestBean>() {
{
put(new SimpleTestBean(5), new SimpleTestBean(-5));
put(new SimpleTestBean(-4), new SimpleTestBean(4));
}
});
rpc.sendWrappedGenerics(new HashMap<Set<SimpleTestBean>, Map<Integer, List<SimpleTestBean>>>() {
{
put(Collections.singleton(new SimpleTestBean(42)),
new HashMap<Integer, List<SimpleTestBean>>() {
{
put(1, Arrays.asList(new SimpleTestBean(1),
new SimpleTestBean(3)));
}
});
}
});

testExtension.registerRpc(new SerializerTestRpc() {
public void sendBoolean(boolean value, Boolean boxedValue,
boolean[] array) {
log.log("sendBoolean: " + value + ", " + boxedValue + ", "
+ Arrays.toString(array));
}

public void sendByte(byte value, Byte boxedValue, byte[] array) {
log.log("sendByte: " + value + ", " + boxedValue + ", "
+ Arrays.toString(array));
}

public void sendChar(char value, Character boxedValue, char[] array) {
log.log("sendChar: " + value + ", " + boxedValue + ", "
+ Arrays.toString(array));
}

public void sendInt(int value, Integer boxedValue, int[] array) {
log.log("sendInt: " + value + ", " + boxedValue + ", "
+ Arrays.toString(array));
}

public void sendLong(long value, Long boxedValue, long[] array) {
log.log("sendLong: " + value + ", " + boxedValue + ", "
+ Arrays.toString(array));
}

public void sendFloat(float value, Float boxedValue, float[] array) {
log.log("sendFloat: " + value + ", " + boxedValue + ", "
+ Arrays.toString(array));
}

public void sendDouble(double value, Double boxedValue,
double[] array) {
log.log("sendDouble: " + value + ", " + boxedValue + ", "
+ Arrays.toString(array));
}

public void sendString(String value) {
log.log("sendString: " + value);
}

public void sendConnector(Connector connector) {
log.log("sendConnector: " + connector.getClass().getName());
}

public void sendBean(ComplexTestBean complexBean,
SimpleTestBean simpleBean, SimpleTestBean[] array) {
log.log("sendBean: " + complexBean + ", " + simpleBean + ", "
+ Arrays.toString(array));
}

public void sendNull(String value1, String value2) {
log.log("sendNull: " + value1 + ", " + value2);
}

public void sendNestedArray(int[][] nestedIntArray,
SimpleTestBean[][] nestedBeanArray) {
log.log("sendNestedArray: "
+ Arrays.deepToString(nestedIntArray) + ", "
+ Arrays.deepToString(nestedBeanArray));
}

public void sendList(List<Integer> intList,
List<Connector> connectorList, List<SimpleTestBean> beanList) {
log.log("sendList: " + intList + ", "
+ connectorCollectionToString(connectorList) + ", "
+ beanList);
}

private String connectorCollectionToString(
Collection<Connector> collection) {
StringBuilder sb = new StringBuilder();

for (Connector connector : collection) {
if (sb.length() != 0) {
sb.append(", ");
}
sb.append(connector.getClass());
}

String string = sb.toString();
return string;
}

public void sendArrayList(List<int[]> primitiveArrayList,
List<Integer[]> objectArrayList,
List<SimpleTestBean[]> beanArrayList) {
log.log("sendArrayList: " + primitiveArrayList + ", "
+ objectArrayList + ", " + beanArrayList);
}

public void sendListArray(List<Integer>[] objectListArray,
List<SimpleTestBean>[] beanListArray) {
log.log("sendArrayList: " + Arrays.toString(objectListArray)
+ ", " + Arrays.toString(beanListArray));
}

public void sendSet(Set<Integer> intSet,
Set<Connector> connectorSet, Set<SimpleTestBean> beanSet) {
log.log("sendSet: " + intSet + ", "
+ connectorCollectionToString(connectorSet) + ", "
+ beanSet);
}

public void sendMap(Map<String, SimpleTestBean> stringMap,
Map<Connector, Boolean> connectorMap,
Map<Integer, Connector> intMap,
Map<SimpleTestBean, SimpleTestBean> beanMap) {
StringBuilder sb = new StringBuilder();
for (Entry<Connector, Boolean> entry : connectorMap.entrySet()) {
if (sb.length() == 0) {
sb.append('[');
} else {
sb.append(", ");
}
sb.append(entry.getKey().getClass().getName());
sb.append('=');
sb.append(entry.getValue());
}
sb.append(']');
String connectorMapString = sb.toString();

sb = new StringBuilder();
for (Entry<Integer, Connector> entry : intMap.entrySet()) {
if (sb.length() == 0) {
sb.append('[');
} else {
sb.append(", ");
}
sb.append(entry.getKey());
sb.append('=');
sb.append(entry.getValue().getClass().getName());
}
sb.append(']');
String intMapString = sb.toString();

log.log("sendMap: " + stringMap + ", " + connectorMapString
+ ", " + intMapString + ", " + beanMap);
}

public void sendWrappedGenerics(
Map<Set<SimpleTestBean>, Map<Integer, List<SimpleTestBean>>> generics) {
log.log("sendWrappedGenerics: " + generics.toString());
}

});
}

@Override
protected String getTestDescription() {
return "Test for lots of different cases of encoding and decoding variuos data types";
}

@Override
protected Integer getTicketNumber() {
return Integer.valueOf(8655);
}

}

+ 70
- 0
tests/testbench/com/vaadin/tests/widgetset/client/ComplexTestBean.java View File

@@ -0,0 +1,70 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.tests.widgetset.client;

import java.util.List;

import com.vaadin.terminal.gwt.client.communication.SharedState;

@SuppressWarnings("javadoc")
public class ComplexTestBean extends SharedState {
private SimpleTestBean innerBean1;
private SimpleTestBean innerBean2;
private List<SimpleTestBean> innerBeanCollection;
private int privimite;

public ComplexTestBean() {
// Default
}

public ComplexTestBean(SimpleTestBean innerBean1,
SimpleTestBean innerBean2,
List<SimpleTestBean> innerBeanCollection, int privimite) {
this.innerBean1 = innerBean1;
this.innerBean2 = innerBean2;
this.innerBeanCollection = innerBeanCollection;
this.privimite = privimite;
}

public SimpleTestBean getInnerBean1() {
return innerBean1;
}

public void setInnerBean1(SimpleTestBean innerBean) {
innerBean1 = innerBean;
}

public SimpleTestBean getInnerBean2() {
return innerBean2;
}

public void setInnerBean2(SimpleTestBean innerBean2) {
this.innerBean2 = innerBean2;
}

public List<SimpleTestBean> getInnerBeanCollection() {
return innerBeanCollection;
}

public void setInnerBeanCollection(List<SimpleTestBean> innerBeanCollection) {
this.innerBeanCollection = innerBeanCollection;
}

public int getPrivimite() {
return privimite;
}

public void setPrivimite(int privimite) {
this.privimite = privimite;
}

@Override
public String toString() {
return "ComplexTestBean [innerBean1=" + innerBean1 + ", innerBean2="
+ innerBean2 + ", innerBeanCollection=" + innerBeanCollection
+ ", privimite=" + privimite + "]";
}

}

+ 227
- 0
tests/testbench/com/vaadin/tests/widgetset/client/SerializerTestConnector.java View File

@@ -0,0 +1,227 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.tests.widgetset.client;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.vaadin.terminal.gwt.client.Connector;
import com.vaadin.terminal.gwt.client.communication.RpcProxy;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
import com.vaadin.terminal.gwt.client.extensions.AbstractExtensionConnector;
import com.vaadin.terminal.gwt.client.ui.Connect;
import com.vaadin.tests.widgetset.server.SerializerTestExtension;

@Connect(SerializerTestExtension.class)
public class SerializerTestConnector extends AbstractExtensionConnector {

private SerializerTestRpc rpc = RpcProxy.create(SerializerTestRpc.class,
this);

public SerializerTestConnector() {
registerRpc(SerializerTestRpc.class, new SerializerTestRpc() {
public void sendWrappedGenerics(
Map<Set<SimpleTestBean>, Map<Integer, List<SimpleTestBean>>> generics) {
Map<Set<SimpleTestBean>, Map<Integer, List<SimpleTestBean>>> updated = new HashMap<Set<SimpleTestBean>, Map<Integer, List<SimpleTestBean>>>();

SimpleTestBean firstValue = generics.values().iterator().next()
.get(Integer.valueOf(1)).get(0);
Set<SimpleTestBean> key = new HashSet<SimpleTestBean>(Arrays
.asList(firstValue));

Map<Integer, List<SimpleTestBean>> value = new HashMap<Integer, List<SimpleTestBean>>();
Set<SimpleTestBean> firstKeyValue = generics.keySet()
.iterator().next();
value.put(Integer.valueOf(1), new ArrayList<SimpleTestBean>(
firstKeyValue));

updated.put(key, value);

rpc.sendWrappedGenerics(updated);
}

public void sendString(String value) {
char[] chars = value.toCharArray();
Arrays.sort(chars);
rpc.sendString(new String(chars));
}

public void sendSet(Set<Integer> intSet,
Set<Connector> connectorSet, Set<SimpleTestBean> beanSet) {

beanSet.iterator().next().setValue(intSet.size());
Set<Integer> updatedIntSet = new HashSet<Integer>();

for (Integer integer : intSet) {
updatedIntSet.add(Integer.valueOf(-integer.intValue()));
}
rpc.sendSet(updatedIntSet,
Collections.singleton(getRootConnector()), beanSet);
}

public void sendNestedArray(int[][] nestedIntArray,
SimpleTestBean[][] nestedBeanArray) {
rpc.sendNestedArray(new int[][] { { nestedIntArray[1][0],
nestedIntArray[0][0] } }, new SimpleTestBean[][] {
{ nestedBeanArray[0][1] }, { nestedBeanArray[0][0] } });
}

public void sendMap(Map<String, SimpleTestBean> stringMap,
Map<Connector, Boolean> connectorMap,
Map<Integer, Connector> intMap,
Map<SimpleTestBean, SimpleTestBean> beanMap) {
Map<SimpleTestBean, SimpleTestBean> updatedBeanMap = new HashMap<SimpleTestBean, SimpleTestBean>();
for (Entry<SimpleTestBean, SimpleTestBean> entry : beanMap
.entrySet()) {
updatedBeanMap.put(entry.getValue(), entry.getKey());
}

rpc.sendMap(Collections.singletonMap("a", stringMap.get("b")),
Collections.singletonMap(getThisConnector(),
connectorMap.get(getRootConnector())),
Collections.singletonMap(
Integer.valueOf(stringMap.size()),
getThisConnector()), updatedBeanMap);
}

public void sendLong(long value, Long boxedValue, long[] array) {
rpc.sendLong(array[0], Long.valueOf(value), new long[] {
array[1], boxedValue.longValue() });
}

public void sendList(List<Integer> intList,
List<Connector> connectorList, List<SimpleTestBean> beanList) {
Collections.sort(intList);
Collections.reverse(beanList);
rpc.sendList(intList,
Arrays.asList(getThisConnector(), getRootConnector()),
beanList);
}

public void sendInt(int value, Integer boxedValue, int[] array) {
rpc.sendInt(array.length, Integer.valueOf(array[0]), new int[] {
value, boxedValue.intValue() });
}

public void sendFloat(float value, Float boxedValue, float[] array) {
Arrays.sort(array);
rpc.sendFloat(boxedValue.floatValue(), Float.valueOf(value),
array);
}

public void sendDouble(double value, Double boxedValue,
double[] array) {
rpc.sendDouble(value + boxedValue.doubleValue(),
Double.valueOf(value - boxedValue.doubleValue()),
new double[] { array.length, array[0], array[1] });
}

public void sendConnector(Connector connector) {
rpc.sendConnector(getThisConnector());
}

public void sendChar(char value, Character boxedValue, char[] array) {
rpc.sendChar(Character.toUpperCase(boxedValue.charValue()),
Character.valueOf(value), new String(array)
.toLowerCase().toCharArray());
}

public void sendByte(byte value, Byte boxedValue, byte[] array) {
// There will most certainly be a bug that is not discovered
// because this particular method doesn't do anything with it's
// values...
rpc.sendByte(value, boxedValue, array);
}

public void sendBoolean(boolean value, Boolean boxedValue,
boolean[] array) {
boolean[] inverseArray = new boolean[array.length];
for (int i = 0; i < array.length; i++) {
inverseArray[i] = !array[i];
}
rpc.sendBoolean(boxedValue == Boolean.TRUE,
Boolean.valueOf(!value), inverseArray);
}

public void sendBean(ComplexTestBean complexBean,
SimpleTestBean simpleBean, SimpleTestBean[] array) {
SimpleTestBean updatedSimpleBean = new SimpleTestBean();
updatedSimpleBean.setValue(complexBean.getInnerBean1()
.getValue());

ComplexTestBean updatedComplexBean = new ComplexTestBean();
updatedComplexBean.setInnerBean1(complexBean.getInnerBean2());
updatedComplexBean.setInnerBean2(complexBean
.getInnerBeanCollection().get(0));
updatedComplexBean.setInnerBeanCollection(Arrays.asList(
simpleBean, updatedSimpleBean));
updatedComplexBean.setPrivimite(complexBean.getPrivimite() + 1);

ArrayList<SimpleTestBean> arrayList = new ArrayList<SimpleTestBean>(
Arrays.asList(array));
Collections.reverse(arrayList);

rpc.sendBean(updatedComplexBean, updatedSimpleBean,
arrayList.toArray(new SimpleTestBean[array.length]));
}

public void sendArrayList(List<int[]> primitiveArrayList,
List<Integer[]> objectArrayList,
List<SimpleTestBean[]> beanArrayList) {
Collections.reverse(beanArrayList);
List<Integer[]> updatedObjectArrayList = new ArrayList<Integer[]>();
for (int[] array : primitiveArrayList) {
updatedObjectArrayList.add(new Integer[] {
Integer.valueOf(array.length),
Integer.valueOf(array[0]) });
}

rpc.sendArrayList(Arrays.asList(
new int[] { primitiveArrayList.size() },
new int[] { objectArrayList.get(0).length }),
updatedObjectArrayList, beanArrayList);
}

public void sendNull(String value1, String value2) {
rpc.sendNull(value2, value1);
}

public void sendListArray(List<Integer>[] objectListArray,
List<SimpleTestBean>[] beanListArray) {
rpc.sendListArray(new List[] { objectListArray[1],
objectListArray[0] }, new List[] { Collections
.singletonList(beanListArray[0].get(0)) });
}
});
}

private Connector getRootConnector() {
return getConnection().getRootConnector();
}

private Connector getThisConnector() {
// Cast to Connector for use in e.g. Collections.singleton() to get a
// Set<Connector>
return this;
}

@Override
public ComplexTestBean getState() {
return (ComplexTestBean) super.getState();
}

@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
// TODO do something clever
}

}

+ 64
- 0
tests/testbench/com/vaadin/tests/widgetset/client/SerializerTestRpc.java View File

@@ -0,0 +1,64 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.tests.widgetset.client;

import java.util.List;
import java.util.Map;
import java.util.Set;

import com.vaadin.terminal.gwt.client.Connector;
import com.vaadin.terminal.gwt.client.communication.ClientRpc;
import com.vaadin.terminal.gwt.client.communication.ServerRpc;

@SuppressWarnings("javadoc")
public interface SerializerTestRpc extends ServerRpc, ClientRpc {
public void sendBoolean(boolean value, Boolean boxedValue, boolean[] array);

public void sendByte(byte value, Byte boxedValue, byte[] array);

public void sendChar(char value, Character boxedValue, char[] array);

public void sendInt(int value, Integer boxedValue, int[] array);

public void sendLong(long value, Long boxedValue, long[] array);

public void sendFloat(float value, Float boxedValue, float[] array);

public void sendDouble(double value, Double boxedValue, double[] array);

public void sendString(String value);

public void sendConnector(Connector connector);

public void sendBean(ComplexTestBean complexBean,
SimpleTestBean simpleBean, SimpleTestBean[] array);

public void sendNull(String value1, String value2);

public void sendNestedArray(int[][] nestedIntArray,
SimpleTestBean[][] nestedBeanArray);

public void sendList(List<Integer> intList, List<Connector> connectorList,
List<SimpleTestBean> beanList);

public void sendArrayList(List<int[]> primitiveArrayList,
List<Integer[]> objectArrayList,
List<SimpleTestBean[]> beanArrayList);

public void sendListArray(List<Integer>[] objectListArray,
List<SimpleTestBean>[] beanListArray);

public void sendSet(Set<Integer> intSet, Set<Connector> connectorSet,
Set<SimpleTestBean> beanSet);

public void sendMap(Map<String, SimpleTestBean> stringMap,
Map<Connector, Boolean> connectorMap,
Map<Integer, Connector> intMap,
Map<SimpleTestBean, SimpleTestBean> beanMap);

public void sendWrappedGenerics(
Map<Set<SimpleTestBean>, Map<Integer, List<SimpleTestBean>>> generics);

}

+ 38
- 0
tests/testbench/com/vaadin/tests/widgetset/client/SimpleTestBean.java View File

@@ -0,0 +1,38 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.tests.widgetset.client;

import java.io.Serializable;

public class SimpleTestBean implements Serializable {
private int value;

public SimpleTestBean() {
this(0);
}

public SimpleTestBean(int value) {
this.value = value;
}

public int getValue() {
return value;
}

public void setValue(int value) {
this.value = value;
}

@Override
public String toString() {
return "SimpleTestBean(" + value + ")";
}

@Override
public int hashCode() {
// Implement hash code to get consistent HashSet.toString
return value;
}
}

+ 22
- 0
tests/testbench/com/vaadin/tests/widgetset/server/SerializerTestExtension.java View File

@@ -0,0 +1,22 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.tests.widgetset.server;

import com.vaadin.terminal.AbstractExtension;
import com.vaadin.tests.widgetset.client.ComplexTestBean;
import com.vaadin.tests.widgetset.client.SerializerTestRpc;

public class SerializerTestExtension extends AbstractExtension {

@Override
public ComplexTestBean getState() {
return (ComplexTestBean) super.getState();
}

public void registerRpc(SerializerTestRpc rpc) {
super.registerRpc(rpc);
}

}

Loading…
Cancel
Save