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

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

There is a newer version: 2.11.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.client.GWT;
import com.google.gwt.core.client.GwtScriptOnly;
import com.google.gwt.core.client.JsArrayString;
import com.google.gwt.core.ext.BadPropertyValueException;
import com.google.gwt.core.ext.CachedGeneratorResult;
import com.google.gwt.core.ext.ConfigurationProperty;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.util.log.speedtracer.CompilerEventType;
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger;
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event;
import com.google.gwt.user.client.rpc.SerializationStreamReader;
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
import com.google.gwt.user.client.rpc.impl.SerializerBase;
import com.google.gwt.user.client.rpc.impl.TypeHandler;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * This class generates a class with name 'typeSerializerClassName' that is able
 * to serialize and deserialize a set of types into or out of a stream. The set
 * of types is obtained from the SerializableTypeOracle object.
 */
public class TypeSerializerCreator {

  /**
   * Configuration property to use type indices instead of type signatures.
   */
  public static final String GWT_ELIDE_TYPE_NAMES_FROM_RPC = "gwt.elideTypeNamesFromRPC";

  /**
   * Default number of types to split createMethodMap entries into. Zero means
   * no sharding occurs. Stored as a string since it is used as a default
   * property value.
   *
   * Note that the inliner will likely reassemble the shards if it is used in
   * Production Mode, but it isn't needed there anyway.
   *
   * TODO: remove this (and related code) when it is no longer needed.
   */
  private static final String DEFAULT_CREATEMETHODMAP_SHARD_SIZE = "0";

  /**
   * Java system property name to override the above.
   */
  private static final String GWT_CREATEMETHODMAP_SHARD_SIZE = "gwt.typecreator.shard.size";

  private static int shardSize = -1;

  /**
   * The maximum number of bytes that should be used in the source code of a method body.
   * The absolute maximum limit is 64k (or it will fail to compile) however 8k is the limit
   * for the JIT compiler (HotSpot) and methods over this limit will run slower. We will leave a 1k
   * buffer and set the limit at 7k.
   */
  private static final int MAX_BYTES_PER_METHOD = 7168;
  private static final String LOAD_METHODS_JAVA_HELPER_PREFIX  = "populateLoadMethodsJavaMap";
  private static final String LOAD_SIGNATURES_JAVA_HELPER_PREFIX = "populateLoadSignaturesJavaMap";

  private static void computeShardSize(TreeLogger logger) throws UnableToCompleteException {
    String shardSizeProperty =
        System.getProperty(GWT_CREATEMETHODMAP_SHARD_SIZE, DEFAULT_CREATEMETHODMAP_SHARD_SIZE);
    try {
      shardSize = Integer.valueOf(shardSizeProperty);
      if (shardSize < 0) {
        logger.log(TreeLogger.ERROR, GWT_CREATEMETHODMAP_SHARD_SIZE + " must be non-negative: "
            + shardSizeProperty);
        throw new UnableToCompleteException();
      }
    } catch (NumberFormatException e) {
      logger.log(TreeLogger.ERROR, "Property " + GWT_CREATEMETHODMAP_SHARD_SIZE + " not a number: "
          + shardSizeProperty, e);
      throw new UnableToCompleteException();
    }
  }

  private final GeneratorContext context;

  private final SerializableTypeOracle deserializationOracle;

  private final boolean elideTypeNames;

  private final JType[] serializableTypes;

  private final SerializableTypeOracle serializationOracle;

  private final SourceWriter srcWriter;

  private final TypeOracle typeOracle;

  private final String typeSerializerClassName;

  private final String typeSerializerSimpleName;

  private final Map typeStrings = new IdentityHashMap();

  private final Set typesNotUsingCustomFieldSerializers;

  private final Set customFieldSerializersUsed;

