com.google.gwt.user.rebind.rpc.SerializationUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gwt.user.rebind.rpc.SerializationUtils.java

Source

/*
 * Copyright 2008 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.rebind.rpc;

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.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.util.Util;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.zip.CRC32;

/**
 * Utilities used for implementing serialization.
 */
public class SerializationUtils {
    static final Comparator<JField> FIELD_COMPARATOR = new Comparator<JField>() {
        public int compare(JField f1, JField f2) {
            return f1.getName().compareTo(f2.getName());
        }
    };
    static final String GENERATED_FIELD_SERIALIZER_SUFFIX = "_FieldSerializer";
    static final String TYPE_SERIALIZER_SUFFIX = "_TypeSerializer";
    static final Set<String> TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES = new HashSet<String>();

    static {
        TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Boolean");
        TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Byte");
        TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Character");
        TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Double");
        TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Exception");
        TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Float");
        TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Integer");
        TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Long");
        TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Object");
        TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Short");
        TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.String");
        TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("java.lang.Throwable");

        /*
         * Work around for incompatible type hierarchy (and therefore signature)
         * between JUnit3 and JUnit4.
         */
        TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES.add("junit.framework.AssertionFailedError");
    }

    /**
     * Returns the binary name of a type. This is the same name that would be
     * returned by {@link Class#getName()} for this type.
     * 
     * @param type TypeOracle type to get the name for
     * @return binary name for a type
     */
    public static String getRpcTypeName(JType type) {
        JPrimitiveType primitiveType = type.isPrimitive();
        if (primitiveType != null) {
            return primitiveType.getJNISignature();
        }

        JArrayType arrayType = type.isArray();
        if (arrayType != null) {
            JType component = arrayType.getComponentType();
            if (component.isClassOrInterface() != null) {
                return "[L" + getRpcTypeName(arrayType.getComponentType()) + ";";
            } else {
                return "[" + getRpcTypeName(arrayType.getComponentType());
            }
        }

        JParameterizedType parameterizedType = type.isParameterized();
        if (parameterizedType != null) {
            return getRpcTypeName(parameterizedType.getBaseType());
        }

        JClassType classType = type.isClassOrInterface();
        assert (classType != null);

        JClassType enclosingType = classType.getEnclosingType();
        if (enclosingType != null) {
            return getRpcTypeName(enclosingType) + "$" + classType.getSimpleSourceName();
        }

        return classType.getQualifiedSourceName();
    }

    /**
     * Returns the set of fields that are serializable for a given class type.
     * This method does not consider any superclass fields.
     * 
     * @param typeOracle the type oracle
     * @param classType the class for which we want serializable fields
     * @return array of fields that meet the serialization criteria
     */
    public static JField[] getSerializableFields(TypeOracle typeOracle, JClassType classType) {
        assert (classType != null);

        List<JField> fields = new ArrayList<JField>();
        JField[] declFields = classType.getFields();
        assert (declFields != null);
        for (JField field : declFields) {
            if (SerializableTypeOracleBuilder.shouldConsiderForSerialization(TreeLogger.NULL, true, field)) {
                fields.add(field);
            }
        }

        Collections.sort(fields, FIELD_COMPARATOR);
        return fields.toArray(new JField[fields.size()]);
    }

    /**
     * Returns the name of the field serializer for a particular type. This name
     * can be either the name of a custom field serializer or that of a generated
     * field serializer. If the type is not serializable then it can return null.
     * 
     * @param type the type that is going to be serialized
     * @return the fully qualified name of the field serializer for the given type
     */
    static String getFieldSerializerName(TypeOracle typeOracle, JType type) {
        JClassType customSerializer = SerializableTypeOracleBuilder.findCustomFieldSerializer(typeOracle, type);
        if (customSerializer != null) {
            return customSerializer.getQualifiedSourceName();
        }

        assert (type.isClassOrInterface() != null || type.isArray() != null);
        JClassType classType = (JClassType) type;
        return getStandardSerializerName(classType);
    }

