You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ad...@apache.org on 2014/10/26 20:31:17 UTC

[1/4] git commit: JCLOUDS-750 Added @SerializedNames which can apply to either a constructor or factory method to capture the corresponding json field names.

Repository: jclouds
Updated Branches:
  refs/heads/master 2a1dff243 -> c0e6a2c51


JCLOUDS-750 Added @SerializedNames which can apply to either a constructor or factory method to capture the corresponding json field names.

Removed wildly confusing mixed naming of constructor params feature.


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/0b88dadb
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/0b88dadb
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/0b88dadb

Branch: refs/heads/master
Commit: 0b88dadb8f1ae9ca893465e81dc89707eae35bec
Parents: 671749d
Author: Adrian Cole <ad...@gmail.com>
Authored: Sun Oct 26 09:04:05 2014 -0700
Committer: Adrian Cole <ad...@gmail.com>
Committed: Sun Oct 26 12:31:05 2014 -0700

----------------------------------------------------------------------
 .../java/org/jclouds/json/SerializedNames.java  | 33 ++++++++++++++++
 .../org/jclouds/json/config/GsonModule.java     |  4 +-
 .../jclouds/json/internal/NamingStrategies.java | 24 ++++++++----
 ...ctorAndReflectiveTypeAdapterFactoryTest.java | 15 +++++---
 .../json/internal/NamingStrategiesTest.java     | 40 +-------------------
 5 files changed, 63 insertions(+), 53 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/0b88dadb/core/src/main/java/org/jclouds/json/SerializedNames.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/jclouds/json/SerializedNames.java b/core/src/main/java/org/jclouds/json/SerializedNames.java
