Skip to content

Commit 022bbc0

Browse files
authored
[issue 768]FromXmlParser lacks extension point for custom XmlTokenStream (#769)
1 parent 500e06a commit 022bbc0

File tree

5 files changed

+72
-20
lines changed

5 files changed

+72
-20
lines changed

release-notes/CREDITS-2.x

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,3 +276,8 @@ Bas Passon (@bpasson)
276276

277277
* Contributed #745: Add feature to include `standalone='yes'` in xml declaration
278278
(2.19.0)
279+
280+
(@xzxiaoshan)
281+
* Contributed #768: `FromXmlParser` lacks extension point for passing
282+
custom `XmlTokenStream`
283+
(2.20.0)

release-notes/VERSION-2.x

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ Project: jackson-dataformat-xml
66

77
2.20.0 (not yet released)
88

9+
#768: `FromXmlParser` lacks extension point for passing custom `XmlTokenStream`
10+
(contributed by @xzxiaoshan)
911
- Generate SBOMs [JSTEP-14]
1012

1113
2.19.1 (13-Jun-2025)

src/main/java/com/fasterxml/jackson/dataformat/xml/XmlFactory.java

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,16 @@ public class XmlFactory extends JsonFactory
3838
public final static String FORMAT_NAME_XML = "XML";
3939

4040
/**
41-
* Bitfield (set of flags) of all parser features that are enabled
41+
* Bit field (set of flags) of all parser features that are enabled
4242
* by default.
4343
*/
44-
final static int DEFAULT_XML_PARSER_FEATURE_FLAGS = FromXmlParser.Feature.collectDefaults();
44+
protected final static int DEFAULT_XML_PARSER_FEATURE_FLAGS = FromXmlParser.Feature.collectDefaults();
4545

4646
/**
47-
* Bitfield (set of flags) of all generator features that are enabled
47+
* Bit field (set of flags) of all generator features that are enabled
4848
* by default.
4949
*/
50-
final static int DEFAULT_XML_GENERATOR_FEATURE_FLAGS = ToXmlGenerator.Feature.collectDefaults();
50+
protected final static int DEFAULT_XML_GENERATOR_FEATURE_FLAGS = ToXmlGenerator.Feature.collectDefaults();
5151

5252
/*
5353
/**********************************************************
@@ -513,7 +513,7 @@ public ToXmlGenerator createGenerator(OutputStream out, JsonEncoding enc) throws
513513
// false -> we won't manage the stream unless explicitly directed to
514514
final IOContext ctxt = _createContext(_createContentReference(out), false);
515515
ctxt.setEncoding(enc);
516-
return new ToXmlGenerator(ctxt,
516+
return createGenerator(ctxt,
517517
_generatorFeatures, _xmlGeneratorFeatures,
518518
_objectCodec, _createXmlWriter(ctxt, out), _nameProcessor);
519519
}
@@ -522,7 +522,7 @@ public ToXmlGenerator createGenerator(OutputStream out, JsonEncoding enc) throws
522522
public ToXmlGenerator createGenerator(Writer out) throws IOException
523523
{
524524
final IOContext ctxt = _createContext(_createContentReference(out), false);
525-
return new ToXmlGenerator(ctxt,
525+
return createGenerator(ctxt,
526526
_generatorFeatures, _xmlGeneratorFeatures,
527527
_objectCodec, _createXmlWriter(ctxt, out), _nameProcessor);
528528
}
@@ -535,7 +535,7 @@ public ToXmlGenerator createGenerator(File f, JsonEncoding enc) throws IOExcepti
535535
// true -> yes, we have to manage the stream since we created it
536536
final IOContext ctxt = _createContext(_createContentReference(out), true);
537537
ctxt.setEncoding(enc);
538-
return new ToXmlGenerator(ctxt, _generatorFeatures, _xmlGeneratorFeatures,
538+
return createGenerator(ctxt, _generatorFeatures, _xmlGeneratorFeatures,
539539
_objectCodec, _createXmlWriter(ctxt, out), _nameProcessor);
540540
}
541541

@@ -559,14 +559,25 @@ public FromXmlParser createParser(XMLStreamReader sr) throws IOException
559559
}
560560

561561
// false -> not managed
562-
FromXmlParser xp = new FromXmlParser(_createContext(_createContentReference(sr), false),
562+
FromXmlParser xp = this.createParser(_createContext(_createContentReference(sr), false),
563563
_parserFeatures, _xmlParserFeatures, _objectCodec, sr, _nameProcessor);
564564
if (_cfgNameForTextElement != null) {
565565
xp.setXMLTextElementName(_cfgNameForTextElement);
566566
}
567567
return xp;
568568
}
569569

570+
/**
571+
* Creates and returns a new instance of {@link FromXmlParser} configured with the provided parameters.
572+
* If you need to extend or customize the FromXmlParser, you can simply override this method.
573+
*
574+
* @since 2.20
575+
*/
576+
protected FromXmlParser createParser(IOContext ctxt, int genericParserFeatures, int xmlFeatures, ObjectCodec codec,
577+
XMLStreamReader xmlReader, XmlNameProcessor tagProcessor) throws IOException {
578+
return new FromXmlParser(ctxt, genericParserFeatures, xmlFeatures, codec, xmlReader, tagProcessor);
579+
}
580+
570581
/**
571582
* Factory method that wraps given {@link XMLStreamWriter}, usually to allow
572583
* incremental serialization to compose large output by serializing a sequence
@@ -578,10 +589,21 @@ public ToXmlGenerator createGenerator(XMLStreamWriter sw) throws IOException
578589
{
579590
sw = _initializeXmlWriter(sw);
580591
IOContext ctxt = _createContext(_createContentReference(sw), false);
581-
return new ToXmlGenerator(ctxt, _generatorFeatures, _xmlGeneratorFeatures,
592+
return createGenerator(ctxt, _generatorFeatures, _xmlGeneratorFeatures,
582593
_objectCodec, sw, _nameProcessor);
583594
}
584595

596+
/**
597+
* Factory method called by more other {@code creatoGenerator} methods.
598+
* Overriding this method makes it easy to extend and customize the ToXmlGenerator.
599+
*
600+
* @since 2.20
601+
*/
602+
public ToXmlGenerator createGenerator(IOContext ctxt, int stdFeatures, int xmlFeatures, ObjectCodec codec,
603+
XMLStreamWriter sw, XmlNameProcessor nameProcessor) {
604+
return new ToXmlGenerator(ctxt, stdFeatures, xmlFeatures, codec, sw, nameProcessor);
605+
}
606+
585607
/*
586608
/**********************************************************
587609
/* Internal factory method overrides
@@ -598,7 +620,7 @@ protected FromXmlParser _createParser(InputStream in, IOContext ctxt) throws IOE
598620
return StaxUtil.throwAsParseException(e, null);
599621
}
600622
sr = _initializeXmlReader(sr);
601-
FromXmlParser xp = new FromXmlParser(ctxt, _parserFeatures, _xmlParserFeatures,
623+
FromXmlParser xp = this.createParser(ctxt, _parserFeatures, _xmlParserFeatures,
602624
_objectCodec, sr, _nameProcessor);
603625
if (_cfgNameForTextElement != null) {
604626
xp.setXMLTextElementName(_cfgNameForTextElement);
@@ -616,7 +638,7 @@ protected FromXmlParser _createParser(Reader r, IOContext ctxt) throws IOExcepti
616638
return StaxUtil.throwAsParseException(e, null);
617639
}
618640
sr = _initializeXmlReader(sr);
619-
FromXmlParser xp = new FromXmlParser(ctxt, _parserFeatures, _xmlParserFeatures,
641+
FromXmlParser xp = this.createParser(ctxt, _parserFeatures, _xmlParserFeatures,
620642
_objectCodec, sr, _nameProcessor);
621643
if (_cfgNameForTextElement != null) {
622644
xp.setXMLTextElementName(_cfgNameForTextElement);
@@ -643,7 +665,7 @@ protected FromXmlParser _createParser(char[] data, int offset, int len, IOContex
643665
return StaxUtil.throwAsParseException(e, null);
644666
}
645667
sr = _initializeXmlReader(sr);
646-
FromXmlParser xp = new FromXmlParser(ctxt, _parserFeatures, _xmlParserFeatures,
668+
FromXmlParser xp = this.createParser(ctxt, _parserFeatures, _xmlParserFeatures,
647669
_objectCodec, sr, _nameProcessor);
648670
if (_cfgNameForTextElement != null) {
649671
xp.setXMLTextElementName(_cfgNameForTextElement);
@@ -677,7 +699,7 @@ protected FromXmlParser _createParser(byte[] data, int offset, int len, IOContex
677699
return StaxUtil.throwAsParseException(e, null);
678700
}
679701
sr = _initializeXmlReader(sr);
680-
FromXmlParser xp = new FromXmlParser(ctxt, _parserFeatures, _xmlParserFeatures,
702+
FromXmlParser xp = this.createParser(ctxt, _parserFeatures, _xmlParserFeatures,
681703
_objectCodec, sr, _nameProcessor);
682704
if (_cfgNameForTextElement != null) {
683705
xp.setXMLTextElementName(_cfgNameForTextElement);

src/main/java/com/fasterxml/jackson/dataformat/xml/deser/FromXmlParser.java

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.io.Writer;
66
import java.math.BigDecimal;
77
import java.math.BigInteger;
8+
import java.util.Objects;
89
import java.util.Set;
910

1011
import javax.xml.XMLConstants;
@@ -274,17 +275,29 @@ private Feature(boolean defaultState) {
274275
*/
275276

276277
public FromXmlParser(IOContext ctxt, int genericParserFeatures, int xmlFeatures,
277-
ObjectCodec codec, XMLStreamReader xmlReader, XmlNameProcessor tagProcessor)
278-
throws IOException
279-
{
278+
ObjectCodec codec, XMLStreamReader xmlReader, XmlNameProcessor tagProcessor) throws IOException {
279+
this(ctxt, genericParserFeatures, codec, new XmlTokenStream(xmlReader, ctxt.contentReference(), xmlFeatures, tagProcessor));
280+
}
281+
282+
/**
283+
* Constructs a new {@link FromXmlParser} instance using the provided XML token stream.
284+
* This constructor initializes the parser with the given I/O context, parser features,
285+
* and object codec for deserializing XML content into Java objects.
286+
*
287+
* @since 2.20
288+
* @param ctxt I/O context used for handling low-level I/O operations and buffering
289+
* @param genericParserFeatures set of bitmasked parser features to control parsing behavior
290+
* @param codec object codec used for converting between JSON-like structures and Java objects
291+
* @param xmlTokenStream the pre-processed XML token stream to parse from
292+
* @throws IOException if an I/O error occurs during initialization or parsing setup
293+
*/
294+
public FromXmlParser(IOContext ctxt, int genericParserFeatures, ObjectCodec codec, XmlTokenStream xmlTokenStream) throws IOException {
280295
super(genericParserFeatures, ctxt.streamReadConstraints());
281-
_formatFeatures = xmlFeatures;
282296
_ioContext = ctxt;
283297
_objectCodec = codec;
284298
_parsingContext = XmlReadContext.createRootContext(-1, -1);
285-
_xmlTokens = new XmlTokenStream(xmlReader, ctxt.contentReference(),
286-
_formatFeatures, tagProcessor);
287-
299+
_xmlTokens = Objects.requireNonNull(xmlTokenStream, "xmlTokenStream cannot be null");
300+
_formatFeatures = xmlTokenStream.getFormatFeatures();
288301
final int firstToken;
289302
try {
290303
firstToken = _xmlTokens.initialize();

src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlTokenStream.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,16 @@ protected void setFormatFeatures(int f) {
254254
_cfgProcessXsiType = FromXmlParser.Feature.AUTO_DETECT_XSI_TYPE.enabledIn(f);
255255
}
256256

257+
/**
258+
* get FormatFeatures
259+
*
260+
* @return data
261+
* @since 2.20
262+
*/
263+
public int getFormatFeatures() {
264+
return _formatFeatures;
265+
}
266+
257267
/*
258268
/**********************************************************************
259269
/* Public API

0 commit comments

Comments
 (0)