  public TypeSerializerCreator(TreeLogger logger, SerializableTypeOracle serializationOracle,
      SerializableTypeOracle deserializationOracle, GeneratorContext context,
      String typeSerializerClassName, String typeSerializerSimpleName)
      throws UnableToCompleteException {
    this.context = context;
    this.typeSerializerClassName = typeSerializerClassName;
    this.typeSerializerSimpleName = typeSerializerSimpleName;
    this.serializationOracle = serializationOracle;
    this.deserializationOracle = deserializationOracle;

    this.typeOracle = context.getTypeOracle();

    Set typesSet = new HashSet();
    typesSet.addAll(Arrays.asList(serializationOracle.getSerializableTypes()));
    typesSet.addAll(Arrays.asList(deserializationOracle.getSerializableTypes()));
    serializableTypes = typesSet.toArray(new JType[0]);
    Arrays.sort(serializableTypes, SerializableTypeOracleBuilder.JTYPE_COMPARATOR);

    srcWriter = getSourceWriter(logger, context);
    if (shardSize < 0) {
      computeShardSize(logger);
    }
    if (logger.isLoggable(TreeLogger.TRACE)) {
      logger.log(TreeLogger.TRACE, "Using a shard size of " + shardSize
          + " for TypeSerializerCreator createMethodMap");
    }

    try {
      ConfigurationProperty prop =
          context.getPropertyOracle().getConfigurationProperty(GWT_ELIDE_TYPE_NAMES_FROM_RPC);
      elideTypeNames = Boolean.parseBoolean(prop.getValues().get(0));
    } catch (BadPropertyValueException e) {
      logger.log(TreeLogger.ERROR, "The configuration property " + GWT_ELIDE_TYPE_NAMES_FROM_RPC
          + " was not defined. Is RemoteService.gwt.xml inherited?");
      throw new UnableToCompleteException();
    }

    if (context.isGeneratorResultCachingEnabled()) {
      typesNotUsingCustomFieldSerializers = new HashSet();
      customFieldSerializersUsed = new HashSet();
    } else {
      typesNotUsingCustomFieldSerializers = null;
      customFieldSerializersUsed = null;
    }
  }

  public Set getCustomSerializersUsed() {
    return customFieldSerializersUsed;
  }

  public Set getTypesNotUsingCustomSerializers() {
    return typesNotUsingCustomFieldSerializers;
  }

  public Map getTypeStrings() {
    return Collections.unmodifiableMap(typeStrings);
  }

  public String realize(TreeLogger logger) {
    logger =
        logger.branch(TreeLogger.DEBUG, "Generating TypeSerializer for service interface '"
            + typeSerializerClassName + "'", null);

    createFieldSerializers(logger, context);

    int index = 0;
    for (JType type : getSerializableTypes()) {

      String typeString;
      if (elideTypeNames) {
        typeString = Integer.toString(++index, Character.MAX_RADIX);
      } else {
        typeString = getTypeString(type);
      }
      typeStrings.put(type, typeString);
    }

    if (srcWriter != null) {
      writeStaticFields();
      writeStaticInitializer();

      if (context.isProdMode()) {
        writeLoadMethodsNative();
        writeLoadSignaturesNative();
      } else {
        writeLoadMethodsJava();
        writeLoadSignaturesJava();
      }

      writeConstructor();
      srcWriter.commit(logger);
    }

    return typeSerializerClassName;
  }

  /*
   * Create a field serializer for a type if it does not have a custom
   * serializer.
   */
  private void createFieldSerializer(TreeLogger logger, GeneratorContext ctx, JType type) {
    Event event = SpeedTracerLogger.start(CompilerEventType.GENERATOR_RPC_FIELD_SERIALIZER);
    try {
      assert (type != null);
      assert (serializationOracle.isSerializable(type) || deserializationOracle
          .isSerializable(type));

      JParameterizedType parameterizedType = type.isParameterized();
      if (parameterizedType != null) {
        createFieldSerializer(logger, ctx, parameterizedType.getRawType());
        return;
      }

      /*
       * Only a JClassType can reach this point in the code. JPrimitives have
       * been removed because their serialization is built in, interfaces have
       * been removed because they are not an instantiable type and
       * parameterized types have been broken down into their raw types.
       */
      assert (type.isClass() != null || type.isArray() != null);

      // get custom field serializer, if available
      JClassType customFieldSerializer =
          SerializableTypeOracleBuilder.findCustomFieldSerializer(typeOracle, type);

      if (ctx.isGeneratorResultCachingEnabled()) {
        // update cached info for next iteration
        if (customFieldSerializer != null) {
          customFieldSerializersUsed.add(customFieldSerializer);
        } else {
          typesNotUsingCustomFieldSerializers.add(type);
        }

        // check the cache for a valid field serializer for the current type
        if (findReusableCachedFieldSerializerIfAvailable(logger, ctx, type,
            customFieldSerializer)) {
          // we can skip re-generation of the field serializer for the current
          // type
          return;
        }
      }

      // generate a new field serializer
      FieldSerializerCreator creator =
          new FieldSerializerCreator(logger, context, serializationOracle, deserializationOracle,
              (JClassType) type, customFieldSerializer);
      creator.realize(logger, ctx);
    } finally {
      event.end();
    }
  }

