X-Git-Url: https://juplo.de/gitweb/?p=simple-mapper;a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fde%2Fjuplo%2Fsimplemapper%2FSimpleMapper.java;fp=src%2Fmain%2Fjava%2Fde%2Fjuplo%2Fsimplemapper%2FSimpleMapper.java;h=f9143d0d87ab686c19441b66a7d68f4590132097;hp=0000000000000000000000000000000000000000;hb=fd93d60388fecb8ec83dc5c0a411bc1cbe3d1d67;hpb=13bc66491ff7d0524655dc01d9c9360e9147abd5 diff --git a/src/main/java/de/juplo/simplemapper/SimpleMapper.java b/src/main/java/de/juplo/simplemapper/SimpleMapper.java new file mode 100644 index 0000000..f9143d0 --- /dev/null +++ b/src/main/java/de/juplo/simplemapper/SimpleMapper.java @@ -0,0 +1,401 @@ +package de.juplo.simplemapper; + + +import com.fasterxml.jackson.core.JsonLocation; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import java.io.IOException; +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.function.Consumer; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + + +/** + * + * @author kai + */ +public abstract class SimpleMapper +{ + private static final Logger LOG = + LoggerFactory.getLogger(SimpleMapper.class); + + + public static Spliterator getArraySpliterator(final JsonParser parser) + throws + IOException + { + JsonToken token = parser.nextToken(); + + if (token == null) + return null; + + 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((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) + return null; + + 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((Entry e) -> { next = e; }); + } + + @Override + public Entry next() + { + if (next == null && !hasNext()) + throw new NoSuchElementException(); + Entry e = next; + next = null; + return e; + } + }; + } + + + public static List convertArray(JsonParser parser) throws IOException + { + JsonToken token = parser.nextToken(); + + if (token == null) + return null; + + 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; + } + + public static Map convertObject(JsonParser parser) throws IOException + { + JsonToken token = parser.nextToken(); + + if (token == null) + return null; + + 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; + } + + public static Object convert(JsonParser parser) throws IOException + { + JsonToken token = parser.nextToken(); + + if (token == null) + 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"); + return null; // << Will never be reached, because fail always throws an exception + } + + 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); + 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); + } +}