From 1bb872d7797daf2488abbd066b8ff6f3642f275d Mon Sep 17 00:00:00 2001 From: Kai Moritz Date: Mon, 13 Jun 2016 14:52:51 +0200 Subject: [PATCH 1/1] Initial implementation of SimpleMapper --- .gitignore | 1 + pom.xml | 69 ++ .../java/de/juplo/jackson/SimpleMapper.java | 971 ++++++++++++++++++ 3 files changed, 1041 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/de/juplo/jackson/SimpleMapper.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a6f89c2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target/ \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..ec1fc3a --- /dev/null +++ b/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + + de.juplo.jackson + simple-mapper + 1.0-SNAPSHOT + + + + + 1.8 + + + UTF-8 + 1.8 + 1.8 + UTF-8 + + + + + + + com.fasterxml.jackson.core + jackson-annotations + + + com.fasterxml.jackson.core + jackson-core + + + com.fasterxml.jackson.core + jackson-databind + + + org.slf4j + slf4j-api + + + + + + junit + junit + test + + + ch.qos.logback + logback-classic + test + + + + + + + + + org.springframework.boot + spring-boot-dependencies + 1.3.5.RELEASE + pom + import + + + + + diff --git a/src/main/java/de/juplo/jackson/SimpleMapper.java b/src/main/java/de/juplo/jackson/SimpleMapper.java new file mode 100644 index 0000000..0426720 --- /dev/null +++ b/src/main/java/de/juplo/jackson/SimpleMapper.java @@ -0,0 +1,971 @@ +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 getArraySpliterator(File file) + throws + IOException + { + return getArraySpliterator(factory.createParser(file)); + } + + public Spliterator getArraySpliterator(InputStream is) + throws + IOException + { + return getArraySpliterator(factory.createParser(is)); + } + + public Spliterator getArraySpliterator(Reader r) + throws + IOException + { + return getArraySpliterator(factory.createParser(r)); + } + + public Spliterator getArraySpliterator(String content) + throws + IOException + { + return getArraySpliterator(factory.createParser(content)); + } + + public Spliterator getArraySpliterator(URL url) + throws + IOException + { + return getArraySpliterator(factory.createParser(url)); + } + + public Spliterator getArraySpliterator(byte[] data) + throws + IOException + { + return getArraySpliterator(factory.createParser(data)); + } + + public Spliterator getArraySpliterator(char[] content) + throws + IOException + { + return getArraySpliterator(factory.createParser(content)); + } + + public Spliterator getArraySpliterator(byte[] data, int offset, int len) + throws + IOException + { + return getArraySpliterator(factory.createParser(data, offset, len)); + } + + public Spliterator getArraySpliterator(char[] data, int offset, int len) + throws + IOException + { + return getArraySpliterator(factory.createParser(data, offset, len)); + } + + public Stream getArrayStream(File file) + throws + IOException + { + return getArrayStream(factory.createParser(file)); + } + + public Stream getArrayStream(InputStream is) + throws + IOException + { + return getArrayStream(factory.createParser(is)); + } + + public Stream getArrayStream(Reader r) + throws + IOException + { + return getArrayStream(factory.createParser(r)); + } + + public Stream getArrayStream(String content) + throws + IOException + { + return getArrayStream(factory.createParser(content)); + } + + public Stream getArrayStream(URL url) + throws + IOException + { + return getArrayStream(factory.createParser(url)); + } + + public Stream getArrayStream(byte[] data) + throws + IOException + { + return getArrayStream(factory.createParser(data)); + } + + public Stream getArrayStream(char[] content) + throws + IOException + { + return getArrayStream(factory.createParser(content)); + } + + public Stream getArrayStream(byte[] data, int offset, int len) + throws + IOException + { + return getArrayStream(factory.createParser(data, offset, len)); + } + + public Stream getArrayStream(char[] data, int offset, int len) + throws + IOException + { + return getArrayStream(factory.createParser(data, offset, len)); + } + + public Iterator getArrayIterator(File file) + throws + IOException + { + return getArrayIterator(factory.createParser(file)); + } + + public Iterator getArrayIterator(InputStream is) + throws + IOException + { + return getArrayIterator(factory.createParser(is)); + } + + public Iterator getArrayIterator(Reader r) + throws + IOException + { + return getArrayIterator(factory.createParser(r)); + } + + public Iterator getArrayIterator(String content) + throws + IOException + { + return getArrayIterator(factory.createParser(content)); + } + + public Iterator getArrayIterator(URL url) + throws + IOException + { + return getArrayIterator(factory.createParser(url)); + } + + public Iterator getArrayIterator(byte[] data) + throws + IOException + { + return getArrayIterator(factory.createParser(data)); + } + + public Iterator getArrayIterator(char[] content) + throws + IOException + { + return getArrayIterator(factory.createParser(content)); + } + + public Iterator getArrayIterator(byte[] data, int offset, int len) + throws + IOException + { + return getArrayIterator(factory.createParser(data, offset, len)); + } + + public Iterator getArrayIterator(char[] data, int offset, int len) + throws + IOException + { + return getArrayIterator(factory.createParser(data, offset, len)); + } + + + public Spliterator> getObjectSpliterator(File file) + throws + IOException + { + return getObjectSpliterator(factory.createParser(file)); + } + + public Spliterator> getObjectSpliterator(InputStream is) + throws + IOException + { + return getObjectSpliterator(factory.createParser(is)); + } + + public Spliterator> getObjectSpliterator(Reader r) + throws + IOException + { + return getObjectSpliterator(factory.createParser(r)); + } + + public Spliterator> getObjectSpliterator(String content) + throws + IOException + { + return getObjectSpliterator(factory.createParser(content)); + } + + public Spliterator> getObjectSpliterator(URL url) + throws + IOException + { + return getObjectSpliterator(factory.createParser(url)); + } + + public Spliterator> getObjectSpliterator(byte[] data) + throws + IOException + { + return getObjectSpliterator(factory.createParser(data)); + } + + public Spliterator> getObjectSpliterator(char[] content) + throws + IOException + { + return getObjectSpliterator(factory.createParser(content)); + } + + public Spliterator> getObjectSpliterator(byte[] data, int offset, int len) + throws + IOException + { + return getObjectSpliterator(factory.createParser(data, offset, len)); + } + + public Spliterator> getObjectSpliterator(char[] data, int offset, int len) + throws + IOException + { + return getObjectSpliterator(factory.createParser(data, offset, len)); + } + + public Stream> getObjectStream(File file) + throws + IOException + { + return getObjectStream(factory.createParser(file)); + } + + public Stream> getObjectStream(InputStream is) + throws + IOException + { + return getObjectStream(factory.createParser(is)); + } + + public Stream> getObjectStream(Reader r) + throws + IOException + { + return getObjectStream(factory.createParser(r)); + } + + public Stream> getObjectStream(String content) + throws + IOException + { + return getObjectStream(factory.createParser(content)); + } + + public Stream> getObjectStream(URL url) + throws + IOException + { + return getObjectStream(factory.createParser(url)); + } + + public Stream> getObjectStream(byte[] data) + throws + IOException + { + return getObjectStream(factory.createParser(data)); + } + + public Stream> getObjectStream(char[] content) + throws + IOException + { + return getObjectStream(factory.createParser(content)); + } + + public Stream> getObjectStream(byte[] data, int offset, int len) + throws + IOException + { + return getObjectStream(factory.createParser(data, offset, len)); + } + + public Stream> getObjectStream(char[] data, int offset, int len) + throws + IOException + { + return getObjectStream(factory.createParser(data, offset, len)); + } + + public Iterator> getObjectIterator(File file) + throws + IOException + { + return getObjectIterator(factory.createParser(file)); + } + + public Iterator> getObjectIterator(InputStream is) + throws + IOException + { + return getObjectIterator(factory.createParser(is)); + } + + public Iterator> getObjectIterator(Reader r) + throws + IOException + { + return getObjectIterator(factory.createParser(r)); + } + + public Iterator> getObjectIterator(String content) + throws + IOException + { + return getObjectIterator(factory.createParser(content)); + } + + public Iterator> getObjectIterator(URL url) + throws + IOException + { + return getObjectIterator(factory.createParser(url)); + } + + public Iterator> getObjectIterator(byte[] data) + throws + IOException + { + return getObjectIterator(factory.createParser(data)); + } + + public Iterator> getObjectIterator(char[] content) + throws + IOException + { + return getObjectIterator(factory.createParser(content)); + } + + public Iterator> getObjectIterator(byte[] data, int offset, int len) + throws + IOException + { + return getObjectIterator(factory.createParser(data, offset, len)); + } + + public Iterator> getObjectIterator(char[] data, int offset, int len) + throws + IOException + { + return getObjectIterator(factory.createParser(data, offset, len)); + } + + + public static Spliterator 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() + { + @Override + public boolean tryAdvance(Consumer 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 trySplit() + { + return null; + } + + @Override + public long estimateSize() + { + return Long.MAX_VALUE; + } + + @Override + public int characteristics() + { + return IMMUTABLE; + } + }; + } + + public static Stream getArrayStream(final JsonParser parser) + throws + IOException + { + return StreamSupport.stream(getArraySpliterator(parser), false); + } + + public static Iterator getArrayIterator(final JsonParser parser) + throws + IOException + { + Spliterator spliterator = getArraySpliterator(parser); + return new Iterator() + { + private Object next = null; + + + @Override + public boolean hasNext() + { + if (next != null) + return true; + + return spliterator.tryAdvance(new Consumer() + { + @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> 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>() + { + @Override + public boolean tryAdvance(Consumer> 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() + { + @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> trySplit() + { + return null; + } + + @Override + public long estimateSize() + { + return Long.MAX_VALUE; + } + + @Override + public int characteristics() + { + return IMMUTABLE; + } + }; + } + + public static Stream> getObjectStream(final JsonParser parser) + throws + IOException + { + return StreamSupport.stream(getObjectSpliterator(parser), false); + } + + public static Iterator> getObjectIterator( + final JsonParser parser + ) + throws + IOException + { + Spliterator> spliterator = getObjectSpliterator(parser); + return new Iterator>() + { + private Entry next = null; + + + @Override + public boolean hasNext() + { + if (next != null) + return true; + + return spliterator.tryAdvance(new Consumer>() + { + @Override + public void accept(Entry e) + { + next = e; + } + }); + } + + @Override + public Entry next() + { + if (next == null && !hasNext()) + throw new NoSuchElementException(); + Entry e = next; + next = null; + return e; + } + }; + } + + + public List convertArray(File file) throws Exception + { + return convertArray(factory.createParser(file)); + } + + public List convertArray(InputStream is) throws Exception + { + return convertArray(factory.createParser(is)); + } + + public List convertArray(Reader r) throws Exception + { + return convertArray(factory.createParser(r)); + } + + public List convertArray(String content) throws Exception + { + return convertArray(factory.createParser(content)); + } + + public List convertArray(URL url) throws Exception + { + return convertArray(factory.createParser(url)); + } + + public List convertArray(byte[] data) throws Exception + { + return convertArray(factory.createParser(data)); + } + + public List convertArray(char[] content) throws Exception + { + return convertArray(factory.createParser(content)); + } + + public List convertArray(byte[] data, int offset, int len) + throws + Exception + { + return convertArray(factory.createParser(data, offset, len)); + } + + public List convertArray(char[] content, int offset, int len) + throws + Exception + { + return convertArray(factory.createParser(content, offset, len)); + } + + public Map convertObject(File file) throws Exception + { + return convertObject(factory.createParser(file)); + } + + public Map convertObject(InputStream is) throws Exception + { + return convertObject(factory.createParser(is)); + } + + public Map convertObject(Reader r) throws Exception + { + return convertObject(factory.createParser(r)); + } + + public Map convertObject(String content) throws Exception + { + return convertObject(factory.createParser(content)); + } + + public Map convertObject(URL url) throws Exception + { + return convertObject(factory.createParser(url)); + } + + public Map convertObject(byte[] data) throws Exception + { + return convertObject(factory.createParser(data)); + } + + public Map convertObject(char[] content) throws Exception + { + return convertObject(factory.createParser(content)); + } + + public Map convertObject(byte[] data, int offset, int len) + throws + Exception + { + return convertObject(factory.createParser(data, offset, len)); + } + + public Map 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 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 array = convertArrayInternal(parser); + + if (parser.nextToken() != null) + fail(parser, "unexpected data after parsed array"); + + return array; + } + + static Map 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 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 convertObjectInternal(JsonParser parser) + throws + IOException + { + JsonToken token = parser.nextToken(); + if (token == null) + fail(parser, "unexpected EOF"); + + Map 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 convertArrayInternal(JsonParser parser) throws IOException + { + JsonToken token = parser.nextToken(); + if (token == null) + fail(parser, "unexpected EOF"); + + List 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); + } +} -- 2.20.1