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.server.rpc.impl;
017:
018: import com.google.gwt.user.client.rpc.IsSerializable;
019: import com.google.gwt.user.client.rpc.SerializationException;
020: import com.google.gwt.user.server.rpc.SerializationPolicy;
021:
022: import java.io.Serializable;
023: import java.util.Arrays;
024: import java.util.HashSet;
025: import java.util.Set;
026:
027: /**
028: * A serialization policy compatible with GWT 1.3.3 RPC. This is used when no
029: * serialization policy file is present.
030: *
031: * <p>
032: * The set of allowed types are:
033: * </p>
034: * <ol>
035: * <li>Primitives</li>
036: * <li>Types assignable to {@link IsSerializable}</li>
037: * <li>Types with custom field serializers</li>
038: * <li>Arrays of the above types</li>
039: * </ol>
040: * <p>
041: * Types that derive from {@link Serializable} but do not meet any of the above
042: * criteria may not be serialized as leaf types. However, their fields may be
043: * serialized as super types of a legal type.
044: * </p>
045: */
046: public class LegacySerializationPolicy extends SerializationPolicy {
047:
048: /**
049: * Many JRE types would appear to be {@link Serializable} on the server.
050: * However, clients would not see these types as being {@link Serializable}
051: * due to mismatches between the GWT JRE emulation and the real JRE. As a
052: * workaround, this blacklist specifies a list of problematic types which
053: * should be seen as not implementing {@link Serializable} for the purpose
054: * matching the client's expectations. Note that a type on this list may still
055: * be serializable via a custom serializer.
056: */
057: private static final Class<?>[] JRE_BLACKLIST = {
058: java.lang.ArrayStoreException.class,
059: java.lang.AssertionError.class, java.lang.Boolean.class,
060: java.lang.Byte.class, java.lang.Character.class,
061: java.lang.Class.class, java.lang.ClassCastException.class,
062: java.lang.Double.class, java.lang.Error.class,
063: java.lang.Exception.class, java.lang.Float.class,
064: java.lang.IllegalArgumentException.class,
065: java.lang.IllegalStateException.class,
066: java.lang.IndexOutOfBoundsException.class,
067: java.lang.Integer.class, java.lang.Long.class,
068: java.lang.NegativeArraySizeException.class,
069: java.lang.NullPointerException.class,
070: java.lang.Number.class,
071: java.lang.NumberFormatException.class,
072: java.lang.RuntimeException.class, java.lang.Short.class,
073: java.lang.StackTraceElement.class, java.lang.String.class,
074: java.lang.StringBuffer.class,
075: java.lang.StringIndexOutOfBoundsException.class,
076: java.lang.Throwable.class,
077: java.lang.UnsupportedOperationException.class,
078: java.util.ArrayList.class,
079: java.util.ConcurrentModificationException.class,
080: java.util.Date.class, java.util.EmptyStackException.class,
081: java.util.EventObject.class, java.util.HashMap.class,
082: java.util.HashSet.class,
083: java.util.MissingResourceException.class,
084: java.util.NoSuchElementException.class,
085: java.util.Stack.class,
086: java.util.TooManyListenersException.class,
087: java.util.Vector.class };
088:
089: private static final Set<Class<?>> JRE_BLACKSET = new HashSet<Class<?>>(
090: Arrays.asList(JRE_BLACKLIST));
091:
092: private static final LegacySerializationPolicy sInstance = new LegacySerializationPolicy();
093:
094: public static LegacySerializationPolicy getInstance() {
095: return sInstance;
096: }
097:
098: /**
099: * Singleton.
100: */
101: private LegacySerializationPolicy() {
102: }
103:
104: /*
105: * (non-Javadoc)
106: *
107: * @see com.google.gwt.user.server.rpc.SerializationPolicy#shouldDerializeFields(java.lang.String)
108: */
109: @Override
110: public boolean shouldDeserializeFields(Class<?> clazz) {
111: return isFieldSerializable(clazz);
112: }
113:
114: /*
115: * (non-Javadoc)
116: *
117: * @see com.google.gwt.user.server.rpc.SerializationPolicy#shouldSerializeFields(java.lang.String)
118: */
119: @Override
120: public boolean shouldSerializeFields(Class<?> clazz) {
121: return isFieldSerializable(clazz);
122: }
123:
124: /*
125: * (non-Javadoc)
126: *
127: * @see com.google.gwt.user.server.rpc.SerializationPolicy#validateDeserialize(java.lang.String)
128: */
129: @Override
130: public void validateDeserialize(Class<?> clazz)
131: throws SerializationException {
132: if (!isInstantiable(clazz)) {
133: throw new SerializationException(
134: "Type '"
135: + clazz.getName()
136: + "' was not assignable to '"
137: + IsSerializable.class.getName()
138: + "' and did not have a custom field serializer. For security purposes, this type will not be deserialized.");
139: }
140: }
141:
142: /*
143: * (non-Javadoc)
144: *
145: * @see com.google.gwt.user.server.rpc.SerializationPolicy#validateSerialize(java.lang.String)
146: */
147: @Override
148: public void validateSerialize(Class<?> clazz)
149: throws SerializationException {
150: if (!isInstantiable(clazz)) {
151: throw new SerializationException(
152: "Type '"
153: + clazz.getName()
154: + "' was not assignable to '"
155: + IsSerializable.class.getName()
156: + "' and did not have a custom field serializer. For security purposes, this type will not be serialized.");
157: }
158: }
159:
160: /**
161: * Field serializable types are primitives, {@line IsSerializable},
162: * {@link Serializable}, types with custom serializers, and any arrays of
163: * those types.
164: */
165: private boolean isFieldSerializable(Class<?> clazz) {
166: if (isInstantiable(clazz)) {
167: return true;
168: }
169: if (Serializable.class.isAssignableFrom(clazz)) {
170: return !JRE_BLACKSET.contains(clazz);
171: }
172: return false;
173: }
174:
175: /**
176: * Instantiable types are primitives, {@line IsSerializable}, types with
177: * custom serializers, and any arrays of those types. Merely
178: * {@link Serializable} types cannot be instantiated or serialized directly
179: * (only as super types of legacy serializable types).
180: */
181: private boolean isInstantiable(Class<?> clazz) {
182: if (clazz.isPrimitive()) {
183: return true;
184: }
185: if (clazz.isArray()) {
186: return isInstantiable(clazz.getComponentType());
187: }
188: if (IsSerializable.class.isAssignableFrom(clazz)) {
189: return true;
190: }
191: return SerializabilityUtil.hasCustomFieldSerializer(clazz) != null;
192: }
193:
194: }
|