diff --git a/yaml/pom.xml b/yaml/pom.xml
index 863f190da..637a07c7d 100644
--- a/yaml/pom.xml
+++ b/yaml/pom.xml
@@ -28,9 +28,9 @@
- org.yaml
- snakeyaml
- 1.23
+ org.snakeyaml
+ snakeyaml-engine
+ 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
new file mode 100644
index 000000000..95751de28
--- /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.v1.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 94b42cec6..0dac0ac8e 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.v1.common.SpecVersion;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.base.TextualTSFactory;
@@ -42,7 +42,7 @@ public class YAMLFactory
/**********************************************************************
*/
- protected DumperOptions.Version _version; // enum, is serializable
+ protected SpecVersion _version; // enum, is serializable
/**
* 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 a45e9081e..4cba15c91 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,28 @@
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.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;
@@ -97,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),
/**
@@ -168,23 +188,23 @@ private Feature(boolean defaultState) {
protected Writer _writer;
- protected DumperOptions _outputOptions;
+ protected DumpSettings _outputOptions;
// for field names, leave out quotes
- private final static DumperOptions.ScalarStyle STYLE_NAME = DumperOptions.ScalarStyle.PLAIN;
+ private final static ScalarStyle STYLE_NAME = ScalarStyle.PLAIN;
// numbers, booleans, should use implicit
- private final static DumperOptions.ScalarStyle STYLE_SCALAR = DumperOptions.ScalarStyle.PLAIN;
+ private final static ScalarStyle STYLE_SCALAR = ScalarStyle.PLAIN;
// Strings quoted for fun
- private final static DumperOptions.ScalarStyle STYLE_QUOTED = DumperOptions.ScalarStyle.DOUBLE_QUOTED;
+ private final static ScalarStyle STYLE_QUOTED = ScalarStyle.DOUBLE_QUOTED;
// Strings in literal (block) style
- private final static DumperOptions.ScalarStyle STYLE_LITERAL = DumperOptions.ScalarStyle.LITERAL;
+ 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 DumperOptions.ScalarStyle STYLE_BASE64 = STYLE_LITERAL;
+ private final static ScalarStyle STYLE_BASE64 = STYLE_LITERAL;
- private final static DumperOptions.ScalarStyle STYLE_PLAIN = DumperOptions.ScalarStyle.PLAIN;
+ private final static ScalarStyle STYLE_PLAIN = ScalarStyle.PLAIN;
/*
/**********************************************************************
@@ -215,7 +235,7 @@ private Feature(boolean defaultState) {
public YAMLGenerator(ObjectWriteContext writeContext, IOContext ioCtxt,
int streamWriteFeatures, int yamlFeatures,
Writer out,
- org.yaml.snakeyaml.DumperOptions.Version version)
+ SpecVersion version)
throws IOException
{
super(writeContext, streamWriteFeatures);
@@ -225,22 +245,22 @@ public YAMLGenerator(ObjectWriteContext writeContext, IOContext ioCtxt,
_outputOptions = buildDumperOptions(streamWriteFeatures, 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 streamWriteFeatures, int yamlFeatures,
- org.yaml.snakeyaml.DumperOptions.Version version)
+ protected DumpSettings buildDumperOptions(int streamWriteFeatures, int yamlFeatures,
+ SpecVersion version)
{
- DumperOptions opt = new DumperOptions();
+ DumpSettingsBuilder opt = new DumpSettingsBuilder();
// would we want canonical?
if (Feature.CANONICAL_OUTPUT.enabledIn(_formatWriteFeatures)) {
opt.setCanonical(true);
@@ -260,11 +280,7 @@ protected DumperOptions buildDumperOptions(int streamWriteFeatures, int yamlFeat
opt.setIndicatorIndent(1);
opt.setIndent(2);
}
- // 14-May-2018: [dataformats-text#84] allow use of platform linefeed
- if (Feature.USE_PLATFORM_LINE_BREAKS.enabledIn(_formatWriteFeatures)) {
- opt.setLineBreak(DumperOptions.LineBreak.getPlatformLineBreak());
- }
- return opt;
+ return opt.build();
}
/*
@@ -425,8 +441,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();
/* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close()
@@ -460,12 +476,12 @@ public final void writeStartArray() throws IOException
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
@@ -477,7 +493,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
@@ -488,12 +504,11 @@ public final void writeStartObject() throws IOException
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
@@ -505,7 +520,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());
}
/*
@@ -522,7 +537,7 @@ public void writeString(String text) throws IOException,JsonGenerationException
return;
}
_verifyValueWrite("write String value");
- DumperOptions.ScalarStyle style = STYLE_QUOTED;
+ ScalarStyle style = STYLE_QUOTED;
if (Feature.MINIMIZE_QUOTES.enabledIn(_formatWriteFeatures) && !isBooleanContent(text)) {
// If this string could be interpreted as a number, it must be quoted.
if (Feature.ALWAYS_QUOTE_NUMBERS_AS_STRINGS.enabledIn(_formatWriteFeatures)
@@ -752,7 +767,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);
}
@@ -797,7 +812,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, DumperOptions.ScalarStyle style) throws IOException
+ protected void _writeScalar(String value, String type, ScalarStyle style) throws IOException
{
_emitter.emit(_scalarEvent(value, style));
}
@@ -812,27 +827,26 @@ private void _writeScalarBinary(Base64Variant b64variant,
}
final String lf = _lf();
String encoded = b64variant.encode(data, false, lf);
- _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, DumperOptions.ScalarStyle 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);
}
protected String _lf() {
- return _outputOptions.getLineBreak().getString();
+ return _outputOptions.getBestLineBreak();
}
}
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 eeed28946..996c6a08f 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,17 +3,26 @@
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 com.fasterxml.jackson.core.*;
+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.base.ParserBase;
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.core.util.BufferRecycler;
@@ -34,7 +43,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()
@@ -47,16 +56,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; }
}
@@ -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();
/*
/**********************************************************************
@@ -116,7 +125,7 @@ private Feature(boolean defaultState) {
* mostly free of underscores
*/
protected String _cleanedTextValue;
-
+
/**
* Let's also have a local copy of the current field name
*/
@@ -132,21 +141,22 @@ 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;
/*
/**********************************************************************
/* 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;
- _yamlParser = new ParserImpl(new StreamReader(reader));
+ LoadSettings settings = new LoadSettingsBuilder().build();//TODO use parserFeatures
+ _yamlParser = new ParserImpl(new StreamReader(reader, settings), settings);
}
/*
@@ -166,7 +176,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;
@@ -247,13 +257,14 @@ 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
@@ -277,16 +288,16 @@ public JsonToken nextToken() throws IOException
return null;
}
- while (true) {
+ while (true /*_yamlParser.hasNext()*/) {
Event evt;
try {
- evt = _yamlParser.getEvent();
- } catch (org.yaml.snakeyaml.error.YAMLException e) {
+ evt = _yamlParser.next();
+ } catch (org.snakeyaml.engine.v1.exceptions.YamlEngineException e) {
throw new JacksonYAMLParseException(this, e.getMessage(), e);
}
// is null ok? Assume it is, for now, consider to be same as end-of-doc
if (evt == null) {
- _currentAnchor = null;
+ _currentAnchor = Optional.empty();
return (_currToken = null);
}
_lastEvent = evt;
@@ -295,10 +306,10 @@ public JsonToken nextToken() throws IOException
// on values)
if (_parsingContext.inObject()) {
if (_currToken != JsonToken.FIELD_NAME) {
- if (!evt.is(Event.ID.Scalar)) {
- _currentAnchor = null;
+ if (evt.getEventId() != Event.ID.Scalar) {
+ _currentAnchor = Optional.empty();
// end is fine
- if (evt.is(Event.ID.MappingEnd)) {
+ if (evt.getEventId() == Event.ID.MappingEnd) {
if (!_parsingContext.inObject()) { // sanity check is optional, but let's do it for now
_reportMismatchedEndMarker('}', ']');
}
@@ -314,8 +325,8 @@ public JsonToken nextToken() throws IOException
// ... not even 100% sure this is correct, or robust, but does appear to work for specific
// test case given.
final ScalarEvent scalar = (ScalarEvent) evt;
- final String newAnchor = scalar.getAnchor();
- if ((newAnchor != null) || (_currToken != JsonToken.START_OBJECT)) {
+ final Optional newAnchor = scalar.getAnchor();
+ if (newAnchor.isPresent() || (_currToken != JsonToken.START_OBJECT)) {
_currentAnchor = scalar.getAnchor();
}
final String name = scalar.getValue();
@@ -325,71 +336,70 @@ public JsonToken nextToken() throws IOException
}
}
- _currentAnchor = null;
-
- // Ugh. Why not expose id, to be able to Switch?
- _currentAnchor = null;
-
- // scalar values are probably the commonest:
- if (evt.is(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();
- MappingStartEvent map = (MappingStartEvent) evt;
- _currentAnchor = map.getAnchor();
- _parsingContext = _parsingContext.createChildObjectContext(m.getLine(), m.getColumn());
- return (_currToken = JsonToken.START_OBJECT);
- }
- if (evt.is(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();
- _currentAnchor = ((NodeEvent)evt).getAnchor();
- _parsingContext = _parsingContext.createChildArrayContext(m.getLine(), m.getColumn());
- return (_currToken = JsonToken.START_ARRAY);
- }
- if (evt.is(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.is(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)) {
-// DocumentStartEvent dd = (DocumentStartEvent) evt;
- // does this matter? Shouldn't, should it?
- continue;
- }
- if (evt.is(Event.ID.Alias)) {
- AliasEvent alias = (AliasEvent) evt;
- _currentIsAlias = true;
- _textValue = alias.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
- close();
- return (_currToken = null);
- }
- if (evt.is(Event.ID.StreamStart)) { // useless, skip
- continue;
+ _currentAnchor = Optional.empty();
+
+ 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.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);
+
+ case StreamEnd:
+ // end-of-input; force closure
+ close();
+ return (_currToken = null);
+
+ case StreamStart:
+ // useless, skip
+ continue;
}
}
}
@@ -400,11 +410,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;
}
@@ -427,6 +437,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(",")) {
@@ -466,7 +477,7 @@ protected JsonToken _decodeScalar(ScalarEvent scalar) throws IOException
}
}
}
-
+
// any way to figure out actual type? No?
return JsonToken.VALUE_STRING;
}
@@ -474,21 +485,8 @@ protected JsonToken _decodeScalar(ScalarEvent scalar) throws IOException
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:
@@ -553,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)
{
@@ -575,7 +573,7 @@ protected JsonToken _decodeIntWithUnderscores(String value, final int len)
public boolean hasTextCharacters() {
return false;
}
-
+
@Override
public String getText() throws IOException
{
@@ -639,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;
@@ -661,7 +659,7 @@ public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IO
/* Number accessor overrides
/**********************************************************************
*/
-
+
@Override
protected void _parseNumericValue(int expType) throws IOException
{
@@ -713,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) {
@@ -731,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
@@ -768,30 +766,31 @@ 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
{
- return _currentAnchor;
+ return _currentAnchor.map(a -> a.getAnchor()).orElse(null);
}
@Override
public String getTypeId() throws IOException
{
- 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:
while (tag.startsWith("!")) {
@@ -807,7 +806,7 @@ public String getTypeId() throws IOException
/* Internal methods
/**********************************************************************
*/
-
+
/**
* Helper method used to clean up YAML floating-point value so it can be parsed
* using standard JDK classes.
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..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
@@ -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.v1.exceptions.Mark _source;
- protected Mark(org.yaml.snakeyaml.error.Mark src) {
+ protected Mark(org.snakeyaml.engine.v1.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
new file mode 100644
index 000000000..e69de29bb
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 9c0ca5804..93c016022 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.v1.exceptions.YamlEngineException src) {
super(p, src.getMessage(), src);
}
public static YAMLException from(JsonParser p,
- org.yaml.snakeyaml.error.YAMLException 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 200f77e71..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.yaml.snakeyaml.scanner.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)
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());