001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.user.rebind.rpc;
017:
018: import com.google.gwt.core.ext.typeinfo.JClassType;
019: import com.google.gwt.core.ext.typeinfo.JMethod;
020: import com.google.gwt.core.ext.typeinfo.JParameter;
021: import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
022: import com.google.gwt.core.ext.typeinfo.JType;
023:
024: import java.text.MessageFormat;
025: import java.util.ArrayList;
026: import java.util.List;
027:
028: /**
029: * Checks that a custom serializer is valid.
030: */
031: class CustomFieldSerializerValidator {
032: 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)''";
033: 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";
034: 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)''";
035:
036: /**
037: * Returns a list of error messages associated with the custom field
038: * serializer.
039: *
040: * @param streamReaderClass
041: * {@link com.google.gwt.user.client.rpc.SerializationStreamReader SerializationStreamReader}
042: * @param streamWriterClass
043: * {@link com.google.gwt.user.client.rpc.SerializationStreamWriter SerializationStreamWriter}
044: * @param serializer the class which performs the serialization
045: * @param serializee the class being serialized
046: * @return list of error messages, if any, associated with the custom field
047: * serializer
048: */
049: public static List<String> validate(JClassType streamReaderClass,
050: JClassType streamWriterClass, JClassType serializer,
051: JClassType serializee) {
052: List<String> reasons = new ArrayList<String>();
053:
054: if (serializee.isEnum() != null) {
055: /*
056: * Enumerated types cannot have custom field serializers because it would
057: * introduce shared state between the client and the server via the
058: * enumerated constants.
059: */
060: reasons
061: .add("Enumerated types cannot have custom field serializers.");
062: return reasons;
063: }
064:
065: if (!hasSerializationMethod(streamReaderClass, "deserialize",
066: serializer, serializee)) {
067: // No valid deserialize method was found.
068: reasons.add(MessageFormat.format(NO_DESERIALIZE_METHOD,
069: serializer.getQualifiedSourceName(),
070: streamReaderClass.getQualifiedSourceName(),
071: serializee.getQualifiedSourceName()));
072: }
073:
074: if (!hasSerializationMethod(streamWriterClass, "serialize",
075: serializer, serializee)) {
076: // No valid serialize method was found.
077: reasons.add(MessageFormat.format(NO_SERIALIZE_METHOD,
078: serializer.getQualifiedSourceName(),
079: streamWriterClass.getQualifiedSourceName(),
080: serializee.getQualifiedSourceName()));
081: }
082:
083: if (!Shared.isDefaultInstantiable(serializee)) {
084: if (!hasInstantiationMethod(streamReaderClass, serializer,
085: serializee)) {
086: // Not default instantiable and no instantiate method was found.
087: reasons.add(MessageFormat.format(NO_INSTANTIATE_METHOD,
088: serializer.getQualifiedSourceName(), serializee
089: .getQualifiedSourceName(),
090: streamReaderClass.getQualifiedSourceName()));
091: }
092: }
093:
094: return reasons;
095: }
096:
097: private static boolean hasInstantiationMethod(
098: JClassType streamReaderClass, JClassType serializer,
099: JClassType serializee) {
100: JMethod[] overloads = serializer.getOverloads("instantiate");
101: for (JMethod overload : overloads) {
102: JParameter[] parameters = overload.getParameters();
103:
104: if (parameters.length != 1) {
105: // Different overload
106: continue;
107: }
108:
109: if (parameters[0].getType() != streamReaderClass) {
110: // First param is not a stream class
111: continue;
112: }
113:
114: if (!isValidCustomFieldSerializerMethod(overload)) {
115: continue;
116: }
117:
118: JType type = overload.getReturnType();
119: if (type.isPrimitive() != null) {
120: // Primitives are auto serialized so this can't be the right method
121: continue;
122: }
123:
124: // TODO: if isArray answered yes to isClass this cast would not be
125: // necessary
126: JClassType clazz = (JClassType) type;
127: return clazz.isAssignableFrom(serializee);
128: }
129:
130: return false;
131: }
132:
133: private static boolean hasSerializationMethod(
134: JClassType streamClass, String methodName,
135: JClassType serializer, JClassType serializee) {
136: JMethod[] overloads = serializer.getOverloads(methodName);
137: for (JMethod overload : overloads) {
138: JParameter[] parameters = overload.getParameters();
139:
140: if (parameters.length != 2) {
141: // Different overload
142: continue;
143: }
144:
145: if (parameters[0].getType() != streamClass) {
146: // First param is not a stream class
147: continue;
148: }
149:
150: JParameter serializeeParam = parameters[1];
151: JType type = serializeeParam.getType();
152: if (type.isPrimitive() != null) {
153: // Primitives are auto serialized so this can't be the right method
154: continue;
155: }
156:
157: // TODO: if isArray answered yes to isClass this cast would not be
158: // necessary
159: JClassType clazz = (JClassType) type;
160: if (clazz.isAssignableFrom(serializee)) {
161: if (isValidCustomFieldSerializerMethod(overload)
162: && overload.getReturnType() == JPrimitiveType.VOID) {
163: return true;
164: }
165: }
166: }
167:
168: return false;
169: }
170:
171: private static boolean isValidCustomFieldSerializerMethod(
172: JMethod method) {
173: if (method == null) {
174: return false;
175: }
176:
177: if (!method.isStatic()) {
178: return false;
179: }
180:
181: if (!method.isPublic()) {
182: return false;
183: }
184:
185: return true;
186: }
187:
188: private CustomFieldSerializerValidator() {
189: }
190: }
|