You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2014/11/15 01:05:27 UTC

[18/21] incubator-brooklyn git commit: Adds MultimapSerializer

Adds MultimapSerializer

Should eventually be replaced with the Guava serialisers in the
jackson-datatype-guava module.


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/8ebeebb3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/8ebeebb3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/8ebeebb3

Branch: refs/heads/master
Commit: 8ebeebb3d8828a8d4bcbb3142790bff5d8a5509b
Parents: c77f9ff
Author: Sam Corbett <sa...@cloudsoftcorp.com>
Authored: Fri Nov 14 18:49:42 2014 +0000
Committer: Sam Corbett <sa...@cloudsoftcorp.com>
Committed: Fri Nov 14 18:49:42 2014 +0000

----------------------------------------------------------------------
 .../rest/util/json/BidiSerialization.java       |  9 +-
 .../util/json/BrooklynJacksonJsonProvider.java  | 86 +++++++++++---------
 .../rest/util/json/MultimapSerializer.java      | 63 ++++++++++++++
 .../json/BrooklynJacksonSerializerTest.java     | 19 ++++-
 4 files changed, 132 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8ebeebb3/usage/rest-server/src/main/java/brooklyn/rest/util/json/BidiSerialization.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/util/json/BidiSerialization.java b/usage/rest-server/src/main/java/brooklyn/rest/util/json/BidiSerialization.java
