Implementing RPC for java.util.Arrays.ArrayList.
Getting this to work required changing how custom field serializers are handled.
- CustomFieldSerializerValidator would only verify assignability rather than exact type match on the second argument of a custom field serializer's serialize and deserialize methods.
- However, both the generated TypeSerializer and the server implementations would die horrible deaths if the types did not match exactly.
- Since I needed the looser behavior to implement my custom field serializer anyway, I went ahead and changed TypeSerializerCreator and the ServerSerializationStreams to work with looser declared types.
Review by: bobv (desk)
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2472 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/util/Arrays.java b/user/src/com/google/gwt/user/client/rpc/core/java/util/Arrays.java
new file mode 100644
index 0000000..eb4e4b8
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/rpc/core/java/util/Arrays.java
@@ -0,0 +1,70 @@
+/*
+ * 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
+ * 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.util;
+
+import com.google.gwt.core.client.GWT;
+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 java.util.List;
+
+/**
+ * Dummy class for nesting the custom serializer.
+ */
+public final class Arrays {
+
+ /**
+ * Custom field serializer for {@link java.util.Arrays$ArrayList}.
+ */
+ public static final class ArrayList_CustomFieldSerializer {
+ /*
+ * Note: the reason this implementation differs from that of a standard List
+ * (which serializes a number and then each element) is the requirement that
+ * the underlying array retain its correct type across the wire. This gives
+ * toArray() results the correct type, and can generate internal
+ * ArrayStoreExceptions.
+ */
+
+ public static void deserialize(SerializationStreamReader streamReader,
+ List instance) throws SerializationException {
+ // Handled in instantiate.
+ }
+
+ public static List instantiate(SerializationStreamReader streamReader)
+ throws SerializationException {
+ Object[] array = (Object[]) streamReader.readObject();
+ return java.util.Arrays.asList(array);
+ }
+
+ public static void serialize(SerializationStreamWriter streamWriter,
+ List instance) throws SerializationException {
+ Object[] array;
+ if (GWT.isScript()) {
+ // Violator pattern.
+ array = getArray0(instance);
+ } else {
+ // Clone the underlying array.
+ array = instance.toArray();
+ }
+ streamWriter.writeObject(array);
+ }
+
+ private static native Object[] getArray0(List instance) /*-{
+ return instance.@java.util.Arrays$ArrayList::array;
+ }-*/;
+ }
+}
diff --git a/user/src/com/google/gwt/user/rebind/rpc/CustomFieldSerializerValidator.java b/user/src/com/google/gwt/user/rebind/rpc/CustomFieldSerializerValidator.java
index e01c7ed..6158b31 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/CustomFieldSerializerValidator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/CustomFieldSerializerValidator.java
@@ -20,6 +20,8 @@
import com.google.gwt.core.ext.typeinfo.JParameter;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
+import com.google.gwt.user.client.rpc.SerializationStreamReader;
+import com.google.gwt.user.client.rpc.SerializationStreamWriter;
import java.text.MessageFormat;
import java.util.ArrayList;
@@ -32,6 +34,7 @@
private static final String NO_DESERIALIZE_METHOD = "Custom Field Serializer ''{0}'' does not define a deserialize method: ''public static void deserialize({1} reader,{2} instance)''";
private static final String NO_INSTANTIATE_METHOD = "Custom Field Serializer ''{0}'' does not define an instantiate method: ''public static {1} instantiate({2} reader)''; but ''{1}'' is not default instantiable";
private static final String NO_SERIALIZE_METHOD = "Custom Field Serializer ''{0}'' does not define a serialize method: ''public static void serialize({1} writer,{2} instance)''";
+ private static final String TOO_MANY_METHODS = "Custom Field Serializer ''{0}'' defines too many methods named ''{1}''; please define only one method with that name";
/**
* Returns a list of error messages associated with the custom field
@@ -46,8 +49,8 @@
* @return list of error messages, if any, associated with the custom field
* serializer
*/
- public static List<String> validate(JClassType streamReaderClass,
- JClassType streamWriterClass, JClassType serializer, JClassType serializee) {
+ public static List<String> validate(JClassType serializer,
+ JClassType serializee) {
List<String> reasons = new ArrayList<String>();
if (serializee.isEnum() != null) {
@@ -60,39 +63,49 @@
return reasons;
}
- if (!hasSerializationMethod(streamReaderClass, "deserialize", serializer,
- serializee)) {
+ if (!hasDeserializationMethod(serializer, serializee)) {
// No valid deserialize method was found.
reasons.add(MessageFormat.format(NO_DESERIALIZE_METHOD,
serializer.getQualifiedSourceName(),
- streamReaderClass.getQualifiedSourceName(),
+ SerializationStreamReader.class.getName(),
serializee.getQualifiedSourceName()));
+ } else {
+ checkTooMany("deserialize", serializer, reasons);
}
- if (!hasSerializationMethod(streamWriterClass, "serialize", serializer,
- serializee)) {
+ if (!hasSerializationMethod(serializer, serializee)) {
// No valid serialize method was found.
reasons.add(MessageFormat.format(NO_SERIALIZE_METHOD,
serializer.getQualifiedSourceName(),
- streamWriterClass.getQualifiedSourceName(),
+ SerializationStreamWriter.class.getName(),
serializee.getQualifiedSourceName()));
+ } else {
+ checkTooMany("serialize", serializer, reasons);
}
- if (!serializee.isDefaultInstantiable() && !serializee.isAbstract()) {
- if (!hasInstantiationMethod(streamReaderClass, serializer, serializee)) {
+ if (!hasInstantiationMethod(serializer, serializee)) {
+ if (!serializee.isDefaultInstantiable() && !serializee.isAbstract()) {
// Not default instantiable and no instantiate method was found.
reasons.add(MessageFormat.format(NO_INSTANTIATE_METHOD,
serializer.getQualifiedSourceName(),
serializee.getQualifiedSourceName(),
- streamReaderClass.getQualifiedSourceName()));
+ SerializationStreamReader.class.getName()));
}
+ } else {
+ checkTooMany("instantiate", serializer, reasons);
}
return reasons;
}
- private static boolean hasInstantiationMethod(JClassType streamReaderClass,
- JClassType serializer, JClassType serializee) {
+ static JMethod getDeserializationMethod(JClassType serializer,
+ JClassType serializee) {
+ return getMethod("deserialize", SerializationStreamReader.class.getName(),
+ serializer, serializee);
+ }
+
+ static JMethod getInstantiationMethod(JClassType serializer,
+ JClassType serializee) {
JMethod[] overloads = serializer.getOverloads("instantiate");
for (JMethod overload : overloads) {
JParameter[] parameters = overload.getParameters();
@@ -102,7 +115,8 @@
continue;
}
- if (parameters[0].getType() != streamReaderClass) {
+ if (!parameters[0].getType().getQualifiedSourceName().equals(
+ SerializationStreamReader.class.getName())) {
// First param is not a stream class
continue;
}
@@ -120,14 +134,46 @@
// TODO: if isArray answered yes to isClass this cast would not be
// necessary
JClassType clazz = (JClassType) type;
- return clazz.isAssignableFrom(serializee);
+ if (clazz.isAssignableFrom(serializee)) {
+ return overload;
+ }
}
- return false;
+ return null;
}
- private static boolean hasSerializationMethod(JClassType streamClass,
- String methodName, JClassType serializer, JClassType serializee) {
+ static JMethod getSerializationMethod(JClassType serializer,
+ JClassType serializee) {
+ return getMethod("serialize", SerializationStreamWriter.class.getName(),
+ serializer, serializee);
+ }
+
+ static boolean hasDeserializationMethod(JClassType serializer,
+ JClassType serializee) {
+ return getDeserializationMethod(serializer, serializee) != null;
+ }
+
+ static boolean hasInstantiationMethod(JClassType serializer,
+ JClassType serializee) {
+ return getInstantiationMethod(serializer, serializee) != null;
+ }
+
+ static boolean hasSerializationMethod(JClassType serializer,
+ JClassType serializee) {
+ return getSerializationMethod(serializer, serializee) != null;
+ }
+
+ private static void checkTooMany(String methodName, JClassType serializer,
+ List<String> reasons) {
+ JMethod[] overloads = serializer.getOverloads(methodName);
+ if (overloads.length > 1) {
+ reasons.add(MessageFormat.format(TOO_MANY_METHODS,
+ serializer.getQualifiedSourceName(), methodName));
+ }
+ }
+
+ private static JMethod getMethod(String methodName, String streamClassName,
+ JClassType serializer, JClassType serializee) {
JMethod[] overloads = serializer.getOverloads(methodName);
for (JMethod overload : overloads) {
JParameter[] parameters = overload.getParameters();
@@ -137,7 +183,8 @@
continue;
}
- if (parameters[0].getType() != streamClass) {
+ if (!parameters[0].getType().getQualifiedSourceName().equals(
+ streamClassName)) {
// First param is not a stream class
continue;
}
@@ -155,12 +202,12 @@
if (clazz.isAssignableFrom(serializee)) {
if (isValidCustomFieldSerializerMethod(overload)
&& overload.getReturnType() == JPrimitiveType.VOID) {
- return true;
+ return overload;
}
}
}
- return false;
+ return null;
}
private static boolean isValidCustomFieldSerializerMethod(JMethod method) {
diff --git a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
index 5f25e77..90203ac 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
@@ -33,8 +33,6 @@
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
import com.google.gwt.user.client.rpc.IsSerializable;
-import com.google.gwt.user.client.rpc.SerializationStreamReader;
-import com.google.gwt.user.client.rpc.SerializationStreamWriter;
import java.io.Serializable;
import java.text.MessageFormat;
@@ -546,16 +544,6 @@
*/
private final JClassType serializableClass;
- /**
- * Cache of the {@link JClassType} for {@link SerializationStreamReader}.
- */
- private final JClassType streamReaderClass;
-
- /**
- * Cache of the {@link JClassType} for {@link SerializationStreamWriter}.
- */
- private final JClassType streamWriterClass;
-
private final TypeOracle typeOracle;
/**
@@ -587,8 +575,6 @@
isSerializableClass = typeOracle.getType(IsSerializable.class.getName());
mapClass = typeOracle.getType(Map.class.getName());
serializableClass = typeOracle.getType(Serializable.class.getName());
- streamReaderClass = typeOracle.getType(SerializationStreamReader.class.getName());
- streamWriterClass = typeOracle.getType(SerializationStreamWriter.class.getName());
} catch (NotFoundException e) {
rootLogger.log(TreeLogger.ERROR, null, e);
throw new UnableToCompleteException();
@@ -892,8 +878,7 @@
if (typeInfo.isManuallySerializable()) {
List<String> failures = CustomFieldSerializerValidator.validate(
- streamReaderClass, streamWriterClass, typeInfo.getManualSerializer(),
- type);
+ typeInfo.getManualSerializer(), type);
if (!failures.isEmpty()) {
markAsUninstantiableAndLog(logger, isSpeculative, failures, tic);
return false;
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 3a12ab4..7fefb93 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
@@ -273,10 +273,10 @@
srcWriter.println("[");
{
srcWriter.indent();
-
String serializerName = serializationOracle.getFieldSerializerName(type);
+
+ // First the initialization method
{
- // First the initialization method
srcWriter.print("@");
if (needsCreateMethod(type)) {
srcWriter.print(serializationOracle.getTypeSerializerQualifiedName(getServiceInterface()));
@@ -292,22 +292,39 @@
srcWriter.println(",");
}
- String jsniSignature = type.getJNISignature();
+ JClassType customSerializer = serializationOracle.hasCustomFieldSerializer(type);
+ // Now the deserialization method
{
- // Now the deserialization method
+ // Assume param type is the concrete type of the serialized type.
+ JType paramType = type;
+ if (customSerializer != null) {
+ // But a custom serializer may specify a looser type.
+ JMethod deserializationMethod = CustomFieldSerializerValidator.getDeserializationMethod(
+ customSerializer, (JClassType) type);
+ paramType = deserializationMethod.getParameters()[1].getType();
+ }
srcWriter.print("@" + serializerName);
srcWriter.print("::deserialize(L"
+ SerializationStreamReader.class.getName().replace('.', '/')
- + ";" + jsniSignature + ")");
+ + ";" + paramType.getJNISignature() + ")");
srcWriter.println(",");
}
+
+ // Now the serialization method
{
- // Now the serialization method
+ // Assume param type is the concrete type of the serialized type.
+ JType paramType = type;
+ if (customSerializer != null) {
+ // But a custom serializer may specify a looser type.
+ JMethod serializationMethod = CustomFieldSerializerValidator.getSerializationMethod(
+ customSerializer, (JClassType) type);
+ paramType = serializationMethod.getParameters()[1].getType();
+ }
srcWriter.print("@" + serializerName);
srcWriter.print("::serialize(L"
+ SerializationStreamWriter.class.getName().replace('.', '/')
- + ";" + jsniSignature + ")");
+ + ";" + paramType.getJNISignature() + ")");
srcWriter.println();
}
srcWriter.outdent();
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 4d568fc..eca479f 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
@@ -16,7 +16,6 @@
package com.google.gwt.user.server.rpc.impl;
import com.google.gwt.user.client.rpc.SerializationException;
-import com.google.gwt.user.client.rpc.SerializationStreamReader;
import com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamReader;
import com.google.gwt.user.server.rpc.RPC;
import com.google.gwt.user.server.rpc.SerializationPolicy;
@@ -596,9 +595,13 @@
InvocationTargetException {
assert (!instanceClass.isArray());
- Method deserialize = customSerializer.getMethod("deserialize",
- SerializationStreamReader.class, instanceClass);
- deserialize.invoke(null, this, instance);
+ for (Method method : customSerializer.getMethods()) {
+ if ("deserialize".equals(method.getName())) {
+ method.invoke(null, this, instance);
+ return;
+ }
+ }
+ throw new NoSuchMethodException("deserialize");
}
private String extract() {
@@ -610,13 +613,12 @@
IllegalArgumentException, InvocationTargetException,
NoSuchMethodException {
if (customSerializer != null) {
- try {
- Method instantiate = customSerializer.getMethod("instantiate",
- SerializationStreamReader.class);
- return instantiate.invoke(null, this);
- } catch (NoSuchMethodException e) {
- // purposely ignored
+ for (Method method : customSerializer.getMethods()) {
+ if ("instantiate".equals(method.getName())) {
+ return method.invoke(null, this);
+ }
}
+ // Ok to not have one.
}
if (instanceClass.isArray()) {
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 499ea9b..6946d47 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
@@ -16,7 +16,6 @@
package com.google.gwt.user.server.rpc.impl;
import com.google.gwt.user.client.rpc.SerializationException;
-import com.google.gwt.user.client.rpc.SerializationStreamWriter;
import com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamWriter;
import com.google.gwt.user.server.rpc.SerializationPolicy;
@@ -660,15 +659,16 @@
private void serializeWithCustomSerializer(Class<?> customSerializer,
Object instance, Class<?> instanceClass) throws SerializationException {
- Method serialize;
try {
assert (!instanceClass.isArray());
- serialize = customSerializer.getMethod("serialize",
- SerializationStreamWriter.class, instanceClass);
-
- serialize.invoke(null, this, instance);
-
+ for (Method method : customSerializer.getMethods()) {
+ if ("serialize".equals(method.getName())) {
+ method.invoke(null, this, instance);
+ return;
+ }
+ }
+ throw new NoSuchMethodException("serialize");
} catch (SecurityException e) {
throw new SerializationException(e);
diff --git a/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java b/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
index b151e17..214dea4 100644
--- a/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
@@ -101,6 +101,25 @@
});
}
+ public void testArraysAsList() {
+ delayTestFinish(TEST_DELAY);
+
+ CollectionsTestServiceAsync service = getServiceAsync();
+ final List expected = TestSetFactory.createArraysAsList();
+
+ service.echoArraysAsList(expected, new AsyncCallback() {
+ public void onFailure(Throwable caught) {
+ TestSetValidator.rethrowException(caught);
+ }
+
+ public void onSuccess(Object result) {
+ assertNotNull(result);
+ assertEquals(expected, result);
+ finishTest();
+ }
+ });
+ }
+
public void testBooleanArray() {
delayTestFinish(TEST_DELAY);
@@ -173,34 +192,6 @@
});
}
- /**
- * This method checks that attempting to return
- * {@link java.util.Arrays#asList(Object[])} from the server will result in an
- * InvocationException on the client.
- */
- public void testFailureWhenReturningArraysAsList() {
- delayTestFinish(TEST_DELAY);
-
- CollectionsTestServiceAsync service = getServiceAsync();
- final List expected = new ArrayList();
- for (byte i = 0; i < 10; ++i) {
- expected.add(new Byte(i));
- }
-
- service.getArraysAsList(expected, new AsyncCallback() {
- public void onFailure(Throwable caught) {
- assertTrue(caught.getClass().getName()
- + " should have been an InvocationException",
- caught instanceof InvocationException);
- finishTest();
- }
-
- public void onSuccess(Object result) {
- fail("Expected an InvocationException");
- }
- });
- }
-
public void testFloatArray() {
delayTestFinish(TEST_DELAY);
diff --git a/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java b/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java
index 02ec4eb..114f2c8 100644
--- a/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java
@@ -98,5 +98,6 @@
Vector<IsSerializable> echo(Vector<IsSerializable> value)
throws CollectionsTestServiceException;
- List<IsSerializable> getArraysAsList(List<IsSerializable> value);
+ List<IsSerializable> echoArraysAsList(List<IsSerializable> value)
+ throws CollectionsTestServiceException;
}
diff --git a/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java b/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java
index 23e6081..1a4d331 100644
--- a/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java
@@ -84,6 +84,6 @@
void echo(Vector<IsSerializable> value,
AsyncCallback<Vector<IsSerializable>> callback);
- void getArraysAsList(List<IsSerializable> value,
+ void echoArraysAsList(List<IsSerializable> value,
AsyncCallback<List<IsSerializable>> callback);
}
diff --git a/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java b/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java
index 1b99843..cbe483d 100644
--- a/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java
+++ b/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java
@@ -18,9 +18,11 @@
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Vector;
/**
@@ -397,6 +399,10 @@
return list;
}
+ static List createArraysAsList() {
+ return Arrays.asList((byte) 0, (byte) 1, (byte) 2, (byte) 3);
+ }
+
static SerializableDoublyLinkedNode createComplexCyclicGraph() {
SerializableDoublyLinkedNode n1 = new SerializableDoublyLinkedNode();
n1.setData("n0");
diff --git a/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java b/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java
index 188ba01..dd663fb 100644
--- a/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java
+++ b/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java
@@ -24,6 +24,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
@@ -305,7 +306,7 @@
return actual.getValue() == 1;
}
-
+
/**
* We want to assert that the two fields have object identity.
*/
@@ -359,6 +360,19 @@
return true;
}
+ public static boolean isValidAsList(List list) {
+ if (list == null) {
+ return false;
+ }
+
+ List reference = TestSetFactory.createArraysAsList();
+ if (reference.size() != list.size()) {
+ return false;
+ }
+
+ return reference.equals(list);
+ }
+
public static boolean isValidComplexCyclicGraph(
SerializableDoublyLinkedNode actual) {
diff --git a/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java b/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java
index f7c2337..c002e2e 100644
--- a/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java
+++ b/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java
@@ -312,12 +312,12 @@
* InvocationException on the client.
*/
@SuppressWarnings("unchecked")
- public List getArraysAsList(List value) {
- Byte[] retVal = new Byte[10];
- for (byte i = 0; i < 10; ++i) {
- retVal[i] = (Byte) value.get(i);
+ public List echoArraysAsList(List value)
+ throws CollectionsTestServiceException {
+ if (!TestSetValidator.isValidAsList(value)) {
+ throw new CollectionsTestServiceException();
}
- return Arrays.asList(retVal);
+ return value;
}
}