From 7b34ff20fa4ae575cdd0f0a5a26ca4110a9e7878 Mon Sep 17 00:00:00 2001 From: asomov Date: Thu, 10 May 2018 20:32:17 +0200 Subject: [PATCH 1/6] Introduce SnakeYAML engine --- yaml/pom.xml | 6 +- .../dataformat/yaml/WriterWrapper.java | 41 +++++++ .../jackson/dataformat/yaml/YAMLFactory.java | 4 +- .../dataformat/yaml/YAMLGenerator.java | 99 ++++++++-------- .../jackson/dataformat/yaml/YAMLParser.java | 106 ++++++++++-------- .../dataformat/yaml/snakeyaml/error/Mark.java | 18 +-- .../snakeyaml/error/MarkedYAMLException.java | 6 +- .../yaml/snakeyaml/error/YAMLException.java | 4 +- .../yaml/ExceptionConversionTest.java | 2 +- 9 files changed, 175 insertions(+), 111 deletions(-) create mode 100644 yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/WriterWrapper.java diff --git a/yaml/pom.xml b/yaml/pom.xml index 363c556cb..0c1bac228 100644 --- a/yaml/pom.xml +++ b/yaml/pom.xml @@ -28,9 +28,9 @@ - org.yaml - snakeyaml - 1.19 + org.snakeyaml + snakeyaml-engine + 0.1-SNAPSHOT diff --git a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/WriterWrapper.java b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/WriterWrapper.java new file mode 100644 index 000000000..51a9f3cd7 --- /dev/null +++ b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/WriterWrapper.java @@ -0,0 +1,41 @@ +package com.fasterxml.jackson.dataformat.yaml; + +import java.io.IOException; +import java.io.Writer; + +import org.snakeyaml.engine.api.StreamDataWriter; + +public class WriterWrapper implements StreamDataWriter { + private final Writer _writer; + + public WriterWrapper(Writer _writer) { + this._writer = _writer; + } + + @Override + public void flush() { + try { + _writer.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void write(String str) { + try { + _writer.write(str); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void write(String str, int off, int len) { + try { + _writer.write(str, off, len); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLFactory.java b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLFactory.java index d3fd8b6da..81184d27a 100644 --- a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLFactory.java +++ b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLFactory.java @@ -3,7 +3,7 @@ import java.io.*; import java.nio.charset.Charset; -import org.yaml.snakeyaml.DumperOptions; +import org.snakeyaml.engine.common.SpecVersion; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.base.TextualTSFactory; @@ -43,7 +43,7 @@ public class YAMLFactory /********************************************************************** */ - protected DumperOptions.Version _version; + protected SpecVersion _version; /** * Default constructor used to create factory instances. diff --git a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLGenerator.java b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLGenerator.java index c86f5e75e..4582e0175 100644 --- a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLGenerator.java +++ b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLGenerator.java @@ -6,13 +6,27 @@ import java.util.Arrays; import java.util.Collections; import java.util.Map; +import java.util.Optional; import java.util.regex.Pattern; -import org.yaml.snakeyaml.DumperOptions; -import org.yaml.snakeyaml.DumperOptions.FlowStyle; -import org.yaml.snakeyaml.emitter.Emitter; -import org.yaml.snakeyaml.events.*; -import org.yaml.snakeyaml.nodes.Tag; +import org.snakeyaml.engine.api.DumpSettings; +import org.snakeyaml.engine.common.Anchor; +import org.snakeyaml.engine.common.FlowStyle; +import org.snakeyaml.engine.common.ScalarStyle; +import org.snakeyaml.engine.common.SpecVersion; +import org.snakeyaml.engine.emitter.Emitter; +import org.snakeyaml.engine.events.AliasEvent; +import org.snakeyaml.engine.events.DocumentEndEvent; +import org.snakeyaml.engine.events.DocumentStartEvent; +import org.snakeyaml.engine.events.ImplicitTuple; +import org.snakeyaml.engine.events.MappingEndEvent; +import org.snakeyaml.engine.events.MappingStartEvent; +import org.snakeyaml.engine.events.ScalarEvent; +import org.snakeyaml.engine.events.SequenceEndEvent; +import org.snakeyaml.engine.events.SequenceStartEvent; +import org.snakeyaml.engine.events.StreamEndEvent; +import org.snakeyaml.engine.events.StreamStartEvent; +import org.snakeyaml.engine.nodes.Tag; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.base.GeneratorBase; @@ -159,23 +173,23 @@ private Feature(boolean defaultState) { protected Writer _writer; - protected DumperOptions _outputOptions; + protected DumpSettings _outputOptions; // for field names, leave out quotes - private final static Character STYLE_NAME = null; + private final static ScalarStyle STYLE_NAME = ScalarStyle.PLAIN; // numbers, booleans, should use implicit - private final static Character STYLE_SCALAR = null; + private final static ScalarStyle STYLE_SCALAR = ScalarStyle.PLAIN; // Strings quoted for fun - private final static Character STYLE_QUOTED = Character.valueOf('"'); + private final static ScalarStyle STYLE_QUOTED = ScalarStyle.DOUBLE_QUOTED; // Strings in literal (block) style - private final static Character STYLE_LITERAL = Character.valueOf('|'); + private final static ScalarStyle STYLE_LITERAL = ScalarStyle.LITERAL; // Which flow style to use for Base64? Maybe basic quoted? // 29-Nov-2017, tatu: Actually SnakeYAML uses block style so: - private final static Character STYLE_BASE64 = STYLE_LITERAL; + private final static ScalarStyle STYLE_BASE64 = STYLE_LITERAL; - private final static Character STYLE_PLAIN = null; + private final static ScalarStyle STYLE_PLAIN = ScalarStyle.PLAIN; /* /********************************************************** @@ -206,7 +220,7 @@ private Feature(boolean defaultState) { public YAMLGenerator(ObjectWriteContext writeContext, IOContext ioCtxt, int generatorFeatures, int yamlFeatures, Writer out, - org.yaml.snakeyaml.DumperOptions.Version version) + SpecVersion version) throws IOException { super(writeContext, generatorFeatures); @@ -216,22 +230,22 @@ public YAMLGenerator(ObjectWriteContext writeContext, IOContext ioCtxt, _outputOptions = buildDumperOptions(generatorFeatures, yamlFeatures, version); - _emitter = new Emitter(_writer, _outputOptions); + _emitter = new Emitter( _outputOptions, new WriterWrapper(_writer)); // should we start output now, or try to defer? - _emitter.emit(new StreamStartEvent(null, null)); + _emitter.emit(new StreamStartEvent()); Map noTags = Collections.emptyMap(); boolean startMarker = Feature.WRITE_DOC_START_MARKER.enabledIn(yamlFeatures); - _emitter.emit(new DocumentStartEvent(null, null, startMarker, - version, // for 1.10 was: ((version == null) ? null : version.getArray()), + _emitter.emit(new DocumentStartEvent(startMarker, Optional.empty(), + // for 1.10 was: ((version == null) ? null : version.getArray()), noTags)); } - protected DumperOptions buildDumperOptions(int jsonFeatures, int yamlFeatures, - org.yaml.snakeyaml.DumperOptions.Version version) + protected DumpSettings buildDumperOptions(int jsonFeatures, int yamlFeatures, + SpecVersion version) { - DumperOptions opt = new DumperOptions(); + DumpSettings opt = new DumpSettings(); // would we want canonical? if (Feature.CANONICAL_OUTPUT.enabledIn(_formatFeatures)) { opt.setCanonical(true); @@ -410,8 +424,8 @@ public final void flush() throws IOException public void close() throws IOException { if (!isClosed()) { - _emitter.emit(new DocumentEndEvent(null, null, false)); - _emitter.emit(new StreamEndEvent(null, null)); + _emitter.emit(new DocumentEndEvent( false)); + _emitter.emit(new StreamEndEvent()); super.close(); _writer.close(); } @@ -428,15 +442,15 @@ public final void writeStartArray() throws IOException { _verifyValueWrite("start an array"); _outputContext = _outputContext.createChildArrayContext(); - Boolean style = _outputOptions.getDefaultFlowStyle().getStyleBoolean(); + FlowStyle style = _outputOptions.getDefaultFlowStyle(); String yamlTag = _typeId; boolean implicit = (yamlTag == null); - String anchor = _objectId; - if (anchor != null) { + Optional anchor = Optional.ofNullable(_objectId).map(s -> new Anchor(s)); + if (anchor.isPresent()) { _objectId = null; } - _emitter.emit(new SequenceStartEvent(anchor, yamlTag, - implicit, null, null, style)); + _emitter.emit(new SequenceStartEvent(anchor, Optional.ofNullable(yamlTag), + implicit, style)); } @Override @@ -448,7 +462,7 @@ public final void writeEndArray() throws IOException // just to make sure we don't "leak" type ids _typeId = null; _outputContext = _outputContext.getParent(); - _emitter.emit(new SequenceEndEvent(null, null)); + _emitter.emit(new SequenceEndEvent()); } @Override @@ -456,15 +470,14 @@ public final void writeStartObject() throws IOException { _verifyValueWrite("start an object"); _outputContext = _outputContext.createChildObjectContext(); - Boolean style = _outputOptions.getDefaultFlowStyle().getStyleBoolean(); + FlowStyle style = _outputOptions.getDefaultFlowStyle(); String yamlTag = _typeId; boolean implicit = (yamlTag == null); - String anchor = _objectId; - if (anchor != null) { + Optional anchor = Optional.ofNullable(_objectId).map(s -> new Anchor(s)); + if (anchor.isPresent()) { _objectId = null; } - _emitter.emit(new MappingStartEvent(anchor, yamlTag, - implicit, null, null, style)); + _emitter.emit(new MappingStartEvent(anchor, Optional.ofNullable(yamlTag), implicit, style)); } @Override @@ -476,7 +489,7 @@ public final void writeEndObject() throws IOException // just to make sure we don't "leak" type ids _typeId = null; _outputContext = _outputContext.getParent(); - _emitter.emit(new MappingEndEvent(null, null)); + _emitter.emit(new MappingEndEvent()); } /* @@ -493,7 +506,7 @@ public void writeString(String text) throws IOException,JsonGenerationException return; } _verifyValueWrite("write String value"); - Character style = STYLE_QUOTED; + ScalarStyle style = STYLE_QUOTED; if (Feature.MINIMIZE_QUOTES.enabledIn(_formatFeatures) && !isBooleanContent(text)) { // If this string could be interpreted as a number, it must be quoted. if (Feature.ALWAYS_QUOTE_NUMBERS_AS_STRINGS.enabledIn(_formatFeatures) @@ -723,7 +736,7 @@ public void writeObjectRef(Object id) throws IOException { _verifyValueWrite("write Object reference"); - AliasEvent evt = new AliasEvent(String.valueOf(id), null, null); + AliasEvent evt = new AliasEvent(Optional.of(String.valueOf(id)).map(s -> new Anchor(s))); _emitter.emit(evt); } @@ -768,7 +781,7 @@ protected void _releaseBuffers() { // ... and sometimes we specifically DO want explicit tag: private final static ImplicitTuple EXPLICIT_TAGS = new ImplicitTuple(false, false); - protected void _writeScalar(String value, String type, Character style) throws IOException + protected void _writeScalar(String value, String type, ScalarStyle style) throws IOException { _emitter.emit(_scalarEvent(value, style)); } @@ -782,23 +795,21 @@ private void _writeScalarBinary(Base64Variant b64variant, b64variant = Base64Variants.MIME; } String encoded = b64variant.encode(data); - _emitter.emit(new ScalarEvent(null, TAG_BINARY, EXPLICIT_TAGS, encoded, - null, null, STYLE_BASE64)); + _emitter.emit(new ScalarEvent(Optional.empty(), Optional.ofNullable(TAG_BINARY), EXPLICIT_TAGS, encoded, STYLE_BASE64)); } - protected ScalarEvent _scalarEvent(String value, Character style) + protected ScalarEvent _scalarEvent(String value, ScalarStyle style) { String yamlTag = _typeId; if (yamlTag != null) { _typeId = null; } - String anchor = _objectId; - if (anchor != null) { + Optional anchor = Optional.ofNullable(_objectId).map(s -> new Anchor(s)); + if (anchor.isPresent()) { _objectId = null; } // 29-Nov-2017, tatu: Not 100% sure why we don't force explicit tags for // type id, but trying to do so seems to double up tag output... - return new ScalarEvent(anchor, yamlTag, NO_TAGS, value, - null, null, style); + return new ScalarEvent(anchor, Optional.ofNullable(yamlTag), NO_TAGS, value, style); } } diff --git a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java index 5cbc95551..7490dabbf 100644 --- a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java +++ b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java @@ -3,15 +3,24 @@ import java.io.*; import java.math.BigDecimal; import java.math.BigInteger; +import java.util.Optional; import java.util.regex.Pattern; -import org.yaml.snakeyaml.error.Mark; -import org.yaml.snakeyaml.events.*; -import org.yaml.snakeyaml.nodes.NodeId; -import org.yaml.snakeyaml.nodes.Tag; -import org.yaml.snakeyaml.parser.ParserImpl; -import org.yaml.snakeyaml.reader.StreamReader; -import org.yaml.snakeyaml.resolver.Resolver; +import org.snakeyaml.engine.api.LoadSettings; +import org.snakeyaml.engine.common.Anchor; +import org.snakeyaml.engine.events.AliasEvent; +import org.snakeyaml.engine.events.CollectionStartEvent; +import org.snakeyaml.engine.events.Event; +import org.snakeyaml.engine.events.MappingStartEvent; +import org.snakeyaml.engine.events.NodeEvent; +import org.snakeyaml.engine.events.ScalarEvent; +import org.snakeyaml.engine.exceptions.Mark; +import org.snakeyaml.engine.nodes.NodeType; +import org.snakeyaml.engine.nodes.Tag; +import org.snakeyaml.engine.parser.ParserImpl; +import org.snakeyaml.engine.resolver.JsonScalarResolver; +import org.snakeyaml.engine.resolver.ScalarResolver; +import org.snakeyaml.engine.scanner.StreamReader; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.base.ParserBase; @@ -93,7 +102,7 @@ private Feature(boolean defaultState) { protected final Reader _reader; protected final ParserImpl _yamlParser; - protected final Resolver _yamlResolver = new Resolver(); + protected final ScalarResolver _yamlResolver = new JsonScalarResolver(); /* /********************************************************************** @@ -132,7 +141,7 @@ private Feature(boolean defaultState) { * Anchor for the value that parser currently points to: in case of * structured types, value whose first token current token is. */ - protected String _currentAnchor; + protected Optional _currentAnchor; /* /********************************************************************** @@ -146,7 +155,8 @@ public YAMLParser(ObjectReadContext readCtxt, IOContext ioCtxt, super(readCtxt, ioCtxt, parserFeatures); // _formatFeatures = formatFeatures; _reader = reader; - _yamlParser = new ParserImpl(new StreamReader(reader)); + LoadSettings settings = new LoadSettings();//TODO use parserFeatures + _yamlParser = new ParserImpl(new StreamReader(reader, settings), settings); } /* @@ -234,12 +244,13 @@ public JsonLocation getCurrentLocation() { return _locationFor(_lastEvent.getEndMark()); } - protected JsonLocation _locationFor(Mark m) + protected JsonLocation _locationFor(Optional option) { - if (m == null) { + if (!option.isPresent()) { return new JsonLocation(_ioContext.getSourceReference(), -1, -1, -1); } + Mark m = option.get(); return new JsonLocation(_ioContext.getSourceReference(), -1, m.getLine() + 1, // from 0- to 1-based @@ -260,19 +271,19 @@ public JsonToken nextToken() throws IOException { _currentIsAlias = false; _binaryValue = null; - _currentAnchor = null; + _currentAnchor = Optional.empty(); if (_closed) { return null; } - while (true) { + while (_yamlParser.hasNext()) { Event evt; try { - evt = _yamlParser.getEvent(); - } catch (org.yaml.snakeyaml.error.YAMLException e) { - if (e instanceof org.yaml.snakeyaml.error.MarkedYAMLException) { + evt = _yamlParser.next(); + } catch (org.snakeyaml.engine.exceptions.YamlEngineException e) { + if (e instanceof org.snakeyaml.engine.exceptions.MarkedYamlEngineException) { throw com.fasterxml.jackson.dataformat.yaml.snakeyaml.error.MarkedYAMLException.from - (this, (org.yaml.snakeyaml.error.MarkedYAMLException) e); + (this, (org.snakeyaml.engine.exceptions.MarkedYamlEngineException) e); } throw com.fasterxml.jackson.dataformat.yaml.snakeyaml.error.YAMLException.from(this, e); } @@ -286,9 +297,9 @@ public JsonToken nextToken() throws IOException * fact that we are in Object context... */ if (_parsingContext.inObject() && _currToken != JsonToken.FIELD_NAME) { - if (!evt.is(Event.ID.Scalar)) { + if (!evt.isEvent(Event.ID.Scalar)) { // end is fine - if (evt.is(Event.ID.MappingEnd)) { + if (evt.isEvent(Event.ID.MappingEnd)) { if (!_parsingContext.inObject()) { // sanity check is optional, but let's do it for now _reportMismatchedEndMarker('}', ']'); } @@ -304,33 +315,35 @@ public JsonToken nextToken() throws IOException _currentAnchor = scalar.getAnchor(); return (_currToken = JsonToken.FIELD_NAME); } - // Ugh. Why not expose id, to be able to Switch? + // TODO Ugh. Why not expose id, to be able to Switch? // scalar values are probably the commonest: - if (evt.is(Event.ID.Scalar)) { + if (evt.isEvent(Event.ID.Scalar)) { JsonToken t = _decodeScalar((ScalarEvent) evt); _currToken = t; return t; } // followed by maps, then arrays - if (evt.is(Event.ID.MappingStart)) { - Mark m = evt.getStartMark(); + if (evt.isEvent(Event.ID.MappingStart)) { + Optional m = evt.getStartMark(); MappingStartEvent map = (MappingStartEvent) evt; _currentAnchor = map.getAnchor(); - _parsingContext = _parsingContext.createChildObjectContext(m.getLine(), m.getColumn()); + _parsingContext = _parsingContext.createChildObjectContext( + m.map(mark -> mark.getLine()).orElse(0), m.map(mark -> mark.getColumn()).orElse(0)); return (_currToken = JsonToken.START_OBJECT); } - if (evt.is(Event.ID.MappingEnd)) { // actually error; can not have map-end here + if (evt.isEvent(Event.ID.MappingEnd)) { // actually error; can not have map-end here _reportError("Not expecting END_OBJECT but a value"); } - if (evt.is(Event.ID.SequenceStart)) { - Mark m = evt.getStartMark(); + if (evt.isEvent(Event.ID.SequenceStart)) { + Optional m = evt.getStartMark(); _currentAnchor = ((NodeEvent)evt).getAnchor(); - _parsingContext = _parsingContext.createChildArrayContext(m.getLine(), m.getColumn()); + _parsingContext = _parsingContext.createChildArrayContext( + m.map(mark -> mark.getLine()).orElse(0), m.map(mark -> mark.getColumn()).orElse(0)); return (_currToken = JsonToken.START_ARRAY); } - if (evt.is(Event.ID.SequenceEnd)) { + if (evt.isEvent(Event.ID.SequenceEnd)) { if (!_parsingContext.inArray()) { // sanity check is optional, but let's do it for now _reportMismatchedEndMarker(']', '}'); } @@ -340,34 +353,36 @@ public JsonToken nextToken() throws IOException // after this, less common tokens: - if (evt.is(Event.ID.DocumentEnd)) { + if (evt.isEvent(Event.ID.DocumentEnd)) { // [dataformat-yaml#72]: logical end of doc; fine. Two choices; either skip, // or return null as marker (but do NOT close). Earlier returned `null`, but // to allow multi-document reading should actually just skip. // return (_currToken = null); continue; } - if (evt.is(Event.ID.DocumentStart)) { + if (evt.isEvent(Event.ID.DocumentStart)) { // DocumentStartEvent dd = (DocumentStartEvent) evt; // does this matter? Shouldn't, should it? continue; } - if (evt.is(Event.ID.Alias)) { + if (evt.isEvent(Event.ID.Alias)) { AliasEvent alias = (AliasEvent) evt; _currentIsAlias = true; - _textValue = alias.getAnchor(); + _textValue = alias.getAlias().getAnchor(); _cleanedTextValue = null; // for now, nothing to do: in future, maybe try to expose as ObjectIds? return (_currToken = JsonToken.VALUE_STRING); } - if (evt.is(Event.ID.StreamEnd)) { // end-of-input; force closure + if (evt.isEvent(Event.ID.StreamEnd)) { // end-of-input; force closure close(); return (_currToken = null); } - if (evt.is(Event.ID.StreamStart)) { // useless, skip + if (evt.isEvent(Event.ID.StreamStart)) { // useless, skip continue; } } + //TODO what should be thrown here ? + throw new RuntimeException("Unexpected events."); } protected JsonToken _decodeScalar(ScalarEvent scalar) throws IOException @@ -376,11 +391,11 @@ protected JsonToken _decodeScalar(ScalarEvent scalar) throws IOException _textValue = value; _cleanedTextValue = null; // we may get an explicit tag, if so, use for corroborating... - String typeTag = scalar.getTag(); + Optional typeTagOptional = scalar.getTag(); final int len = value.length(); - if (typeTag == null || typeTag.equals("!")) { // no, implicit - Tag nodeTag = _yamlResolver.resolve(NodeId.scalar, value, scalar.getImplicit().canOmitTagInPlainScalar()); + if (!typeTagOptional.isPresent() || typeTagOptional.get().equals("!")) { // no, implicit + Tag nodeTag = _yamlResolver.resolve(value, scalar.getImplicit().canOmitTagInPlainScalar()); if (nodeTag == Tag.STR) { return JsonToken.VALUE_STRING; } @@ -403,6 +418,7 @@ protected JsonToken _decodeScalar(ScalarEvent scalar) throws IOException return JsonToken.VALUE_STRING; } } else { // yes, got type tag + String typeTag = typeTagOptional.get(); if (typeTag.startsWith("tag:yaml.org,2002:")) { typeTag = typeTag.substring("tag:yaml.org,2002:".length()); if (typeTag.contains(",")) { @@ -447,6 +463,7 @@ protected JsonToken _decodeScalar(ScalarEvent scalar) throws IOException return JsonToken.VALUE_STRING; } + //TODO leave only true and false protected Boolean _matchYAMLBoolean(String value, int len) { switch (len) { @@ -753,21 +770,22 @@ public boolean canReadTypeId() { @Override public String getObjectId() throws IOException, JsonGenerationException { - return _currentAnchor; + return _currentAnchor.map(a -> a.getAnchor()).orElse(null); } @Override public String getTypeId() throws IOException, JsonGenerationException { - String tag; + Optional tagOpt; if (_lastEvent instanceof CollectionStartEvent) { - tag = ((CollectionStartEvent) _lastEvent).getTag(); + tagOpt = ((CollectionStartEvent) _lastEvent).getTag(); } else if (_lastEvent instanceof ScalarEvent) { - tag = ((ScalarEvent) _lastEvent).getTag(); + tagOpt = ((ScalarEvent) _lastEvent).getTag(); } else { return null; } - if (tag != null) { + if (tagOpt.isPresent()) { + String tag = tagOpt.get(); /* 04-Aug-2013, tatu: Looks like YAML parser's expose these in... * somewhat exotic ways sometimes. So let's prepare to peel off * some wrappings: diff --git a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/Mark.java b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/Mark.java index 1fdef64ed..9aeec7546 100644 --- a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/Mark.java +++ b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/Mark.java @@ -1,5 +1,7 @@ package com.fasterxml.jackson.dataformat.yaml.snakeyaml.error; +import java.util.Optional; + /** * Placeholder for shaded org.yaml.snakeyaml.error.Mark * @@ -10,28 +12,20 @@ @Deprecated // since 2.8 public class Mark { - protected final org.yaml.snakeyaml.error.Mark _source; + protected final org.snakeyaml.engine.exceptions.Mark _source; - protected Mark(org.yaml.snakeyaml.error.Mark src) { + protected Mark(org.snakeyaml.engine.exceptions.Mark src) { _source = src; } - public static Mark from(org.yaml.snakeyaml.error.Mark src) { - return (src == null) ? null : new Mark(src); + public static Mark from(Optional src) { + return (!src.isPresent()) ? null : new Mark(src.get()); } public String getName() { return _source.getName(); } - public String get_snippet() { - return _source.get_snippet(); - } - - public String get_snippet(int indent, int max_length) { - return _source.get_snippet(indent, max_length); - } - public int getColumn() { return _source.getColumn(); } diff --git a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/MarkedYAMLException.java b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/MarkedYAMLException.java index 8a50767ca..e61e5dc7e 100644 --- a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/MarkedYAMLException.java +++ b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/MarkedYAMLException.java @@ -14,16 +14,16 @@ public class MarkedYAMLException extends YAMLException { private static final long serialVersionUID = 1L; - protected final org.yaml.snakeyaml.error.MarkedYAMLException _source; + protected final org.snakeyaml.engine.exceptions.MarkedYamlEngineException _source; protected MarkedYAMLException(JsonParser p, - org.yaml.snakeyaml.error.MarkedYAMLException src) { + org.snakeyaml.engine.exceptions.MarkedYamlEngineException src) { super(p, src); _source = src; } public static MarkedYAMLException from(JsonParser p, - org.yaml.snakeyaml.error.MarkedYAMLException src) { + org.snakeyaml.engine.exceptions.MarkedYamlEngineException src) { return new MarkedYAMLException(p, src); } diff --git a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/YAMLException.java b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/YAMLException.java index 95ed5a363..0c658f28a 100644 --- a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/YAMLException.java +++ b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/YAMLException.java @@ -16,12 +16,12 @@ public class YAMLException extends JacksonYAMLParseException private static final long serialVersionUID = 1L; public YAMLException(JsonParser p, - org.yaml.snakeyaml.error.YAMLException src) { + org.snakeyaml.engine.exceptions.YamlEngineException src) { super(p, src.getMessage(), src); } public static YAMLException from(JsonParser p, - org.yaml.snakeyaml.error.YAMLException src) { + org.snakeyaml.engine.exceptions.YamlEngineException src) { return new YAMLException(p, src); } } diff --git a/yaml/src/test/java/com/fasterxml/jackson/dataformat/yaml/ExceptionConversionTest.java b/yaml/src/test/java/com/fasterxml/jackson/dataformat/yaml/ExceptionConversionTest.java index 200f77e71..e7e7881cc 100644 --- a/yaml/src/test/java/com/fasterxml/jackson/dataformat/yaml/ExceptionConversionTest.java +++ b/yaml/src/test/java/com/fasterxml/jackson/dataformat/yaml/ExceptionConversionTest.java @@ -14,7 +14,7 @@ public void testSimpleParsingLeakage() throws Exception try { mapper.readTree("foo:\nbar: true\n baz: false"); fail("Should not pass with invalid YAML"); - } catch (org.yaml.snakeyaml.scanner.ScannerException e) { + } catch (org.snakeyaml.engine.exceptions.ScannerException e) { fail("Internal exception type: "+e); } catch (JacksonYAMLParseException e) { // as of 2.8, this is the type to expect // (subtype of JsonParseException) From 207b5b15a9e74efe8502d7155ceef5a12278ab8f Mon Sep 17 00:00:00 2001 From: asomov Date: Thu, 10 May 2018 22:32:03 +0200 Subject: [PATCH 2/6] Improve tests for YAML 1.2 --- .../yaml/deser/StreamingParseTest.java | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/yaml/src/test/java/com/fasterxml/jackson/dataformat/yaml/deser/StreamingParseTest.java b/yaml/src/test/java/com/fasterxml/jackson/dataformat/yaml/deser/StreamingParseTest.java index 506f64fb8..623f39e60 100644 --- a/yaml/src/test/java/com/fasterxml/jackson/dataformat/yaml/deser/StreamingParseTest.java +++ b/yaml/src/test/java/com/fasterxml/jackson/dataformat/yaml/deser/StreamingParseTest.java @@ -162,8 +162,8 @@ public void testIntParsingWithLimits() throws Exception p.close(); } - // Testing addition of underscores - public void testIntParsingUnderscoresSm() throws Exception + // TODO Testing addition of underscores (It was dropped in YAML 1.2) + public void /*test*/ IntParsingUnderscoresSm() throws Exception { // First, couple of simple small values try (JsonParser p = MAPPER.createParser("num: 10_345")) { @@ -305,7 +305,7 @@ public void testDoubleParsing() throws Exception // First, test out valid use case. String YAML; - YAML = "num: +1_000.25"; // note underscores; legal in YAML apparently + YAML = "num: +1000.25"; JsonParser p = MAPPER.createParser(YAML); assertToken(JsonToken.START_OBJECT, p.nextToken()); @@ -315,16 +315,16 @@ public void testDoubleParsing() throws Exception StringWriter w = new StringWriter(); assertEquals(3, p.getText(w)); assertEquals("num", w.toString()); - + // should be considered a String... assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken()); assertEquals(1000.25, p.getDoubleValue()); // let's retain exact representation text however: - assertEquals("+1_000.25", p.getText()); + assertEquals("+1000.25", p.getText()); p.close(); - + // and then non-number that may be mistaken - + final String IP = "10.12.45.127"; YAML = "ip: "+IP+"\n"; p = MAPPER.createParser(YAML); @@ -337,7 +337,7 @@ public void testDoubleParsing() throws Exception w = new StringWriter(); assertEquals(IP.length(), p.getText(w)); assertEquals(IP, w.toString()); - + assertEquals(IP, p.getText()); p.close(); } @@ -365,7 +365,7 @@ public void testColons() throws Exception p.close(); } - + /** * How should YAML Anchors be exposed? */ @@ -418,7 +418,7 @@ public void testAnchorParsing() throws Exception assertToken(JsonToken.END_OBJECT, yp.nextToken()); assertToken(JsonToken.END_OBJECT, yp.nextToken()); - + assertNull(yp.nextToken()); yp.close(); } @@ -536,7 +536,10 @@ public void testNulls() throws Exception p.close(); } - public void testTildeNulls() throws Exception + /* + * Tilde '~' is back to string in YAML 1.2 (using the JSON schema) + */ + public void testTildeIsString() throws Exception { String YAML = "nulls: [~ ]"; JsonParser p = MAPPER.createParser(YAML); @@ -545,7 +548,7 @@ public void testTildeNulls() throws Exception assertToken(JsonToken.FIELD_NAME, p.nextToken()); assertEquals("nulls", p.currentName()); assertToken(JsonToken.START_ARRAY, p.nextToken()); - assertToken(JsonToken.VALUE_NULL, p.nextToken()); + assertToken(JsonToken.VALUE_STRING, p.nextToken()); assertToken(JsonToken.END_ARRAY, p.nextToken()); assertToken(JsonToken.END_OBJECT, p.nextToken()); assertNull(p.nextToken()); From e054a8c013fc40d8b8468a503bc455b326bd2d2e Mon Sep 17 00:00:00 2001 From: asomov Date: Fri, 11 May 2018 23:32:04 +0200 Subject: [PATCH 3/6] Use switch instead of many if statements --- .../jackson/dataformat/yaml/YAMLParser.java | 183 +++++++++--------- 1 file changed, 94 insertions(+), 89 deletions(-) diff --git a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java index 7490dabbf..2f1e3113d 100644 --- a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java +++ b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java @@ -15,14 +15,20 @@ import org.snakeyaml.engine.events.NodeEvent; import org.snakeyaml.engine.events.ScalarEvent; import org.snakeyaml.engine.exceptions.Mark; -import org.snakeyaml.engine.nodes.NodeType; import org.snakeyaml.engine.nodes.Tag; import org.snakeyaml.engine.parser.ParserImpl; import org.snakeyaml.engine.resolver.JsonScalarResolver; import org.snakeyaml.engine.resolver.ScalarResolver; import org.snakeyaml.engine.scanner.StreamReader; -import com.fasterxml.jackson.core.*; +import com.fasterxml.jackson.core.Base64Variant; +import com.fasterxml.jackson.core.Base64Variants; +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.core.JsonLocation; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.core.ObjectReadContext; +import com.fasterxml.jackson.core.Version; import com.fasterxml.jackson.core.base.ParserBase; import com.fasterxml.jackson.core.io.IOContext; import com.fasterxml.jackson.core.util.BufferRecycler; @@ -43,7 +49,7 @@ public enum Feature implements FormatFeature final boolean _defaultState; final int _mask; - + // Method that calculates bit set (flags) of all features that // are enabled by default. public static int collectDefaults() @@ -56,16 +62,16 @@ public static int collectDefaults() } return flags; } - + private Feature(boolean defaultState) { _defaultState = defaultState; _mask = (1 << ordinal()); } - + @Override public boolean enabledByDefault() { return _defaultState; } @Override - public boolean enabledIn(int flags) { return (flags & _mask) != 0; } + public boolean enabledIn(int flags) { return (flags & _mask) != 0; } @Override public int getMask() { return _mask; } } @@ -125,7 +131,7 @@ private Feature(boolean defaultState) { * mostly free of underscores */ protected String _cleanedTextValue; - + /** * Let's also have a local copy of the current field name */ @@ -148,11 +154,11 @@ private Feature(boolean defaultState) { /* Life-cycle /********************************************************************** */ - + public YAMLParser(ObjectReadContext readCtxt, IOContext ioCtxt, BufferRecycler br, int parserFeatures, Reader reader) { - super(readCtxt, ioCtxt, parserFeatures); + super(readCtxt, ioCtxt, parserFeatures); // _formatFeatures = formatFeatures; _reader = reader; LoadSettings settings = new LoadSettings();//TODO use parserFeatures @@ -176,7 +182,7 @@ public boolean isCurrentAlias() { /** * Method that can be used to check if the current token has an * associated anchor (id to reference via Alias) - * + * * deprecated Since 2.3 (was added in 2.1) -- use {@link #getObjectId} instead public String getCurrentAnchor() { return _currentAnchor; @@ -243,7 +249,7 @@ public JsonLocation getCurrentLocation() { } return _locationFor(_lastEvent.getEndMark()); } - + protected JsonLocation _locationFor(Optional option) { if (!option.isPresent()) { @@ -283,7 +289,7 @@ public JsonToken nextToken() throws IOException } catch (org.snakeyaml.engine.exceptions.YamlEngineException e) { if (e instanceof org.snakeyaml.engine.exceptions.MarkedYamlEngineException) { throw com.fasterxml.jackson.dataformat.yaml.snakeyaml.error.MarkedYAMLException.from - (this, (org.snakeyaml.engine.exceptions.MarkedYamlEngineException) e); + (this, (org.snakeyaml.engine.exceptions.MarkedYamlEngineException) e); } throw com.fasterxml.jackson.dataformat.yaml.snakeyaml.error.YAMLException.from(this, e); } @@ -292,7 +298,7 @@ public JsonToken nextToken() throws IOException return (_currToken = null); } _lastEvent = evt; - + /* One complication: field names are only inferred from the * fact that we are in Object context... */ @@ -315,70 +321,69 @@ public JsonToken nextToken() throws IOException _currentAnchor = scalar.getAnchor(); return (_currToken = JsonToken.FIELD_NAME); } - // TODO Ugh. Why not expose id, to be able to Switch? - - // scalar values are probably the commonest: - if (evt.isEvent(Event.ID.Scalar)) { - JsonToken t = _decodeScalar((ScalarEvent) evt); - _currToken = t; - return t; - } - - // followed by maps, then arrays - if (evt.isEvent(Event.ID.MappingStart)) { - Optional m = evt.getStartMark(); - MappingStartEvent map = (MappingStartEvent) evt; - _currentAnchor = map.getAnchor(); - _parsingContext = _parsingContext.createChildObjectContext( - m.map(mark -> mark.getLine()).orElse(0), m.map(mark -> mark.getColumn()).orElse(0)); - return (_currToken = JsonToken.START_OBJECT); - } - if (evt.isEvent(Event.ID.MappingEnd)) { // actually error; can not have map-end here - _reportError("Not expecting END_OBJECT but a value"); - } - if (evt.isEvent(Event.ID.SequenceStart)) { - Optional m = evt.getStartMark(); - _currentAnchor = ((NodeEvent)evt).getAnchor(); - _parsingContext = _parsingContext.createChildArrayContext( - m.map(mark -> mark.getLine()).orElse(0), m.map(mark -> mark.getColumn()).orElse(0)); - return (_currToken = JsonToken.START_ARRAY); - } - if (evt.isEvent(Event.ID.SequenceEnd)) { - if (!_parsingContext.inArray()) { // sanity check is optional, but let's do it for now - _reportMismatchedEndMarker(']', '}'); - } - _parsingContext = _parsingContext.getParent(); - return (_currToken = JsonToken.END_ARRAY); - } - - // after this, less common tokens: - - if (evt.isEvent(Event.ID.DocumentEnd)) { - // [dataformat-yaml#72]: logical end of doc; fine. Two choices; either skip, - // or return null as marker (but do NOT close). Earlier returned `null`, but - // to allow multi-document reading should actually just skip. -// return (_currToken = null); - continue; - } - if (evt.isEvent(Event.ID.DocumentStart)) { -// DocumentStartEvent dd = (DocumentStartEvent) evt; - // does this matter? Shouldn't, should it? - continue; - } - if (evt.isEvent(Event.ID.Alias)) { - AliasEvent alias = (AliasEvent) evt; - _currentIsAlias = true; - _textValue = alias.getAlias().getAnchor(); - _cleanedTextValue = null; - // for now, nothing to do: in future, maybe try to expose as ObjectIds? - return (_currToken = JsonToken.VALUE_STRING); - } - if (evt.isEvent(Event.ID.StreamEnd)) { // end-of-input; force closure - close(); - return (_currToken = null); - } - if (evt.isEvent(Event.ID.StreamStart)) { // useless, skip - continue; + switch (evt.getEventId()) { + case Scalar: + // scalar values are probably the commonest: + JsonToken t = _decodeScalar((ScalarEvent) evt); + _currToken = t; + return t; + + case MappingStart: + // followed by maps, then arrays + Optional m = evt.getStartMark(); + MappingStartEvent map = (MappingStartEvent) evt; + _currentAnchor = map.getAnchor(); + _parsingContext = _parsingContext.createChildObjectContext( + m.map(mark -> mark.getLine()).orElse(0), m.map(mark -> mark.getColumn()).orElse(0)); + return (_currToken = JsonToken.START_OBJECT); + + case MappingEnd: + // actually error; can not have map-end here + _reportError("Not expecting END_OBJECT but a value"); + + case SequenceStart: + Optional mrk = evt.getStartMark(); + _currentAnchor = ((NodeEvent) evt).getAnchor(); + _parsingContext = _parsingContext.createChildArrayContext( + mrk.map(mark -> mark.getLine()).orElse(0), mrk.map(mark -> mark.getColumn()).orElse(0)); + return (_currToken = JsonToken.START_ARRAY); + + case SequenceEnd: + if (!_parsingContext.inArray()) { // sanity check is optional, but let's do it for now + _reportMismatchedEndMarker(']', '}'); + } + _parsingContext = _parsingContext.getParent(); + return (_currToken = JsonToken.END_ARRAY); + + // after this, less common tokens: + case DocumentEnd: + // [dataformat-yaml#72]: logical end of doc; fine. Two choices; either skip, + // or return null as marker (but do NOT close). Earlier returned `null`, but + // to allow multi-document reading should actually just skip. + // return (_currToken = null); + continue; + + case DocumentStart: + // DocumentStartEvent dd = (DocumentStartEvent) evt; + // does this matter? Shouldn't, should it? + continue; + + case Alias: + AliasEvent alias = (AliasEvent) evt; + _currentIsAlias = true; + _textValue = alias.getAlias().getAnchor(); + _cleanedTextValue = null; + // for now, nothing to do: in future, maybe try to expose as ObjectIds? + return (_currToken = JsonToken.VALUE_STRING); + + case StreamEnd: + // end-of-input; force closure + close(); + return (_currToken = null); + + case StreamStart: + // useless, skip + continue; } } //TODO what should be thrown here ? @@ -458,7 +463,7 @@ protected JsonToken _decodeScalar(ScalarEvent scalar) throws IOException } } } - + // any way to figure out actual type? No? return JsonToken.VALUE_STRING; } @@ -546,11 +551,11 @@ protected JsonToken _decodeNumberScalar(String value, final int len) _numTypesValid = 0; return _cleanYamlFloat(_textValue); } - + // 25-Aug-2016, tatu: If we can't actually match it to valid number, // consider String; better than claiming there's not toekn return JsonToken.VALUE_STRING; - } + } protected JsonToken _decodeIntWithUnderscores(String value, final int len) { @@ -568,7 +573,7 @@ protected JsonToken _decodeIntWithUnderscores(String value, final int len) public boolean hasTextCharacters() { return false; } - + @Override public String getText() throws IOException { @@ -632,7 +637,7 @@ public int getText(Writer writer) throws IOException @Override public Object getEmbeddedObject() throws IOException { - if (_currToken == JsonToken.VALUE_EMBEDDED_OBJECT ) { + if (_currToken == JsonToken.VALUE_EMBEDDED_OBJECT) { return _binaryValue; } return null; @@ -654,7 +659,7 @@ public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IO /* Number accessor overrides /********************************************************************** */ - + @Override protected void _parseNumericValue(int expType) throws IOException { @@ -706,7 +711,7 @@ protected void _parseNumericValue(int expType) throws IOException } catch (NumberFormatException nex) { // NOTE: pass non-cleaned variant for error message // Can this ever occur? Due to overflow, maybe? - _wrapError("Malformed numeric value '"+_textValue+"'", nex); + _wrapError("Malformed numeric value '" + _textValue + "'", nex); } } if (_currToken == JsonToken.VALUE_NUMBER_FLOAT) { @@ -724,11 +729,11 @@ protected void _parseNumericValue(int expType) throws IOException } catch (NumberFormatException nex) { // Can this ever occur? Due to overflow, maybe? // NOTE: pass non-cleaned variant for error message - _wrapError("Malformed numeric value '"+_textValue+"'", nex); + _wrapError("Malformed numeric value '" + _textValue + "'", nex); } return; } - _reportError("Current token ("+_currToken+") not numeric, can not use numeric value accessors"); + _reportError("Current token (" + _currToken + ") not numeric, can not use numeric value accessors"); } @Override @@ -761,12 +766,12 @@ protected int _parseIntValue() throws IOException public boolean canReadObjectId() { // yup return true; } - + @Override public boolean canReadTypeId() { return true; // yes, YAML got 'em } - + @Override public String getObjectId() throws IOException, JsonGenerationException { @@ -803,7 +808,7 @@ public String getTypeId() throws IOException, JsonGenerationException /* Internal methods /********************************************************************** */ - + /** * Helper method used to clean up YAML floating-point value so it can be parsed * using standard JDK classes. From 472e4263116a3452bfc0d7c5ef9ec1e3184f1bef Mon Sep 17 00:00:00 2001 From: asomov Date: Fri, 11 May 2018 23:37:17 +0200 Subject: [PATCH 4/6] JSON schema contains only 2 values for boolean --- .../jackson/dataformat/yaml/YAMLParser.java | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java index 2f1e3113d..111d1d886 100644 --- a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java +++ b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java @@ -468,25 +468,11 @@ protected JsonToken _decodeScalar(ScalarEvent scalar) throws IOException return JsonToken.VALUE_STRING; } - //TODO leave only true and false protected Boolean _matchYAMLBoolean(String value, int len) { switch (len) { - case 1: - switch (value.charAt(0)) { - case 'y': case 'Y': return Boolean.TRUE; - case 'n': case 'N': return Boolean.FALSE; - } - break; - case 2: - if ("no".equalsIgnoreCase(value)) return Boolean.FALSE; - if ("on".equalsIgnoreCase(value)) return Boolean.TRUE; - break; - case 3: - if ("yes".equalsIgnoreCase(value)) return Boolean.TRUE; - if ("off".equalsIgnoreCase(value)) return Boolean.FALSE; - break; case 4: + //TODO it should be only lower case if ("true".equalsIgnoreCase(value)) return Boolean.TRUE; break; case 5: From 2cfc7d7331af28be399ab147c73907f594f0b107 Mon Sep 17 00:00:00 2001 From: asomov Date: Fri, 11 May 2018 23:58:49 +0200 Subject: [PATCH 5/6] Do not call _yamlParser.hasNext() to wrap the exception --- .../com/fasterxml/jackson/dataformat/yaml/YAMLParser.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java index 111d1d886..5961a3c43 100644 --- a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java +++ b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java @@ -282,7 +282,7 @@ public JsonToken nextToken() throws IOException return null; } - while (_yamlParser.hasNext()) { + while (true /*_yamlParser.hasNext()*/) { Event evt; try { evt = _yamlParser.next(); @@ -386,8 +386,6 @@ public JsonToken nextToken() throws IOException continue; } } - //TODO what should be thrown here ? - throw new RuntimeException("Unexpected events."); } protected JsonToken _decodeScalar(ScalarEvent scalar) throws IOException From b5505ac9533a44101680cb20adec62bb6c1cb9ca Mon Sep 17 00:00:00 2001 From: Andrey Somov Date: Sat, 8 Sep 2018 21:31:10 +0200 Subject: [PATCH 6/6] SnakeYAML Engine is updated to its release 1.0 --- yaml/pom.xml | 2 +- .../dataformat/yaml/WriterWrapper.java | 2 +- .../jackson/dataformat/yaml/YAMLFactory.java | 2 +- .../dataformat/yaml/YAMLGenerator.java | 50 ++++++++++--------- .../jackson/dataformat/yaml/YAMLParser.java | 39 ++++++++------- .../dataformat/yaml/snakeyaml/error/Mark.java | 6 +-- .../snakeyaml/error/MarkedYAMLException.java | 6 +-- .../yaml/snakeyaml/error/YAMLException.java | 4 +- .../yaml/ExceptionConversionTest.java | 2 +- 9 files changed, 58 insertions(+), 55 deletions(-) diff --git a/yaml/pom.xml b/yaml/pom.xml index 0c1bac228..637a07c7d 100644 --- a/yaml/pom.xml +++ b/yaml/pom.xml @@ -30,7 +30,7 @@ org.snakeyaml snakeyaml-engine - 0.1-SNAPSHOT + 1.0 diff --git a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/WriterWrapper.java b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/WriterWrapper.java index 51a9f3cd7..95751de28 100644 --- a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/WriterWrapper.java +++ b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/WriterWrapper.java @@ -3,7 +3,7 @@ import java.io.IOException; import java.io.Writer; -import org.snakeyaml.engine.api.StreamDataWriter; +import org.snakeyaml.engine.v1.api.StreamDataWriter; public class WriterWrapper implements StreamDataWriter { private final Writer _writer; diff --git a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLFactory.java b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLFactory.java index 81184d27a..406a1e9ce 100644 --- a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLFactory.java +++ b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLFactory.java @@ -3,7 +3,7 @@ import java.io.*; import java.nio.charset.Charset; -import org.snakeyaml.engine.common.SpecVersion; +import org.snakeyaml.engine.v1.common.SpecVersion; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.base.TextualTSFactory; diff --git a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLGenerator.java b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLGenerator.java index 5ba08a44d..df9a31fea 100644 --- a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLGenerator.java +++ b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLGenerator.java @@ -9,24 +9,25 @@ import java.util.Optional; import java.util.regex.Pattern; -import org.snakeyaml.engine.api.DumpSettings; -import org.snakeyaml.engine.common.Anchor; -import org.snakeyaml.engine.common.FlowStyle; -import org.snakeyaml.engine.common.ScalarStyle; -import org.snakeyaml.engine.common.SpecVersion; -import org.snakeyaml.engine.emitter.Emitter; -import org.snakeyaml.engine.events.AliasEvent; -import org.snakeyaml.engine.events.DocumentEndEvent; -import org.snakeyaml.engine.events.DocumentStartEvent; -import org.snakeyaml.engine.events.ImplicitTuple; -import org.snakeyaml.engine.events.MappingEndEvent; -import org.snakeyaml.engine.events.MappingStartEvent; -import org.snakeyaml.engine.events.ScalarEvent; -import org.snakeyaml.engine.events.SequenceEndEvent; -import org.snakeyaml.engine.events.SequenceStartEvent; -import org.snakeyaml.engine.events.StreamEndEvent; -import org.snakeyaml.engine.events.StreamStartEvent; -import org.snakeyaml.engine.nodes.Tag; +import org.snakeyaml.engine.v1.api.DumpSettings; +import org.snakeyaml.engine.v1.api.DumpSettingsBuilder; +import org.snakeyaml.engine.v1.common.Anchor; +import org.snakeyaml.engine.v1.common.FlowStyle; +import org.snakeyaml.engine.v1.common.ScalarStyle; +import org.snakeyaml.engine.v1.common.SpecVersion; +import org.snakeyaml.engine.v1.emitter.Emitter; +import org.snakeyaml.engine.v1.events.AliasEvent; +import org.snakeyaml.engine.v1.events.DocumentEndEvent; +import org.snakeyaml.engine.v1.events.DocumentStartEvent; +import org.snakeyaml.engine.v1.events.ImplicitTuple; +import org.snakeyaml.engine.v1.events.MappingEndEvent; +import org.snakeyaml.engine.v1.events.MappingStartEvent; +import org.snakeyaml.engine.v1.events.ScalarEvent; +import org.snakeyaml.engine.v1.events.SequenceEndEvent; +import org.snakeyaml.engine.v1.events.SequenceStartEvent; +import org.snakeyaml.engine.v1.events.StreamEndEvent; +import org.snakeyaml.engine.v1.events.StreamStartEvent; +import org.snakeyaml.engine.v1.nodes.Tag; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.base.GeneratorBase; @@ -111,7 +112,12 @@ public enum Feature implements FormatFeature * If disabled, Unix linefeed ({@code \n}) will be used. *

* Default value is `false` for backwards compatibility. + * + * This setting does not do anything. Regardless of its value, SnakeYAML Engine will use the line break defined + * in System.getProperty("line.separator") + * @deprecated */ + @Deprecated USE_PLATFORM_LINE_BREAKS(false), /** @@ -254,7 +260,7 @@ public YAMLGenerator(ObjectWriteContext writeContext, IOContext ioCtxt, protected DumpSettings buildDumperOptions(int jsonFeatures, int yamlFeatures, SpecVersion version) { - DumpSettings opt = new DumpSettings(); + DumpSettingsBuilder opt = new DumpSettingsBuilder(); // would we want canonical? if (Feature.CANONICAL_OUTPUT.enabledIn(_formatFeatures)) { opt.setCanonical(true); @@ -274,11 +280,7 @@ protected DumpSettings buildDumperOptions(int jsonFeatures, int yamlFeatures, opt.setIndicatorIndent(1); opt.setIndent(2); } - // 14-May-2018: [dataformats-text#84] allow use of platform linefeed - if (Feature.USE_PLATFORM_LINE_BREAKS.enabledIn(_formatFeatures)) { - opt.setLineBreak(DumperOptions.LineBreak.getPlatformLineBreak()); - } - return opt; + return opt.build(); } /* diff --git a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java index 5961a3c43..66238612b 100644 --- a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java +++ b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java @@ -6,20 +6,21 @@ import java.util.Optional; import java.util.regex.Pattern; -import org.snakeyaml.engine.api.LoadSettings; -import org.snakeyaml.engine.common.Anchor; -import org.snakeyaml.engine.events.AliasEvent; -import org.snakeyaml.engine.events.CollectionStartEvent; -import org.snakeyaml.engine.events.Event; -import org.snakeyaml.engine.events.MappingStartEvent; -import org.snakeyaml.engine.events.NodeEvent; -import org.snakeyaml.engine.events.ScalarEvent; -import org.snakeyaml.engine.exceptions.Mark; -import org.snakeyaml.engine.nodes.Tag; -import org.snakeyaml.engine.parser.ParserImpl; -import org.snakeyaml.engine.resolver.JsonScalarResolver; -import org.snakeyaml.engine.resolver.ScalarResolver; -import org.snakeyaml.engine.scanner.StreamReader; +import org.snakeyaml.engine.v1.api.LoadSettings; +import org.snakeyaml.engine.v1.api.LoadSettingsBuilder; +import org.snakeyaml.engine.v1.common.Anchor; +import org.snakeyaml.engine.v1.events.AliasEvent; +import org.snakeyaml.engine.v1.events.CollectionStartEvent; +import org.snakeyaml.engine.v1.events.Event; +import org.snakeyaml.engine.v1.events.MappingStartEvent; +import org.snakeyaml.engine.v1.events.NodeEvent; +import org.snakeyaml.engine.v1.events.ScalarEvent; +import org.snakeyaml.engine.v1.exceptions.Mark; +import org.snakeyaml.engine.v1.nodes.Tag; +import org.snakeyaml.engine.v1.parser.ParserImpl; +import org.snakeyaml.engine.v1.resolver.JsonScalarResolver; +import org.snakeyaml.engine.v1.resolver.ScalarResolver; +import org.snakeyaml.engine.v1.scanner.StreamReader; import com.fasterxml.jackson.core.Base64Variant; import com.fasterxml.jackson.core.Base64Variants; @@ -161,7 +162,7 @@ public YAMLParser(ObjectReadContext readCtxt, IOContext ioCtxt, super(readCtxt, ioCtxt, parserFeatures); // _formatFeatures = formatFeatures; _reader = reader; - LoadSettings settings = new LoadSettings();//TODO use parserFeatures + LoadSettings settings = new LoadSettingsBuilder().build();//TODO use parserFeatures _yamlParser = new ParserImpl(new StreamReader(reader, settings), settings); } @@ -286,10 +287,10 @@ public JsonToken nextToken() throws IOException Event evt; try { evt = _yamlParser.next(); - } catch (org.snakeyaml.engine.exceptions.YamlEngineException e) { - if (e instanceof org.snakeyaml.engine.exceptions.MarkedYamlEngineException) { + } catch (org.snakeyaml.engine.v1.exceptions.YamlEngineException e) { + if (e instanceof org.snakeyaml.engine.v1.exceptions.MarkedYamlEngineException) { throw com.fasterxml.jackson.dataformat.yaml.snakeyaml.error.MarkedYAMLException.from - (this, (org.snakeyaml.engine.exceptions.MarkedYamlEngineException) e); + (this, (org.snakeyaml.engine.v1.exceptions.MarkedYamlEngineException) e); } throw com.fasterxml.jackson.dataformat.yaml.snakeyaml.error.YAMLException.from(this, e); } @@ -371,7 +372,7 @@ public JsonToken nextToken() throws IOException case Alias: AliasEvent alias = (AliasEvent) evt; _currentIsAlias = true; - _textValue = alias.getAlias().getAnchor(); + _textValue = alias.getAnchor().orElseThrow(() -> new RuntimeException("Alias must be provided.")).getAnchor(); _cleanedTextValue = null; // for now, nothing to do: in future, maybe try to expose as ObjectIds? return (_currToken = JsonToken.VALUE_STRING); diff --git a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/Mark.java b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/Mark.java index 9aeec7546..a784a8998 100644 --- a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/Mark.java +++ b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/Mark.java @@ -12,13 +12,13 @@ @Deprecated // since 2.8 public class Mark { - protected final org.snakeyaml.engine.exceptions.Mark _source; + protected final org.snakeyaml.engine.v1.exceptions.Mark _source; - protected Mark(org.snakeyaml.engine.exceptions.Mark src) { + protected Mark(org.snakeyaml.engine.v1.exceptions.Mark src) { _source = src; } - public static Mark from(Optional src) { + public static Mark from(Optional src) { return (!src.isPresent()) ? null : new Mark(src.get()); } diff --git a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/MarkedYAMLException.java b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/MarkedYAMLException.java index e61e5dc7e..1158cbeac 100644 --- a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/MarkedYAMLException.java +++ b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/MarkedYAMLException.java @@ -14,16 +14,16 @@ public class MarkedYAMLException extends YAMLException { private static final long serialVersionUID = 1L; - protected final org.snakeyaml.engine.exceptions.MarkedYamlEngineException _source; + protected final org.snakeyaml.engine.v1.exceptions.MarkedYamlEngineException _source; protected MarkedYAMLException(JsonParser p, - org.snakeyaml.engine.exceptions.MarkedYamlEngineException src) { + org.snakeyaml.engine.v1.exceptions.MarkedYamlEngineException src) { super(p, src); _source = src; } public static MarkedYAMLException from(JsonParser p, - org.snakeyaml.engine.exceptions.MarkedYamlEngineException src) { + org.snakeyaml.engine.v1.exceptions.MarkedYamlEngineException src) { return new MarkedYAMLException(p, src); } diff --git a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/YAMLException.java b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/YAMLException.java index 0c658f28a..311b344a4 100644 --- a/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/YAMLException.java +++ b/yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/snakeyaml/error/YAMLException.java @@ -16,12 +16,12 @@ public class YAMLException extends JacksonYAMLParseException private static final long serialVersionUID = 1L; public YAMLException(JsonParser p, - org.snakeyaml.engine.exceptions.YamlEngineException src) { + org.snakeyaml.engine.v1.exceptions.YamlEngineException src) { super(p, src.getMessage(), src); } public static YAMLException from(JsonParser p, - org.snakeyaml.engine.exceptions.YamlEngineException src) { + org.snakeyaml.engine.v1.exceptions.YamlEngineException src) { return new YAMLException(p, src); } } diff --git a/yaml/src/test/java/com/fasterxml/jackson/dataformat/yaml/ExceptionConversionTest.java b/yaml/src/test/java/com/fasterxml/jackson/dataformat/yaml/ExceptionConversionTest.java index e7e7881cc..fbef01329 100644 --- a/yaml/src/test/java/com/fasterxml/jackson/dataformat/yaml/ExceptionConversionTest.java +++ b/yaml/src/test/java/com/fasterxml/jackson/dataformat/yaml/ExceptionConversionTest.java @@ -14,7 +14,7 @@ public void testSimpleParsingLeakage() throws Exception try { mapper.readTree("foo:\nbar: true\n baz: false"); fail("Should not pass with invalid YAML"); - } catch (org.snakeyaml.engine.exceptions.ScannerException e) { + } catch (org.snakeyaml.engine.v1.exceptions.ScannerException e) { fail("Internal exception type: "+e); } catch (JacksonYAMLParseException e) { // as of 2.8, this is the type to expect // (subtype of JsonParseException)