  /*
   * Create all of the necessary field serializers.
   */
  private void createFieldSerializers(TreeLogger logger, GeneratorContext ctx) {
    JType[] types = getSerializableTypes();
    int typeCount = types.length;
    for (int typeIndex = 0; typeIndex < typeCount; ++typeIndex) {
      JType type = types[typeIndex];
      assert (type != null);

      createFieldSerializer(logger, ctx, type);
    }
  }

  /*
   * check whether we can use a previously generated version of a
   * FieldSerializer. If so, mark it for reuse, and return true. Otherwise
   * return false.
   */
  private boolean findReusableCachedFieldSerializerIfAvailable(TreeLogger logger,
      GeneratorContext ctx, JType type, JType customFieldSerializer) {

    CachedGeneratorResult lastResult = ctx.getCachedGeneratorResult();
    if (lastResult == null || !ctx.isGeneratorResultCachingEnabled()) {
      return false;
    }

    String fieldSerializerName = SerializationUtils.getStandardSerializerName((JClassType) type);

    if (type instanceof JClassType) {
      // check that it is available for reuse
      if (!lastResult.isTypeCached(fieldSerializerName)) {
        if (logger.isLoggable(TreeLogger.TRACE)) {
          if (ctx.getTypeOracle().findType(fieldSerializerName) == null) {
            logger.log(TreeLogger.TRACE, "No cached field serializer available for "
                + type.getQualifiedSourceName());
          }
        }
        return false;
      }
    } else {
      return false;
    }

    @SuppressWarnings("unchecked")
    CachedRpcTypeInformation cachedTypeInfo =
        (CachedRpcTypeInformation) lastResult.getClientData(ProxyCreator.CACHED_TYPE_INFO_KEY);

    assert cachedTypeInfo != null;
    boolean foundMatch = false;
    if (cachedTypeInfo.checkLastModifiedTime(type)
        && ((customFieldSerializer != null && cachedTypeInfo
            .checkLastModifiedTime(customFieldSerializer)) || (customFieldSerializer == null && cachedTypeInfo
            .checkTypeNotUsingCustomSerializer(type)))) {
      // use cached version, if available
      foundMatch = ctx.tryReuseTypeFromCache(fieldSerializerName);
    }

    if (logger.isLoggable(TreeLogger.TRACE)) {
      String msg;
      if (foundMatch) {
        msg = "Reusing cached field serializer for " + type.getQualifiedSourceName();
      } else {
        msg = "Can't reuse cached field serializer for " + type.getQualifiedSourceName();
      }
      logger.log(TreeLogger.TRACE, msg);
    }

    return foundMatch;
  }

  private String[] getPackageAndClassName(String fullClassName) {
    String className = fullClassName;
    String packageName = "";
    int index = -1;
    if ((index = className.lastIndexOf('.')) >= 0) {
      packageName = className.substring(0, index);
      className = className.substring(index + 1, className.length());
    }
    return new String[] {packageName, className};
  }

  private JType[] getSerializableTypes() {
    return serializableTypes;
  }

