Revision: 9481
Author: jbrosenb...@google.com
Date: Thu Dec 23 06:00:26 2010
Log: Generator Result Caching for RPC, with some refinements to the underlying framework

Review at http://gwt-code-reviews.appspot.com/1243801

http://code.google.com/p/google-web-toolkit/source/detail?r=9481

Added:
 /trunk/dev/core/src/com/google/gwt/core/ext/GeneratorContextExtWrapper.java
 /trunk/dev/core/src/com/google/gwt/core/ext/GeneratorExtWrapper.java
Modified:
 /trunk/dev/core/src/com/google/gwt/core/ext/GeneratorExt.java
 /trunk/dev/core/src/com/google/gwt/dev/javac/StandardGeneratorContext.java
 /trunk/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java
 /trunk/user/src/com/google/gwt/rpc/rebind/RpcProxyCreator.java
 /trunk/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
/trunk/user/src/com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java
 /trunk/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java

=======================================
--- /dev/null
+++ /trunk/dev/core/src/com/google/gwt/core/ext/GeneratorContextExtWrapper.java Thu Dec 23 06:00:26 2010
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2010 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.core.ext;
+
+import com.google.gwt.core.ext.linker.Artifact;
+import com.google.gwt.core.ext.linker.GeneratedResource;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.dev.javac.rebind.CachedRebindResult;
+import com.google.gwt.dev.resource.ResourceOracle;
+
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+/**
+ * EXPERIMENTAL and subject to change. Do not use this in production code.
+ * <p>
+ * A wrapper to access a base {...@link GeneratorContext} instance as a
+ * {...@link GeneratorContextExt} instance.  Methods from the
+ * {...@link GeneratorContext} interface are passed through to the baseContext,
+ * while methods from the {...@link GeneratorContextExt} interface are given
+ * default stub implementations.
+ */
+public class GeneratorContextExtWrapper implements GeneratorContextExt {
+
+  /**
+   * Get a new instance wrapped from a base {...@link GeneratorContext}
+   * implementation.
+   */
+ public static GeneratorContextExt newInstance(GeneratorContext baseContext) {
+    return new GeneratorContextExtWrapper(baseContext);
+  }
+
+  private final GeneratorContext baseContext;
+
+  public GeneratorContextExtWrapper(GeneratorContext baseContext) {
+    this.baseContext = baseContext;
+  }
+
+  public void commit(TreeLogger logger, PrintWriter pw) {
+    baseContext.commit(logger, pw);
+  }
+
+  public void commitArtifact(TreeLogger logger, Artifact<?> artifact)
+      throws UnableToCompleteException {
+    baseContext.commitArtifact(logger, artifact);
+  }
+
+ public GeneratedResource commitResource(TreeLogger logger, OutputStream os)
+      throws UnableToCompleteException {
+    return baseContext.commitResource(logger, os);
+  }
+
+  public CachedRebindResult getCachedGeneratorResult() {
+    return null;
+  }
+
+  public PropertyOracle getPropertyOracle() {
+    return baseContext.getPropertyOracle();
+  }
+
+  public ResourceOracle getResourcesOracle() {
+    return baseContext.getResourcesOracle();
+  }
+
+  public long getSourceLastModifiedTime(JClassType sourceType) {
+    return 0L;
+  }
+
+  public TypeOracle getTypeOracle() {
+    return baseContext.getTypeOracle();
+  }
+
+  public boolean isGeneratorResultCachingEnabled() {
+    return false;
+  }
+
+  public boolean reuseTypeFromCacheIfAvailable(String typeName) {
+    return false;
+  }
+
+  public PrintWriter tryCreate(
+      TreeLogger logger, String packageName, String simpleName) {
+    return baseContext.tryCreate(logger, packageName, simpleName);
+  }
+
+ public OutputStream tryCreateResource(TreeLogger logger, String partialPath)
+      throws UnableToCompleteException {
+    return baseContext.tryCreateResource(logger, partialPath);
+  }
+}
=======================================
--- /dev/null
+++ /trunk/dev/core/src/com/google/gwt/core/ext/GeneratorExtWrapper.java Thu Dec 23 06:00:26 2010
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2010 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.core.ext;
+
+import com.google.gwt.dev.javac.rebind.RebindResult;
+import com.google.gwt.dev.javac.rebind.RebindStatus;
+
+/**
+ * EXPERIMENTAL and subject to change. Do not use this in production code.
+ * <p>
+ * A wrapper class for using base {...@link Generator} implementations where
+ * a {...@link GeneratorExt} instance is needed.
+ */
+public class GeneratorExtWrapper extends GeneratorExt {
+
+  /**
+ * Get a new instance wrapped from a base {...@link Generator} implementation.
+   */
+  public static GeneratorExt newInstance(Generator baseGenerator) {
+    return new GeneratorExtWrapper(baseGenerator);
+  }
+
+  private final Generator baseGenerator;
+
+  public GeneratorExtWrapper(Generator baseGenerator) {
+    this.baseGenerator = baseGenerator;
+  }
+
+  /**
+   * Pass through to the base generator's generate method.
+   */
+  @Override
+  public String generate(TreeLogger logger, GeneratorContext context,
+      String typeName) throws UnableToCompleteException {
+    return this.baseGenerator.generate(logger, context, typeName);
+  }
+
+  /**
+   * Call base generator's generate method, and don't attempt any caching.
+   */
+  @Override
+  public RebindResult generateIncrementally(TreeLogger logger,
+      GeneratorContextExt context, String typeName)
+      throws UnableToCompleteException {
+
+    RebindStatus status;
+    String resultTypeName = generate(logger, context, typeName);
+    if (resultTypeName == null) {
+      status = RebindStatus.USE_EXISTING;
+      resultTypeName = typeName;
+    } else {
+      status = RebindStatus.USE_ALL_NEW_WITH_NO_CACHING;
+    }
+
+    return new RebindResult(status, resultTypeName);
+  }
+}
=======================================
--- /trunk/dev/core/src/com/google/gwt/core/ext/GeneratorExt.java Mon Dec 20 10:49:11 2010 +++ /trunk/dev/core/src/com/google/gwt/core/ext/GeneratorExt.java Thu Dec 23 06:00:26 2010
@@ -16,49 +16,25 @@
 package com.google.gwt.core.ext;

 import com.google.gwt.dev.javac.rebind.RebindResult;
