You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@johnzon.apache.org by rm...@apache.org on 2019/08/07 17:07:06 UTC

[johnzon] branch master updated: JOHNZON-229 serializing streams as list for now

This is an automated email from the ASF dual-hosted git repository.

rmannibucau pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/johnzon.git


The following commit(s) were added to refs/heads/master by this push:
     new cb1b21b  JOHNZON-229 serializing streams as list for now
cb1b21b is described below

commit cb1b21b216aee6a94dd4d1cbec03304b0e6201c6
Author: Romain Manni-Bucau <rm...@apache.org>
AuthorDate: Wed Aug 7 19:06:59 2019 +0200

    JOHNZON-229 serializing streams as list for now
---
 .../johnzon/mapper/MappingGeneratorImpl.java       | 73 ++++++++++++++--------
 .../apache/johnzon/mapper/MappingParserImpl.java   | 27 +++++++-
 .../java/org/apache/johnzon/mapper/StreamTest.java | 51 +++++++++++++++
 3 files changed, 123 insertions(+), 28 deletions(-)

diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
index 9febaa8..34ae88e 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
@@ -32,7 +32,9 @@ import java.util.Base64;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Map;
+import java.util.stream.BaseStream;
 
 public class MappingGeneratorImpl implements MappingGenerator {
     private final MapperConfig config;
@@ -385,33 +387,9 @@ public class MappingGeneratorImpl implements MappingGenerator {
         }
         if ((!dynamic && array) || (dynamic && type.isArray())) {
             writeArray(type, itemConverter, key, value, ignoredProperties, jsonPointer);
-        } else if ((!dynamic && collection) || (dynamic && Collection.class.isAssignableFrom(type))) {
-            generator.writeStartArray(key);
-            int i = 0;
-            for (final Object o : Collection.class.cast(value)) {
-                String valJsonPointer = jsonPointers.get(o);
-                if (valJsonPointer != null) {
-                    // write JsonPointer instead of the original object
-                    writePrimitives(valJsonPointer);
-                } else {
-                    ObjectConverter.Writer objectConverterToUse = objectConverter;
-                    if (o != null && objectConverterToUse == null) {
-                        objectConverterToUse = config.findObjectConverterWriter(o.getClass());
-                    }
-
-                    if (objectConverterToUse != null) {
-                        final DynamicMappingGenerator dynamicMappingGenerator = new DynamicMappingGenerator(this,
-                                generator::writeStartObject, generator::writeEnd, null);
-                        objectConverterToUse.writeJson(o, dynamicMappingGenerator);
-                        dynamicMappingGenerator.flushIfNeeded();
-                    } else {
-                        writeItem(itemConverter != null ? itemConverter.from(o) : o, ignoredProperties,
-                                isDeduplicateObjects ? new JsonPointerTracker(jsonPointer, i) : null);
-                    }
-                }
-                i++;
-            }
-            generator.writeEnd();
+        } else if ((!dynamic && collection) || (dynamic && Iterable.class.isAssignableFrom(type))) {
+            writeIterator(itemConverter, key, objectConverter, ignoredProperties, jsonPointer, generator,
+                    Iterable.class.cast(value).iterator());
         } else if ((!dynamic && map) || (dynamic && Map.class.isAssignableFrom(type))) {
             generator.writeStartObject(key);
             writeMapBody((Map<?, ?>) value, itemConverter);
@@ -425,6 +403,12 @@ public class MappingGeneratorImpl implements MappingGenerator {
             } else {
                 writePrimitives(key, type, value, generator);
             }
+        } else if (BaseStream.class.isAssignableFrom(type)) {
+            writeIterator(itemConverter, key, objectConverter, ignoredProperties, jsonPointer, generator,
+                    BaseStream.class.cast(value).iterator());
+        } else if (Iterator.class.isAssignableFrom(type)) {
+            writeIterator(itemConverter, key, objectConverter, ignoredProperties, jsonPointer, generator,
+                    Iterator.class.cast(value));
         } else {
             if (objectConverter != null) {
                 final DynamicMappingGenerator dynamicMappingGenerator = new DynamicMappingGenerator(this,
@@ -465,6 +449,41 @@ public class MappingGeneratorImpl implements MappingGenerator {
         }
     }
 
+    private void writeIterator(final Adapter itemConverter, final String key,
+                               final ObjectConverter.Writer objectConverter,
+                               final Collection<String> ignoredProperties,
+                               final JsonPointerTracker jsonPointer,
+                               final JsonGenerator generator,
+                               final Iterator<?> iterator) {
+        int i = 0;
+        generator.writeStartArray(key);
+        while (iterator.hasNext()) {
+            final Object o = iterator.next();
+            String valJsonPointer = jsonPointers.get(o);
+            if (valJsonPointer != null) {
+                // write JsonPointer instead of the original object
+                writePrimitives(valJsonPointer);
+            } else {
+                ObjectConverter.Writer objectConverterToUse = objectConverter;
+                if (o != null && objectConverterToUse == null) {
+                    objectConverterToUse = config.findObjectConverterWriter(o.getClass());
+                }
+
+                if (objectConverterToUse != null) {
+                    final DynamicMappingGenerator dynamicMappingGenerator = new DynamicMappingGenerator(this,
+                            generator::writeStartObject, generator::writeEnd, null);
+                    objectConverterToUse.writeJson(o, dynamicMappingGenerator);
+                    dynamicMappingGenerator.flushIfNeeded();
+                } else {
+                    writeItem(itemConverter != null ? itemConverter.from(o) : o, ignoredProperties,
+                            isDeduplicateObjects ? new JsonPointerTracker(jsonPointer, i) : null);
+                }
+            }
+            i++;
+        }
+        generator.writeEnd();
+    }
+
     /**
      * Write a JSON Array with a given Array Value, like byte[], int[], Person[] etc.
      * @param key either the attribute key or {@code null} if the array should be rendered without key
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
index c9aa1b4..0068880 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
@@ -69,6 +69,10 @@ import java.util.TreeSet;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
 
 import static java.util.Arrays.asList;
 import static javax.json.JsonValue.ValueType.ARRAY;
@@ -667,7 +671,14 @@ public class MappingParserImpl implements MappingParser {
         }
 
         if (ParameterizedType.class.isInstance(type)) {
-            final Mappings.CollectionMapping mapping = mappings.findCollectionMapping(ParameterizedType.class.cast(type), rootType);
+            final ParameterizedType genericType = ParameterizedType.class.cast(type);
+            if (Stream.class == genericType.getRawType()) {
+                return Stream.of(1).flatMap(seed -> Collection.class.cast(buildArray(
+                        new JohnzonParameterizedType(List.class, genericType.getActualTypeArguments()),
+                        jsonArray, itemConverter, objectConverter, jsonPointer, rootType)).stream());
+            }
+
+            final Mappings.CollectionMapping mapping = mappings.findCollectionMapping(genericType, rootType);
             if (mapping != null) {
                 return mapCollection(mapping, jsonArray, itemConverter, objectConverter, jsonPointer, rootType);
             }
@@ -677,6 +688,20 @@ public class MappingParserImpl implements MappingParser {
             return buildArray(ANY_LIST, jsonArray, null, null, jsonPointer, rootType);
         }
 
+        // guess we don't want to map stream impls - keep it lazy since it is the only advantage to have streams there
+        if (IntStream.class == type) {
+            return Stream.of(1).flatMapToInt(seed -> IntStream.of(int[].class.cast(
+                    buildArray(int[].class, jsonArray, null, null, jsonPointer, rootType))));
+        }
+        if (LongStream.class == type) {
+            return Stream.of(1).flatMapToLong(seed -> LongStream.of(long[].class.cast(
+                    buildArray(long[].class, jsonArray, null, null, jsonPointer, rootType))));
+        }
+        if (DoubleStream.class == type) {
+            return Stream.of(1).flatMapToDouble(seed -> DoubleStream.of(double[].class.cast(
+                    buildArray(double[].class, jsonArray, null, null, jsonPointer, rootType))));
+        }
+
         throw new UnsupportedOperationException("type " + type + " not supported");
     }
 
diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/StreamTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/StreamTest.java
new file mode 100644
index 0000000..3fdafbf
--- /dev/null
+++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/StreamTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.apache.johnzon.mapper;
+
+import static java.util.Arrays.asList;
+import static java.util.stream.Collectors.toList;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import org.junit.Test;
+
+public class StreamTest {
+    private final Mapper mapper = new MapperBuilder().setAttributeOrder(String::compareTo).build();
+
+    @Test
+    public void roundTrip() {
+        final String json = "{\"ints\":[0,1,2,3,4],\"strings\":[\"a\",\"b\",\"c\"]}";
+        final ILoveStreams instance = new ILoveStreams();
+        assertEquals(json, mapper.writeObjectAsString(instance));
+        instance.ints = null;
+        instance.strings = null;
+        assertEquals("{}", mapper.writeObjectAsString(instance));
+        final ILoveStreams deserialized = mapper.readObject(json, ILoveStreams.class);
+        assertEquals(asList("a", "b", "c"), deserialized.strings.collect(toList()));
+        assertArrayEquals(IntStream.range(0, 5).toArray(), deserialized.ints.toArray());
+    }
+
+    public static class ILoveStreams {
+        public Stream<String> strings = Stream.of("a", "b", "c");
+        public IntStream ints = IntStream.range(0, 5);
+    }
+}