  private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext ctx) {
    String name[] = getPackageAndClassName(typeSerializerClassName);
    String packageName = name[0];
    String className = name[1];
    PrintWriter printWriter = ctx.tryCreate(logger, packageName, className);
    if (printWriter == null) {
      return null;
    }

    ClassSourceFileComposerFactory composerFactory =
        new ClassSourceFileComposerFactory(packageName, className);

    composerFactory.addImport(GWT.class.getName());
    composerFactory.addImport(JsArrayString.class.getName());
    composerFactory.addImport(TypeHandler.class.getName());
    composerFactory.addImport(HashMap.class.getName());
    composerFactory.addImport(Map.class.getName());
    composerFactory.addImport(GwtScriptOnly.class.getName());

    composerFactory.setSuperclass(SerializerBase.class.getName());
    return composerFactory.createSourceWriter(ctx, printWriter);
  }

  private String getTypeString(JType type) {
    String typeString =
        SerializationUtils.getRpcTypeName(type) + "/"
            + SerializationUtils.getSerializationSignature(context, type);
    return typeString;
  }

  /**
   * Return true if the custom field serializer has an instantiate
   * method.
   */
  private boolean hasInstantiateMethod(JClassType customSerializer, JType type) {
    return CustomFieldSerializerValidator.getInstantiationMethod(customSerializer,
        (JClassType) type) != null;
  }

  /**
   * Writes constructor.
   *
   * 
   * public SchoolCalendarService_TypeSerializer() {
   *   super(methodMapJava, methodMapNative, signatureMapJava, signatureMapNative);
   * }
   * 
*/ private void writeConstructor() { srcWriter.println("public " + typeSerializerSimpleName + "() {"); if (context.isProdMode()) { srcWriter.indentln("super(null, methodMapNative, null, signatureMapNative);"); } else { srcWriter.indentln("super(methodMapJava, null, signatureMapJava, null);"); } srcWriter.println("}"); srcWriter.println(); } /** * Writes a method to produce a map of type string -> class name of * {@link TypeHandler} for Java. We are forced to use repeated helper methods to populate the map * because of the limit on Java method size. * *
   * private static Map<String, String> loadMethodsJava() {
   *   Map<String, String> result = new HashMap<String, String>();
   *   populateLoadMethodsJavaMap0(result);
   *   populateLoadMethodsJavaMap1(result);
   *   ...
   *   return result;
   * }
   * 
*/ private void writeLoadMethodsJava() { List filteredTypes = new ArrayList(); JType[] types = getSerializableTypes(); int n = types.length; for (int index = 0; index < n; ++index) { JType type = types[index]; if (serializationOracle.maybeInstantiated(type) || deserializationOracle.maybeInstantiated(type)) { filteredTypes.add(type); } } // Write out as many helper methods as necessary. Iterator filteredTypesIter = filteredTypes.iterator(); int numHelpers = 0; while (filteredTypesIter.hasNext()) { writeLoadMethodsJavaHelper(filteredTypesIter, Integer.toString(numHelpers)); numHelpers++; } srcWriter.println("@SuppressWarnings(\"deprecation\")"); srcWriter.println("private static Map loadMethodsJava() {"); srcWriter.indent(); srcWriter.println("Map result = new HashMap();"); // Call all the helper methods to populate the map. for (int helperNum = 0; helperNum < numHelpers; helperNum++) { srcWriter.println(LOAD_METHODS_JAVA_HELPER_PREFIX + Integer.toString(helperNum) + "(result);"); } srcWriter.println("return result;"); srcWriter.outdent(); srcWriter.println("}"); srcWriter.println(); } /** * Writes a helper method to add the type signatures for the specified types to the result map. * Adds as many of the types as possible by destructively modifying the iterator but may * finish with elements still left. * *
   * private static void populateLoadMethodsJavaMap#(Map<String, String> result) {
   *   result.put(
   *       "java.lang.String/2004016611",
   *       "com.google.gwt.user.client.rpc.core.java.lang.String_FieldSerializer");
   *   ...
   * }
   * 
*/ private void writeLoadMethodsJavaHelper(Iterator iter, String methodSuffix) { srcWriter.println("private static void " + LOAD_METHODS_JAVA_HELPER_PREFIX + methodSuffix); srcWriter.println("(Map result) {"); srcWriter.indent(); int totalBytesEstimate = 0; while (iter.hasNext() && totalBytesEstimate < MAX_BYTES_PER_METHOD) { JType type = iter.next(); String typeString = typeStrings.get(type); assert typeString != null : "Missing type signature for " + type.getQualifiedSourceName(); String line = "result.put(\"" + typeString + "\", \"" + SerializationUtils.getStandardSerializerName((JClassType) type) + "\");"; totalBytesEstimate += line.getBytes().length; srcWriter.println(line); } srcWriter.outdent(); srcWriter.println("}"); srcWriter.println(); } /** * Writes a method to produce a native map of type string -> handler funcs. * *
   * private static native MethodMap loadMethodsNative() /*-{
   *     var result = {};
   *     result["java.lang.String/2004016611"] = [
   *         @com.google.gwt.user.client.rpc.core.java.lang.String_CustomFieldSerializer::instantiate(Lcom/google/gwt/user/client/rpc/SerializationStreamReader;),
   *         @com.google.gwt.user.client.rpc.core.java.lang.String_CustomFieldSerializer::deserialize(Lcom/google/gwt/user/client/rpc/SerializationStreamReader;Ljava/lang/String;),
   *         @com.google.gwt.user.client.rpc.core.java.lang.String_CustomFieldSerializer::serialize(Lcom/google/gwt/user/client/rpc/SerializationStreamWriter;Ljava/lang/String;)
   *       ];
   *     ...
   *     return result;
   *   }-*/;
   * 