    /**
     * Returns the serialization signature for a type.
     * 
     * @param instanceType
     * @return a string representing the serialization signature of a type
     */
    static String getSerializationSignature(TypeOracle typeOracle, JType type) throws RuntimeException {
        CRC32 crc = new CRC32();

        try {
            generateSerializationSignature(typeOracle, type, crc);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("Could not compute the serialization signature", e);
        }

        return Long.toString(crc.getValue());
    }

    /**
     * Returns the name of the generated field serializer.
     */
    static String getStandardSerializerName(JClassType classType) {
        String[] name = Shared.synthesizeTopLevelClassName(classType,
                SerializationUtils.GENERATED_FIELD_SERIALIZER_SUFFIX);
        if (name[0].length() > 0) {
            String serializerName = name[0] + "." + name[1];
            if (SerializableTypeOracleBuilder.isInStandardJavaPackage(classType.getQualifiedSourceName())) {
                /*
                 * Don't generate code into java packages. If you do Development Mode
                 * CompilingClassLoader will fail to resolve references to the generated
                 * code.
                 */
                serializerName = "com.google.gwt.user.client.rpc.core." + serializerName;
            }

            return serializerName;
        } else {
            return name[1];
        }
    }

    /**
     * Returns the qualified name of the type serializer class for the given
     * service interface.
     * 
     * @param serviceIntf service interface
     * @return name of the type serializer that handles the service interface
     */
    static String getTypeSerializerQualifiedName(JClassType serviceIntf) throws IllegalArgumentException {
        if (serviceIntf.isInterface() == null) {
            throw new IllegalArgumentException(
                    serviceIntf.getQualifiedSourceName() + " is not a service interface");
        }

        String[] name = Shared.synthesizeTopLevelClassName(serviceIntf, TYPE_SERIALIZER_SUFFIX);
        if (name[0].length() > 0) {
            return name[0] + "." + name[1];
        } else {
            return name[1];
        }
    }

    /**
     * Returns the simple name of the type serializer class for the given service
     * interface.
     * 
     * @param serviceIntf service interface
     * @return the simple name of the type serializer class
     */
    static String getTypeSerializerSimpleName(JClassType serviceIntf) throws IllegalArgumentException {
        if (serviceIntf.isInterface() == null) {
            throw new IllegalArgumentException(
                    serviceIntf.getQualifiedSourceName() + " is not a service interface");
        }

        String[] name = Shared.synthesizeTopLevelClassName(serviceIntf, TYPE_SERIALIZER_SUFFIX);
        return name[1];
    }

    private static boolean excludeImplementationFromSerializationSignature(JType instanceType) {
        if (TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES
                .contains(instanceType.getQualifiedSourceName())) {
            return true;
        }

        return false;
    }

    private static void generateSerializationSignature(TypeOracle typeOracle, JType type, CRC32 crc)
            throws UnsupportedEncodingException {
        JParameterizedType parameterizedType = type.isParameterized();
        if (parameterizedType != null) {
            generateSerializationSignature(typeOracle, parameterizedType.getRawType(), crc);

            return;
        }

        String serializedTypeName = getRpcTypeName(type);
        crc.update(serializedTypeName.getBytes(Util.DEFAULT_ENCODING));

        if (excludeImplementationFromSerializationSignature(type)) {
            return;
        }

        JClassType customSerializer = SerializableTypeOracleBuilder.findCustomFieldSerializer(typeOracle, type);
        if (customSerializer != null) {
            generateSerializationSignature(typeOracle, customSerializer, crc);
        } else if (type.isArray() != null) {
            JArrayType isArray = type.isArray();
            generateSerializationSignature(typeOracle, isArray.getComponentType(), crc);
        } else if (type.isClassOrInterface() != null) {
            JClassType isClassOrInterface = type.isClassOrInterface();
            JField[] fields = getSerializableFields(typeOracle, isClassOrInterface);
            for (JField field : fields) {
                assert (field != null);

                crc.update(field.getName().getBytes(Util.DEFAULT_ENCODING));
                crc.update(getRpcTypeName(field.getType()).getBytes(Util.DEFAULT_ENCODING));
            }

            JClassType superClass = isClassOrInterface.getSuperclass();
            if (superClass != null) {
                generateSerializationSignature(typeOracle, superClass, crc);
            }
        }
    }
}