All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.user.rebind.rpc.SerializationUtils Maven / Gradle / Ivy

There is a newer version: 2.10.0
Show newest version
/*
 * 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.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.JEnumConstant;
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.Arrays;
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 FIELD_COMPARATOR = new Comparator() {
    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 TYPES_WHOSE_IMPLEMENTATION_IS_EXCLUDED_FROM_SIGNATURES =
      new HashSet();

  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 context the context
   * @param classType the class for which we want serializable fields
   * @return array of fields that meet the serialization criteria
   */
  public static JField[] getSerializableFields(GeneratorContext context, JClassType classType) {
    assert (classType != null);

    List fields = new ArrayList();
    JField[] declFields = classType.getFields();
    assert (declFields != null);
    for (JField field : declFields) {
      if (SerializableTypeOracleBuilder
          .shouldConsiderForSerialization(TreeLogger.NULL, context, 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(GeneratorContext context, JType type)
      throws RuntimeException {
    CRC32 crc = new CRC32();

    try {
      generateSerializationSignature(context, 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(GeneratorContext context, JType type, CRC32 crc)
      throws UnsupportedEncodingException {
    JParameterizedType parameterizedType = type.isParameterized();
    if (parameterizedType != null) {
      generateSerializationSignature(context, parameterizedType.getRawType(), crc);

      return;
    }

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

    if (excludeImplementationFromSerializationSignature(type)) {
      return;
    }

    JClassType customSerializer =
        SerializableTypeOracleBuilder.findCustomFieldSerializer(context.getTypeOracle(), type);
    if (customSerializer != null) {
      generateSerializationSignature(context, customSerializer, crc);
    } else if (type.isArray() != null) {
      JArrayType isArray = type.isArray();
      generateSerializationSignature(context, isArray.getComponentType(), crc);
    } else if (type.isEnum() != null) {
      List constants = Arrays.asList(type.isEnum().getEnumConstants());
      // Make sure the list is sorted; the getEnumConstants contract doesn't guarantees it.
      Collections.sort(constants, new Comparator() {
        @Override
        public int compare(JEnumConstant o1, JEnumConstant o2) {
          int i1 = o1.getOrdinal();
          int i2 = o2.getOrdinal();
          if (i1 < i2) {
            return -1;
          } else if (i1 > i2) {
            return 1;
          } else {
            return 0;
          }
        }
      });
      for (JEnumConstant constant : constants) {
        crc.update(constant.getName().getBytes(Util.DEFAULT_ENCODING));
      }
    } else if (type.isClassOrInterface() != null) {
      JClassType isClassOrInterface = type.isClassOrInterface();
      JField[] fields = getSerializableFields(context, 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(context, superClass, crc);
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy