--- /dev/null
+package de.juplo.jackson;
+
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonLocation;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.net.URL;
+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;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+
+/**
+ *
+ * @author kai
+ */
+public class SimpleMapper
+{
+ private static final Logger LOG =
+ LoggerFactory.getLogger(SimpleMapper.class);
+
+
+ private final JsonFactory factory;
+
+
+ public SimpleMapper(JsonFactory factory)
+ {
+ this.factory = factory;
+ }
+
+
+ public Spliterator<Object> getArraySpliterator(File file)
+ throws
+ IOException
+ {
+ return getArraySpliterator(factory.createParser(file));
+ }
+
+ public Spliterator<Object> getArraySpliterator(InputStream is)
+ throws
+ IOException
+ {
+ return getArraySpliterator(factory.createParser(is));
+ }
+
+ public Spliterator<Object> getArraySpliterator(Reader r)
+ throws
+ IOException
+ {
+ return getArraySpliterator(factory.createParser(r));
+ }
+
+ public Spliterator<Object> getArraySpliterator(String content)
+ throws
+ IOException
+ {
+ return getArraySpliterator(factory.createParser(content));
+ }
+
+ public Spliterator<Object> getArraySpliterator(URL url)
+ throws
+ IOException
+ {
+ return getArraySpliterator(factory.createParser(url));
+ }
+
+ public Spliterator<Object> getArraySpliterator(byte[] data)
+ throws
+ IOException
+ {
+ return getArraySpliterator(factory.createParser(data));
+ }
+
+ public Spliterator<Object> getArraySpliterator(char[] content)
+ throws
+ IOException
+ {
+ return getArraySpliterator(factory.createParser(content));
+ }
+
+ public Spliterator<Object> getArraySpliterator(byte[] data, int offset, int len)
+ throws
+ IOException
+ {
+ return getArraySpliterator(factory.createParser(data, offset, len));
+ }
+
+ public Spliterator<Object> getArraySpliterator(char[] data, int offset, int len)
+ throws
+ IOException
+ {
+ return getArraySpliterator(factory.createParser(data, offset, len));
+ }
+
+ public Stream<Object> getArrayStream(File file)
+ throws
+ IOException
+ {
+ return getArrayStream(factory.createParser(file));
+ }
+
+ public Stream<Object> getArrayStream(InputStream is)
+ throws
+ IOException
+ {
+ return getArrayStream(factory.createParser(is));
+ }
+
+ public Stream<Object> getArrayStream(Reader r)
+ throws
+ IOException
+ {
+ return getArrayStream(factory.createParser(r));
+ }
+
+ public Stream<Object> getArrayStream(String content)
+ throws
+ IOException
+ {
+ return getArrayStream(factory.createParser(content));
+ }
+
+ public Stream<Object> getArrayStream(URL url)
+ throws
+ IOException
+ {
+ return getArrayStream(factory.createParser(url));
+ }
+
+ public Stream<Object> getArrayStream(byte[] data)
+ throws
+ IOException
+ {
+ return getArrayStream(factory.createParser(data));
+ }
+
+ public Stream<Object> getArrayStream(char[] content)
+ throws
+ IOException
+ {
+ return getArrayStream(factory.createParser(content));
+ }
+
+ public Stream<Object> getArrayStream(byte[] data, int offset, int len)
+ throws
+ IOException
+ {
+ return getArrayStream(factory.createParser(data, offset, len));
+ }
+
+ public Stream<Object> getArrayStream(char[] data, int offset, int len)
+ throws
+ IOException
+ {
+ return getArrayStream(factory.createParser(data, offset, len));
+ }
+
+ public Iterator<Object> getArrayIterator(File file)
+ throws
+ IOException
+ {
+ return getArrayIterator(factory.createParser(file));
+ }
+
+ public Iterator<Object> getArrayIterator(InputStream is)
+ throws
+ IOException
+ {
+ return getArrayIterator(factory.createParser(is));
+ }
+
+ public Iterator<Object> getArrayIterator(Reader r)
+ throws
+ IOException
+ {
+ return getArrayIterator(factory.createParser(r));
+ }
+
+ public Iterator<Object> getArrayIterator(String content)
+ throws
+ IOException
+ {
+ return getArrayIterator(factory.createParser(content));
+ }
+
+ public Iterator<Object> getArrayIterator(URL url)
+ throws
+ IOException
+ {
+ return getArrayIterator(factory.createParser(url));
+ }
+
+ public Iterator<Object> getArrayIterator(byte[] data)
+ throws
+ IOException
+ {
+ return getArrayIterator(factory.createParser(data));
+ }
+
+ public Iterator<Object> getArrayIterator(char[] content)
+ throws
+ IOException
+ {
+ return getArrayIterator(factory.createParser(content));
+ }
+
+ public Iterator<Object> getArrayIterator(byte[] data, int offset, int len)
+ throws
+ IOException
+ {
+ return getArrayIterator(factory.createParser(data, offset, len));
+ }
+
+ public Iterator<Object> getArrayIterator(char[] data, int offset, int len)
+ throws
+ IOException
+ {
+ return getArrayIterator(factory.createParser(data, offset, len));
+ }
+
+
+ public Spliterator<Entry<String, Object>> getObjectSpliterator(File file)
+ throws
+ IOException
+ {
+ return getObjectSpliterator(factory.createParser(file));
+ }
+
+ public Spliterator<Entry<String, Object>> getObjectSpliterator(InputStream is)
+ throws
+ IOException
+ {
+ return getObjectSpliterator(factory.createParser(is));
+ }
+
+ public Spliterator<Entry<String, Object>> getObjectSpliterator(Reader r)
+ throws
+ IOException
+ {
+ return getObjectSpliterator(factory.createParser(r));
+ }
+
+ public Spliterator<Entry<String, Object>> getObjectSpliterator(String content)
+ throws
+ IOException
+ {
+ return getObjectSpliterator(factory.createParser(content));
+ }
+
+ public Spliterator<Entry<String, Object>> getObjectSpliterator(URL url)
+ throws
+ IOException
+ {
+ return getObjectSpliterator(factory.createParser(url));
+ }
+
+ public Spliterator<Entry<String, Object>> getObjectSpliterator(byte[] data)
+ throws
+ IOException
+ {
+ return getObjectSpliterator(factory.createParser(data));
+ }
+
+ public Spliterator<Entry<String, Object>> getObjectSpliterator(char[] content)
+ throws
+ IOException
+ {
+ return getObjectSpliterator(factory.createParser(content));
+ }
+
+ public Spliterator<Entry<String, Object>> getObjectSpliterator(byte[] data, int offset, int len)
+ throws
+ IOException
+ {
+ return getObjectSpliterator(factory.createParser(data, offset, len));
+ }
+
+ public Spliterator<Entry<String, Object>> getObjectSpliterator(char[] data, int offset, int len)
+ throws
+ IOException
+ {
+ return getObjectSpliterator(factory.createParser(data, offset, len));
+ }
+
+ public Stream<Entry<String, Object>> getObjectStream(File file)
+ throws
+ IOException
+ {
+ return getObjectStream(factory.createParser(file));
+ }
+
+ public Stream<Entry<String, Object>> getObjectStream(InputStream is)
+ throws
+ IOException
+ {
+ return getObjectStream(factory.createParser(is));
+ }
+
+ public Stream<Entry<String, Object>> getObjectStream(Reader r)
+ throws
+ IOException
+ {
+ return getObjectStream(factory.createParser(r));
+ }
+
+ public Stream<Entry<String, Object>> getObjectStream(String content)
+ throws
+ IOException
+ {
+ return getObjectStream(factory.createParser(content));
+ }
+
+ public Stream<Entry<String, Object>> getObjectStream(URL url)
+ throws
+ IOException
+ {
+ return getObjectStream(factory.createParser(url));
+ }
+
+ public Stream<Entry<String, Object>> getObjectStream(byte[] data)
+ throws
+ IOException
+ {
+ return getObjectStream(factory.createParser(data));
+ }
+
+ public Stream<Entry<String, Object>> getObjectStream(char[] content)
+ throws
+ IOException
+ {
+ return getObjectStream(factory.createParser(content));
+ }
+
+ public Stream<Entry<String, Object>> getObjectStream(byte[] data, int offset, int len)
+ throws
+ IOException
+ {
+ return getObjectStream(factory.createParser(data, offset, len));
+ }
+
+ public Stream<Entry<String, Object>> getObjectStream(char[] data, int offset, int len)
+ throws
+ IOException
+ {
+ return getObjectStream(factory.createParser(data, offset, len));
+ }
+
+ public Iterator<Entry<String, Object>> getObjectIterator(File file)
+ throws
+ IOException
+ {
+ return getObjectIterator(factory.createParser(file));
+ }
+
+ public Iterator<Entry<String, Object>> getObjectIterator(InputStream is)
+ throws
+ IOException
+ {
+ return getObjectIterator(factory.createParser(is));
+ }
+
+ public Iterator<Entry<String, Object>> getObjectIterator(Reader r)
+ throws
+ IOException
+ {
+ return getObjectIterator(factory.createParser(r));
+ }
+
+ public Iterator<Entry<String, Object>> getObjectIterator(String content)
+ throws
+ IOException
+ {
+ return getObjectIterator(factory.createParser(content));
+ }
+
+ public Iterator<Entry<String, Object>> getObjectIterator(URL url)
+ throws
+ IOException
+ {
+ return getObjectIterator(factory.createParser(url));
+ }
+
+ public Iterator<Entry<String, Object>> getObjectIterator(byte[] data)
+ throws
+ IOException
+ {
+ return getObjectIterator(factory.createParser(data));
+ }
+
+ public Iterator<Entry<String, Object>> getObjectIterator(char[] content)
+ throws
+ IOException
+ {
+ return getObjectIterator(factory.createParser(content));
+ }
+
+ public Iterator<Entry<String, Object>> getObjectIterator(byte[] data, int offset, int len)
+ throws
+ IOException
+ {
+ return getObjectIterator(factory.createParser(data, offset, len));
+ }
+
+ public Iterator<Entry<String, Object>> getObjectIterator(char[] data, int offset, int len)
+ throws
+ IOException
+ {
+ return getObjectIterator(factory.createParser(data, offset, len));
+ }
+
+
+ public static Spliterator<Object> getArraySpliterator(final JsonParser parser)
+ throws
+ IOException
+ {
+ JsonToken token = parser.nextToken();
+
+ if (token == null)
+ {
+ LOG.warn("empty input");
+ return Spliterators.emptySpliterator();
+ }
+
+ if (!JsonToken.START_ARRAY.equals(token))
+ fail(parser, "The root-element must be an array!");
+
+ return new Spliterator<Object>()
+ {
+ @Override
+ public boolean tryAdvance(Consumer<? super Object> action)
+ {
+ try
+ {
+ JsonToken token = parser.nextToken();
+ if (token == null)
+ fail(parser, "Unexpected end of data!");
+ if (JsonToken.END_ARRAY.equals(token))
+ {
+ if (parser.nextToken() != null)
+ fail(parser, "unexpected data after parsed array");
+ return false;
+ }
+ action.accept(convertInternal(parser));
+ return true;
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ @Override
+ public Spliterator<Object> trySplit()
+ {
+ return null;
+ }
+
+ @Override
+ public long estimateSize()
+ {
+ return Long.MAX_VALUE;
+ }
+
+ @Override
+ public int characteristics()
+ {
+ return IMMUTABLE;
+ }
+ };
+ }
+
+ public static Stream<Object> getArrayStream(final JsonParser parser)
+ throws
+ IOException
+ {
+ return StreamSupport.stream(getArraySpliterator(parser), false);
+ }
+
+ 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 Spliterator<Entry<String, Object>> getObjectSpliterator(final JsonParser parser)
+ throws
+ IOException
+ {
+ JsonToken token = parser.nextToken();
+
+ if (token == null)
+ {
+ LOG.warn("empty input");
+ return Spliterators.emptySpliterator();
+ }
+
+ if (!JsonToken.START_OBJECT.equals(token))
+ fail(parser, "The root-element must be an object!");
+
+ return new Spliterator<Entry<String, Object>>()
+ {
+ @Override
+ public boolean tryAdvance(Consumer<? super Entry<String, Object>> action)
+ {
+ try
+ {
+ JsonToken token = parser.nextToken();
+ if (token == null)
+ fail(parser, "Unexpected end of data!");
+ if (JsonToken.END_OBJECT.equals(token))
+ {
+ if (parser.nextToken() != null)
+ fail(parser, "unexpected data after parsed object");
+ return false;
+ }
+ if (!JsonToken.FIELD_NAME.equals(token))
+ fail(parser, "expected a field-name");
+ final String key = parser.getText();
+ parser.nextToken();
+ final Object value = convertInternal(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)
+ {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ @Override
+ public Spliterator<Entry<String, Object>> trySplit()
+ {
+ return null;
+ }
+
+ @Override
+ public long estimateSize()
+ {
+ return Long.MAX_VALUE;
+ }
+
+ @Override
+ public int characteristics()
+ {
+ return IMMUTABLE;
+ }
+ };
+ }
+
+ public static Stream<Entry<String, Object>> getObjectStream(final JsonParser parser)
+ throws
+ IOException
+ {
+ return StreamSupport.stream(getObjectSpliterator(parser), false);
+ }
+
+ public static Iterator<Entry<String, Object>> getObjectIterator(
+ final JsonParser parser
+ )
+ throws
+ IOException
+ {
+ Spliterator<Entry<String, Object>> spliterator = getObjectSpliterator(parser);
+ return new Iterator<Entry<String, Object>>()
+ {
+ private Entry<String, Object> next = null;
+
+
+ @Override
+ public boolean hasNext()
+ {
+ if (next != null)
+ return true;
+
+ return spliterator.tryAdvance(new Consumer<Entry<String, Object>>()
+ {
+ @Override
+ public void accept(Entry<String, Object> e)
+ {
+ next = e;
+ }
+ });
+ }
+
+ @Override
+ public Entry<String, Object> next()
+ {
+ if (next == null && !hasNext())
+ throw new NoSuchElementException();
+ Entry<String, Object> e = next;
+ next = null;
+ return e;
+ }
+ };
+ }
+
+
+ public List<Object> convertArray(File file) throws Exception
+ {
+ return convertArray(factory.createParser(file));
+ }
+
+ public List<Object> convertArray(InputStream is) throws Exception
+ {
+ return convertArray(factory.createParser(is));
+ }
+
+ public List<Object> convertArray(Reader r) throws Exception
+ {
+ return convertArray(factory.createParser(r));
+ }
+
+ public List<Object> convertArray(String content) throws Exception
+ {
+ return convertArray(factory.createParser(content));
+ }
+
+ public List<Object> convertArray(URL url) throws Exception
+ {
+ return convertArray(factory.createParser(url));
+ }
+
+ public List<Object> convertArray(byte[] data) throws Exception
+ {
+ return convertArray(factory.createParser(data));
+ }
+
+ public List<Object> convertArray(char[] content) throws Exception
+ {
+ return convertArray(factory.createParser(content));
+ }
+
+ public List<Object> convertArray(byte[] data, int offset, int len)
+ throws
+ Exception
+ {
+ return convertArray(factory.createParser(data, offset, len));
+ }
+
+ public List<Object> convertArray(char[] content, int offset, int len)
+ throws
+ Exception
+ {
+ return convertArray(factory.createParser(content, offset, len));
+ }
+
+ public Map<String, Object> convertObject(File file) throws Exception
+ {
+ return convertObject(factory.createParser(file));
+ }
+
+ public Map<String, Object> convertObject(InputStream is) throws Exception
+ {
+ return convertObject(factory.createParser(is));
+ }
+
+ public Map<String, Object> convertObject(Reader r) throws Exception
+ {
+ return convertObject(factory.createParser(r));
+ }
+
+ public Map<String, Object> convertObject(String content) throws Exception
+ {
+ return convertObject(factory.createParser(content));
+ }
+
+ public Map<String, Object> convertObject(URL url) throws Exception
+ {
+ return convertObject(factory.createParser(url));
+ }
+
+ public Map<String, Object> convertObject(byte[] data) throws Exception
+ {
+ return convertObject(factory.createParser(data));
+ }
+
+ public Map<String, Object> convertObject(char[] content) throws Exception
+ {
+ return convertObject(factory.createParser(content));
+ }
+
+ public Map<String, Object> convertObject(byte[] data, int offset, int len)
+ throws
+ Exception
+ {
+ return convertObject(factory.createParser(data, offset, len));
+ }
+
+ public Map<String, Object> convertObject(char[] content, int offset, int len)
+ throws
+ Exception
+ {
+ return convertObject(factory.createParser(content, offset, len));
+ }
+
+ public Object convert(File file) throws Exception
+ {
+ return convert(factory.createParser(file));
+ }
+
+ public Object convert(InputStream is) throws Exception
+ {
+ return convert(factory.createParser(is));
+ }
+
+ public Object convert(Reader r) throws Exception
+ {
+ return convert(factory.createParser(r));
+ }
+
+ public Object convert(String content) throws Exception
+ {
+ return convert(factory.createParser(content));
+ }
+
+ public Object convert(URL url) throws Exception
+ {
+ return convert(factory.createParser(url));
+ }
+
+ public Object convert(byte[] data) throws Exception
+ {
+ return convert(factory.createParser(data));
+ }
+
+ public Object convert(char[] content) throws Exception
+ {
+ return convert(factory.createParser(content));
+ }
+
+ public Object convert(byte[] data, int offset, int len)
+ throws
+ Exception
+ {
+ return convert(factory.createParser(data, offset, len));
+ }
+
+ public Object convert(char[] content, int offset, int len)
+ throws
+ Exception
+ {
+ return convert(factory.createParser(content, offset, len));
+ }
+
+
+ static List<Object> convertArray(JsonParser parser) throws IOException
+ {
+ JsonToken token = parser.nextToken();
+
+ if (token == null)
+ {
+ LOG.warn("empty input");
+ return Collections.EMPTY_LIST;
+ }
+
+ if (!JsonToken.START_ARRAY.equals(token))
+ fail(parser, "The root-element must be an array!");
+
+ List<Object> array = convertArrayInternal(parser);
+
+ if (parser.nextToken() != null)
+ fail(parser, "unexpected data after parsed array");
+
+ return array;
+ }
+
+ static Map<String, Object> convertObject(JsonParser parser) throws IOException
+ {
+ JsonToken token = parser.nextToken();
+
+ if (token == null)
+ {
+ LOG.warn("empty input");
+ return Collections.EMPTY_MAP;
+ }
+
+ if (!JsonToken.START_OBJECT.equals(token))
+ fail(parser, "The root-element must be an object!");
+
+ Map<String, Object> object = convertObjectInternal(parser);
+
+ if (parser.nextToken() != null)
+ fail(parser, "unexpected data after parsed object");
+
+ return object;
+ }
+
+ static Object convert(JsonParser parser) throws IOException
+ {
+ JsonToken token = parser.nextToken();
+
+ if (token == null)
+ {
+ LOG.warn("empty input");
+ return null;
+ }
+
+ switch (token)
+ {
+ case START_ARRAY:
+ case START_OBJECT:
+ break;
+ default:
+ fail(parser, "The root-element must be either an object or an array!");
+ }
+
+ Object object = convertInternal(parser);
+
+ if (parser.nextToken() != null)
+ fail(parser, "unexpected data after parsed object");
+
+ return object;
+ }
+
+
+ static Object convertInternal(JsonParser parser) throws IOException
+ {
+ JsonToken token = parser.getCurrentToken();
+ if (token == null)
+ fail(parser, "unexpected EOF");
+
+ switch (token)
+ {
+ case VALUE_STRING: return parser.getText();
+ case VALUE_NUMBER_INT: return parser.getIntValue();
+ case VALUE_NUMBER_FLOAT: return parser.getDoubleValue();
+ case START_OBJECT: return convertObjectInternal(parser);
+ case START_ARRAY: return convertArrayInternal(parser);
+ case VALUE_TRUE: return Boolean.TRUE;
+ case VALUE_FALSE: return Boolean.FALSE;
+ case VALUE_NULL: return null;
+ }
+
+ fail(parser, "unexpected token " + token.toString());
+ return null; // << Will never be reached, because fail always throws an exception
+ }
+
+
+ static Map<String, Object> convertObjectInternal(JsonParser parser)
+ throws
+ IOException
+ {
+ JsonToken token = parser.nextToken();
+ if (token == null)
+ fail(parser, "unexpected EOF");
+
+ Map<String, Object> map = new LinkedHashMap<>();
+
+ while (!JsonToken.END_OBJECT.equals(token))
+ {
+ if (!JsonToken.FIELD_NAME.equals(token))
+ fail(parser, "expected a field-name");
+
+ String name = parser.getText();
+ parser.nextToken();
+ Object value = convertInternal(parser);
+ map.put(name, value);
+
+ token = parser.nextToken();
+ if (token == null)
+ fail(parser, "unexpected EOF");
+ }
+
+ return map;
+ }
+
+ static List<Object> convertArrayInternal(JsonParser parser) throws IOException
+ {
+ JsonToken token = parser.nextToken();
+ if (token == null)
+ fail(parser, "unexpected EOF");
+
+ List<Object> list = new LinkedList<>();
+
+ while (!JsonToken.END_ARRAY.equals(token))
+ {
+ list.add(convertInternal(parser));
+
+ token = parser.nextToken();
+ if (token == null)
+ fail(parser, "unexpected EOF");
+ }
+
+ return list;
+ }
+
+
+ static void fail(JsonParser parser, String message)
+ {
+ JsonLocation location = parser.getCurrentLocation();
+ LOG.error(
+ "{} at char-offset {} (line {}, column {})",
+ message,
+ location.getCharOffset(),
+ location.getLineNr(),
+ location.getColumnNr()
+ );
+ throw new IllegalArgumentException("Cannot parse JSON: " + message);
+ }
+}