*/ private void writeLoadMethodsNative() { srcWriter.println("@SuppressWarnings(\"deprecation\")"); srcWriter.println("@GwtScriptOnly"); srcWriter.println("private static native MethodMap loadMethodsNative() /*-{"); srcWriter.indent(); srcWriter.println("var result = {};"); List filteredTypes = new ArrayList(); JType[] types = getSerializableTypes(); int n = types.length; for (int index = 0; index < n; ++index) { JType type = types[index]; if (serializationOracle.maybeInstantiated(type) || deserializationOracle.maybeInstantiated(type)) { filteredTypes.add(type); } } boolean shard = shardSize > 0 && filteredTypes.size() > shardSize; int shardCount = 0; if (shard) { srcWriter.println("(function() {"); } for (JType type : filteredTypes) { if (shard && ++shardCount % shardSize == 0) { srcWriter.println("})();"); srcWriter.println("(function() {"); } String typeString = typeStrings.get(type); assert typeString != null : "Missing type signature for " + type.getQualifiedSourceName(); srcWriter.println("result[\"" + typeString + "\"] = ["); srcWriter.indent(); writeTypeMethodsNative(type); srcWriter.outdent(); srcWriter.indentln("];"); srcWriter.println(); } if (shard) { srcWriter.println("})();"); } srcWriter.println("return result;"); srcWriter.outdent(); srcWriter.println("}-*/;"); srcWriter.println(); } /** * Writes a method to produce a map of class name to type string for Java. * *
   * private static Map<String<?>, String> loadSignaturesJava() {
   *   Map<String<?>, String> result = new HashMap<String<?>, String>();
   *   populateLoadSignaturesJavaMap0(result);
   *   populateLoadSignaturesJavaMap1(result);
   *   ...
   *   return result;
   * }
   * 
*/ private void writeLoadSignaturesJava() { List allTypes = Arrays.asList(getSerializableTypes()); Iterator allTypesIter = allTypes.iterator(); // Write out as many helper methods as necessary. int numHelpers = 0; while (allTypesIter.hasNext()) { writeLoadSignaturesJavaHelper(allTypesIter, Integer.toString(numHelpers)); numHelpers++; } srcWriter.println("@SuppressWarnings(\"deprecation\")"); srcWriter.println("private static Map loadSignaturesJava() {"); srcWriter.indent(); srcWriter.println("Map result = new HashMap();"); // Call all the helper methods to populate the map. for (int helperNum = 0; helperNum < numHelpers; helperNum++) { srcWriter.println(LOAD_SIGNATURES_JAVA_HELPER_PREFIX + Integer.toString(helperNum) + "(result);"); } srcWriter.println("return result;"); srcWriter.outdent(); srcWriter.println("}"); srcWriter.println(); } /** * Writes a helper method to produce a map of class name to type string for Java. Adds as many of * the signatures as possible by destructively modifying the iterator but may finish with elements * still left. * *
   * private static void populateLoadSignaturesJavaMap#(Map<String<?>, String> result) {
   *   result.put(
   *       com.google.gwt.user.client.rpc.core.java.lang.String_FieldSerializer.concreteType(),
   *       "java.lang.String/2004016611");
   *   ...
   * }
   * 
*/ private void writeLoadSignaturesJavaHelper(Iterator iter, String methodSuffix) { srcWriter.println("private static void " + LOAD_SIGNATURES_JAVA_HELPER_PREFIX + methodSuffix); srcWriter.println("(Map result) {"); srcWriter.indent(); int totalBytesEstimate = 0; while (iter.hasNext() && totalBytesEstimate < MAX_BYTES_PER_METHOD) { JType type = iter.next(); String typeString = typeStrings.get(type); if (!serializationOracle.maybeInstantiated(type) && !deserializationOracle.maybeInstantiated(type)) { continue; } String typeRef; JClassType customSerializer = SerializableTypeOracleBuilder.findCustomFieldSerializer(typeOracle, type); if (customSerializer != null && CustomFieldSerializerValidator.getConcreteTypeMethod(customSerializer) != null) { typeRef = customSerializer.getQualifiedSourceName() + ".concreteType()"; } else { typeRef = '"' + SerializationUtils.getRpcTypeName(type) + '"'; } String line = "result.put(" + typeRef + ", \"" + typeString + "\");"; totalBytesEstimate += line.getBytes().length; srcWriter.println(line); } srcWriter.outdent(); srcWriter.println("}"); srcWriter.println(); } /** * Writes a method to produce a native map of system hash code to type string. * *
   * private static native JsArrayString loadSignaturesNative() /*-{
   *   var result = [];
   *   result[@com.google.gwt.core.client.impl.Impl::getHashCode(Ljava/lang/Object;)(@java.lang.String::class)] = "java.lang.String/2004016611";
   *   ...
   *   return result;
   * }-*/;
   * 