-import com.google.gwt.dev.javac.rebind.RebindStatus;

 /**
  * EXPERIMENTAL and subject to change. Do not use this in production code.
  * <p>
- * Adds a new {...@link #generateIfNecessary} method.
+ * Adds a new {...@link #generateIncrementally} method.
  * <p>
* TODO(jbrosenberg): Merge this into {...@link Generator} directly, once the api
  * has stabilized and we can remove the "experimental" moniker.
  */
 public abstract class GeneratorExt extends Generator {
-
+
   /**
- * A wrapper class for using old style {...@link Generator} implementations where
-   * a GeneratorExt instance is needed.
-   */
-  private static class BaseGeneratorWrapper extends GeneratorExt {
-    final Generator baseGenerator;
-
-    public BaseGeneratorWrapper(Generator baseGenerator) {
-      this.baseGenerator = baseGenerator;
-    }
-
-    @Override
-    public String generate(TreeLogger logger, GeneratorContext context,
-        String typeName) throws UnableToCompleteException {
-      return this.baseGenerator.generate(logger, context, typeName);
-    }
-  }
-
-  /**
-   * Get a new instance wrapped from an old style {...@link Generator}
-   * implementation.
-   */
-  public static GeneratorExt getWrappedInstance(Generator baseGenerator) {
-    return new BaseGeneratorWrapper(baseGenerator);
-  }
-
-  /**
- * A default implementation of the abstract method defined in the old style
-   * {...@link Generator}.
+   * A default implementation of the abstract method defined in the base
+   * {...@link Generator} class.  This will wrap a call to
+   * {...@link #generateIncrementally}, and attempt no caching.  This supports
+ * backwards compatibility for applications or other generators which call + * this generator directly, as outside of the normal internal rebind process.
    * <p>
- * Note, it is recommended that {...@link #generateIncrementally} be used instead.
+   * It is recommended that {...@link #generateIncrementally} be used instead.
    *
* @return the name of a subclass to substitute for the requested class, or * return <code>null</code> to cause the requested type itself to be
@@ -67,8 +43,13 @@
   @Override
   public String generate(TreeLogger logger, GeneratorContext context,
       String typeName) throws UnableToCompleteException {
- // to override (implementing generateIncrementally instead is recommended)
-    return null;
+
+    // wrap the passed in context
+    GeneratorContextExt contextExt =
+      GeneratorContextExtWrapper.newInstance(context);
+
+ RebindResult result = generateIncrementally(logger, contextExt, typeName);
+    return result.getReturnedTypeName();
   }

   /**
@@ -76,37 +57,21 @@
    * type.  The generator can use information from the context to determine
* whether it needs to regenerate everything, or whether it can selectively
    * regenerate a subset of its output, or whether it can return quickly to
-   * allow use of all previously cached objects.  It will return a
-   * {...@link RebindResult}, which contains a {...@link RebindStatus} field
-   * indicating whether to use previously cached artifacts, newly generated
-   * ones, or a partial mixture of both cached and newly generated objects.
+   * allow reuse of all previously cached objects.  It will return a
+   * {...@link RebindResult}, which contains a
+   * {...@link com.google.gwt.dev.javac.rebind.RebindStatus} field indicating
+   * whether to use previously cached artifacts, newly generated ones, or a
+   * partial mixture of both cached and newly generated objects.
    * <p>
    * The result also includes a field for the name of the subclass to
    * substitute for the requested class.
    * <p>
- * For backwards compatibility, the default implementation calls the old-style
-   * generate() method, and doesn't attempt any generator result caching.
-   * <p>
    * The generator throws an <code>UnableToCompleteException</code> if for
    * any reason it cannot complete successfully.
    *
-   * @return a GeneratorResult
+   * @return a RebindResult
    */
-  public RebindResult generateIncrementally(TreeLogger logger,
+  public abstract RebindResult generateIncrementally(TreeLogger logger,
       GeneratorContextExt context, String typeName)
-      throws UnableToCompleteException {
-
- // to override (default implementation calls unconditional generate() method)
-
-    RebindStatus status;
-    String resultTypeName = generate(logger, context, typeName);
-    if (resultTypeName == null) {
-      status = RebindStatus.USE_EXISTING;
-      resultTypeName = typeName;
-    } else {
-      status = RebindStatus.USE_ALL_NEW_WITH_NO_CACHING;
-    }
-
-    return new RebindResult(status, resultTypeName);
-  }
-}
+      throws UnableToCompleteException;
+}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/javac/StandardGeneratorContext.java Mon Dec 20 10:49:11 2010 +++ /trunk/dev/core/src/com/google/gwt/dev/javac/StandardGeneratorContext.java Thu Dec 23 06:00:26 2010
@@ -19,6 +19,7 @@
 import com.google.gwt.core.ext.GeneratorContext;
 import com.google.gwt.core.ext.GeneratorContextExt;
 import com.google.gwt.core.ext.GeneratorExt;
