Generator Result Caching for RPC, with some refinements to the underlying framework Review at http://gwt-code-reviews.appspot.com/1243801 git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9481 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/GeneratorContextExtWrapper.java b/dev/core/src/com/google/gwt/core/ext/GeneratorContextExtWrapper.java new file mode 100644 index 0000000..9eed7ac --- /dev/null +++ b/dev/core/src/com/google/gwt/core/ext/GeneratorContextExtWrapper.java
@@ -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); + } +}
diff --git a/dev/core/src/com/google/gwt/core/ext/GeneratorExt.java b/dev/core/src/com/google/gwt/core/ext/GeneratorExt.java index 2a1313c..ed8c976 100644 --- a/dev/core/src/com/google/gwt/core/ext/GeneratorExt.java +++ b/dev/core/src/com/google/gwt/core/ext/GeneratorExt.java
@@ -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; }
diff --git a/dev/core/src/com/google/gwt/core/ext/GeneratorExtWrapper.java b/dev/core/src/com/google/gwt/core/ext/GeneratorExtWrapper.java new file mode 100644 index 0000000..bc8a250 --- /dev/null +++ b/dev/core/src/com/google/gwt/core/ext/GeneratorExtWrapper.java
@@ -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); + } +} \ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/javac/StandardGeneratorContext.java b/dev/core/src/com/google/gwt/dev/javac/StandardGeneratorContext.java index bc7d51c..1b3e4b7 100644 --- a/dev/core/src/com/google/gwt/dev/javac/StandardGeneratorContext.java +++ b/dev/core/src/com/google/gwt/dev/javac/StandardGeneratorContext.java
@@ -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; }
diff --git a/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java b/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java index 5736eb5..50bb0c2 100644 --- a/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java +++ b/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java
@@ -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();
diff --git a/user/src/com/google/gwt/rpc/rebind/RpcProxyCreator.java b/user/src/com/google/gwt/rpc/rebind/RpcProxyCreator.java index 644501d..19e33bc 100644 --- a/user/src/com/google/gwt/rpc/rebind/RpcProxyCreator.java +++ b/user/src/com/google/gwt/rpc/rebind/RpcProxyCreator.java
@@ -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 {
diff --git a/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java b/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java index 4921dd4..da4e52e 100644 --- a/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java +++ b/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
@@ -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();
diff --git a/user/src/com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java b/user/src/com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java index ded7cda..67b0c31 100644 --- a/user/src/com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java +++ b/user/src/com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java
@@ -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) {
diff --git a/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java b/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java index ebb31d8..0f7726a 100644 --- a/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java +++ b/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
@@ -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; + 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(); } - - /* - * 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(); } /* * 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];