new file mode 100644
index 0000000..35a32ce
--- /dev/null
+++ b/core/src/main/java/org/jclouds/json/SerializedNames.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.jclouds.json;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import com.google.common.annotations.Beta;
+
+/** An ordered list of json field names that correspond to factory method or constructor parameters. */
+@Beta @Target({ CONSTRUCTOR, METHOD }) @Retention(RUNTIME)
+public @interface SerializedNames {
+
+   String[] value();
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/0b88dadb/core/src/main/java/org/jclouds/json/config/GsonModule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/jclouds/json/config/GsonModule.java b/core/src/main/java/org/jclouds/json/config/GsonModule.java
index 58606fb..afbed11 100644
--- a/core/src/main/java/org/jclouds/json/config/GsonModule.java
+++ b/core/src/main/java/org/jclouds/json/config/GsonModule.java
@@ -42,6 +42,7 @@ import com.google.inject.Provides;
 import org.jclouds.date.DateService;
 import org.jclouds.domain.JsonBall;
 import org.jclouds.json.Json;
+import org.jclouds.json.SerializedNames;
 import org.jclouds.json.internal.DeserializationConstructorAndReflectiveTypeAdapterFactory;
 import org.jclouds.json.internal.EnumTypeAdapterThatReturnsFromValue;
 import org.jclouds.json.internal.GsonWrapper;
@@ -119,7 +120,8 @@ public class GsonModule extends AbstractModule {
       builder.registerTypeAdapterFactory(immutableMap);
 
       AnnotationConstructorNamingStrategy deserializationPolicy = new AnnotationConstructorNamingStrategy(
-            ImmutableSet.of(ConstructorProperties.class, Inject.class), ImmutableSet.of(new ExtractNamed()));
+            ImmutableSet.of(ConstructorProperties.class, SerializedNames.class, Inject.class),
+            ImmutableSet.of(new ExtractNamed()));
 
       builder.registerTypeAdapterFactory(new DeserializationConstructorAndReflectiveTypeAdapterFactory(
             new ConstructorConstructor(ImmutableMap.<Type, InstanceCreator<?>>of()), serializationPolicy, Excluder.DEFAULT, deserializationPolicy));

http://git-wip-us.apache.org/repos/asf/jclouds/blob/0b88dadb/core/src/main/java/org/jclouds/json/internal/NamingStrategies.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/jclouds/json/internal/NamingStrategies.java b/core/src/main/java/org/jclouds/json/internal/NamingStrategies.java
index bb5c03b..7a94ce3 100644
--- a/core/src/main/java/org/jclouds/json/internal/NamingStrategies.java
+++ b/core/src/main/java/org/jclouds/json/internal/NamingStrategies.java
@@ -32,6 +32,8 @@ import java.util.Map;
 
 import javax.inject.Named;
 
+import org.jclouds.json.SerializedNames;
+
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Function;
 import com.google.common.base.Joiner;
@@ -229,17 +231,25 @@ public class NamingStrategies {
       <T> String translateName(Invokable<T, T> c, int index) {
          String name = null;
 
-         if (markers.contains(ConstructorProperties.class) && c.getAnnotation(ConstructorProperties.class) != null) {
-            String[] names = c.getAnnotation(ConstructorProperties.class).value();
+         if ((markers.contains(ConstructorProperties.class) && c.getAnnotation(ConstructorProperties.class) != null)
+               || (markers.contains(SerializedNames.class) && c.getAnnotation(SerializedNames.class) != null)) {
+
+            String[] names = c.getAnnotation(SerializedNames.class) != null
+                  ? c.getAnnotation(SerializedNames.class).value()
+                  : c.getAnnotation(ConstructorProperties.class).value();
+
+            checkArgument(names.length == c.getParameters().size(), "Incorrect count of names on annotation of %s", c);
+
             if (names != null && names.length > index) {
                name = names[index];
             }
-         }
 
-         for (Annotation annotation : c.getParameters().get(index).getAnnotations()) {
-            if (annotationToNameExtractor.containsKey(annotation.annotationType())) {
-               name = annotationToNameExtractor.get(annotation.annotationType()).apply(annotation);
-               break;
+         } else {
+            for (Annotation annotation : c.getParameters().get(index).getAnnotations()) {
+               if (annotationToNameExtractor.containsKey(annotation.annotationType())) {
+                  name = annotationToNameExtractor.get(annotation.annotationType()).apply(annotation);
+                  break;
+               }
             }
          }
          return name;

http://git-wip-us.apache.org/repos/asf/jclouds/blob/0b88dadb/core/src/test/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactoryTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactoryTest.java b/core/src/test/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactoryTest.java
index 6567125..1d54d09 100644
--- a/core/src/test/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactoryTest.java
+++ b/core/src/test/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactoryTest.java
@@ -30,6 +30,7 @@ import java.util.Map;
 import javax.inject.Inject;
 import javax.inject.Named;
 
+import org.jclouds.json.SerializedNames;
 import org.jclouds.json.internal.NamingStrategies.AnnotationConstructorNamingStrategy;
 import org.jclouds.json.internal.NamingStrategies.AnnotationOrNameFieldNamingStrategy;
 import org.jclouds.json.internal.NamingStrategies.ExtractNamed;
@@ -63,7 +64,8 @@ public final class DeserializationConstructorAndReflectiveTypeAdapterFactoryTest
       FieldNamingStrategy serializationPolicy = new AnnotationOrNameFieldNamingStrategy(ImmutableSet.of(
             new ExtractSerializedName(), new ExtractNamed()));
       AnnotationConstructorNamingStrategy deserializationPolicy = new AnnotationConstructorNamingStrategy(
-            ImmutableSet.of(ConstructorProperties.class, Inject.class), ImmutableSet.of(new ExtractNamed()));
+            ImmutableSet.of(ConstructorProperties.class, SerializedNames.class, Inject.class),
+            ImmutableSet.of(new ExtractNamed()));
 
       return new DeserializationConstructorAndReflectiveTypeAdapterFactory(new ConstructorConstructor(ImmutableMap.<Type, InstanceCreator<?>>of()),
             serializationPolicy, Excluder.DEFAULT, deserializationPolicy);
@@ -157,8 +159,8 @@ public final class DeserializationConstructorAndReflectiveTypeAdapterFactoryTest
       abstract List<String> foo();
       abstract Map<String, String> bar();
 
-      @Inject
-      static ValueTypeWithFactory create(@Named("foo") List<String> foo, @Named("bar") Map<String, String> bar) {
+      @SerializedNames({ "foo", "bar" })
+      static ValueTypeWithFactory create(List<String> foo, Map<String, String> bar) {
          return new GenericParamsCopiedIn(foo, bar);
       }
    }
@@ -196,14 +198,15 @@ public final class DeserializationConstructorAndReflectiveTypeAdapterFactoryTest
    }
 
    private abstract static class ValueTypeWithFactoryMissingSerializedNames {
-      @Inject
+      @SerializedNames({ "foo" })
       static ValueTypeWithFactoryMissingSerializedNames create(List<String> foo, Map<String, String> bar) {
          return null;
       }
    }
 
-   @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = ".* parameter 0 failed to be named by AnnotationBasedNamingStrategy requiring one of javax.inject.Named")
-   public void testSerializedNameRequiredOnAllFactoryMethodParameters() {
+   @Test(expectedExceptions = IllegalArgumentException.class,
+         expectedExceptionsMessageRegExp = "Incorrect count of names on annotation of .*")
+   public void testSerializedNamesMustHaveCorrectCountOfNames() {
       parameterizedCtorFactory.create(gson, TypeToken.get(ValueTypeWithFactoryMissingSerializedNames.class));
    }
 

http://git-wip-us.apache.org/repos/asf/jclouds/blob/0b88dadb/core/src/test/java/org/jclouds/json/internal/NamingStrategiesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/jclouds/json/internal/NamingStrategiesTest.java b/core/src/test/java/org/jclouds/json/internal/NamingStrategiesTest.java
index 4ac7720..ccd947a 100644
--- a/core/src/test/java/org/jclouds/json/internal/NamingStrategiesTest.java
+++ b/core/src/test/java/org/jclouds/json/internal/NamingStrategiesTest.java
@@ -54,7 +54,7 @@ public final class NamingStrategiesTest {
       private String d;
       
       @ConstructorProperties({"aardvark", "bat", "coyote", "dog"})
-      private SimpleTest(String aa, String bb, String cc, @Named("dingo") String dd) {
+      private SimpleTest(String aa, String bb, String cc, String dd) {
       }
       
       @Inject
@@ -62,14 +62,6 @@ public final class NamingStrategiesTest {
       }
    }
 
-   private static class MixedConstructorTest {
-      @Inject
-      @ConstructorProperties("thiscanbeoverriddenbyNamed")
-      private MixedConstructorTest(@Named("aardvark") String aa, @Named("bat") String bb, @Named("cat") String cc, @Named("dog") String dd) {
-      }
-   }
-
-
    public void testExtractSerializedName() throws Exception {
       NameExtractor<SerializedName> extractor = new ExtractSerializedName();
       assertEquals(extractor.extractName(SimpleTest.class.getDeclaredField("a").getAnnotation(SerializedName.class)),
@@ -137,17 +129,6 @@ public final class NamingStrategiesTest {
       assertEquals(strategy.translateName(constructor, 0), "aardvark");
       assertEquals(strategy.translateName(constructor, 1), "bat");
       assertEquals(strategy.translateName(constructor, 2), "coyote");
-      // Note: @Named overrides the ConstructorProperties setting
-      assertEquals(strategy.translateName(constructor, 3), "dingo");
-
-      Invokable<MixedConstructorTest, MixedConstructorTest> mixedCtor = strategy.getDeserializer(typeToken(MixedConstructorTest.class));
-      assertNotNull(mixedCtor);
-      assertEquals(mixedCtor.getParameters().size(), 4);
-
-      assertEquals(strategy.translateName(mixedCtor, 0), "aardvark");
-      assertEquals(strategy.translateName(mixedCtor, 1), "bat");
-      assertEquals(strategy.translateName(mixedCtor, 2), "cat");
-      assertEquals(strategy.translateName(mixedCtor, 3), "dog");
    }
 
    public void testAnnotationConstructorFieldNamingStrategyCP() throws Exception {
@@ -162,15 +143,6 @@ public final class NamingStrategiesTest {
       assertEquals(strategy.translateName(constructor, 1), "bat");
       assertEquals(strategy.translateName(constructor, 2), "coyote");
       assertEquals(strategy.translateName(constructor, 3), "dog");
-
-      Invokable<MixedConstructorTest, MixedConstructorTest> mixedCtor = strategy.getDeserializer(typeToken(MixedConstructorTest.class));
-      assertNotNull(mixedCtor);
-      assertEquals(mixedCtor.getParameters().size(), 4);
-
-      assertEquals(strategy.translateName(mixedCtor, 0), "thiscanbeoverriddenbyNamed");
-      assertNull(strategy.translateName(mixedCtor, 1));
-      assertNull(strategy.translateName(mixedCtor, 2));
-      assertNull(strategy.translateName(mixedCtor, 3));
    }
    
    public void testAnnotationConstructorFieldNamingStrategyInject() throws Exception {
@@ -185,15 +157,5 @@ public final class NamingStrategiesTest {
       assertEquals(strategy.translateName(constructor, 1), "bb");
       assertEquals(strategy.translateName(constructor, 2), "cc");
       assertEquals(strategy.translateName(constructor, 3), "dd");
-
-      Invokable<MixedConstructorTest, MixedConstructorTest> mixedCtor = strategy.getDeserializer(typeToken(MixedConstructorTest.class));
-      assertNotNull(mixedCtor);
-      assertEquals(mixedCtor.getParameters().size(), 4);
-
-      assertEquals(strategy.translateName(mixedCtor, 0), "aardvark");
-      assertEquals(strategy.translateName(mixedCtor, 1), "bat");
-      assertEquals(strategy.translateName(mixedCtor, 2), "cat");
-      assertEquals(strategy.translateName(mixedCtor, 3), "dog");
    }
-
 }


[2/4] git commit: JCLOUDS-750 Allow abstract value types to be constructed from json using static factory methods.

Posted by ad...@apache.org.
JCLOUDS-750 Allow abstract value types to be constructed from json using static factory methods.


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/671749d6
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/671749d6
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/671749d6

Branch: refs/heads/master
Commit: 671749d6b72340493244f4136dec2ba6ed57ddf4
Parents: 2a1dff2
Author: Adrian Cole <ad...@gmail.com>
Authored: Sat Oct 25 23:16:45 2014 -0700
Committer: Adrian Cole <ad...@gmail.com>
Committed: Sun Oct 26 12:31:05 2014 -0700

----------------------------------------------------------------------
 .../java/org/jclouds/reflect/Reflection2.java   | 29 ++++-------
 ...ctorAndReflectiveTypeAdapterFactoryTest.java | 54 +++++++++++++++++---
 .../org/jclouds/reflect/Reflection2Test.java    | 19 +++++++
 3 files changed, 78 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/671749d6/core/src/main/java/org/jclouds/reflect/Reflection2.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/jclouds/reflect/Reflection2.java b/core/src/main/java/org/jclouds/reflect/Reflection2.java
index 7246f64..03db79f 100644
--- a/core/src/main/java/org/jclouds/reflect/Reflection2.java
+++ b/core/src/main/java/org/jclouds/reflect/Reflection2.java
@@ -23,6 +23,7 @@ import static com.google.common.collect.Iterables.tryFind;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
 import java.util.Arrays;
 import java.util.Collection;
@@ -71,23 +72,6 @@ public class Reflection2 {
    }
 
    /**
-    * returns an {@link Invokable} object that reflects a constructor present in the {@link TypeToken} type.
-    * 
-    * @param ownerType
-    *           corresponds to {@link Invokable#getOwnerType()}
-    * @param parameterTypes
-    *           corresponds to {@link Constructor#getParameterTypes()}
-    * 
-    * @throws IllegalArgumentException
-    *            if the constructor doesn't exist or a security exception occurred
-    */
-   @SuppressWarnings("unchecked")
-   public static <T> Invokable<T, T> constructor(Class<T> ownerType, Class<?>... parameterTypes) {
-      return (Invokable<T, T>) get(constructorForParams, new TypeTokenAndParameterTypes(typeToken(ownerType),
-            parameterTypes));
-   }
-
-   /**
     * return all constructors present in the class as {@link Invokable}s.
     * 
     * @param ownerType
@@ -144,7 +128,8 @@ public class Reflection2 {
    }
 
    /**
-    * this gets all declared constructors, not just public ones. makes them accessible, as well.
+    * This gets all declared constructors, not just public ones. makes them accessible, as well.
+    * This also includes factory methods on abstract types, defined static methods returning the same type.
     */
    private static LoadingCache<TypeToken<?>, Set<Invokable<?, ?>>> constructorsForTypeToken = CacheBuilder
          .newBuilder().build(new CacheLoader<TypeToken<?>, Set<Invokable<?, ?>>>() {
@@ -154,6 +139,14 @@ public class Reflection2 {
                   ctor.setAccessible(true);
                   builder.add(key.constructor(ctor));
                }
+               // Look for factory methods, if this is an abstract type.
+               if (Modifier.isAbstract(key.getRawType().getModifiers())) {
+                  for (Invokable<?, Object> method : methods(key.getRawType())){
+                     if (method.isStatic() && method.getReturnType().equals(key)) {
+                        builder.add(method);
+                     }
+                  }
+               }
                return builder.build();
             }
          });

http://git-wip-us.apache.org/repos/asf/jclouds/blob/671749d6/core/src/test/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactoryTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactoryTest.java b/core/src/test/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactoryTest.java
index 665fc2a..6567125 100644
--- a/core/src/test/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactoryTest.java
+++ b/core/src/test/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactoryTest.java
@@ -30,6 +30,7 @@ import java.util.Map;
 import javax.inject.Inject;
 import javax.inject.Named;
 
+import org.jclouds.json.internal.NamingStrategies.AnnotationConstructorNamingStrategy;
 import org.jclouds.json.internal.NamingStrategies.AnnotationOrNameFieldNamingStrategy;
 import org.jclouds.json.internal.NamingStrategies.ExtractNamed;
 import org.jclouds.json.internal.NamingStrategies.ExtractSerializedName;
@@ -61,7 +62,7 @@ public final class DeserializationConstructorAndReflectiveTypeAdapterFactoryTest
    static DeserializationConstructorAndReflectiveTypeAdapterFactory parameterizedCtorFactory() {
       FieldNamingStrategy serializationPolicy = new AnnotationOrNameFieldNamingStrategy(ImmutableSet.of(
             new ExtractSerializedName(), new ExtractNamed()));
-      NamingStrategies.AnnotationConstructorNamingStrategy deserializationPolicy = new NamingStrategies.AnnotationConstructorNamingStrategy(
+      AnnotationConstructorNamingStrategy deserializationPolicy = new AnnotationConstructorNamingStrategy(
             ImmutableSet.of(ConstructorProperties.class, Inject.class), ImmutableSet.of(new ExtractNamed()));
 
       return new DeserializationConstructorAndReflectiveTypeAdapterFactory(new ConstructorConstructor(ImmutableMap.<Type, InstanceCreator<?>>of()),
@@ -152,15 +153,58 @@ public final class DeserializationConstructorAndReflectiveTypeAdapterFactoryTest
         gson.fromJson("{\"bar\":1}", ValidatedConstructor.class);
     }
 
-   private static class GenericParamsCopiedIn {
+   private abstract static class ValueTypeWithFactory {
+      abstract List<String> foo();
+      abstract Map<String, String> bar();
+
+      @Inject
+      static ValueTypeWithFactory create(@Named("foo") List<String> foo, @Named("bar") Map<String, String> bar) {
+         return new GenericParamsCopiedIn(foo, bar);
+      }
+   }
+
+   private static class GenericParamsCopiedIn extends ValueTypeWithFactory {
       final List<String> foo;
       final Map<String, String> bar;
 
-      @Inject
-      GenericParamsCopiedIn(@Named("foo") List<String> foo, @Named("bar") Map<String, String> bar) {
+      @Inject GenericParamsCopiedIn(@Named("foo") List<String> foo, @Named("bar") Map<String, String> bar) {
          this.foo = Lists.newArrayList(foo);
          this.bar = Maps.newHashMap(bar);
       }
+
+      @Override List<String> foo() {
+         return foo;
+      }
+
+      @Override Map<String, String> bar() {
+         return bar;
+      }
+   }
+
+   public void testBuilderOnAbstractValueType() throws IOException {
+      TypeAdapter<ValueTypeWithFactory> adapter = parameterizedCtorFactory.create(gson,
+            TypeToken.get(ValueTypeWithFactory.class));
+      List<String> inputFoo = Lists.newArrayList();
+      inputFoo.add("one");
+      Map<String, String> inputBar = Maps.newHashMap();
+      inputBar.put("2", "two");
+
+      ValueTypeWithFactory toTest = adapter.fromJson("{ \"foo\":[\"one\"], \"bar\":{ \"2\":\"two\"}}");
+      assertEquals(inputFoo, toTest.foo());
+      assertNotSame(inputFoo, toTest.foo());
+      assertEquals(inputBar, toTest.bar());
+   }
+
+   private abstract static class ValueTypeWithFactoryMissingSerializedNames {
+      @Inject
+      static ValueTypeWithFactoryMissingSerializedNames create(List<String> foo, Map<String, String> bar) {
+         return null;
+      }
+   }
+
+   @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = ".* parameter 0 failed to be named by AnnotationBasedNamingStrategy requiring one of javax.inject.Named")
+   public void testSerializedNameRequiredOnAllFactoryMethodParameters() {
+      parameterizedCtorFactory.create(gson, TypeToken.get(ValueTypeWithFactoryMissingSerializedNames.class));
    }
 
    public void testGenericParamsCopiedIn() throws IOException {
@@ -175,7 +219,6 @@ public final class DeserializationConstructorAndReflectiveTypeAdapterFactoryTest
       assertEquals(inputFoo, toTest.foo);
       assertNotSame(inputFoo, toTest.foo);
       assertEquals(inputBar, toTest.bar);
-
    }
 
    private static class RenamedFields {
@@ -259,5 +302,4 @@ public final class DeserializationConstructorAndReflectiveTypeAdapterFactoryTest
             .create(gson, TypeToken.get(ComposedObjects.class));
       assertNull(adapter.fromJson("{\"x\":{\"foo\":0,\"bar\":1}}"));
    }
-
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/671749d6/core/src/test/java/org/jclouds/reflect/Reflection2Test.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/jclouds/reflect/Reflection2Test.java b/core/src/test/java/org/jclouds/reflect/Reflection2Test.java
index 340e32d..a51e0da 100644
--- a/core/src/test/java/org/jclouds/reflect/Reflection2Test.java
+++ b/core/src/test/java/org/jclouds/reflect/Reflection2Test.java
@@ -65,6 +65,25 @@ public class Reflection2Test {
             "[int arg0, float arg1]", "[int arg0]", "[int arg0, float arg1, boolean arg2]"));
    }
 
+   private abstract static class MyValue {
+      abstract String foo();
+
+      static MyValue create(String foo){
+         return null;
+      }
+   }
+
+   public void testConstructorsReturnsFactoryMethods() {
+      Set<String> ctorParams = FluentIterable.from(constructors(TypeToken.of(MyValue.class)))
+            .transform(new Function<Invokable<?, ?>, Iterable<Parameter>>() {
+               public Iterable<Parameter> apply(Invokable<?, ?> input) {
+                  return input.getParameters();
+               }
+            }).transform(toStringFunction()).toSet();
+
+      assertEquals(ctorParams, ImmutableSet.of("[]", "[java.lang.String arg0]"));
+   }
+
    public void testTypeTokenForClass() {
       assertEquals(typeToken(String.class), TypeToken.of(String.class));
    }


[4/4] git commit: Fixed bug found in docker provider where deserialization constructors don't handle json null.

Posted by ad...@apache.org.
Fixed bug found in docker provider where deserialization constructors don't handle json null.


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/c0e6a2c5
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/c0e6a2c5
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/c0e6a2c5

Branch: refs/heads/master
Commit: c0e6a2c51cd131bcef2ee051cfe200b41afda528
Parents: 5b6f1e9
Author: Adrian Cole <ad...@gmail.com>
Authored: Sun Oct 26 11:44:48 2014 -0700
Committer: Adrian Cole <ad...@gmail.com>
Committed: Sun Oct 26 12:31:06 2014 -0700

----------------------------------------------------------------------
 ...structorAndReflectiveTypeAdapterFactory.java |  2 +-
 .../java/org/jclouds/reflect/Reflection2.java   |  5 +-
 .../test/java/org/jclouds/json/JsonTest.java    | 59 +++++++++++---------
 3 files changed, 38 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/c0e6a2c5/core/src/main/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactory.java b/core/src/main/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactory.java
index e00f57c..87e9d32 100644
--- a/core/src/main/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactory.java
+++ b/core/src/main/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactory.java
@@ -166,7 +166,7 @@ public final class DeserializationConstructorAndReflectiveTypeAdapterFactory imp
                empty = false;
                String name = in.nextName();
                ParameterReader<?> parameter = parameterReaders.get(name);
-               if (parameter == null) {
+               if (parameter == null || in.peek() == JsonToken.NULL) {
                   in.skipValue();
                } else {
                   Object value = parameter.read(in);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c0e6a2c5/core/src/main/java/org/jclouds/reflect/Reflection2.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/jclouds/reflect/Reflection2.java b/core/src/main/java/org/jclouds/reflect/Reflection2.java
index 03db79f..bfd39b4 100644
--- a/core/src/main/java/org/jclouds/reflect/Reflection2.java
+++ b/core/src/main/java/org/jclouds/reflect/Reflection2.java
@@ -128,8 +128,8 @@ public class Reflection2 {
    }
 
    /**
-    * This gets all declared constructors, not just public ones. makes them accessible, as well.
-    * This also includes factory methods on abstract types, defined static methods returning the same type.
+    * This gets all declared constructors or factory methods on abstract types, not just public ones, and makes them
+    * accessible.
     */
    private static LoadingCache<TypeToken<?>, Set<Invokable<?, ?>>> constructorsForTypeToken = CacheBuilder
          .newBuilder().build(new CacheLoader<TypeToken<?>, Set<Invokable<?, ?>>>() {
@@ -143,6 +143,7 @@ public class Reflection2 {
                if (Modifier.isAbstract(key.getRawType().getModifiers())) {
                   for (Invokable<?, Object> method : methods(key.getRawType())){
                      if (method.isStatic() && method.getReturnType().equals(key)) {
+                        method.setAccessible(true);
                         builder.add(method);
                      }
                   }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c0e6a2c5/core/src/test/java/org/jclouds/json/JsonTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/jclouds/json/JsonTest.java b/core/src/test/java/org/jclouds/json/JsonTest.java
index ed32220..3a559db 100644
--- a/core/src/test/java/org/jclouds/json/JsonTest.java
+++ b/core/src/test/java/org/jclouds/json/JsonTest.java
@@ -20,14 +20,17 @@ import static com.google.common.io.BaseEncoding.base16;
 import static com.google.common.primitives.Bytes.asList;
 import static org.testng.Assert.assertEquals;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
+import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.json.config.GsonModule;
 import org.jclouds.json.config.GsonModule.DefaultExclusionStrategy;
 import org.testng.annotations.Test;
 
+import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.gson.FieldAttributes;
@@ -210,67 +213,73 @@ public class JsonTest {
                EnumInsideWithParser.Test.UNRECOGNIZED);
    }
 
-   private abstract static class SpinalCasedType {
+   private abstract static class UpperCamelCasedType {
       abstract String id();
 
-      abstract String contentType();
+      @Nullable abstract Map<String, String> volumes();
 
       // Currently, this only works for deserialization. Need to set a naming policy for serialization!
-      @SerializedNames({ "id", "content-type" })
-      private static SpinalCasedType create(String id, String contentType) {
-         return new SpinalCasedTypeImpl(id, contentType);
+      @SerializedNames({ "Id", "Volumes" })
+      private static UpperCamelCasedType create(String id, Map<String, String> volumes) {
+         return new UpperCamelCasedTypeImpl(id, volumes);
       }
    }
 
-   public void spinalCaseWithSerializedNames() {
+   public void upperCamelCaseWithSerializedNames() {
       Json json = Guice.createInjector(new GsonModule(), new AbstractModule() {
          @Override protected void configure() {
-            bind(FieldNamingPolicy.class).toInstance(FieldNamingPolicy.LOWER_CASE_WITH_DASHES);
+            bind(FieldNamingPolicy.class).toInstance(FieldNamingPolicy.UPPER_CAMEL_CASE);
          }
       }).getInstance(Json.class);
 
-      SpinalCasedType resource = SpinalCasedType.create("1234", "application/json");
-      String spinalJson = "{\"id\":\"1234\",\"content-type\":\"application/json\"}";
+      UpperCamelCasedType resource = UpperCamelCasedType.create("1234", Collections.<String, String>emptyMap());
+      String spinalJson = "{\"Id\":\"1234\",\"Volumes\":{}}";
 
       assertEquals(json.toJson(resource), spinalJson);
-      assertEquals(spinalJson, json.toJson(resource));
+      assertEquals(json.fromJson(spinalJson, UpperCamelCasedType.class), resource);
    }
 
-   private static class SpinalCasedTypeImpl extends SpinalCasedType {
+   public void upperCamelCaseWithSerializedNamesNullJsonValue() {
+      Json json = Guice.createInjector(new GsonModule(), new AbstractModule() {
+         @Override protected void configure() {
+            bind(FieldNamingPolicy.class).toInstance(FieldNamingPolicy.UPPER_CAMEL_CASE);
+         }
+      }).getInstance(Json.class);
+
+      assertEquals(json.fromJson("{\"Id\":\"1234\",\"Volumes\":null}", UpperCamelCasedType.class),
+            UpperCamelCasedType.create("1234", null));
+   }
+
+   private static class UpperCamelCasedTypeImpl extends UpperCamelCasedType {
       private final String id;
-      private final String contentType;
+      private final Map<String, String> volumes;
 
-      private SpinalCasedTypeImpl(String id, String contentType) {
+      private UpperCamelCasedTypeImpl(String id, Map<String, String> volumes) {
          this.id = id;
-         this.contentType = contentType;
+         this.volumes = volumes;
       }
 
       @Override String id() {
          return id;
       }
 
-      @Override String contentType() {
-         return contentType;
+      @Override @Nullable Map<String, String> volumes() {
+         return volumes;
       }
 
       @Override public boolean equals(Object o) {
          if (o == this) {
             return true;
          }
-         if (o instanceof SpinalCasedType) {
-            SpinalCasedType that = (SpinalCasedType) o;
-            return (this.id.equals(that.id())) && (this.contentType.equals(that.contentType()));
+         if (o instanceof UpperCamelCasedType) {
+            UpperCamelCasedType that = (UpperCamelCasedType) o;
+            return Objects.equal(this.id, that.id()) && Objects.equal(this.volumes, that.volumes());
          }
          return false;
       }
 
       @Override public int hashCode() {
-         int h = 1;
-         h *= 1000003;
-         h ^= id.hashCode();
-         h *= 1000003;
-         h ^= contentType.hashCode();
-         return h;
+         return Objects.hashCode(id, volumes);
       }
    }
 }


[3/4] git commit: JCLOUDS-750 allow apis to bind FieldNamingPolicy, which controls fallback naming policy of serialized fields.

Posted by ad...@apache.org.
JCLOUDS-750 allow apis to bind FieldNamingPolicy, which controls fallback naming policy of serialized fields.


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/5b6f1e92
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/5b6f1e92
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/5b6f1e92

Branch: refs/heads/master
Commit: 5b6f1e929ef4b6438facc06df0f081ddef8c9cf6
Parents: 0b88dad
Author: Adrian Cole <ad...@gmail.com>
Authored: Sun Oct 26 10:22:48 2014 -0700
Committer: Adrian Cole <ad...@gmail.com>
Committed: Sun Oct 26 12:31:06 2014 -0700

----------------------------------------------------------------------
 .../org/jclouds/json/config/GsonModule.java     | 17 ++++--
 .../jclouds/json/internal/NamingStrategies.java | 14 +++--
 .../test/java/org/jclouds/json/JsonTest.java    | 64 ++++++++++++++++++++
 ...ctorAndReflectiveTypeAdapterFactoryTest.java |  3 +-
 .../json/internal/NamingStrategiesTest.java     | 12 ++--
 5 files changed, 94 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/5b6f1e92/core/src/main/java/org/jclouds/json/config/GsonModule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/jclouds/json/config/GsonModule.java b/core/src/main/java/org/jclouds/json/config/GsonModule.java
index afbed11..9aebbe9 100644
--- a/core/src/main/java/org/jclouds/json/config/GsonModule.java
+++ b/core/src/main/java/org/jclouds/json/config/GsonModule.java
@@ -24,6 +24,7 @@ import com.google.common.collect.Sets;
 import com.google.common.primitives.Bytes;
 import com.google.gson.ExclusionStrategy;
 import com.google.gson.FieldAttributes;
+import com.google.gson.FieldNamingPolicy;
 import com.google.gson.FieldNamingStrategy;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
@@ -38,6 +39,7 @@ import com.google.gson.stream.JsonReader;
 import com.google.gson.stream.JsonWriter;
 import com.google.inject.AbstractModule;
 import com.google.inject.ImplementedBy;
+import com.google.inject.Inject;
 import com.google.inject.Provides;
 import org.jclouds.date.DateService;
 import org.jclouds.domain.JsonBall;
@@ -63,7 +65,6 @@ import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.SetTypeAdapte
 import org.jclouds.json.internal.NullHackJsonLiteralAdapter;
 import org.jclouds.json.internal.OptionalTypeAdapterFactory;
 
-import javax.inject.Inject;
 import javax.inject.Provider;
 import javax.inject.Singleton;
 import java.beans.ConstructorProperties;
@@ -78,11 +79,14 @@ import java.util.Set;
 
 import static com.google.common.io.BaseEncoding.base16;
 
-/**
- * Contains logic for parsing objects from Strings.
- */
 public class GsonModule extends AbstractModule {
 
+   /** Optionally override the fallback policy when name annotations aren't on fields. */
+   private static class FallbackFieldNamingPolicy {
+      @Inject(optional = true)
+      FieldNamingPolicy fallback = FieldNamingPolicy.IDENTITY;
+   }
+
    @SuppressWarnings("rawtypes")
    @Provides
    @Singleton
@@ -92,10 +96,11 @@ public class GsonModule extends AbstractModule {
          MapTypeAdapterFactory map, MultimapTypeAdapterFactory multimap, IterableTypeAdapterFactory iterable,
          CollectionTypeAdapterFactory collection, ListTypeAdapterFactory list,
          ImmutableListTypeAdapterFactory immutableList, FluentIterableTypeAdapterFactory fluentIterable,
-         ImmutableMapTypeAdapterFactory immutableMap, DefaultExclusionStrategy exclusionStrategy) {
+         ImmutableMapTypeAdapterFactory immutableMap, DefaultExclusionStrategy exclusionStrategy,
+         FallbackFieldNamingPolicy fallbackFieldNamingPolicy) {
 
       FieldNamingStrategy serializationPolicy = new AnnotationOrNameFieldNamingStrategy(ImmutableSet.of(
-            new ExtractSerializedName(), new ExtractNamed()));
+            new ExtractSerializedName(), new ExtractNamed()), fallbackFieldNamingPolicy.fallback);
 
       GsonBuilder builder = new GsonBuilder().setFieldNamingStrategy(serializationPolicy)
                                              .setExclusionStrategies(exclusionStrategy);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/5b6f1e92/core/src/main/java/org/jclouds/json/internal/NamingStrategies.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/jclouds/json/internal/NamingStrategies.java b/core/src/main/java/org/jclouds/json/internal/NamingStrategies.java
index 7a94ce3..c3931a1 100644
--- a/core/src/main/java/org/jclouds/json/internal/NamingStrategies.java
+++ b/core/src/main/java/org/jclouds/json/internal/NamingStrategies.java
@@ -43,6 +43,7 @@ import com.google.common.collect.FluentIterable;
 import com.google.common.collect.Maps;
 import com.google.common.reflect.Invokable;
 import com.google.common.reflect.TypeToken;
+import com.google.gson.FieldNamingPolicy;
 import com.google.gson.FieldNamingStrategy;
 import com.google.gson.annotations.SerializedName;
 
@@ -162,10 +163,14 @@ public class NamingStrategies {
    public static class AnnotationFieldNamingStrategy extends AnnotationBasedNamingStrategy implements
          FieldNamingStrategy {
 
-      public AnnotationFieldNamingStrategy(Iterable<? extends NameExtractor<?>> extractors) {
+      private final FieldNamingPolicy fallback;
+
+      public AnnotationFieldNamingStrategy(Iterable<? extends NameExtractor<?>> extractors,
+            FieldNamingPolicy fallback) {
          super(extractors);
          checkArgument(extractors.iterator().hasNext(), "you must supply at least one name extractor, for example: "
                + ExtractSerializedName.class.getSimpleName());
+         this.fallback = checkNotNull(fallback, "fallback fieldNamingPolicy");
       }
 
       @Override
@@ -175,15 +180,16 @@ public class NamingStrategies {
                return annotationToNameExtractor.get(annotation.annotationType()).apply(annotation);
             }
          }
-         return null;
+         return fallback.translateName(f);
       }
    }
 
    public static class AnnotationOrNameFieldNamingStrategy extends AnnotationFieldNamingStrategy implements
          FieldNamingStrategy {
 
-      public AnnotationOrNameFieldNamingStrategy(Iterable<? extends NameExtractor<?>> extractors) {
-         super(extractors);
+      public AnnotationOrNameFieldNamingStrategy(Iterable<? extends NameExtractor<?>> extractors,
+            FieldNamingPolicy fallback) {
+         super(extractors, fallback);
       }
 
       @Override

http://git-wip-us.apache.org/repos/asf/jclouds/blob/5b6f1e92/core/src/test/java/org/jclouds/json/JsonTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/jclouds/json/JsonTest.java b/core/src/test/java/org/jclouds/json/JsonTest.java
index 3dd5584..ed32220 100644
--- a/core/src/test/java/org/jclouds/json/JsonTest.java
+++ b/core/src/test/java/org/jclouds/json/JsonTest.java
@@ -31,6 +31,7 @@ import org.testng.annotations.Test;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.gson.FieldAttributes;
+import com.google.gson.FieldNamingPolicy;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.TypeLiteral;
@@ -209,4 +210,67 @@ public class JsonTest {
                EnumInsideWithParser.Test.UNRECOGNIZED);
    }
 
+   private abstract static class SpinalCasedType {
+      abstract String id();
+
+      abstract String contentType();
+
+      // Currently, this only works for deserialization. Need to set a naming policy for serialization!
+      @SerializedNames({ "id", "content-type" })
+      private static SpinalCasedType create(String id, String contentType) {
+         return new SpinalCasedTypeImpl(id, contentType);
+      }
+   }
+
+   public void spinalCaseWithSerializedNames() {
+      Json json = Guice.createInjector(new GsonModule(), new AbstractModule() {
+         @Override protected void configure() {
+            bind(FieldNamingPolicy.class).toInstance(FieldNamingPolicy.LOWER_CASE_WITH_DASHES);
+         }
+      }).getInstance(Json.class);
+
+      SpinalCasedType resource = SpinalCasedType.create("1234", "application/json");
+      String spinalJson = "{\"id\":\"1234\",\"content-type\":\"application/json\"}";
+
+      assertEquals(json.toJson(resource), spinalJson);
+      assertEquals(spinalJson, json.toJson(resource));
+   }
+
+   private static class SpinalCasedTypeImpl extends SpinalCasedType {
+      private final String id;
+      private final String contentType;
+
+      private SpinalCasedTypeImpl(String id, String contentType) {
+         this.id = id;
+         this.contentType = contentType;
+      }
+
+      @Override String id() {
+         return id;
+      }
+
+      @Override String contentType() {
+         return contentType;
+      }
+
+      @Override public boolean equals(Object o) {
+         if (o == this) {
+            return true;
+         }
+         if (o instanceof SpinalCasedType) {
+            SpinalCasedType that = (SpinalCasedType) o;
+            return (this.id.equals(that.id())) && (this.contentType.equals(that.contentType()));
+         }
+         return false;
+      }
+
+      @Override public int hashCode() {
+         int h = 1;
+         h *= 1000003;
+         h ^= id.hashCode();
+         h *= 1000003;
+         h ^= contentType.hashCode();
+         return h;
+      }
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/5b6f1e92/core/src/test/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactoryTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactoryTest.java b/core/src/test/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactoryTest.java
index 1d54d09..b4f0202 100644
--- a/core/src/test/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactoryTest.java
+++ b/core/src/test/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactoryTest.java
@@ -43,6 +43,7 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.gson.FieldNamingPolicy;
 import com.google.gson.FieldNamingStrategy;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
@@ -62,7 +63,7 @@ public final class DeserializationConstructorAndReflectiveTypeAdapterFactoryTest
 
    static DeserializationConstructorAndReflectiveTypeAdapterFactory parameterizedCtorFactory() {
       FieldNamingStrategy serializationPolicy = new AnnotationOrNameFieldNamingStrategy(ImmutableSet.of(
-            new ExtractSerializedName(), new ExtractNamed()));
+            new ExtractSerializedName(), new ExtractNamed()), FieldNamingPolicy.IDENTITY);
       AnnotationConstructorNamingStrategy deserializationPolicy = new AnnotationConstructorNamingStrategy(
             ImmutableSet.of(ConstructorProperties.class, SerializedNames.class, Inject.class),
             ImmutableSet.of(new ExtractNamed()));

http://git-wip-us.apache.org/repos/asf/jclouds/blob/5b6f1e92/core/src/test/java/org/jclouds/json/internal/NamingStrategiesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/jclouds/json/internal/NamingStrategiesTest.java b/core/src/test/java/org/jclouds/json/internal/NamingStrategiesTest.java
index ccd947a..20c6046 100644
--- a/core/src/test/java/org/jclouds/json/internal/NamingStrategiesTest.java
+++ b/core/src/test/java/org/jclouds/json/internal/NamingStrategiesTest.java
@@ -19,7 +19,6 @@ package org.jclouds.json.internal;
 import static org.jclouds.reflect.Reflection2.typeToken;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertNull;
 import static org.testng.Assert.fail;
 
 import java.beans.ConstructorProperties;
@@ -37,6 +36,7 @@ import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.reflect.Invokable;
+import com.google.gson.FieldNamingPolicy;
 import com.google.gson.FieldNamingStrategy;
 import com.google.gson.annotations.SerializedName;
 
@@ -101,16 +101,18 @@ public final class NamingStrategiesTest {
    }
    
    public void testAnnotationFieldNamingStrategy() throws Exception {
-      FieldNamingStrategy strategy = new AnnotationFieldNamingStrategy(ImmutableSet.of(new ExtractNamed()));
+      FieldNamingStrategy strategy = new AnnotationFieldNamingStrategy(ImmutableSet.of(new ExtractNamed()),
+            FieldNamingPolicy.UPPER_CAMEL_CASE);
 
-      assertNull(strategy.translateName(SimpleTest.class.getDeclaredField("a")));
-      assertNull(strategy.translateName(SimpleTest.class.getDeclaredField("b")));
+      assertEquals(strategy.translateName(SimpleTest.class.getDeclaredField("a")), "A"); // Per fallback!
+      assertEquals(strategy.translateName(SimpleTest.class.getDeclaredField("b")), "B"); // Per fallback!
       assertEquals(strategy.translateName(SimpleTest.class.getDeclaredField("c")), "cat");
       assertEquals(strategy.translateName(SimpleTest.class.getDeclaredField("d")), "dog");
    }
 
    public void testAnnotationOrNameFieldNamingStrategy() throws Exception {
-      FieldNamingStrategy strategy = new AnnotationOrNameFieldNamingStrategy(ImmutableSet.of(new ExtractNamed()));
+      FieldNamingStrategy strategy = new AnnotationOrNameFieldNamingStrategy(ImmutableSet.of(new ExtractNamed()),
+            FieldNamingPolicy.IDENTITY);
 
       assertEquals(strategy.translateName(SimpleTest.class.getDeclaredField("a")), "a");
       assertEquals(strategy.translateName(SimpleTest.class.getDeclaredField("b")), "b");