*/ private void writeLoadSignaturesNative() { srcWriter.println("@SuppressWarnings(\"deprecation\")"); srcWriter.println("@GwtScriptOnly"); srcWriter.println("private static native JsArrayString loadSignaturesNative() /*-{"); srcWriter.indent(); srcWriter.println("var result = [];"); boolean shard = shardSize > 0 && getSerializableTypes().length > shardSize; int shardCount = 0; if (shard) { srcWriter.println("(function() {"); } for (JType type : getSerializableTypes()) { String typeString = typeStrings.get(type); if (!serializationOracle.maybeInstantiated(type) && !deserializationOracle.maybeInstantiated(type)) { continue; } if (shard && ++shardCount % shardSize == 0) { srcWriter.println("})();"); srcWriter.println("(function() {"); } srcWriter .println("result[@javaemul.internal.HashCodes::getObjectIdentityHashCode(*)(@" + type.getQualifiedSourceName() + "::class)] = \"" + typeString + "\";"); } if (shard) { srcWriter.println("})();"); } srcWriter.println("return result;"); srcWriter.outdent(); srcWriter.println("}-*/;"); srcWriter.println(); } /** * Writes the class's static fields. * *
   * private static final Map<String, String> methodMapJava;
   * private static final MethodMap methodMapNative;
   * private static final Map<String<?>, String> signatureMapJava;
   * private static final JsArrayString signatureMapNative;
   * 
*/ private void writeStaticFields() { if (context.isProdMode()) { srcWriter.println("private static final MethodMap methodMapNative;"); srcWriter.println("private static final JsArrayString signatureMapNative;"); } else { srcWriter.println("private static final Map methodMapJava;"); srcWriter.println("private static final Map signatureMapJava;"); } srcWriter.println(); } /** * Statically initializes the class fields either for script or JVM. * *
   * static {
   *   if (GWT.isScript()) {
   *     methodMapJava = null;
   *     methodMapNative = loadMethodsNative();
   *     signatureMapJava = null;
   *     signatureMapNative = loadSignaturesNative();
   *   } else {
   *     methodMapJava = loadMethodsJava();
   *     methodMapNative = null;
   *     signatureMapJava = loadSignaturesJava();
   *     signatureMapNative = null;
   *   }
   * }
   * 
*/ private void writeStaticInitializer() { srcWriter.println("static {"); srcWriter.indent(); if (context.isProdMode()) { srcWriter.println("methodMapNative = loadMethodsNative();"); srcWriter.println("signatureMapNative = loadSignaturesNative();"); } else { srcWriter.println("methodMapJava = loadMethodsJava();"); srcWriter.println("signatureMapJava = loadSignaturesJava();"); } srcWriter.outdent(); srcWriter.println("}"); srcWriter.println(); } /** * Write an entry in the methodMapNative for one type. * * @param type type to generate entry for */ private void writeTypeMethodsNative(JType type) { srcWriter.indent(); String serializerName = SerializationUtils.getFieldSerializerName(typeOracle, type); JClassType customSerializer = SerializableTypeOracleBuilder.findCustomFieldSerializer(typeOracle, type); // First the initialization method if (deserializationOracle.maybeInstantiated(type)) { srcWriter.print("@"); if (customSerializer != null) { if (hasInstantiateMethod(customSerializer, type)) { srcWriter.print(serializerName); } else { srcWriter.print(SerializationUtils.getStandardSerializerName((JClassType) type)); } } else { srcWriter.print(serializerName); } srcWriter.print("::instantiate"); srcWriter.print("(L" + SerializationStreamReader.class.getName().replace('.', '/') + ";)"); } srcWriter.println(","); // Now the deserialization method if (deserializationOracle.isSerializable(type)) { // 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('.', '/') + ";" + paramType.getJNISignature() + ")"); } srcWriter.println(","); // Now the serialization method if (serializationOracle.isSerializable(type)) { // 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('.', '/') + ";" + paramType.getJNISignature() + ")"); srcWriter.println(); } srcWriter.outdent(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy