From 9c2a6accdf53e9861bd90b3710e6c2d1184c8f7b Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Sat, 31 Aug 2019 13:15:49 +0200 Subject: [PATCH] Rework JsonParserImpl to not depend anymore on jackson databind --- .../core/parsetools/impl/JsonEventImpl.java | 31 +---- .../core/parsetools/impl/JsonParserImpl.java | 128 ++++++++++++++---- .../vertx/core/parsetools/JsonParserTest.java | 8 +- 3 files changed, 113 insertions(+), 54 deletions(-) diff --git a/src/main/java/io/vertx/core/parsetools/impl/JsonEventImpl.java b/src/main/java/io/vertx/core/parsetools/impl/JsonEventImpl.java index e39fbd72d..350246419 100644 --- a/src/main/java/io/vertx/core/parsetools/impl/JsonEventImpl.java +++ b/src/main/java/io/vertx/core/parsetools/impl/JsonEventImpl.java @@ -12,16 +12,13 @@ package io.vertx.core.parsetools.impl; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.util.TokenBuffer; import io.vertx.core.buffer.Buffer; import io.vertx.core.json.DecodeException; -import io.vertx.core.json.Json; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; import io.vertx.core.json.impl.JacksonCodec; import io.vertx.core.parsetools.JsonEvent; import io.vertx.core.parsetools.JsonEventType; -import io.vertx.core.spi.json.JsonCodec; import java.time.Instant; import java.util.Base64; @@ -36,17 +33,11 @@ public class JsonEventImpl implements JsonEvent { private final JsonEventType type; private final String field; private final Object value; - private final TokenBuffer buffer; public JsonEventImpl(JsonEventType type, String field, Object value) { - this(type, field, value, null); - } - - public JsonEventImpl(JsonEventType type, String field, Object value, TokenBuffer buffer) { this.type = type; this.field = field; this.value = value; - this.buffer = buffer; } @Override @@ -96,27 +87,19 @@ public class JsonEventImpl implements JsonEvent { @Override public T mapTo(Class type) { - if (buffer != null) { - try { - return Json.mapper.readValue(buffer.asParser(), type); - } catch (Exception e) { - throw new DecodeException(e.getMessage()); - } - } else { - return JsonCodec.INSTANCE.fromValue(value, type); + try { + return JacksonCodec.INSTANCE.fromValue(value, type); + } catch (Exception e) { + throw new DecodeException(e.getMessage(), e); } } @Override public T mapTo(TypeReference type) { - if (buffer != null) { - try { - return Json.mapper.readValue(buffer.asParser(), type); - } catch (Exception e) { - throw new DecodeException(e.getMessage()); - } - } else { + try { return JacksonCodec.fromValue(value, type); + } catch (Exception e) { + throw new DecodeException(e.getMessage(), e); } } diff --git a/src/main/java/io/vertx/core/parsetools/impl/JsonParserImpl.java b/src/main/java/io/vertx/core/parsetools/impl/JsonParserImpl.java index e325b41da..c61a6e5b2 100644 --- a/src/main/java/io/vertx/core/parsetools/impl/JsonParserImpl.java +++ b/src/main/java/io/vertx/core/parsetools/impl/JsonParserImpl.java @@ -13,8 +13,10 @@ package io.vertx.core.parsetools.impl; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.core.ObjectCodec; +import com.fasterxml.jackson.core.base.ParserBase; +import com.fasterxml.jackson.core.io.IOContext; import com.fasterxml.jackson.core.json.async.NonBlockingJsonParser; -import com.fasterxml.jackson.databind.util.TokenBuffer; import io.vertx.core.Handler; import io.vertx.core.VertxException; import io.vertx.core.buffer.Buffer; @@ -29,6 +31,7 @@ import io.vertx.core.parsetools.JsonParser; import io.vertx.core.streams.ReadStream; import java.io.IOException; +import java.util.ArrayDeque; import java.util.List; import java.util.Map; @@ -279,7 +282,7 @@ public class JsonParserImpl implements JsonParser { if (objectHandler == null) { BufferingHandler handler = new BufferingHandler(); handler.handler = buffer -> { - handleEvent(new JsonEventImpl(JsonEventType.VALUE, currentField, new JsonObject(handler.convert(Map.class)), handler.buffer)); + handleEvent(new JsonEventImpl(JsonEventType.VALUE, currentField, new JsonObject(handler.convert(Map.class)))); }; objectHandler = handler; } @@ -300,18 +303,93 @@ public class JsonParserImpl implements JsonParser { if (arrayHandler == null) { BufferingHandler handler = new BufferingHandler(); handler.handler = buffer -> { - handleEvent(new JsonEventImpl(JsonEventType.VALUE, currentField, new JsonArray(handler.convert(List.class)), handler.buffer)); + handleEvent(new JsonEventImpl(JsonEventType.VALUE, currentField, new JsonArray(handler.convert(List.class)))); }; arrayHandler = handler; } return this; } + /** + * A parser implementation that feeds from a list of tokens instead of bytes. + */ + private static class TokenParser extends ParserBase { + + private ArrayDeque tokens = new ArrayDeque<>(); + private String text; + + private TokenParser(IOContext ctxt, int features) { + super(ctxt, features); + } + + @Override + public JsonToken nextToken() throws IOException { + if (tokens.isEmpty()) { + return JsonToken.NOT_AVAILABLE; + } + text = null; + _numTypesValid = NR_UNKNOWN; + _numberLong = 0L; + _numberDouble = 0L; + _currToken = (JsonToken) tokens.removeFirst(); + if (_currToken == JsonToken.FIELD_NAME) { + String field = (String) tokens.removeFirst(); + _parsingContext.setCurrentName(field); + text = field; + } else if (_currToken == JsonToken.VALUE_NUMBER_INT) { + Long v = (Long) tokens.removeFirst(); + _numTypesValid = NR_LONG; + _numberLong = v; + } else if (_currToken == JsonToken.VALUE_NUMBER_FLOAT) { + Double v = (Double) tokens.removeFirst(); + _numTypesValid = NR_DOUBLE; + _numberDouble = v; + } else if (_currToken == JsonToken.VALUE_STRING) { + text = (String) tokens.removeFirst(); + } + return _currToken; + } + + @Override + public String getText() { + return text; + } + + @Override + public char[] getTextCharacters() { + throw new UnsupportedOperationException(); + } + + @Override + public int getTextLength() { + throw new UnsupportedOperationException(); + } + + @Override + public int getTextOffset() { + throw new UnsupportedOperationException(); + } + + @Override + public ObjectCodec getCodec() { + throw new UnsupportedOperationException(); + } + + @Override + public void setCodec(ObjectCodec c) { + throw new UnsupportedOperationException(); + } + + @Override + protected void _closeInput() { + } + } + private class BufferingHandler implements Handler { Handler handler; int depth; - TokenBuffer buffer; + TokenParser buffer; @Override public void handle(JsonToken event) { @@ -320,46 +398,40 @@ public class JsonParserImpl implements JsonParser { case START_OBJECT: case START_ARRAY: if (depth++ == 0) { - buffer = new TokenBuffer(Json.mapper, false); - } - if (event == JsonToken.START_OBJECT) { - buffer.writeStartObject(); - } else { - buffer.writeStartArray(); + JsonFactory factory = new JsonFactory(); + buffer = new TokenParser(new IOContext(factory._getBufferRecycler(), this, true), com.fasterxml.jackson.core.JsonParser.Feature.collectDefaults()); } + buffer.tokens.add(event); break; case FIELD_NAME: - buffer.writeFieldName(parser.getCurrentName()); + buffer.tokens.add(event); + buffer.tokens.add(parser.currentName()); break; case VALUE_NUMBER_INT: - buffer.writeNumber(parser.getLongValue()); + buffer.tokens.add(event); + buffer.tokens.add(parser.getLongValue()); break; case VALUE_NUMBER_FLOAT: - buffer.writeNumber(parser.getDoubleValue()); + buffer.tokens.add(event); + buffer.tokens.add(parser.getDoubleValue()); break; case VALUE_STRING: - buffer.writeString(parser.getText()); - break; - case VALUE_TRUE: - buffer.writeBoolean(true); + buffer.tokens.add(event); + buffer.tokens.add(parser.getText()); break; case VALUE_FALSE: - buffer.writeBoolean(false); - break; + case VALUE_TRUE: case VALUE_NULL: - buffer.writeNull(); + buffer.tokens.add(event); break; case END_OBJECT: case END_ARRAY: - if (event == JsonToken.END_OBJECT) { - buffer.writeEndObject(); - } else { - buffer.writeEndArray(); - } + buffer.tokens.add(event); if (--depth == 0) { tokenHandler = JsonParserImpl.this::handleToken; - buffer.flush(); handler.handle(null); + buffer.close(); + buffer = null; } break; default: @@ -373,9 +445,9 @@ public class JsonParserImpl implements JsonParser { T convert(Class type) { try { - return Json.mapper.readValue(buffer.asParser(), type); + return Json.mapper.readValue(buffer, type); } catch (Exception e) { - throw new DecodeException(e.getMessage()); + throw new DecodeException(e.getMessage(), e); } } } diff --git a/src/test/java/io/vertx/core/parsetools/JsonParserTest.java b/src/test/java/io/vertx/core/parsetools/JsonParserTest.java index 28d777684..be967b1da 100644 --- a/src/test/java/io/vertx/core/parsetools/JsonParserTest.java +++ b/src/test/java/io/vertx/core/parsetools/JsonParserTest.java @@ -584,7 +584,9 @@ public class JsonParserTest { JsonParser parser = JsonParser.newParser(); List values = new ArrayList<>(); parser.arrayValueMode(); - parser.handler(event -> values.add(event.mapTo(LinkedList.class))); + parser.handler(event -> { + values.add(event.mapTo(LinkedList.class)); + }); parser.handle(new JsonArray().add(0).add(1).add(2).toBuffer()); assertEquals(Collections.singletonList(Arrays.asList(0L, 1L, 2L)), values); assertEquals(LinkedList.class, values.get(0).getClass()); @@ -598,7 +600,9 @@ public class JsonParserTest { assertEquals(Collections.emptyList(), values); assertEquals(1, errors.size()); try { - JsonParser.newParser().arrayValueMode().handler(event -> values.add(event.mapTo(TheObject.class))).write(Buffer.buffer("[]")).end(); + JsonParser.newParser().arrayValueMode().handler(event -> { + values.add(event.mapTo(TheObject.class)); + }).write(Buffer.buffer("[]")).end(); fail(); } catch (DecodeException expected) { }