WIP
[maven-thymeleaf-skin] / src / main / java / de / juplo / jackson / SimpleMapper.java
index 941c4b1..db2df37 100644 (file)
@@ -6,13 +6,12 @@ import com.fasterxml.jackson.core.JsonLocation;
 import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.core.JsonToken;
 import java.io.IOException;
-import java.io.InputStream;
-import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.NoSuchElementException;
 import java.util.Spliterator;
 import static java.util.Spliterator.IMMUTABLE;
@@ -58,9 +57,7 @@ public class SimpleMapper
     }
 
     if (!JsonToken.START_ARRAY.equals(token))
-    {
-      throw new IllegalArgumentException("The root-element must be an array!");
-    }
+      fail(parser, "The root-element must be an array!");
 
     return new Spliterator<Object>()
     {
@@ -71,7 +68,7 @@ public class SimpleMapper
         {
           JsonToken token = parser.nextToken();
           if (token == null)
-            throw new IllegalArgumentException("Unexpected end of data!");
+            fail(parser, "Unexpected end of data!");
           if (JsonToken.END_ARRAY.equals(token))
             return false;
           action.accept(convert(parser));
@@ -106,34 +103,101 @@ public class SimpleMapper
   public static Iterator<Object> getArrayIterator(final JsonParser parser)
       throws
         IOException
+  {
+    Spliterator<Object> spliterator = getArraySpliterator(parser);
+    return new Iterator<Object>()
+    {
+      private Object next = null;
+
+
+      @Override
+      public boolean hasNext()
+      {
+        if (next != null)
+          return true;
+
+        return spliterator.tryAdvance(new Consumer<Object>()
+        {
+          @Override
+          public void accept(Object o)
+          {
+            next = o;
+          }
+        });
+      }
+
+      @Override
+      public Object next()
+      {
+        if (next == null && !hasNext())
+          throw new NoSuchElementException();
+        Object o = next;
+        next = null;
+        return o;
+      }
+    };
+  }
+
+
+  public static Stream<Entry<String, Object>> getObjectStream(final JsonParser parser)
+      throws
+        IOException
+  {
+    return StreamSupport.stream(getObjectSpliterator(parser), false);
+  }
+
+  public static Spliterator<Entry<String, Object>> getObjectSpliterator(final JsonParser parser)
+      throws
+        IOException
   {
     JsonToken token = parser.nextToken();
 
     if (token == null)
     {
       LOG.warn("empty input");
-      return Collections.emptyIterator();
+      return Spliterators.emptySpliterator();
     }
 
-    if (!JsonToken.START_ARRAY.equals(token))
-    {
-      throw new IllegalArgumentException("The root-element must be an array!");
-    }
+    if (!JsonToken.START_OBJECT.equals(token))
+      fail(parser, "The root-element must be an array!");
 
-    return new Iterator<Object>()
+    return new Spliterator<Entry<String, Object>>()
     {
-      
       @Override
-      public boolean tryAdvance(Consumer<? super Object> action)
+      public boolean tryAdvance(Consumer<? super Entry<String, Object>> action)
       {
         try
         {
           JsonToken token = parser.nextToken();
           if (token == null)
-            throw new IllegalArgumentException("Unexpected end of data!");
-          if (JsonToken.END_ARRAY.equals(token))
-            throw new NoSuchElementException();
-          action.accept(convert(parser));
+            fail(parser, "Unexpected end of data!");
+          if (JsonToken.END_OBJECT.equals(token))
+            return false;
+          if (!JsonToken.FIELD_NAME.equals(token))
+            fail(parser, "expected a field-name");
+          final String key = parser.getText();
+          parser.nextToken();
+          final Object value = convert(parser);
+          action.accept(new Entry<String, Object>()
+          {
+            @Override
+            public String getKey()
+            {
+              return key;
+            }
+
+            @Override
+            public Object getValue()
+            {
+              return value;
+            }
+
+            @Override
+            public Object setValue(Object value)
+            {
+              throw new UnsupportedOperationException("Not supported.");
+            }
+          });
           return true;
         }
         catch (IOException e)
@@ -141,61 +205,65 @@ public class SimpleMapper
           throw new IllegalArgumentException(e);
         }
       }
+
       @Override
-      public boolean hasNext()
+      public Spliterator<Entry<String, Object>> trySplit()
       {
+        return null;
       }
 
       @Override
-      public Object next()
+      public long estimateSize()
       {
-        try
-        {
-          JsonToken token = parser.nextToken();
-          if (token == null)
-            throw new IllegalArgumentException("Unexpected end of data!");
-          if (JsonToken.END_ARRAY.equals(token))
-            return false;
-          action.accept(convert(parser));
-          return true;
-        }
-        catch (IOException e)
-        {
-          throw new IllegalArgumentException(e);
-        }
+        return Long.MAX_VALUE;
+      }
+
+      @Override
+      public int characteristics()
+      {
+        return IMMUTABLE;
       }
     };
   }
 
-  public Object processAttribute(InputStream is)
+  public static Iterator<Entry<String, Object>> getObjectIterator(
+      final JsonParser parser
+      )
+      throws
+        IOException
   {
-    try
+    Spliterator<Entry<String, Object>> spliterator = getObjectSpliterator(parser);
+    return new Iterator<Entry<String, Object>>()
     {
-      /**
-       * Read the JSON and create the variables
-       */
-      JsonParser parser = factory.createParser(is);
+      private Entry<String, Object> next = null;
 
-      JsonToken token = parser.nextToken();
 
-      if (token == null)
+      @Override
+      public boolean hasNext()
       {
-        LOG.warn("empty input-stream");
-        return null;
-      }
-
-      Object result = convert(parser);
+        if (next != null)
+          return true;
 
-      if (parser.nextToken() != null)
-        fail(parser, "unexpected data after parsed variables");
+        return spliterator.tryAdvance(new Consumer<Entry<String, Object>>()
+        {
+          @Override
+          public void accept(Entry<String, Object> e)
+          {
+            next = e;
+          }
+        });
+      }
 
-      return result;
-    }
-    catch (IOException e)
-    {
-      LOG.error("cannot parse input-stream as JSON: {}", e.getMessage());
-      throw new RuntimeException(e);
-    }
+      @Override
+      public Entry<String, Object> next()
+      {
+        if (next == null && !hasNext())
+          throw new NoSuchElementException();
+        Entry<String, Object> e = next;
+        next = null;
+        return e;
+      }
+    };
   }
 
 
@@ -277,6 +345,6 @@ public class SimpleMapper
         location.getLineNr(),
         location.getColumnNr()
         );
-    throw new RuntimeException("Cannot parse JSON: " + message);
+    throw new IllegalArgumentException("Cannot parse JSON: " + message);
   }
 }