index 262d202..682fd63 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/util/json/BidiSerialization.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/util/json/BidiSerialization.java
@@ -40,18 +40,21 @@ public class BidiSerialization {
 
     protected final static ThreadLocal<Boolean> STRICT_SERIALIZATION = new ThreadLocal<Boolean>(); 
 
-    /** sets strict serialization on, or off (the default), for the current thread;
-     * recommended to be used in a <code>try { ... } finally { ... }</code> block
+    /**
+     * Sets strict serialization on, or off (the default), for the current thread.
+     * Recommended to be used in a <code>try { ... } finally { ... }</code> block
      * with {@link #clearStrictSerialization()} at the end.
      * <p>
-     * with strict serialization, classes must have public fields or annotated fields, else they will not be serialized
+     * With strict serialization, classes must have public fields or annotated fields, else they will not be serialized.
      */
     public static void setStrictSerialization(Boolean value) {
         STRICT_SERIALIZATION.set(value);
     }
+
     public static void clearStrictSerialization() {
         STRICT_SERIALIZATION.remove();
     }
+
     public static boolean isStrictSerialization() {
         Boolean result = STRICT_SERIALIZATION.get();
         if (result!=null) return result;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8ebeebb3/usage/rest-server/src/main/java/brooklyn/rest/util/json/BrooklynJacksonJsonProvider.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/util/json/BrooklynJacksonJsonProvider.java b/usage/rest-server/src/main/java/brooklyn/rest/util/json/BrooklynJacksonJsonProvider.java
index 88a2792..b79de3f 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/util/json/BrooklynJacksonJsonProvider.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/util/json/BrooklynJacksonJsonProvider.java
@@ -41,40 +41,40 @@ import brooklyn.management.ManagementContextInjectable;
 public class BrooklynJacksonJsonProvider extends JacksonJsonProvider implements ManagementContextInjectable {
 
     private static final Logger log = LoggerFactory.getLogger(BrooklynJacksonJsonProvider.class);
-    
+
     public static final String BROOKLYN_REST_OBJECT_MAPPER = BrooklynServiceAttributes.BROOKLYN_REST_OBJECT_MAPPER;
-    
+
     @Context protected ServletContext servletContext;
-    
+
     protected ObjectMapper ourMapper;
     protected boolean notFound = false;
 
     private ManagementContext mgmt;
-    
+
     public ObjectMapper locateMapper(Class<?> type, MediaType mediaType) {
-        if (ourMapper!=null) 
+        if (ourMapper != null)
             return ourMapper;
-        
+
         findSharedMapper();
-        
-        if (ourMapper!=null)
+
+        if (ourMapper != null)
             return ourMapper;
-        
+
         if (!notFound) {
             log.warn("Management context not available; using default ObjectMapper in "+this);
             notFound = true;
         }
-        
+
         return super.locateMapper(Object.class, MediaType.APPLICATION_JSON_TYPE);
     }
-    
+
     protected synchronized ObjectMapper findSharedMapper() {
-        if (ourMapper!=null || notFound) 
+        if (ourMapper != null || notFound)
             return ourMapper;
-                
+
         ourMapper = findSharedObjectMapper(servletContext, mgmt);
-        if (ourMapper==null) return null;
-        
+        if (ourMapper == null) return null;
+
         if (notFound) {
             notFound = false;
         }
@@ -82,25 +82,27 @@ public class BrooklynJacksonJsonProvider extends JacksonJsonProvider implements
 
         return ourMapper;
     }
-    
-    /** finds a shared {@link ObjectMapper} or makes a new one, stored against the servlet context;
-     * returns null if a shared instance cannot be created */
+
+    /**
+     * Finds a shared {@link ObjectMapper} or makes a new one, stored against the servlet context;
+     * returns null if a shared instance cannot be created.
+     */
     public static ObjectMapper findSharedObjectMapper(ServletContext servletContext, ManagementContext mgmt) {
-        if (servletContext!=null) {
+        if (servletContext != null) {
             synchronized (servletContext) {
                 ObjectMapper mapper = (ObjectMapper) servletContext.getAttribute(BROOKLYN_REST_OBJECT_MAPPER);
-                if (mapper!=null) return mapper;
+                if (mapper != null) return mapper;
 
                 mapper = newPrivateObjectMapper(getManagementContext(servletContext));
                 servletContext.setAttribute(BROOKLYN_REST_OBJECT_MAPPER, mapper);
                 return mapper;
             }
         }
-        if (mgmt!=null) {
+        if (mgmt != null) {
             synchronized (mgmt) {
                 ConfigKey<ObjectMapper> key = ConfigKeys.newConfigKey(ObjectMapper.class, BROOKLYN_REST_OBJECT_MAPPER);
                 ObjectMapper mapper = mgmt.getConfig().getConfig(key);
-                if (mapper!=null) return mapper;
+                if (mapper != null) return mapper;
 
                 mapper = newPrivateObjectMapper(mgmt);
                 log.debug("Storing new ObjectMapper against "+mgmt+" because no ServletContext available: "+mapper);
@@ -111,49 +113,55 @@ public class BrooklynJacksonJsonProvider extends JacksonJsonProvider implements
         return null;
     }
 
-    /** like {@link #findSharedObjectMapper(ServletContext)} but will create a private one if it can,
-     * from the servlet context and/or the management context, or else fail */
+    /**
+     * Like {@link #findSharedObjectMapper(ServletContext, ManagementContext)} but will create a private
+     * ObjectMapper if it can, from the servlet context and/or the management context, or else fail
+     */
     public static ObjectMapper findAnyObjectMapper(ServletContext servletContext, ManagementContext mgmt) {
         ObjectMapper mapper = findSharedObjectMapper(servletContext, mgmt);
-        if (mapper!=null) return mapper;
-        
-        if (mgmt==null && servletContext!=null) {
+        if (mapper != null) return mapper;
+
+        if (mgmt == null && servletContext != null) {
             mgmt = getManagementContext(servletContext);
         }
         return newPrivateObjectMapper(mgmt);
     }
 
-    /** creates a new Brooklyn-specific ObjectMapper; normally {@link #findSharedObjectMapper(ServletContext)} is preferred */
+    /**
+     * @return A new Brooklyn-specific ObjectMapper.
+     *   Normally {@link #findSharedObjectMapper(ServletContext, ManagementContext)} is preferred
+     */
     public static ObjectMapper newPrivateObjectMapper(ManagementContext mgmt) {
-        if (mgmt==null) {
+        if (mgmt == null) {
             throw new IllegalStateException("No management context available for creating ObjectMapper");
         }
-        
+
         SerializationConfig defaultConfig = new ObjectMapper().getSerializationConfig();
         SerializationConfig sc = new SerializationConfig(
-            defaultConfig.getClassIntrospector() /* ObjectMapper.DEFAULT_INTROSPECTOR */, 
-            defaultConfig.getAnnotationIntrospector() /* ObjectMapper.DEFAULT_ANNOTATION_INTROSPECTOR */, 
+            defaultConfig.getClassIntrospector() /* ObjectMapper.DEFAULT_INTROSPECTOR */,
+            defaultConfig.getAnnotationIntrospector() /* ObjectMapper.DEFAULT_ANNOTATION_INTROSPECTOR */,
             new PossiblyStrictPreferringFieldsVisibilityChecker(),
             null, null, TypeFactory.defaultInstance(), null);
-        
+
         ConfigurableSerializerProvider sp = new ConfigurableSerializerProvider();
         sp.setUnknownTypeSerializer(new ErrorAndToStringUnknownTypeSerializer());
-        
+
         ObjectMapper mapper = new ObjectMapper(null, sp, null, sc, null);
         SimpleModule mapperModule = new SimpleModule("Brooklyn", new Version(0, 0, 0, "ignored"));
-        
+
         new BidiSerialization.ManagementContextSerialization(mgmt).install(mapperModule);
         new BidiSerialization.EntitySerialization(mgmt).install(mapperModule);
         new BidiSerialization.LocationSerialization(mgmt).install(mapperModule);
-        
+        mapperModule.addSerializer(new MultimapSerializer());
+
         mapper.registerModule(mapperModule);
         return mapper;
     }
 
     public static ManagementContext getManagementContext(ServletContext servletContext) {
-        if (servletContext==null)
+        if (servletContext == null)
             return null;
-        
+
         return (ManagementContext) servletContext.getAttribute(BrooklynServiceAttributes.BROOKLYN_MANAGEMENT_CONTEXT);
     }
 
@@ -161,5 +169,5 @@ public class BrooklynJacksonJsonProvider extends JacksonJsonProvider implements
     public void injectManagementContext(ManagementContext mgmt) {
         this.mgmt = mgmt;
     }
-    
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8ebeebb3/usage/rest-server/src/main/java/brooklyn/rest/util/json/MultimapSerializer.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/util/json/MultimapSerializer.java b/usage/rest-server/src/main/java/brooklyn/rest/util/json/MultimapSerializer.java
new file mode 100644
index 0000000..294f771
--- /dev/null
+++ b/usage/rest-server/src/main/java/brooklyn/rest/util/json/MultimapSerializer.java
@@ -0,0 +1,63 @@
+/*
+ * 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 brooklyn.rest.util.json;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.map.JsonSerializer;
+import org.codehaus.jackson.map.SerializerProvider;
+import org.codehaus.jackson.map.ser.std.SerializerBase;
+
+import com.google.api.client.util.Lists;
+import com.google.common.annotations.Beta;
+import com.google.common.collect.Multimap;
+
+/**
+ * Provides a serializer for {@link Multimap} instances.
+ * <p>
+ * When Brooklyn's Jackson dependency is updated from org.codehaus.jackson:1.9.13 to
+ * com.fasterxml.jackson:2.3+ then this class should be replaced with a dependency on
+ * jackson-datatype-guava and a GuavaModule registered with Brooklyn's ObjectMapper.
+ */
+@Beta
+public class MultimapSerializer extends SerializerBase<Multimap<?, ?>> {
+
+    protected MultimapSerializer() {
+        super((Class<Multimap<?, ?>>) (Class) Multimap.class);
+    }
+
+    @Override
+    public void serialize(Multimap<?, ?> value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
+        jgen.writeStartObject();
+        writeEntries(value, jgen, provider);
+        jgen.writeEndObject();
+    }
+
+    private void writeEntries(Multimap<?, ?> value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
+        for (Map.Entry<?, ? extends Collection<?>> entry : value.asMap().entrySet()) {
+            provider.findKeySerializer(provider.constructType(String.class), null)
+                    .serialize(entry.getKey(), jgen, provider);
+            provider.defaultSerializeValue(Lists.newArrayList(entry.getValue()), jgen);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8ebeebb3/usage/rest-server/src/test/java/brooklyn/rest/util/json/BrooklynJacksonSerializerTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/brooklyn/rest/util/json/BrooklynJacksonSerializerTest.java b/usage/rest-server/src/test/java/brooklyn/rest/util/json/BrooklynJacksonSerializerTest.java
index e4a47de..552999f 100644
--- a/usage/rest-server/src/test/java/brooklyn/rest/util/json/BrooklynJacksonSerializerTest.java
+++ b/usage/rest-server/src/test/java/brooklyn/rest/util/json/BrooklynJacksonSerializerTest.java
@@ -54,6 +54,8 @@ import brooklyn.util.stream.Streams;
 import brooklyn.util.text.Strings;
 
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.MultimapBuilder;
 import com.google.gson.Gson;
 
 public class BrooklynJacksonSerializerTest {
@@ -198,11 +200,22 @@ public class BrooklynJacksonSerializerTest {
         ll.add(1); ll.add("two");
         String result = checkSerializesAs(ll, null);
         log.info("LLIST json is: "+result);
-        Assert.assertFalse(result.toString().contains("error"), "Shouldn't have had an error, instead got: "+result);
+        Assert.assertFalse(result.contains("error"), "Shouldn't have had an error, instead got: "+result);
         Assert.assertEquals(Strings.collapseWhitespace(result, ""), "[1,\"two\"]");
     }
 
     @Test
+    public void testMultiMapSerialization() throws Exception {
+        Multimap<String, Integer> m = MultimapBuilder.hashKeys().arrayListValues().build();
+        m.put("bob", 24);
+        m.put("bob", 25);
+        String result = checkSerializesAs(m, null);
+        log.info("multimap serialized as: " + result);
+        Assert.assertFalse(result.contains("error"), "Shouldn't have had an error, instead got: "+result);
+        Assert.assertEquals(Strings.collapseWhitespace(result, ""), "{\"bob\":[24,25]}");
+    }
+
+    @Test
     public void testSupplierSerialization() throws Exception {
         String result = checkSerializesAs(Strings.toStringSupplier(Streams.byteArrayOfString("x")), null);
         log.info("SUPPLIER json is: "+result);
@@ -235,7 +248,7 @@ public class BrooklynJacksonSerializerTest {
     protected Map<?,?> checkSerializesAsMapWithErrorAndToString(Object x) {
         Map<?,?> rt = checkSerializesAs(x, Map.class);
         Assert.assertEquals(rt.get("toString"), x.toString());
-        Assert.assertEquals(rt.get("error"), true);
+        Assert.assertEquals(rt.get("error"), Boolean.TRUE);
         return rt;
     }
     protected void checkNonSerializableWhenStrict(Object x) {
@@ -357,7 +370,7 @@ public class BrooklynJacksonSerializerTest {
             // (but with our custom VisibilityChecker server just gives us the nicer error!)
             log.info("CONFIG SERVER is:\n"+content);
             assertErrorObjectMatchingToString(content, server);
-            Assert.assertTrue(content.indexOf(NotSerializableException.class.getCanonicalName())>=0, "server should have contained things which are not serializable");
+            Assert.assertTrue(content.contains(NotSerializableException.class.getCanonicalName()), "server should have contained things which are not serializable");
             Assert.assertTrue(content.length() < 1024, "content should not have been very long; instead was: "+content.length());
             
         } finally {