SerializableTypeOracleBuilder no longer warns when it sees a final
field of a class that has a custom serializer.  It simply
quietly ignores the field.

Review by: jat



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5075 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
index fa8eb9e..0f2a4e7 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
@@ -461,8 +461,18 @@
     }
 
     if (field.isFinal()) {
+      Type logLevel;
+      if (isManuallySerializable(field.getEnclosingType())) {
+        /*
+         * If the type has a custom serializer, assume the programmer knows
+         * best.
+         */
+        logLevel = TreeLogger.DEBUG;
+      } else {
+        logLevel = TreeLogger.WARN;
+      }
       logger.branch(suppressNonStaticFinalFieldWarnings ? TreeLogger.DEBUG
-          : TreeLogger.WARN, "Field '" + field.toString()
+          : logLevel, "Field '" + field.toString()
           + "' will not be serialized because it is final", null);
       return false;
     }
diff --git a/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java b/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
index e7b1258..1f89dbc 100644
--- a/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
+++ b/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
@@ -38,6 +38,7 @@
 import com.google.gwt.dev.javac.MockCompilationUnit;
 import com.google.gwt.dev.javac.TypeOracleTestingUtils;
 import com.google.gwt.dev.javac.impl.SourceFileCompilationUnit;
+import com.google.gwt.dev.util.UnitTestTreeLogger;
 import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
 import com.google.gwt.user.rebind.rpc.testcases.client.AbstractSerializableTypes;
 import com.google.gwt.user.rebind.rpc.testcases.client.ClassWithTypeParameterThatErasesToObject;
@@ -105,6 +106,13 @@
 
   private static final int EXPOSURE_NONE = TypeParameterExposureComputer.EXPOSURE_NONE;
 
+  private static void addAnnotation(Set<CompilationUnit> units) {
+    StringBuffer code = new StringBuffer();
+    code.append("package java.lang.annotation;\n");
+    code.append("public interface Annotation { }\n");
+    units.add(createMockCompilationUnit("java.lang.annotation.Annotation", code));
+  }
+
   private static void addGwtTransient(Set<CompilationUnit> units) {
     StringBuffer code = new StringBuffer();
     code.append("package com.google.gwt.user.client.rpc;\n");
@@ -174,7 +182,24 @@
     units.add(new SourceFileCompilationUnit(JavaSourceCodeBase.MAP));
   }
 
+  private static void addSerializationStreamReader(Set<CompilationUnit> units) {
+    StringBuffer code = new StringBuffer();
+    code.append("package com.google.gwt.user.client.rpc;\n");
+    code.append("public class SerializationStreamReader { }\n");
+    units.add(createMockCompilationUnit(
+        "com.google.gwt.user.client.rpc.SerializationStreamReader", code));
+  }
+
+  private static void addSerializationStreamWriter(Set<CompilationUnit> units) {
+    StringBuffer code = new StringBuffer();
+    code.append("package com.google.gwt.user.client.rpc;\n");
+    code.append("public class SerializationStreamWriter { }\n");
+    units.add(createMockCompilationUnit(
+        "com.google.gwt.user.client.rpc.SerializationStreamWriter", code));
+  }
+
   private static void addStandardClasses(Set<CompilationUnit> units) {
+    addAnnotation(units);
     addGwtTransient(units);
     addJavaIoSerializable(units);
     addJavaLangObject(units);
@@ -308,7 +333,6 @@
 
   public SerializableTypeOracleBuilderTest() throws UnableToCompleteException {
     TreeLogger logger = createLogger();
-
     moduleDef = ModuleDefLoader.createSyntheticModule(logger,
         "com.google.gwt.user.rebind.rpc.testcases.RebindRPCTestCases.JUnit",
         new String[] {
@@ -1407,6 +1431,63 @@
   }
 
   /**
+   * Make sure that when serializing a class that has a custom field serializer,
+   * the warning about final fields is disabled. See issue 2931.
+   */
+  public void testManualSerializerWithFinalField() throws NotFoundException,
+      UnableToCompleteException {
+    Set<CompilationUnit> units = new HashSet<CompilationUnit>();
+    addStandardClasses(units);
+    addSerializationStreamReader(units);
+    addSerializationStreamWriter(units);
+
+    {
+      StringBuffer code = new StringBuffer();
+      code.append("import java.io.Serializable;\n");
+      code.append("class Bar implements Serializable { }\n");
+      units.add(createMockCompilationUnit("Bar", code));
+    }
+    {
+      StringBuffer code = new StringBuffer();
+      code.append("import java.io.Serializable;\n");
+      code.append("class Foo {\n");
+      code.append(" final Bar bar = new Bar();\n");
+      code.append("}\n");
+      units.add(createMockCompilationUnit("Foo", code));
+    }
+    {
+      StringBuffer code = new StringBuffer();
+      code.append("import com.google.gwt.user.client.rpc.SerializationStreamReader;\n");
+      code.append("import com.google.gwt.user.client.rpc.SerializationStreamWriter;\n");
+      code.append("class Foo_CustomFieldSerializer {\n");
+      code.append("  public static void serialize(SerializationStreamWriter ssw, Foo instance) {\n");
+      code.append("  }\n");
+      code.append("\n");
+      code.append("  public static void deserialize(SerializationStreamReader ssr, Foo instance) {\n");
+      code.append("  }\n");
+      code.append("}\n");
+      units.add(createMockCompilationUnit("Foo_CustomFieldSerializer", code));
+    }
+
+    UnitTestTreeLogger.Builder treeLoggerBuilder = new UnitTestTreeLogger.Builder();
+    treeLoggerBuilder.setLowestLogLevel(TreeLogger.WARN);
+    // expect no output
+    UnitTestTreeLogger logger = treeLoggerBuilder.createLogger();
+
+    TypeOracle to = TypeOracleTestingUtils.buildTypeOracle(logger, units);
+
+    JClassType foo = to.getType("Foo");
+
+    SerializableTypeOracleBuilder stob = createSerializableTypeOracleBuilder(
+        logger, to);
+    stob.addRootType(logger, foo);
+    SerializableTypeOracle so = stob.build(logger);
+
+    logger.assertCorrectLogEntries();
+    assertSerializableTypes(so, foo);
+  }
+
+  /**
    * Tests that a raw List (missing gwt.typeArgs) will not result in a failure.
    * The set of types is not currently being checked.
    */