+import com.google.gwt.core.ext.GeneratorExtWrapper;
 import com.google.gwt.core.ext.PropertyOracle;
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
@@ -332,7 +333,7 @@
* Adds all available cached generated units to the context. Existing units
    * for a given type will not be overwritten.
    */
-  public void addGeneratedUnitsFromCachedRebindResult() {
+  public void addGeneratedUnitsFromCache() {
     if (cachedRebindResult != null
         && cachedRebindResult.getGeneratedUnits() != null) {
       addGeneratedUnits(cachedRebindResult.getGeneratedUnits());
@@ -392,7 +393,7 @@
   /**
    * Commits all available cached Artifacts to the context.
    */
-  public void commitArtifactsFromCachedRebindResult(TreeLogger logger) {
+  public void commitArtifactsFromCache(TreeLogger logger) {
     if (cachedRebindResult != null
         && cachedRebindResult.getArtifacts() != null) {
       for (Artifact<?> art : cachedRebindResult.getArtifacts()) {
@@ -654,7 +655,7 @@
       if (generator instanceof GeneratorExt) {
         generatorExt = (GeneratorExt) generator;
       } else {
-        generatorExt = GeneratorExt.getWrappedInstance(generator);
+        generatorExt = GeneratorExtWrapper.newInstance(generator);
       }

       RebindResult result;
@@ -686,7 +687,7 @@
   /**
    * Set previously cached rebind result for currently active generator.
    */
- public void setCachedRebindResult(CachedRebindResult cachedRebindResult) { + public void setCachedGeneratorResult(CachedRebindResult cachedRebindResult) {
     this.cachedRebindResult = cachedRebindResult;
   }

=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java Mon Dec 20 10:49:11 2010 +++ /trunk/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java Thu Dec 23 06:00:26 2010
@@ -67,7 +67,7 @@

         CachedRebindResult cachedResult = rebindCacheGet(rule, typeName);
         if (cachedResult != null) {
-          genCtx.setCachedRebindResult(cachedResult);
+          genCtx.setCachedGeneratorResult(cachedResult);
         }

// realize the rule (call a generator, or do type replacement, etc.)
@@ -189,8 +189,8 @@
           // use all cached results
           assert (cachedResult != null);

-          genCtx.commitArtifactsFromCachedRebindResult(logger);
-          genCtx.addGeneratedUnitsFromCachedRebindResult();
+          genCtx.commitArtifactsFromCache(logger);
+          genCtx.addGeneratedUnitsFromCache();

           // use cached type name
           resultTypeName = cachedResult.getReturnedTypeName();
=======================================
--- /trunk/user/src/com/google/gwt/rpc/rebind/RpcProxyCreator.java Wed Dec 22 07:49:33 2010 +++ /trunk/user/src/com/google/gwt/rpc/rebind/RpcProxyCreator.java Thu Dec 23 06:00:26 2010
@@ -19,7 +19,7 @@
 import com.google.gwt.core.client.impl.ArtificialRescue;
 import com.google.gwt.core.client.impl.Impl;
 import com.google.gwt.core.client.impl.ArtificialRescue.Rescue;
-import com.google.gwt.core.ext.GeneratorContext;
+import com.google.gwt.core.ext.GeneratorContextExt;
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.JArrayType;
@@ -118,7 +118,7 @@
   }

   @Override
- protected void generateTypeHandlers(TreeLogger logger, GeneratorContext ctx, + protected void generateTypeHandlers(TreeLogger logger, GeneratorContextExt ctx,
       SerializableTypeOracle serializationSto,
       SerializableTypeOracle deserializationSto)
       throws UnableToCompleteException {
@@ -271,7 +271,7 @@

   @Override
   protected String writeSerializationPolicyFile(TreeLogger logger,
-      GeneratorContext ctx, SerializableTypeOracle serializationSto,
+      GeneratorContextExt ctx, SerializableTypeOracle serializationSto,
       SerializableTypeOracle deserializationSto)
       throws UnableToCompleteException {

=======================================
--- /trunk/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java Wed Dec 22 07:49:33 2010 +++ /trunk/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java Thu Dec 23 06:00:26 2010
@@ -19,7 +19,7 @@
 import com.google.gwt.core.client.impl.Impl;
 import com.google.gwt.core.ext.BadPropertyValueException;
 import com.google.gwt.core.ext.ConfigurationProperty;
-import com.google.gwt.core.ext.GeneratorContext;
+import com.google.gwt.core.ext.GeneratorContextExt;
 import com.google.gwt.core.ext.PropertyOracle;
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
@@ -248,7 +248,7 @@
    *
    * @throws UnableToCompleteException
    */
-  public String create(TreeLogger logger, GeneratorContext context)
+  public String create(TreeLogger logger, GeneratorContextExt context)
       throws UnableToCompleteException {
     TypeOracle typeOracle = context.getTypeOracle();

@@ -690,7 +690,7 @@
   }

   protected void generateTypeHandlers(TreeLogger logger,
- GeneratorContext context, SerializableTypeOracle typesSentFromBrowser, + GeneratorContextExt context, SerializableTypeOracle typesSentFromBrowser,
       SerializableTypeOracle typesSentToBrowser)
       throws UnableToCompleteException {
Event event = SpeedTracerLogger.start(CompilerEventType.GENERATOR_RPC_TYPE_SERIALIZER);
@@ -729,7 +729,7 @@
   }

   protected String writeSerializationPolicyFile(TreeLogger logger,
-      GeneratorContext ctx, SerializableTypeOracle serializationSto,
+      GeneratorContextExt ctx, SerializableTypeOracle serializationSto,
       SerializableTypeOracle deserializationSto)
       throws UnableToCompleteException {
     try {
@@ -830,7 +830,7 @@
   }

   private void emitPolicyFileArtifact(TreeLogger logger,
-      GeneratorContext context, String partialPath)
+      GeneratorContextExt context, String partialPath)
       throws UnableToCompleteException {
     try {
       String qualifiedSourceName = serviceIntf.getQualifiedSourceName();
@@ -881,7 +881,7 @@
     return ResponseReader.OBJECT;
   }

- private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext ctx, + private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContextExt ctx,
       JClassType serviceAsync) {
     JPackage serviceIntfPkg = serviceAsync.getPackage();
String packageName = serviceIntfPkg == null ? "" : serviceIntfPkg.getName();
=======================================
--- /trunk/user/src/com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java Wed Dec 22 07:49:33 2010 +++ /trunk/user/src/com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java Thu Dec 23 06:00:26 2010
@@ -15,23 +15,25 @@
  */
 package com.google.gwt.user.rebind.rpc;

-import com.google.gwt.core.ext.Generator;
-import com.google.gwt.core.ext.GeneratorContext;
+import com.google.gwt.core.ext.GeneratorContextExt;
+import com.google.gwt.core.ext.GeneratorExt;
 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.TypeOracle;
+import com.google.gwt.dev.javac.rebind.RebindResult;
+import com.google.gwt.dev.javac.rebind.RebindStatus;

 /**
  * Generator for producing the asynchronous version of a
* {...@link com.google.gwt.user.client.rpc.RemoteService RemoteService} interface.
  */
-public class ServiceInterfaceProxyGenerator extends Generator {
-
+public class ServiceInterfaceProxyGenerator extends GeneratorExt {
+
   @Override
-  public String generate(TreeLogger logger, GeneratorContext ctx,
+ public RebindResult generateIncrementally(TreeLogger logger, GeneratorContextExt ctx,
       String requestedClass) throws UnableToCompleteException {
-
+
     TypeOracle typeOracle = ctx.getTypeOracle();
     assert (typeOracle != null);

@@ -54,7 +56,16 @@
         "Generating client proxy for remote service interface '"
             + remoteService.getQualifiedSourceName() + "'", null);

-    return proxyCreator.create(proxyLogger, ctx);
+    String returnTypeName = proxyCreator.create(proxyLogger, ctx);
+
+    /*
+ * Return with RebindStatus.USE_PARTIAL_CACHED, since we are implementing an + * incremental scheme, which allows us to use a mixture of previously cached + * and newly generated compilation units and artifacts. For example, the + * field serializers only need to be generated fresh if their source type
+     * has changed (or if no previously cached version exists).
+     */
+ return new RebindResult(RebindStatus.USE_PARTIAL_CACHED, returnTypeName);
   }

   protected ProxyCreator createProxyCreator(JClassType remoteService) {
=======================================
--- /trunk/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java Wed Dec 22 07:49:33 2010 +++ /trunk/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java Thu Dec 23 06:00:26 2010
@@ -21,7 +21,7 @@
 import com.google.gwt.core.client.JsArrayString;
 import com.google.gwt.core.ext.BadPropertyValueException;
 import com.google.gwt.core.ext.ConfigurationProperty;
-import com.google.gwt.core.ext.GeneratorContext;
+import com.google.gwt.core.ext.GeneratorContextExt;
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.JClassType;
@@ -29,6 +29,7 @@
 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.javac.rebind.CachedRebindResult;
 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;
@@ -99,7 +100,7 @@
     }
   }

-  private final GeneratorContext context;
+  private final GeneratorContextExt context;

   private final SerializableTypeOracle deserializationOracle;

@@ -121,7 +122,7 @@

   public TypeSerializerCreator(TreeLogger logger,
       SerializableTypeOracle serializationOracle,
- SerializableTypeOracle deserializationOracle, GeneratorContext context, + SerializableTypeOracle deserializationOracle, GeneratorContextExt context,
       String typeSerializerClassName, String typeSerializerSimpleName)
       throws UnableToCompleteException {
     this.context = context;
@@ -202,44 +203,52 @@

     return typeSerializerClassName;
   }
-
+
   /*
    * Create a field serializer for a type if it does not have a custom
    * serializer.
    */
- private void createFieldSerializer(TreeLogger logger, GeneratorContext ctx, + private void createFieldSerializer(TreeLogger logger, GeneratorContextExt ctx,
       JType type) {
Event event = SpeedTracerLogger.start(CompilerEventType.GENERATOR_RPC_FIELD_SERIALIZER);
-    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);
-
- JClassType customFieldSerializer = SerializableTypeOracleBuilder.findCustomFieldSerializer(
-        typeOracle, type);
-    FieldSerializerCreator creator = new FieldSerializerCreator(typeOracle,
-        serializationOracle, deserializationOracle, (JClassType) type,
-        customFieldSerializer);
-    creator.realize(logger, ctx);
-    event.end();
+    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);
+
+ if (findCacheableFieldSerializerAndMarkForReuseIfAvailable(ctx, type)) {
+        // skip generation of field serializer
+        return;
+      }
+
+ JClassType customFieldSerializer = SerializableTypeOracleBuilder.findCustomFieldSerializer(
+          typeOracle, type);
+ FieldSerializerCreator creator = new FieldSerializerCreator(typeOracle,
+          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) { + private void createFieldSerializers(TreeLogger logger, GeneratorContextExt ctx) {
     JType[] types = getSerializableTypes();
     int typeCount = types.length;
     for (int typeIndex = 0; typeIndex < typeCount; ++typeIndex) {
@@ -249,7 +258,51 @@
       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 findCacheableFieldSerializerAndMarkForReuseIfAvailable(
+      GeneratorContextExt ctx, JType type) {
+
+    CachedRebindResult 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)) {
+        return false;
+      }
+    } else {
+      return false;
+    }
+
+    try {
+      /*
+       * TODO(jbrosenberg): Change this check to use getVersion() from
+       * TypeOracle, once that is available.
+       */
+      long lastModified = ctx.getSourceLastModifiedTime((JClassType) type);
+
+      if (lastModified != 0L &&
+          lastModified < lastResult.getTimeGenerated()) {
+
+        // use cached version
+        return ctx.reuseTypeFromCacheIfAvailable(fieldSerializerName);
+      }
+    } catch (RuntimeException ex) {
+      // could get an exception checking modified time
+    }
+
+    return false;
+  }
   private String[] getPackageAndClassName(String fullClassName) {
     String className = fullClassName;
     String packageName = "";
@@ -265,7 +318,7 @@
     return serializableTypes;
   }

- private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext ctx) { + private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContextExt ctx) {
     String name[] = getPackageAndClassName(typeSerializerClassName);
     String packageName = name[0];
     String className = name[1];

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to