Prior to this patch, all types which could be used over RPC needed to be accessible and instantiable from the package in which the remote service interface was declared. This patch updates the RPC type and field serializer generators to allow default access and protected classes with non-private constructors to be used. It does this by adding an instantiate method to the generated field serializer and by emitting serializers for arrays in the same package as it's corresponding leaf type. Effectively, this means that arrays are no longer dealt with via custom field serializers.
Patch by: mmendez
Review by: scottb
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1503 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JArrayType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JArrayType.java
index d7e6694..a206c4b 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JArrayType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JArrayType.java
@@ -143,7 +143,7 @@
@Override
public JField[] getFields() {
// TODO length
- return null;
+ return TypeOracle.NO_JFIELDS;
}
@Override
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/lang/boolean_Array_CustomFieldSerializer.java b/user/src/com/google/gwt/user/client/rpc/core/java/lang/boolean_Array_CustomFieldSerializer.java
deleted file mode 100644
index 6ee5858..0000000
--- a/user/src/com/google/gwt/user/client/rpc/core/java/lang/boolean_Array_CustomFieldSerializer.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2006 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.user.client.rpc.core.java.lang;
-
-import com.google.gwt.user.client.rpc.SerializationException;
-import com.google.gwt.user.client.rpc.SerializationStreamReader;
-import com.google.gwt.user.client.rpc.SerializationStreamWriter;
-
-/**
- * Custom Serializer for arrays of booleans.
- */
-public class boolean_Array_CustomFieldSerializer {
-
- public static void deserialize(SerializationStreamReader streamReader,
- boolean[] instance) throws SerializationException {
- for (int itemIndex = 0; itemIndex < instance.length; ++itemIndex) {
- instance[itemIndex] = streamReader.readBoolean();
- }
- }
-
- public static void serialize(SerializationStreamWriter streamWriter,
- boolean[] instance) throws SerializationException {
- int itemCount = instance.length;
- streamWriter.writeInt(itemCount);
- for (int itemIndex = 0; itemIndex < itemCount; ++itemIndex) {
- streamWriter.writeBoolean(instance[itemIndex]);
- }
- }
-
-}
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/lang/byte_Array_CustomFieldSerializer.java b/user/src/com/google/gwt/user/client/rpc/core/java/lang/byte_Array_CustomFieldSerializer.java
deleted file mode 100644
index 6edea72..0000000
--- a/user/src/com/google/gwt/user/client/rpc/core/java/lang/byte_Array_CustomFieldSerializer.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2006 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.user.client.rpc.core.java.lang;
-
-import com.google.gwt.user.client.rpc.SerializationException;
-import com.google.gwt.user.client.rpc.SerializationStreamReader;
-import com.google.gwt.user.client.rpc.SerializationStreamWriter;
-
-/**
- * Custom Serializer for arrays of byte.
- */
-public class byte_Array_CustomFieldSerializer {
-
- public static void deserialize(SerializationStreamReader streamReader,
- byte[] instance) throws SerializationException {
- for (int itemIndex = 0; itemIndex < instance.length; ++itemIndex) {
- instance[itemIndex] = streamReader.readByte();
- }
- }
-
- public static void serialize(SerializationStreamWriter streamWriter,
- byte[] instance) throws SerializationException {
- int itemCount = instance.length;
- streamWriter.writeInt(itemCount);
- for (int itemIndex = 0; itemIndex < itemCount; ++itemIndex) {
- streamWriter.writeByte(instance[itemIndex]);
- }
- }
-
-}
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/lang/char_Array_CustomFieldSerializer.java b/user/src/com/google/gwt/user/client/rpc/core/java/lang/char_Array_CustomFieldSerializer.java
deleted file mode 100644
index de4c4de..0000000
--- a/user/src/com/google/gwt/user/client/rpc/core/java/lang/char_Array_CustomFieldSerializer.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2006 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.user.client.rpc.core.java.lang;
-
-import com.google.gwt.user.client.rpc.SerializationException;
-import com.google.gwt.user.client.rpc.SerializationStreamReader;
-import com.google.gwt.user.client.rpc.SerializationStreamWriter;
-
-/**
- * Custom Serializer for arrays of char.
- */
-public class char_Array_CustomFieldSerializer {
-
- public static void deserialize(SerializationStreamReader streamReader,
- char[] instance) throws SerializationException {
-
- for (int i = 0; i < instance.length; ++i) {
- instance[i] = streamReader.readChar();
- }
- }
-
- public static void serialize(SerializationStreamWriter streamWriter,
- char[] instance) throws SerializationException {
-
- streamWriter.writeInt(instance.length);
-
- for (int i = 0; i < instance.length; ++i) {
- streamWriter.writeChar(instance[i]);
- }
- }
-
-}
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/lang/double_Array_CustomFieldSerializer.java b/user/src/com/google/gwt/user/client/rpc/core/java/lang/double_Array_CustomFieldSerializer.java
deleted file mode 100644
index 0301a77..0000000
--- a/user/src/com/google/gwt/user/client/rpc/core/java/lang/double_Array_CustomFieldSerializer.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2006 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.user.client.rpc.core.java.lang;
-
-import com.google.gwt.user.client.rpc.SerializationException;
-import com.google.gwt.user.client.rpc.SerializationStreamReader;
-import com.google.gwt.user.client.rpc.SerializationStreamWriter;
-
-/**
- * Custom Serializer for arrays of double.
- */
-public class double_Array_CustomFieldSerializer {
-
- public static void deserialize(SerializationStreamReader streamReader,
- double[] instance) throws SerializationException {
- for (int itemIndex = 0; itemIndex < instance.length; ++itemIndex) {
- instance[itemIndex] = streamReader.readDouble();
- }
- }
-
- public static void serialize(SerializationStreamWriter streamWriter,
- double[] instance) throws SerializationException {
- int itemCount = instance.length;
- streamWriter.writeInt(itemCount);
- for (int itemIndex = 0; itemIndex < itemCount; ++itemIndex) {
- streamWriter.writeDouble(instance[itemIndex]);
- }
- }
-
-}
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/lang/float_Array_CustomFieldSerializer.java b/user/src/com/google/gwt/user/client/rpc/core/java/lang/float_Array_CustomFieldSerializer.java
deleted file mode 100644
index 5c9df9e..0000000
--- a/user/src/com/google/gwt/user/client/rpc/core/java/lang/float_Array_CustomFieldSerializer.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2006 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.user.client.rpc.core.java.lang;
-
-import com.google.gwt.user.client.rpc.SerializationException;
-import com.google.gwt.user.client.rpc.SerializationStreamReader;
-import com.google.gwt.user.client.rpc.SerializationStreamWriter;
-
-/**
- * Custom Serializer for arrays of float.
- */
-public class float_Array_CustomFieldSerializer {
-
- public static void deserialize(SerializationStreamReader streamReader,
- float[] instance) throws SerializationException {
- for (int itemIndex = 0; itemIndex < instance.length; ++itemIndex) {
- instance[itemIndex] = streamReader.readFloat();
- }
- }
-
- public static void serialize(SerializationStreamWriter streamWriter,
- float[] instance) throws SerializationException {
- int itemCount = instance.length;
- streamWriter.writeInt(itemCount);
- for (int itemIndex = 0; itemIndex < itemCount; ++itemIndex) {
- streamWriter.writeFloat(instance[itemIndex]);
- }
- }
-}
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/lang/int_Array_CustomFieldSerializer.java b/user/src/com/google/gwt/user/client/rpc/core/java/lang/int_Array_CustomFieldSerializer.java
deleted file mode 100644
index 61728e9..0000000
--- a/user/src/com/google/gwt/user/client/rpc/core/java/lang/int_Array_CustomFieldSerializer.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2006 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.user.client.rpc.core.java.lang;
-
-import com.google.gwt.user.client.rpc.SerializationException;
-import com.google.gwt.user.client.rpc.SerializationStreamReader;
-import com.google.gwt.user.client.rpc.SerializationStreamWriter;
-
-/**
- * Custom Serializer for arrays of int.
- */
-public class int_Array_CustomFieldSerializer {
-
- public static void deserialize(SerializationStreamReader streamReader,
- int[] instance) throws SerializationException {
- for (int itemIndex = 0; itemIndex < instance.length; ++itemIndex) {
- instance[itemIndex] = streamReader.readInt();
- }
- }
-
- public static void serialize(SerializationStreamWriter streamWriter,
- int[] instance) throws SerializationException {
- int itemCount = instance.length;
- streamWriter.writeInt(itemCount);
- for (int itemIndex = 0; itemIndex < itemCount; ++itemIndex) {
- streamWriter.writeInt(instance[itemIndex]);
- }
- }
-
-}
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/lang/long_Array_CustomFieldSerializer.java b/user/src/com/google/gwt/user/client/rpc/core/java/lang/long_Array_CustomFieldSerializer.java
deleted file mode 100644
index ebf2dd0..0000000
--- a/user/src/com/google/gwt/user/client/rpc/core/java/lang/long_Array_CustomFieldSerializer.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2006 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.user.client.rpc.core.java.lang;
-
-import com.google.gwt.user.client.rpc.SerializationException;
-import com.google.gwt.user.client.rpc.SerializationStreamReader;
-import com.google.gwt.user.client.rpc.SerializationStreamWriter;
-
-/**
- * Custom Serializer for arrays of long.
- */
-public class long_Array_CustomFieldSerializer {
-
- public static void deserialize(SerializationStreamReader streamReader,
- long[] instance) throws SerializationException {
- for (int itemIndex = 0; itemIndex < instance.length; ++itemIndex) {
- instance[itemIndex] = streamReader.readLong();
- }
- }
-
- public static void serialize(SerializationStreamWriter streamWriter,
- long[] instance) throws SerializationException {
- int itemCount = instance.length;
- streamWriter.writeInt(itemCount);
- for (int itemIndex = 0; itemIndex < itemCount; ++itemIndex) {
- streamWriter.writeLong(instance[itemIndex]);
- }
- }
-}
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/lang/short_Array_CustomFieldSerializer.java b/user/src/com/google/gwt/user/client/rpc/core/java/lang/short_Array_CustomFieldSerializer.java
deleted file mode 100644
index 59511b7..0000000
--- a/user/src/com/google/gwt/user/client/rpc/core/java/lang/short_Array_CustomFieldSerializer.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2006 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.user.client.rpc.core.java.lang;
-
-import com.google.gwt.user.client.rpc.SerializationException;
-import com.google.gwt.user.client.rpc.SerializationStreamReader;
-import com.google.gwt.user.client.rpc.SerializationStreamWriter;
-
-/**
- * Custom Serializer for arrays of short.
- */
-public class short_Array_CustomFieldSerializer {
-
- public static void deserialize(SerializationStreamReader streamReader,
- short[] instance) throws SerializationException {
- for (int itemIndex = 0; itemIndex < instance.length; ++itemIndex) {
- instance[itemIndex] = streamReader.readShort();
- }
- }
-
- public static void serialize(SerializationStreamWriter streamWriter,
- short[] instance) throws SerializationException {
- int itemCount = instance.length;
- streamWriter.writeInt(itemCount);
- for (int itemIndex = 0; itemIndex < itemCount; ++itemIndex) {
- streamWriter.writeShort(instance[itemIndex]);
- }
- }
-}
diff --git a/user/src/com/google/gwt/user/rebind/ClassSourceFileComposer.java b/user/src/com/google/gwt/user/rebind/ClassSourceFileComposer.java
index 396e6dc..658c1a6 100644
--- a/user/src/com/google/gwt/user/rebind/ClassSourceFileComposer.java
+++ b/user/src/com/google/gwt/user/rebind/ClassSourceFileComposer.java
@@ -58,7 +58,10 @@
+ targetClassShortName);
}
// Inlined header to only have one method with a huge number of methods.
- println("package " + targetPackageName + ";");
+ if (targetPackageName.length() > 0) {
+ println("package " + targetPackageName + ";");
+ }
+
println();
if (imports != null && imports.length > 0) {
for (int i = 0, n = imports.length; i < n; ++i) {
diff --git a/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java b/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java
index 5ee2530..fbaa697 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java
@@ -24,6 +24,7 @@
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.client.rpc.SerializationStreamReader;
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
+import com.google.gwt.user.client.rpc.core.java.lang.Object_Array_CustomFieldSerializer;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
@@ -68,7 +69,7 @@
public FieldSerializerCreator(SerializableTypeOracle serializationOracle,
JClassType requestedClass) {
assert (requestedClass != null);
- assert (requestedClass.isClass() != null);
+ assert (requestedClass.isClass() != null || requestedClass.isArray() != null);
this.serializationOracle = serializationOracle;
serializableClass = requestedClass;
@@ -92,34 +93,42 @@
writeFieldAccessors();
- writeSerializeMethod();
-
writeDeserializeMethod();
+ writeInstatiateMethod();
+
+ writeSerializeMethod();
+
sourceWriter.commit(logger);
return fieldSerializerName;
}
- /**
- * Returns the name of the field serializer which will deal with this class.
- *
- * @return name of the field serializer
- */
- private String getFieldSerializerClassName() {
- String sourceName = serializationOracle.getFieldSerializerName(serializableClass);
+ private String createArrayInstantiationExpression(JArrayType array) {
+ StringBuilder sb = new StringBuilder();
- int qualifiedSourceNameStart = sourceName.lastIndexOf('.');
- if (qualifiedSourceNameStart >= 0) {
- sourceName = sourceName.substring(qualifiedSourceNameStart + 1);
+ sb.append("new ");
+ sb.append(array.getLeafType().getQualifiedSourceName());
+ sb.append("[rank]");
+ for (int i = 0; i < array.getRank() - 1; ++i) {
+ sb.append("[]");
}
- return sourceName;
+ return sb.toString();
}
private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext ctx) {
- String packageName = serializableClass.getPackage().getName();
- String className = getFieldSerializerClassName();
+ String qualifiedSerializerName = serializationOracle.getFieldSerializerName(serializableClass);
+ int packageNameEnd = qualifiedSerializerName.lastIndexOf('.');
+ String className;
+ String packageName;
+ if (packageNameEnd != -1) {
+ className = qualifiedSerializerName.substring(packageNameEnd + 1);
+ packageName = qualifiedSerializerName.substring(0, packageNameEnd);
+ } else {
+ className = qualifiedSerializerName;
+ packageName = "";
+ }
PrintWriter printWriter = ctx.tryCreate(logger, packageName, className);
if (printWriter == null) {
@@ -149,6 +158,110 @@
return field.isPrivate();
}
+ private void writeArrayDeserializationStatements(JArrayType isArray) {
+ JType componentType = isArray.getComponentType();
+ String readMethodName = Shared.getStreamReadMethodNameFor(componentType);
+
+ if ("readObject".equals(readMethodName)) {
+ // Optimize and use the default object custom serializer...
+ sourceWriter.println(Object_Array_CustomFieldSerializer.class.getName()
+ + ".deserialize(streamReader, instance);");
+ } else {
+ sourceWriter.println("for (int i = 0, n = instance.length; i < n; ++i) {");
+ sourceWriter.indent();
+ sourceWriter.print("instance[i] = streamReader.");
+ sourceWriter.println(readMethodName + "();");
+ sourceWriter.outdent();
+ sourceWriter.println("}");
+ }
+ }
+
+ private void writeArraySerializationStatements(JArrayType isArray) {
+ JType componentType = isArray.getComponentType();
+ String writeMethodName = Shared.getStreamWriteMethodNameFor(componentType);
+ if ("writeObject".equals(writeMethodName)) {
+ // Optimize and use the default object custom serializer...
+ sourceWriter.println(Object_Array_CustomFieldSerializer.class.getName()
+ + ".serialize(streamWriter, instance);");
+ } else {
+ sourceWriter.println("streamWriter.writeInt(instance.length);");
+ sourceWriter.println();
+ sourceWriter.println("for (int i = 0, n = instance.length; i < n; ++i) {");
+ sourceWriter.indent();
+ sourceWriter.print("streamWriter.");
+ sourceWriter.print(writeMethodName);
+ sourceWriter.println("(instance[i]);");
+ sourceWriter.outdent();
+ sourceWriter.println("}");
+ }
+ }
+
+ private void writeClassDeserializationStatements() {
+ for (JField serializableField : serializableFields) {
+ JType fieldType = serializableField.getType();
+
+ String readMethodName = Shared.getStreamReadMethodNameFor(fieldType);
+ String streamReadExpression = "streamReader." + readMethodName + "()";
+ if (Shared.typeNeedsCast(fieldType)) {
+ streamReadExpression = "(" + fieldType.getQualifiedSourceName() + ") "
+ + streamReadExpression;
+ }
+
+ if (needsAccessorMethods(serializableField)) {
+ sourceWriter.print("set");
+ sourceWriter.print(Shared.capitalize(serializableField.getName()));
+ sourceWriter.print("(instance, ");
+ sourceWriter.print(streamReadExpression);
+ sourceWriter.println(");");
+ } else {
+ sourceWriter.print("instance.");
+ sourceWriter.print(serializableField.getName());
+ sourceWriter.print(" = ");
+ sourceWriter.print(streamReadExpression);
+ sourceWriter.println(";");
+ }
+ }
+
+ sourceWriter.println();
+
+ JClassType superClass = serializableClass.getSuperclass();
+ if (superClass != null && serializationOracle.isSerializable(superClass)) {
+ String fieldSerializerName = serializationOracle.getFieldSerializerName(superClass);
+ sourceWriter.print(fieldSerializerName);
+ sourceWriter.println(".deserialize(streamReader, instance);");
+ }
+ }
+
+ private void writeClassSerializationStatements() {
+ for (JField serializableField : serializableFields) {
+ JType fieldType = serializableField.getType();
+
+ String writeMethodName = Shared.getStreamWriteMethodNameFor(fieldType);
+ sourceWriter.print("streamWriter.");
+ sourceWriter.print(writeMethodName);
+ sourceWriter.print("(");
+
+ if (needsAccessorMethods(serializableField)) {
+ sourceWriter.print("get");
+ sourceWriter.print(Shared.capitalize(serializableField.getName()));
+ sourceWriter.println("(instance));");
+ } else {
+ sourceWriter.print("instance.");
+ sourceWriter.print(serializableField.getName());
+ sourceWriter.println(");");
+ }
+ }
+
+ sourceWriter.println();
+
+ JClassType superClass = serializableClass.getSuperclass();
+ if (superClass != null && serializationOracle.isSerializable(superClass)) {
+ String fieldSerializerName = serializationOracle.getFieldSerializerName(superClass);
+ sourceWriter.print(fieldSerializerName);
+ sourceWriter.println(".serialize(streamWriter, instance);");
+ }
+ }
+
private void writeDeserializeMethod() {
sourceWriter.print("public static void deserialize(");
sourceWriter.print(SerializationStreamReader.class.getName());
@@ -158,15 +271,12 @@
+ SerializationException.class.getName() + "{");
sourceWriter.indent();
- writeFieldDeserializationStatements();
-
- JClassType superClass = serializableClass.getSuperclass();
- if (superClass != null && serializationOracle.isSerializable(superClass)) {
- String fieldSerializerName = serializationOracle.getFieldSerializerName(superClass);
- sourceWriter.print(fieldSerializerName);
- sourceWriter.println(".deserialize(streamReader, instance);");
+ JArrayType isArray = serializableClass.isArray();
+ if (isArray != null) {
+ writeArrayDeserializationStatements(isArray);
+ } else {
+ writeClassDeserializationStatements();
}
-
sourceWriter.outdent();
sourceWriter.println("}");
sourceWriter.println();
@@ -178,12 +288,7 @@
* external class to access the field's value.
*/
private void writeFieldAccessors() {
- JField[] jFields = serializableFields;
- int fieldCount = jFields.length;
-
- for (int fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex) {
- JField serializableField = jFields[fieldIndex];
-
+ for (JField serializableField : serializableFields) {
if (!needsAccessorMethods(serializableField)) {
continue;
}
@@ -193,59 +298,6 @@
}
}
- private void writeFieldDeserializationStatements() {
- JType type = serializableClass;
- JArrayType isArray = type.isArray();
- if (isArray != null) {
- sourceWriter.println("for (int itemIndex = 0; itemIndex < instance.length; ++itemIndex) {");
- sourceWriter.indent();
-
- JType componentType = isArray.getComponentType();
-
- sourceWriter.print("instance[itemIndex] = ");
- if (Shared.typeNeedsCast(componentType)) {
- sourceWriter.print("(" + componentType.getQualifiedSourceName() + ") ");
- }
- String readMethodName = "streamReader.read"
- + Shared.getCallSuffix(componentType);
- sourceWriter.println(readMethodName + "();");
- sourceWriter.outdent();
- sourceWriter.println("}");
- } else {
- JField[] jFields = serializableFields;
- int fieldCount = jFields.length;
-
- for (int fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex) {
- JField serializableField = jFields[fieldIndex];
- JType fieldType = serializableField.getType();
- boolean needsAccessor = needsAccessorMethods(serializableField);
-
- String readMethodName = "read" + Shared.getCallSuffix(fieldType);
- String streamReadExpression = "streamReader." + readMethodName + "()";
- if (Shared.typeNeedsCast(fieldType)) {
- streamReadExpression = "(" + fieldType.getQualifiedSourceName()
- + ") " + streamReadExpression;
- }
-
- if (needsAccessor) {
- sourceWriter.print("set");
- sourceWriter.print(Shared.capitalize(serializableField.getName()));
- sourceWriter.print("(instance, ");
- sourceWriter.print(streamReadExpression);
- sourceWriter.println(");");
- } else {
- sourceWriter.print("instance.");
- sourceWriter.print(serializableField.getName());
- sourceWriter.print(" = ");
- sourceWriter.print(streamReadExpression);
- sourceWriter.println(";");
- }
- }
- }
-
- sourceWriter.println();
- }
-
/**
* Write a getter method for an instance field.
*/
@@ -274,51 +326,6 @@
sourceWriter.println();
}
- private void writeFieldSerializationStatements() {
- JType type = serializableClass;
- JArrayType isArray = type.isArray();
- if (isArray != null) {
- sourceWriter.println("int itemCount = instance.length;");
- sourceWriter.println();
- sourceWriter.println("streamWriter.writeInt(itemCount);");
- sourceWriter.println();
- sourceWriter.println("for (int itemIndex = 0; itemIndex < itemCount; ++itemIndex) {");
- sourceWriter.indent();
- String writeMethodName = "write"
- + Shared.getCallSuffix(isArray.getComponentType());
- sourceWriter.print("streamWriter.");
- sourceWriter.print(writeMethodName);
- sourceWriter.println("(instance[itemIndex]);");
- sourceWriter.outdent();
- sourceWriter.println("}");
- } else {
- JField[] jFields = serializableFields;
- int fieldCount = jFields.length;
-
- for (int fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex) {
- JField serializableField = jFields[fieldIndex];
- JType fieldType = serializableField.getType();
-
- String writeMethodName = "write" + Shared.getCallSuffix(fieldType);
- sourceWriter.print("streamWriter.");
- sourceWriter.print(writeMethodName);
- sourceWriter.print("(");
-
- if (needsAccessorMethods(serializableField)) {
- sourceWriter.print("get");
- sourceWriter.print(Shared.capitalize(serializableField.getName()));
- sourceWriter.println("(instance));");
- } else {
- sourceWriter.print("instance.");
- sourceWriter.print(serializableField.getName());
- sourceWriter.println(");");
- }
- }
- }
-
- sourceWriter.println();
- }
-
/**
* Write a setter method for an instance field.
*/
@@ -349,6 +356,34 @@
sourceWriter.println();
}
+ private void writeInstatiateMethod() {
+ if (serializableClass.isAbstract()) {
+ return;
+ }
+
+ sourceWriter.print("public static ");
+ sourceWriter.print(serializableClass.getQualifiedSourceName());
+ sourceWriter.print(" instantiate(");
+ sourceWriter.print(SerializationStreamReader.class.getName());
+ sourceWriter.println(" streamReader) throws "
+ + SerializationException.class.getName() + "{");
+ sourceWriter.indent();
+
+ JArrayType isArray = serializableClass.isArray();
+ if (isArray != null) {
+ sourceWriter.println("int rank = streamReader.readInt();");
+ sourceWriter.println("return "
+ + createArrayInstantiationExpression(isArray) + ";");
+ } else {
+ sourceWriter.println("return new "
+ + serializableClass.getQualifiedSourceName() + "();");
+ }
+
+ sourceWriter.outdent();
+ sourceWriter.println("}");
+ sourceWriter.println();
+ }
+
private void writeSerializeMethod() {
sourceWriter.print("public static void serialize(");
sourceWriter.print(SerializationStreamWriter.class.getName());
@@ -358,15 +393,13 @@
+ SerializationException.class.getName() + " {");
sourceWriter.indent();
- writeFieldSerializationStatements();
-
- JClassType superClass = serializableClass.getSuperclass();
- if (superClass != null && serializationOracle.isSerializable(superClass)) {
- String fieldSerializerName = serializationOracle.getFieldSerializerName(superClass);
- sourceWriter.print(fieldSerializerName);
- sourceWriter.println(".serialize(streamWriter, instance);");
+ JArrayType isArray = serializableClass.isArray();
+ if (isArray != null) {
+ writeArraySerializationStatements(isArray);
+ } else {
+ writeClassSerializationStatements();
}
-
+
sourceWriter.outdent();
sourceWriter.println("}");
sourceWriter.println();
diff --git a/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java b/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
index 6b6d260..1438787 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
@@ -137,7 +137,7 @@
*/
protected final void generateDecodeCall(SourceWriter w, JType type) {
w.print("streamReader.");
- w.print("read" + Shared.getCallSuffix(type) + "()");
+ w.print(Shared.getStreamReadMethodNameFor(type) + "()");
}
/*
@@ -147,7 +147,7 @@
protected void generateEncodeCall(SourceWriter w, JParameter parameter) {
JType paramType = parameter.getType();
w.print("streamWriter.");
- w.print("write" + Shared.getCallSuffix(paramType));
+ w.print(Shared.getStreamWriteMethodNameFor(paramType));
w.println("(" + parameter.getName() + ");");
}
diff --git a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleImpl.java b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleImpl.java
index ee8a6bb..cc91e55 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleImpl.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleImpl.java
@@ -19,7 +19,6 @@
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JField;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
-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.dev.jdt.TypeOracleBuilder;
@@ -38,8 +37,6 @@
final class SerializableTypeOracleImpl implements SerializableTypeOracle {
- private static final String DEFAULT_BUILTIN_CUSTOM_SERIALIZER_PACKAGE_NAME = "com.google.gwt.user.client.rpc.core.java.lang";
-
private static final Comparator<JField> FIELD_COMPARATOR = new Comparator<JField>() {
public int compare(JField f1, JField f2) {
return f1.getName().compareTo(f2.getName());
@@ -95,18 +92,20 @@
return customSerializer.getQualifiedSourceName();
}
- JClassType classType = type.isClassOrInterface();
- if (classType != null) {
- String[] name = Shared.synthesizeTopLevelClassName(classType,
- GENERATED_FIELD_SERIALIZER_SUFFIX);
- if (name[0].length() > 0) {
- return name[0] + "." + name[1];
- } else {
- return name[1];
+ assert (type.isClassOrInterface() != null || type.isArray() != null);
+ JClassType classType = (JClassType) type;
+ String[] name = Shared.synthesizeTopLevelClassName(classType,
+ GENERATED_FIELD_SERIALIZER_SUFFIX);
+ if (name[0].length() > 0) {
+ String serializerName = name[0] + "." + name[1];
+ if (name[0].startsWith("java.")) {
+ serializerName = "com.google.gwt.user.client.rpc.core."
+ + serializerName;
}
+
+ return serializerName;
} else {
- // TODO(mmendez): is this branch ever needed; if not, tighten param type
- return type.getQualifiedSourceName() + GENERATED_FIELD_SERIALIZER_SUFFIX;
+ return name[1];
}
}
@@ -114,8 +113,11 @@
* Returns the fields which qualify for serialization.
*/
public JField[] getSerializableFields(JClassType classType) {
+ assert (classType != null);
+
List<JField> fields = new ArrayList<JField>();
JField[] declFields = classType.getFields();
+ assert (declFields != null);
for (JField field : declFields) {
// TODO(mmendez): this is shared with the serializable type oracle
// builder, join with that
@@ -181,33 +183,8 @@
}
public JClassType hasCustomFieldSerializer(JType type) {
- JClassType customSerializer = SerializableTypeOracleBuilder.findCustomFieldSerializer(
- typeOracle, type);
- if (customSerializer != null) {
- return customSerializer;
- }
-
- if (!isSerializable(type)) {
- return null;
- }
-
- JArrayType arrayType = type.isArray();
- if (arrayType == null) {
- return null;
- }
-
- JType componentType = arrayType.getComponentType();
- JPrimitiveType primitiveType = componentType.isPrimitive();
- String qualifiedSerializerName = DEFAULT_BUILTIN_CUSTOM_SERIALIZER_PACKAGE_NAME
- + ".";
- if (primitiveType != null) {
- qualifiedSerializerName += primitiveType.getSimpleSourceName();
- } else {
- qualifiedSerializerName += typeOracle.getJavaLangObject().getSimpleSourceName();
- }
- qualifiedSerializerName += "_Array_CustomFieldSerializer";
-
- return typeOracle.findType(qualifiedSerializerName);
+ return SerializableTypeOracleBuilder.findCustomFieldSerializer(typeOracle,
+ type);
}
/**
diff --git a/user/src/com/google/gwt/user/rebind/rpc/Shared.java b/user/src/com/google/gwt/user/rebind/rpc/Shared.java
index cae9ddb..0c4d6b3 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/Shared.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/Shared.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 Google Inc.
+ * Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -18,6 +18,7 @@
import com.google.gwt.core.ext.BadPropertyValueException;
import com.google.gwt.core.ext.PropertyOracle;
import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
@@ -26,12 +27,12 @@
import java.util.Locale;
class Shared {
-
/**
* Property used to control whether or not the RPC system will enforce the
* versioning scheme or not.
*/
- static final String RPC_PROP_ENFORCE_TYPE_VERSIONING = "gwt.enforceRPCTypeVersioning";
+ static final String RPC_PROP_ENFORCE_TYPE_VERSIONING =
+ "gwt.enforceRPCTypeVersioning";
/**
* Capitalizes a name.
@@ -43,52 +44,24 @@
return name.substring(0, 1).toUpperCase(Locale.US) + name.substring(1);
}
- /**
- * Gets the suffix needed to make a call for a particular type. For example,
- * the <code>int</code> class needs methods named "readInt" and "writeInt".
- *
- * @param type the type in question
- * @return the suffix of the method to call
- */
- static String getCallSuffix(JType type) {
- JParameterizedType isParameterized = type.isParameterized();
- if (isParameterized != null) {
- return getCallSuffix(isParameterized.getRawType());
- } else if (type.isPrimitive() != null) {
- if (type == JPrimitiveType.BOOLEAN) {
- return "Boolean";
- } else if (type == JPrimitiveType.BYTE) {
- return "Byte";
- } else if (type == JPrimitiveType.CHAR) {
- return "Char";
- } else if (type == JPrimitiveType.DOUBLE) {
- return "Double";
- } else if (type == JPrimitiveType.FLOAT) {
- return "Float";
- } else if (type == JPrimitiveType.INT) {
- return "Int";
- } else if (type == JPrimitiveType.LONG) {
- return "Long";
- } else if (type == JPrimitiveType.SHORT) {
- return "Short";
- } else {
- return null;
- }
- } else if (type.getQualifiedSourceName().equals("java.lang.String")) {
- return "String";
- } else {
- return "Object";
- }
+ static String getStreamReadMethodNameFor(JType type) {
+ return "read" + getCallSuffix(type);
+ }
+
+ static String getStreamWriteMethodNameFor(JType type) {
+ return "write" + getCallSuffix(type);
}
/**
* Returns <code>true</code> if the generated code should enforce type
* versioning.
*/
- static boolean shouldEnforceTypeVersioning(TreeLogger logger, PropertyOracle propertyOracle) {
+ static boolean shouldEnforceTypeVersioning(TreeLogger logger,
+ PropertyOracle propertyOracle) {
try {
- String propVal = propertyOracle.getPropertyValue(logger,
- RPC_PROP_ENFORCE_TYPE_VERSIONING);
+ String propVal =
+ propertyOracle.getPropertyValue(logger,
+ RPC_PROP_ENFORCE_TYPE_VERSIONING);
if (propVal.equals("false")) {
return false;
}
@@ -123,7 +96,24 @@
// Gets the basic name of the type. If it's a nested type, the type name
// will contains dots.
//
- String className = type.getName();
+ String className;
+ String packageName;
+
+ JType leafType = type.getLeafType();
+ if (leafType.isPrimitive() != null) {
+ className = leafType.getSimpleSourceName();
+ packageName = "";
+ } else {
+ JClassType classOrInterface = leafType.isClassOrInterface();
+ assert (classOrInterface != null);
+ className = classOrInterface.getName();
+ packageName = classOrInterface.getPackage().getName();
+ }
+
+ JArrayType isArray = type.isArray();
+ if (isArray != null) {
+ className += "_Array_Rank_" + isArray.getRank();
+ }
// Add the meaningful suffix.
//
@@ -133,7 +123,6 @@
//
className = className.replace('.', '_');
- String packageName = type.getPackage().getName();
return new String[]{packageName, className};
}
@@ -151,4 +140,42 @@
&& !type.getQualifiedSourceName().equals("java.lang.String")
&& !type.getQualifiedSourceName().equals("java.lang.Object");
}
+
+ /**
+ * Gets the suffix needed to make a call for a particular type. For example,
+ * the <code>int</code> class needs methods named "readInt" and "writeInt".
+ *
+ * @param type the type in question
+ * @return the suffix of the method to call
+ */
+ private static String getCallSuffix(JType type) {
+ JParameterizedType isParameterized = type.isParameterized();
+ if (isParameterized != null) {
+ return getCallSuffix(isParameterized.getRawType());
+ } else if (type.isPrimitive() != null) {
+ if (type == JPrimitiveType.BOOLEAN) {
+ return "Boolean";
+ } else if (type == JPrimitiveType.BYTE) {
+ return "Byte";
+ } else if (type == JPrimitiveType.CHAR) {
+ return "Char";
+ } else if (type == JPrimitiveType.DOUBLE) {
+ return "Double";
+ } else if (type == JPrimitiveType.FLOAT) {
+ return "Float";
+ } else if (type == JPrimitiveType.INT) {
+ return "Int";
+ } else if (type == JPrimitiveType.LONG) {
+ return "Long";
+ } else if (type == JPrimitiveType.SHORT) {
+ return "Short";
+ } else {
+ return null;
+ }
+ } else if (type.getQualifiedSourceName().equals("java.lang.String")) {
+ return "String";
+ } else {
+ return "Object";
+ }
+ }
}
diff --git a/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java b/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
index dac5a9c..e30ac4e 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
@@ -19,12 +19,10 @@
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
-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.JPackage;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
-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.user.client.rpc.SerializationException;
@@ -120,25 +118,6 @@
return typeSerializerName;
}
- private String buildArrayInstantiationExpression(JArrayType array) {
- String expression = "[rank]";
- JType componentType = array.getComponentType();
- while (true) {
- array = componentType.isArray();
- if (array == null) {
- break;
- }
-
- expression += "[0]";
-
- componentType = array.getComponentType();
- }
-
- expression = componentType.getQualifiedSourceName() + expression;
-
- return expression;
- }
-
/*
* Create a field serializer for a type if it does not have a custom
* serializer.
@@ -162,14 +141,13 @@
/*
* Only a JClassType can reach this point in the code. JPrimitives have been
* removed because their serialization is built in, interfaces have been
- * removed because they are not an instantiable type, JArrays have custom
- * field serializers, and parameterized types have been broken down into
- * their raw types.
+ * removed because they are not an instantiable type and parameterized types
+ * have been broken down into their raw types.
*/
- assert (type.isClass() != null);
+ assert (type.isClass() != null || type.isArray() != null);
FieldSerializerCreator creator = new FieldSerializerCreator(
- serializationOracle, type.isClass());
+ serializationOracle, (JClassType) type);
creator.realize(logger, ctx);
}
@@ -187,25 +165,8 @@
}
}
- private JMethod getCustomInstantiateMethod(JType type) {
- JClassType serializer = serializationOracle.hasCustomFieldSerializer(type);
- if (serializer == null) {
- return null;
- }
-
- JMethod instantiate = serializer.findMethod(
- "instantiate",
- new JType[] {typeOracle.findType(SerializationStreamReader.class.getName())});
- return instantiate;
- }
-
- private String getInstantiationMethodName(JType type) {
- JArrayType arrayType = type.isArray();
- if (arrayType != null) {
- JType leafType = arrayType.getLeafType();
- return "create_" + leafType.getQualifiedSourceName().replace('.', '_')
- + "_Array_Rank_" + arrayType.getRank();
- }
+ private String getCreateMethodName(JType type) {
+ assert (type.isArray() == null);
return "create_"
+ serializationOracle.getFieldSerializerName(type).replace('.', '_');
@@ -257,40 +218,42 @@
}
/**
- * Given a type determine what JSNI signature to use in the serialize or
- * deserialize method of a custom serializer.
+ * Return <code>true</code> if this type is concrete and has a custom field
+ * serializer that does not declare an instantiate method.
*
* @param type
+ * @return
*/
- private String normalizeJSNIInstanceSerializationMethodSignature(JType type) {
- String jsniSignature;
- JArrayType arrayType = type.isArray();
-
- if (arrayType != null) {
- JType componentType = arrayType.getComponentType();
- JPrimitiveType primitiveType = componentType.isPrimitive();
- if (primitiveType != null) {
- jsniSignature = "[" + primitiveType.getJNISignature();
- } else {
- jsniSignature = "[" + "Ljava/lang/Object;";
- }
- } else {
- jsniSignature = type.getJNISignature();
+ private boolean needsCreateMethod(JType type) {
+ // If this type is abstract it will not be serialized into the stream
+ //
+ if (isAbstractType(type)) {
+ return false;
}
- return jsniSignature;
+ if (type.isArray() != null) {
+ return false;
+ }
+
+ JClassType customSerializer = serializationOracle.hasCustomFieldSerializer(type);
+ if (customSerializer == null) {
+ return false;
+ }
+
+ JMethod customInstantiate = customSerializer.findMethod(
+ "instantiate",
+ new JType[] {typeOracle.findType(SerializationStreamReader.class.getName())});
+ if (customInstantiate != null) {
+ return false;
+ }
+
+ return true;
}
private boolean shouldEnforceTypeVersioning() {
return enforceTypeVersioning;
}
- private void writeArrayInstantiationMethod(JArrayType array) {
- srcWriter.println("int rank = streamReader.readInt();");
- srcWriter.println("return new " + buildArrayInstantiationExpression(array)
- + ";");
- }
-
private void writeCreateMethodMapMethod() {
srcWriter.println("private static native JavaScriptObject createMethodMap() /*-" + '{');
{
@@ -322,30 +285,26 @@
srcWriter.println("[");
{
srcWriter.indent();
+
+ String serializerName = serializationOracle.getFieldSerializerName(type);
{
// First the initialization method
- JMethod instantiationMethod = getCustomInstantiateMethod(type);
- srcWriter.print("function(x){ return ");
- if (instantiationMethod != null) {
- srcWriter.print("@"
- + instantiationMethod.getEnclosingType().getQualifiedSourceName());
+ srcWriter.print("function(x){ return @");
+ if (needsCreateMethod(type)) {
+ srcWriter.print(serializationOracle.getTypeSerializerQualifiedName(getServiceInterface()));
srcWriter.print("::");
- srcWriter.print(instantiationMethod.getName());
+ srcWriter.print(getCreateMethodName(type));
} else {
- srcWriter.print("@"
- + serializationOracle.getTypeSerializerQualifiedName(getServiceInterface()));
- srcWriter.print("::");
- srcWriter.print(getInstantiationMethodName(type));
+ srcWriter.print(serializerName);
+ srcWriter.print("::instantiate");
}
- srcWriter.print("(L"
+ srcWriter.println("(L"
+ SerializationStreamReader.class.getName().replace('.', '/')
- + ";)");
- srcWriter.print("(x);}");
- srcWriter.println(",");
+ + ";)(x);},");
}
- String jsniSignature = normalizeJSNIInstanceSerializationMethodSignature(type);
- String serializerName = serializationOracle.getFieldSerializerName(type);
+ String jsniSignature = type.getJNISignature();
+
{
// Now the deserialization method
srcWriter.print("function(x,y){");
@@ -384,36 +343,25 @@
JType type = types[typeIndex];
assert (serializationOracle.isSerializable(type));
- // If this type is abstract it will not be serialized into the stream
- //
- if (isAbstractType(type)) {
+ if (!needsCreateMethod(type)) {
continue;
}
- JMethod customInstantiate = getCustomInstantiateMethod(type);
- if (customInstantiate != null) {
- continue;
- }
-
+ /*
+ * Only classes with custom field serializers that do no declare
+ * instantiate methods get here
+ */
srcWriter.print("private static ");
srcWriter.print(type.getQualifiedSourceName());
srcWriter.print(" ");
- srcWriter.print(getInstantiationMethodName(type));
+ srcWriter.print(getCreateMethodName(type));
srcWriter.println("(SerializationStreamReader streamReader) throws SerializationException {");
srcWriter.indent();
-
- JArrayType array = type.isArray();
- if (array != null) {
- writeArrayInstantiationMethod(array);
- } else {
- srcWriter.print("return new ");
- srcWriter.print(type.getQualifiedSourceName());
- srcWriter.println("();");
- }
-
+ srcWriter.print("return new ");
+ srcWriter.print(type.getQualifiedSourceName());
+ srcWriter.println("();");
srcWriter.outdent();
srcWriter.println("}");
-
srcWriter.println();
}
}
diff --git a/user/src/com/google/gwt/user/server/rpc/impl/SerializabilityUtil.java b/user/src/com/google/gwt/user/server/rpc/impl/SerializabilityUtil.java
index ed917ff..c080e53 100644
--- a/user/src/com/google/gwt/user/server/rpc/impl/SerializabilityUtil.java
+++ b/user/src/com/google/gwt/user/server/rpc/impl/SerializabilityUtil.java
@@ -23,6 +23,7 @@
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import java.util.zip.CRC32;
@@ -33,13 +34,29 @@
public class SerializabilityUtil {
public static final String DEFAULT_ENCODING = "UTF-8";
-
+
+ /**
+ * Comparator used to sort fields.
+ */
+ public static final Comparator<Field> FIELD_COMPARATOR = new Comparator<Field>() {
+ public int compare(Field f1, Field f2) {
+ return f1.getName().compareTo(f2.getName());
+ }
+ };
+
/**
* A permanent cache of all computed CRCs on classes. This is safe to do
* because a Class is guaranteed not to change within the lifetime of a
* ClassLoader (and thus, this Map). Access must be synchronized.
*/
- private static final Map<Class<?>, String> classCRC32Cache = new HashMap<Class<?>, String>();
+ private static final Map<Class<?>, String> classCRC32Cache = new IdentityHashMap<Class<?>, String>();
+
+ /**
+ * A permanent cache of all serializable fields on classes. This is safe to do
+ * because a Class is guaranteed not to change within the lifetime of a
+ * ClassLoader (and thus, this Map). Access must be synchronized.
+ */
+ private static final Map<Class<?>, Field[]> classSerializableFieldsCache = new IdentityHashMap<Class<?>, Field[]>();
/**
* A permanent cache of all which classes onto custom field serializers. This
@@ -47,7 +64,7 @@
* lifetime of a ClassLoader (and thus, this Map). Access must be
* synchronized.
*/
- private static final Map<Class<?>, Class<?>> classCustomSerializerCache = new HashMap<Class<?>, Class<?>>();
+ private static final Map<Class<?>, Class<?>> classCustomSerializerCache = new IdentityHashMap<Class<?>, Class<?>>();
private static final String JRE_SERIALIZER_PACKAGE = "com.google.gwt.user.client.rpc.core";
@@ -80,32 +97,34 @@
TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add(Throwable.class);
}
- public static Field[] applyFieldSerializationPolicy(Field[] fields) {
- ArrayList<Field> fieldList = new ArrayList<Field>();
- for (Field field : fields) {
- assert (field != null);
+ public static Field[] applyFieldSerializationPolicy(Class<?> clazz) {
+ Field[] serializableFields = getCachedSerializableFieldsForClass(clazz);
+ if (serializableFields == null) {
+ ArrayList<Field> fieldList = new ArrayList<Field>();
+ Field[] fields = clazz.getDeclaredFields();
+ for (Field field : fields) {
+ assert (field != null);
- int fieldModifiers = field.getModifiers();
- if (Modifier.isStatic(fieldModifiers)
- || Modifier.isTransient(fieldModifiers)
- || Modifier.isFinal(fieldModifiers)) {
- continue;
+ int fieldModifiers = field.getModifiers();
+ if (Modifier.isStatic(fieldModifiers)
+ || Modifier.isTransient(fieldModifiers)
+ || Modifier.isFinal(fieldModifiers)) {
+ continue;
+ }
+
+ fieldList.add(field);
}
- fieldList.add(field);
+ serializableFields = fieldList.toArray(new Field[fieldList.size()]);
+
+ // sort the fields by name
+ Arrays.sort(serializableFields, 0, serializableFields.length,
+ FIELD_COMPARATOR);
+
+ putCachedSerializableFieldsForClass(clazz, serializableFields);
}
- Field[] fieldSubset = fieldList.toArray(new Field[fieldList.size()]);
-
- // sort the fields by name
- Comparator<Field> comparator = new Comparator<Field>() {
- public int compare(Field f1, Field f2) {
- return f1.getName().compareTo(f2.getName());
- }
- };
- Arrays.sort(fieldSubset, 0, fieldSubset.length, comparator);
-
- return fieldSubset;
+ return serializableFields;
}
public static SerializedInstanceReference decodeSerializedInstanceReference(
@@ -153,10 +172,15 @@
}
/**
- * This method treats arrays in a special way.
+ * Returns the {@link Class} which can serialize the given instance type. Note
+ * that arrays never have custom field serializers.
*/
public static Class<?> hasCustomFieldSerializer(Class<?> instanceType) {
assert (instanceType != null);
+ if (instanceType.isArray()) {
+ return null;
+ }
+
Class<?> result = getCachedSerializerForClass(instanceType);
if (result != null) {
// this class has a custom serializer
@@ -177,24 +201,7 @@
*/
private static Class<?> computeHasCustomFieldSerializer(Class<?> instanceType) {
assert (instanceType != null);
-
- String qualifiedTypeName;
-
- if (instanceType.isArray()) {
- Class<?> componentType = instanceType.getComponentType();
-
- if (componentType.isPrimitive()) {
- qualifiedTypeName = "java.lang." + componentType.getName();
- } else {
- qualifiedTypeName = Object.class.getName();
- }
-
- qualifiedTypeName += "_Array";
-
- } else {
- qualifiedTypeName = instanceType.getName();
- }
-
+ String qualifiedTypeName = instanceType.getName();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
String simpleSerializerName = qualifiedTypeName + "_CustomFieldSerializer";
Class<?> customSerializer = getCustomFieldSerializer(classLoader,
@@ -229,8 +236,7 @@
private static void generateSerializationSignature(Class<?> instanceType,
CRC32 crc) throws UnsupportedEncodingException {
- crc.update(getSerializedTypeName(instanceType).getBytes(
- DEFAULT_ENCODING));
+ crc.update(getSerializedTypeName(instanceType).getBytes(DEFAULT_ENCODING));
if (excludeImplementationFromSerializationSignature(instanceType)) {
return;
@@ -242,7 +248,7 @@
} else if (instanceType.isArray()) {
generateSerializationSignature(instanceType.getComponentType(), crc);
} else if (!instanceType.isPrimitive()) {
- Field[] fields = applyFieldSerializationPolicy(instanceType.getDeclaredFields());
+ Field[] fields = applyFieldSerializationPolicy(instanceType);
for (Field field : fields) {
assert (field != null);
@@ -264,6 +270,12 @@
}
}
+ private static Field[] getCachedSerializableFieldsForClass(Class<?> clazz) {
+ synchronized (classSerializableFieldsCache) {
+ return classSerializableFieldsCache.get(clazz);
+ }
+ }
+
private static Class<?> getCachedSerializerForClass(Class<?> instanceType) {
synchronized (classCustomSerializerCache) {
return classCustomSerializerCache.get(instanceType);
@@ -287,6 +299,13 @@
}
}
+ private static void putCachedSerializableFieldsForClass(Class<?> clazz,
+ Field[] serializableFields) {
+ synchronized (classSerializableFieldsCache) {
+ classSerializableFieldsCache.put(clazz, serializableFields);
+ }
+ }
+
private static void putCachedSerializerForClass(Class<?> instanceType,
Class<?> customFieldSerializer) {
synchronized (classCustomSerializerCache) {
diff --git a/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamReader.java b/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamReader.java
index 3031a29..55d89ac 100644
--- a/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamReader.java
+++ b/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamReader.java
@@ -28,6 +28,8 @@
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
+import java.util.IdentityHashMap;
+import java.util.Map;
/**
* For internal use only. Used for server call serialization. This class is
@@ -36,6 +38,187 @@
public final class ServerSerializationStreamReader extends
AbstractSerializationStreamReader {
+ /**
+ * Enumeration used to provided typed instance readers.
+ */
+ private enum ValueReader {
+ BOOLEAN {
+ @Override
+ Object readValue(ServerSerializationStreamReader stream) {
+ return stream.readBoolean();
+ }
+ },
+ BYTE {
+ @Override
+ Object readValue(ServerSerializationStreamReader stream) {
+ return stream.readByte();
+ }
+ },
+ CHAR {
+ @Override
+ Object readValue(ServerSerializationStreamReader stream) {
+ return stream.readChar();
+ }
+ },
+ DOUBLE {
+ @Override
+ Object readValue(ServerSerializationStreamReader stream) {
+ return stream.readDouble();
+ }
+ },
+ FLOAT {
+ @Override
+ Object readValue(ServerSerializationStreamReader stream) {
+ return stream.readFloat();
+ }
+ },
+ INT {
+ @Override
+ Object readValue(ServerSerializationStreamReader stream) {
+ return stream.readInt();
+ }
+ },
+ LONG {
+ @Override
+ Object readValue(ServerSerializationStreamReader stream) {
+ return stream.readLong();
+ }
+ },
+ OBJECT {
+ @Override
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
+ return stream.readObject();
+ }
+ },
+ SHORT {
+ @Override
+ Object readValue(ServerSerializationStreamReader stream) {
+ return stream.readShort();
+ }
+ },
+ STRING {
+ @Override
+ Object readValue(ServerSerializationStreamReader stream) {
+ return stream.readString();
+ }
+ };
+
+ abstract Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException;
+ }
+
+ /**
+ * Enumeration used to provided typed instance readers for vectors.
+ */
+ private enum VectorReader {
+ BOOLEAN_VECTOR {
+ @Override
+ void read(ServerSerializationStreamReader stream, Object instance) {
+ boolean[] vector = (boolean[]) instance;
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ vector[i] = stream.readBoolean();
+ }
+ }
+ },
+ BYTE_VECTOR {
+ @Override
+ void read(ServerSerializationStreamReader stream, Object instance) {
+ byte[] vector = (byte[]) instance;
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ vector[i] = stream.readByte();
+ }
+ }
+ },
+ CHAR_VECTOR {
+ @Override
+ void read(ServerSerializationStreamReader stream, Object instance) {
+ char[] vector = (char[]) instance;
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ vector[i] = stream.readChar();
+ }
+ }
+ },
+ DOUBLE_VECTOR {
+ @Override
+ void read(ServerSerializationStreamReader stream, Object instance) {
+ double[] vector = (double[]) instance;
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ vector[i] = stream.readDouble();
+ }
+ }
+ },
+ FLOAT_VECTOR {
+ @Override
+ void read(ServerSerializationStreamReader stream, Object instance) {
+ float[] vector = (float[]) instance;
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ vector[i] = stream.readFloat();
+ }
+ }
+ },
+
+ INT_VECTOR {
+ @Override
+ void read(ServerSerializationStreamReader stream, Object instance) {
+ int[] vector = (int[]) instance;
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ vector[i] = stream.readInt();
+ }
+ }
+ },
+ LONG_VECTOR {
+ @Override
+ void read(ServerSerializationStreamReader stream, Object instance) {
+ long[] vector = (long[]) instance;
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ vector[i] = stream.readLong();
+ }
+ }
+ },
+ OBJECT_VECTOR {
+ @Override
+ void read(ServerSerializationStreamReader stream, Object instance)
+ throws SerializationException {
+ Object[] vector = (Object[]) instance;
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ vector[i] = stream.readObject();
+ }
+ }
+ },
+ SHORT_VECTOR {
+ @Override
+ void read(ServerSerializationStreamReader stream, Object instance) {
+ short[] vector = (short[]) instance;
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ vector[i] = stream.readShort();
+ }
+ }
+ },
+ STRING_VECTOR {
+ @Override
+ void read(ServerSerializationStreamReader stream, Object instance) {
+ String[] vector = (String[]) instance;
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ vector[i] = stream.readString();
+ }
+ }
+ };
+
+ abstract void read(ServerSerializationStreamReader stream, Object instance)
+ throws SerializationException;
+ }
+
+ /**
+ * Map of {@link Class} objects to {@link ValueReader}s.
+ */
+ private static final Map<Class<?>, ValueReader> CLASS_TO_VALUE_READER = new IdentityHashMap<Class<?>, ValueReader>();
+
+ /**
+ * Map of {@link Class} objects to {@link VectorReader}s.
+ */
+ private static final Map<Class<?>, VectorReader> CLASS_TO_VECTOR_READER = new IdentityHashMap<Class<?>, VectorReader>();
+
private final ClassLoader classLoader;
private String[] stringTable;
@@ -47,6 +230,29 @@
private int tokenListIndex;
private final SerializationPolicyProvider serializationPolicyProvider;
+ {
+ CLASS_TO_VECTOR_READER.put(boolean[].class, VectorReader.BOOLEAN_VECTOR);
+ CLASS_TO_VECTOR_READER.put(byte[].class, VectorReader.BYTE_VECTOR);
+ CLASS_TO_VECTOR_READER.put(char[].class, VectorReader.CHAR_VECTOR);
+ CLASS_TO_VECTOR_READER.put(double[].class, VectorReader.DOUBLE_VECTOR);
+ CLASS_TO_VECTOR_READER.put(float[].class, VectorReader.FLOAT_VECTOR);
+ CLASS_TO_VECTOR_READER.put(int[].class, VectorReader.INT_VECTOR);
+ CLASS_TO_VECTOR_READER.put(long[].class, VectorReader.LONG_VECTOR);
+ CLASS_TO_VECTOR_READER.put(Object[].class, VectorReader.OBJECT_VECTOR);
+ CLASS_TO_VECTOR_READER.put(short[].class, VectorReader.SHORT_VECTOR);
+ CLASS_TO_VECTOR_READER.put(String[].class, VectorReader.STRING_VECTOR);
+
+ CLASS_TO_VALUE_READER.put(boolean.class, ValueReader.BOOLEAN);
+ CLASS_TO_VALUE_READER.put(byte.class, ValueReader.BYTE);
+ CLASS_TO_VALUE_READER.put(char.class, ValueReader.CHAR);
+ CLASS_TO_VALUE_READER.put(double.class, ValueReader.DOUBLE);
+ CLASS_TO_VALUE_READER.put(float.class, ValueReader.FLOAT);
+ CLASS_TO_VALUE_READER.put(int.class, ValueReader.INT);
+ CLASS_TO_VALUE_READER.put(long.class, ValueReader.LONG);
+ CLASS_TO_VALUE_READER.put(Object.class, ValueReader.OBJECT);
+ CLASS_TO_VALUE_READER.put(short.class, ValueReader.SHORT);
+ CLASS_TO_VALUE_READER.put(String.class, ValueReader.STRING);
+ }
public ServerSerializationStreamReader(ClassLoader classLoader,
SerializationPolicyProvider serializationPolicyProvider) {
@@ -55,27 +261,13 @@
}
public Object deserializeValue(Class<?> type) throws SerializationException {
- if (type == boolean.class) {
- return readBoolean();
- } else if (type == byte.class) {
- return readByte();
- } else if (type == char.class) {
- return readChar();
- } else if (type == double.class) {
- return readDouble();
- } else if (type == float.class) {
- return readFloat();
- } else if (type == int.class) {
- return readInt();
- } else if (type == long.class) {
- return readLong();
- } else if (type == short.class) {
- return readShort();
- } else if (type == String.class) {
- return readString();
+ ValueReader valueReader = CLASS_TO_VALUE_READER.get(type);
+ if (valueReader != null) {
+ return valueReader.readValue(this);
+ } else {
+ // Arrays of primitive or reference types need to go through readObject.
+ return ValueReader.OBJECT.readValue(this);
}
-
- return readObject();
}
public SerializationPolicy getSerializationPolicy() {
@@ -162,8 +354,8 @@
SerializedInstanceReference serializedInstRef = SerializabilityUtil.decodeSerializedInstanceReference(typeSignature);
try {
- Class<?> instanceClass = Class.forName(serializedInstRef.getName(), false,
- classLoader);
+ Class<?> instanceClass = Class.forName(serializedInstRef.getName(),
+ false, classLoader);
assert (serializationPolicy != null);
@@ -212,45 +404,30 @@
return stringTable[index - 1];
}
- private void deserializeImpl(Class<?> customSerializer, Class<?> instanceClass,
- Object instance) throws NoSuchMethodException, IllegalArgumentException,
- IllegalAccessException, InvocationTargetException,
- SerializationException, ClassNotFoundException {
- if (customSerializer != null) {
- deserializeWithCustomFieldDeserializer(customSerializer, instanceClass,
- instance);
+ /**
+ * Deserialize an instance that is an array. Will default to deserializing as
+ * an Object vector if the instance is not a primitive vector.
+ *
+ * @param instanceClass
+ * @param instance
+ * @throws SerializationException
+ */
+ private void deserializeArray(Class<?> instanceClass, Object instance)
+ throws SerializationException {
+ assert (instanceClass.isArray());
+
+ VectorReader instanceReader = CLASS_TO_VECTOR_READER.get(instanceClass);
+ if (instanceReader != null) {
+ instanceReader.read(this, instance);
} else {
- deserializeWithDefaultFieldDeserializer(instanceClass, instance);
+ VectorReader.OBJECT_VECTOR.read(this, instance);
}
}
- private void deserializeStringTable() {
- int typeNameCount = readInt();
- stringTable = new String[typeNameCount];
- for (int typeNameIndex = 0; typeNameIndex < typeNameCount; ++typeNameIndex) {
- stringTable[typeNameIndex] = extract();
- }
- }
-
- private void deserializeWithCustomFieldDeserializer(Class<?> customSerializer,
- Class<?> instanceClass, Object instance) throws ClassNotFoundException,
- NoSuchMethodException, IllegalAccessException, InvocationTargetException {
- if (instanceClass.isArray()) {
- Class<?> componentType = instanceClass.getComponentType();
- if (!componentType.isPrimitive()) {
- instanceClass = Class.forName("[Ljava.lang.Object;");
- }
- }
- Method deserialize = customSerializer.getMethod("deserialize",
- SerializationStreamReader.class, instanceClass);
- deserialize.invoke(null, this, instance);
- }
-
- private void deserializeWithDefaultFieldDeserializer(Class<?> instanceClass,
- Object instance) throws SerializationException, IllegalAccessException,
+ private void deserializeClass(Class<?> instanceClass, Object instance)
+ throws SerializationException, IllegalAccessException,
NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
- Field[] declFields = instanceClass.getDeclaredFields();
- Field[] serializableFields = SerializabilityUtil.applyFieldSerializationPolicy(declFields);
+ Field[] serializableFields = SerializabilityUtil.applyFieldSerializationPolicy(instanceClass);
for (Field declField : serializableFields) {
assert (declField != null);
@@ -280,6 +457,40 @@
}
}
+ private void deserializeImpl(Class<?> customSerializer,
+ Class<?> instanceClass, Object instance) throws NoSuchMethodException,
+ IllegalArgumentException, IllegalAccessException,
+ InvocationTargetException, SerializationException, ClassNotFoundException {
+
+ if (customSerializer != null) {
+ deserializeWithCustomFieldDeserializer(customSerializer, instanceClass,
+ instance);
+ } else if (instanceClass.isArray()) {
+ deserializeArray(instanceClass, instance);
+ } else {
+ deserializeClass(instanceClass, instance);
+ }
+ }
+
+ private void deserializeStringTable() {
+ int typeNameCount = readInt();
+ stringTable = new String[typeNameCount];
+ for (int typeNameIndex = 0; typeNameIndex < typeNameCount; ++typeNameIndex) {
+ stringTable[typeNameIndex] = extract();
+ }
+ }
+
+ private void deserializeWithCustomFieldDeserializer(
+ Class<?> customSerializer, Class<?> instanceClass, Object instance)
+ throws NoSuchMethodException, IllegalAccessException,
+ InvocationTargetException {
+ assert (!instanceClass.isArray());
+
+ Method deserialize = customSerializer.getMethod("deserialize",
+ SerializationStreamReader.class, instanceClass);
+ deserialize.invoke(null, this, instance);
+ }
+
private String extract() {
return tokenList.get(tokenListIndex++);
}
diff --git a/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamWriter.java b/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamWriter.java
index 0f88abe..9a0dd0e 100644
--- a/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamWriter.java
+++ b/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamWriter.java
@@ -27,6 +27,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
+import java.util.Map;
/**
* For internal use only. Used for server call serialization. This class is
@@ -35,6 +36,186 @@
public final class ServerSerializationStreamWriter extends
AbstractSerializationStreamWriter {
+ /**
+ * Enumeration used to provided typed instance writers.
+ */
+ private enum ValueWriter {
+ BOOLEAN {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ stream.writeBoolean(((Boolean) instance).booleanValue());
+ }
+ },
+ BYTE {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ stream.writeByte(((Byte) instance).byteValue());
+ }
+ },
+ CHAR {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ stream.writeChar(((Character) instance).charValue());
+ }
+ },
+ DOUBLE {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ stream.writeDouble(((Double) instance).doubleValue());
+ }
+ },
+ FLOAT {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ stream.writeFloat(((Float) instance).floatValue());
+ }
+ },
+ INT {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ stream.writeInt(((Integer) instance).intValue());
+ }
+ },
+ LONG {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ stream.writeLong(((Long) instance).longValue());
+ }
+ },
+ OBJECT {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance)
+ throws SerializationException {
+ stream.writeObject(instance);
+ }
+ },
+ SHORT {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ stream.writeShort(((Short) instance).shortValue());
+ }
+ },
+ STRING {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ stream.writeString((String) instance);
+ }
+ };
+
+ abstract void write(ServerSerializationStreamWriter stream, Object instance)
+ throws SerializationException;
+ }
+
+ /**
+ * Enumeration used to provided typed vector writers.
+ */
+ private enum VectorWriter {
+ BOOLEAN_VECTOR {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ boolean[] vector = (boolean[]) instance;
+ stream.writeInt(vector.length);
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ stream.writeBoolean(vector[i]);
+ }
+ }
+ },
+ BYTE_VECTOR {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ byte[] vector = (byte[]) instance;
+ stream.writeInt(vector.length);
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ stream.writeByte(vector[i]);
+ }
+ }
+ },
+ CHAR_VECTOR {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ char[] vector = (char[]) instance;
+ stream.writeInt(vector.length);
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ stream.writeChar(vector[i]);
+ }
+ }
+ },
+ DOUBLE_VECTOR {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ double[] vector = (double[]) instance;
+ stream.writeInt(vector.length);
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ stream.writeDouble(vector[i]);
+ }
+ }
+ },
+ FLOAT_VECTOR {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ float[] vector = (float[]) instance;
+ stream.writeInt(vector.length);
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ stream.writeFloat(vector[i]);
+ }
+ }
+ },
+ INT_VECTOR {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ int[] vector = (int[]) instance;
+ stream.writeInt(vector.length);
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ stream.writeInt(vector[i]);
+ }
+ }
+ },
+ LONG_VECTOR {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ long[] vector = (long[]) instance;
+ stream.writeInt(vector.length);
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ stream.writeLong(vector[i]);
+ }
+ }
+ },
+ OBJECT_VECTOR {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance)
+ throws SerializationException {
+ Object[] vector = (Object[]) instance;
+ stream.writeInt(vector.length);
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ stream.writeObject(vector[i]);
+ }
+ }
+ },
+ SHORT_VECTOR {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ short[] vector = (short[]) instance;
+ stream.writeInt(vector.length);
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ stream.writeShort(vector[i]);
+ }
+ }
+ },
+ STRING_VECTOR {
+ @Override
+ void write(ServerSerializationStreamWriter stream, Object instance) {
+ String[] vector = (String[]) instance;
+ stream.writeInt(vector.length);
+ for (int i = 0, n = vector.length; i < n; ++i) {
+ stream.writeString(vector[i]);
+ }
+ }
+ };
+
+ abstract void write(ServerSerializationStreamWriter stream, Object instance)
+ throws SerializationException;
+ }
+
private static final char NON_BREAKING_HYPHEN = '\u2011';
/**
@@ -68,6 +249,16 @@
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
'E', 'F'};
+ /**
+ * Map of {@link Class} objects to {@link ValueWriter}s.
+ */
+ private static final Map<Class<?>, ValueWriter> CLASS_TO_VALUE_WRITER = new IdentityHashMap<Class<?>, ValueWriter>();
+
+ /**
+ * Map of {@link Class} vector objects to {@link VectorWriter}s.
+ */
+ private static final Map<Class<?>, VectorWriter> CLASS_TO_VECTOR_WRITER = new IdentityHashMap<Class<?>, VectorWriter>();
+
static {
/*
* NOTE: The JS VM in IE6 & IE7 do not interpret \v correctly. They convert
@@ -82,6 +273,28 @@
JS_CHARS_ESCAPED['\r'] = 'r';
JS_CHARS_ESCAPED[JS_ESCAPE_CHAR] = JS_ESCAPE_CHAR;
JS_CHARS_ESCAPED[JS_QUOTE_CHAR] = JS_QUOTE_CHAR;
+
+ CLASS_TO_VECTOR_WRITER.put(boolean[].class, VectorWriter.BOOLEAN_VECTOR);
+ CLASS_TO_VECTOR_WRITER.put(byte[].class, VectorWriter.BYTE_VECTOR);
+ CLASS_TO_VECTOR_WRITER.put(char[].class, VectorWriter.CHAR_VECTOR);
+ CLASS_TO_VECTOR_WRITER.put(double[].class, VectorWriter.DOUBLE_VECTOR);
+ CLASS_TO_VECTOR_WRITER.put(float[].class, VectorWriter.FLOAT_VECTOR);
+ CLASS_TO_VECTOR_WRITER.put(int[].class, VectorWriter.INT_VECTOR);
+ CLASS_TO_VECTOR_WRITER.put(long[].class, VectorWriter.LONG_VECTOR);
+ CLASS_TO_VECTOR_WRITER.put(Object[].class, VectorWriter.OBJECT_VECTOR);
+ CLASS_TO_VECTOR_WRITER.put(short[].class, VectorWriter.SHORT_VECTOR);
+ CLASS_TO_VECTOR_WRITER.put(String[].class, VectorWriter.STRING_VECTOR);
+
+ CLASS_TO_VALUE_WRITER.put(boolean.class, ValueWriter.BOOLEAN);
+ CLASS_TO_VALUE_WRITER.put(byte.class, ValueWriter.BYTE);
+ CLASS_TO_VALUE_WRITER.put(char.class, ValueWriter.CHAR);
+ CLASS_TO_VALUE_WRITER.put(double.class, ValueWriter.DOUBLE);
+ CLASS_TO_VALUE_WRITER.put(float.class, ValueWriter.FLOAT);
+ CLASS_TO_VALUE_WRITER.put(int.class, ValueWriter.INT);
+ CLASS_TO_VALUE_WRITER.put(long.class, ValueWriter.LONG);
+ CLASS_TO_VALUE_WRITER.put(Object.class, ValueWriter.OBJECT);
+ CLASS_TO_VALUE_WRITER.put(short.class, ValueWriter.SHORT);
+ CLASS_TO_VALUE_WRITER.put(String.class, ValueWriter.STRING);
}
/**
@@ -168,7 +381,7 @@
case Character.SPACE_SEPARATOR:
case Character.CONTROL:
- // Minimal
+ // Minimal
case Character.LINE_SEPARATOR:
case Character.FORMAT:
case Character.PARAGRAPH_SEPARATOR:
@@ -221,8 +434,7 @@
private final SerializationPolicy serializationPolicy;
- public ServerSerializationStreamWriter(
- SerializationPolicy serializationPolicy) {
+ public ServerSerializationStreamWriter(SerializationPolicy serializationPolicy) {
this.serializationPolicy = serializationPolicy;
}
@@ -237,26 +449,12 @@
public void serializeValue(Object value, Class<?> type)
throws SerializationException {
- if (type == boolean.class) {
- writeBoolean(((Boolean) value).booleanValue());
- } else if (type == byte.class) {
- writeByte(((Byte) value).byteValue());
- } else if (type == char.class) {
- writeChar(((Character) value).charValue());
- } else if (type == double.class) {
- writeDouble(((Double) value).doubleValue());
- } else if (type == float.class) {
- writeFloat(((Float) value).floatValue());
- } else if (type == int.class) {
- writeInt(((Integer) value).intValue());
- } else if (type == long.class) {
- writeLong(((Long) value).longValue());
- } else if (type == short.class) {
- writeShort(((Short) value).shortValue());
- } else if (type == String.class) {
- writeString((String) value);
+ ValueWriter valueWriter = CLASS_TO_VALUE_WRITER.get(type);
+ if (valueWriter != null) {
+ valueWriter.write(this, value);
} else {
- writeObject(value);
+ // Arrays of primitive or reference types need to go through writeObject.
+ ValueWriter.OBJECT.write(this, value);
}
}
@@ -340,12 +538,32 @@
serializeImpl(instance, clazz);
}
+ /**
+ * Serialize an instance that is an array. Will default to serializing the
+ * instance as an Object vector if the instance is not a vector of primitives,
+ * Strings or Object.
+ *
+ * @param instanceClass
+ * @param instance
+ * @throws SerializationException
+ */
+ private void serializeArray(Class<?> instanceClass, Object instance)
+ throws SerializationException {
+ assert (instanceClass.isArray());
+
+ VectorWriter instanceWriter = CLASS_TO_VECTOR_WRITER.get(instanceClass);
+ if (instanceWriter != null) {
+ instanceWriter.write(this, instance);
+ } else {
+ VectorWriter.OBJECT_VECTOR.write(this, instance);
+ }
+ }
+
private void serializeClass(Object instance, Class<?> instanceClass)
throws SerializationException {
assert (instance != null);
- Field[] declFields = instanceClass.getDeclaredFields();
- Field[] serializableFields = SerializabilityUtil.applyFieldSerializationPolicy(declFields);
+ Field[] serializableFields = SerializabilityUtil.applyFieldSerializationPolicy(instanceClass);
for (Field declField : serializableFields) {
assert (declField != null);
@@ -387,12 +605,12 @@
Class<?> customSerializer = SerializabilityUtil.hasCustomFieldSerializer(instanceClass);
if (customSerializer != null) {
+ // Use custom field serializer
serializeWithCustomSerializer(customSerializer, instance, instanceClass);
+ } else if (instanceClass.isArray()) {
+ serializeArray(instanceClass, instance);
} else {
- // Arrays are serialized using custom serializers so we should never get
- // here for array types.
- //
- assert (!instanceClass.isArray());
+ // Regular class instance
serializeClass(instance, instanceClass);
}
}
@@ -402,12 +620,7 @@
Method serialize;
try {
- if (instanceClass.isArray()) {
- Class<?> componentType = instanceClass.getComponentType();
- if (!componentType.isPrimitive()) {
- instanceClass = Class.forName("[Ljava.lang.Object;");
- }
- }
+ assert (!instanceClass.isArray());
serialize = customSerializer.getMethod("serialize",
SerializationStreamWriter.class, instanceClass);
@@ -428,9 +641,6 @@
} catch (InvocationTargetException e) {
throw new SerializationException(e);
-
- } catch (ClassNotFoundException e) {
- throw new SerializationException(e);
}
}