11
11
import com .fasterxml .jackson .core .json .JsonWriteContext ;
12
12
import com .fasterxml .jackson .core .io .IOContext ;
13
13
import com .fasterxml .jackson .dataformat .csv .impl .CsvEncoder ;
14
+ import com .fasterxml .jackson .dataformat .csv .impl .SimpleTokenWriteContext ;
14
15
15
16
public class CsvGenerator extends GeneratorBase
16
17
{
@@ -159,6 +160,14 @@ private Feature(boolean defaultState) {
159
160
// note: can not be final since we may need to re-create it for new schema
160
161
protected CsvEncoder _writer ;
161
162
163
+ /**
164
+ * Current context, in form we can use it (GeneratorBase has
165
+ * untyped reference; left as null)
166
+ *
167
+ * @since 2.11
168
+ */
169
+ protected SimpleTokenWriteContext _csvWriteContext ;
170
+
162
171
protected CharacterEscapes _characterEscapes = null ;
163
172
164
173
/*
@@ -216,7 +225,7 @@ private Feature(boolean defaultState) {
216
225
*
217
226
* @since 2.7
218
227
*/
219
- protected JsonWriteContext _skipWithin ;
228
+ protected SimpleTokenWriteContext _skipWithin ;
220
229
221
230
/*
222
231
/**********************************************************
@@ -235,7 +244,7 @@ public CsvGenerator(IOContext ctxt, int jsonFeatures, int csvFeatures,
235
244
_formatFeatures = csvFeatures ;
236
245
_schema = schema ;
237
246
_writer = new CsvEncoder (ctxt , csvFeatures , out , schema );
238
-
247
+ _csvWriteContext = SimpleTokenWriteContext . createRootContext ( null );
239
248
_writer .setOutputEscapes (CsvCharacterEscapes .fromCsvFeatures (csvFeatures ).getEscapeCodesForAscii ());
240
249
}
241
250
@@ -246,6 +255,7 @@ public CsvGenerator(IOContext ctxt, int jsonFeatures, int csvFeatures,
246
255
_ioContext = ctxt ;
247
256
_formatFeatures = csvFeatures ;
248
257
_writer = csvWriter ;
258
+ _csvWriteContext = SimpleTokenWriteContext .createRootContext (null );
249
259
}
250
260
251
261
/*
@@ -298,6 +308,11 @@ public int getOutputBuffered() {
298
308
return _writer .getOutputBuffered ();
299
309
}
300
310
311
+ @ Override
312
+ public SimpleTokenWriteContext getOutputContext () {
313
+ return _csvWriteContext ;
314
+ }
315
+
301
316
@ Override
302
317
public void setSchema (FormatSchema schema )
303
318
{
@@ -380,7 +395,7 @@ public boolean canOmitFields() {
380
395
@ Override
381
396
public final void writeFieldName (String name ) throws IOException
382
397
{
383
- if (_writeContext .writeFieldName (name ) == JsonWriteContext . STATUS_EXPECT_VALUE ) {
398
+ if (! _csvWriteContext .writeFieldName (name )) {
384
399
_reportError ("Can not write a field name, expecting a value" );
385
400
}
386
401
_writeFieldName (name );
@@ -390,7 +405,7 @@ public final void writeFieldName(String name) throws IOException
390
405
public final void writeFieldName (SerializableString name ) throws IOException
391
406
{
392
407
// Object is a value, need to verify it's allowed
393
- if (_writeContext .writeFieldName (name .getValue ()) == JsonWriteContext . STATUS_EXPECT_VALUE ) {
408
+ if (! _csvWriteContext .writeFieldName (name .getValue ())) {
394
409
_reportError ("Can not write a field name, expecting a value" );
395
410
}
396
411
_writeFieldName (name .getValue ());
@@ -492,10 +507,10 @@ public final void writeStartArray() throws IOException
492
507
_verifyValueWrite ("start an array" );
493
508
// Ok to create root-level array to contain Objects/Arrays, but
494
509
// can not nest arrays in objects
495
- if (_writeContext .inObject ()) {
510
+ if (_csvWriteContext .inObject ()) {
496
511
if ((_skipWithin == null )
497
512
&& _skipValue && isEnabled (JsonGenerator .Feature .IGNORE_UNKNOWN )) {
498
- _skipWithin = _writeContext ;
513
+ _skipWithin = _csvWriteContext ;
499
514
} else if (!_skipValue ) {
500
515
// First: column may have its own separator
501
516
String sep ;
@@ -525,20 +540,20 @@ && _skipValue && isEnabled(JsonGenerator.Feature.IGNORE_UNKNOWN)) {
525
540
_reportError ("CSV generator does not support nested Array values" );
526
541
}
527
542
}
528
- _writeContext = _writeContext .createChildArrayContext ();
543
+ _csvWriteContext = _csvWriteContext .createChildArrayContext (null );
529
544
// and that's about it, really
530
545
}
531
546
532
547
@ Override
533
548
public final void writeEndArray () throws IOException
534
549
{
535
- if (!_writeContext .inArray ()) {
536
- _reportError ("Current context not Array but " +_writeContext .typeDesc ());
550
+ if (!_csvWriteContext .inArray ()) {
551
+ _reportError ("Current context not Array but " +_csvWriteContext .typeDesc ());
537
552
}
538
- _writeContext = _writeContext .getParent ();
553
+ _csvWriteContext = _csvWriteContext .getParent ();
539
554
// 14-Dec-2015, tatu: To complete skipping of ignored structured value, need this:
540
555
if (_skipWithin != null ) {
541
- if (_writeContext == _skipWithin ) {
556
+ if (_csvWriteContext == _skipWithin ) {
542
557
_skipWithin = null ;
543
558
}
544
559
return ;
@@ -549,7 +564,7 @@ public final void writeEndArray() throws IOException
549
564
}
550
565
// 20-Nov-2014, tatu: When doing "untyped"/"raw" output, this means that row
551
566
// is now done. But not if writing such an array field, so:
552
- if (!_writeContext .inObject ()) {
567
+ if (!_csvWriteContext .inObject ()) {
553
568
finishRow ();
554
569
}
555
570
}
@@ -560,30 +575,30 @@ public final void writeStartObject() throws IOException
560
575
_verifyValueWrite ("start an object" );
561
576
// No nesting for objects; can write Objects inside logical root-level arrays.
562
577
// 14-Dec-2015, tatu: ... except, should be fine if we are ignoring the property
563
- if (_writeContext .inObject () ||
578
+ if (_csvWriteContext .inObject () ||
564
579
// 07-Nov-2017, tatu: But we may actually be nested indirectly; so check
565
- (_writeContext .inArray () && !_writeContext .getParent ().inRoot ())) {
580
+ (_csvWriteContext .inArray () && !_csvWriteContext .getParent ().inRoot ())) {
566
581
if (_skipWithin == null ) { // new in 2.7
567
582
if (_skipValue && isEnabled (JsonGenerator .Feature .IGNORE_UNKNOWN )) {
568
- _skipWithin = _writeContext ;
583
+ _skipWithin = _csvWriteContext ;
569
584
} else {
570
585
_reportMappingError ("CSV generator does not support Object values for properties (nested Objects)" );
571
586
}
572
587
}
573
588
}
574
- _writeContext = _writeContext .createChildObjectContext ();
589
+ _csvWriteContext = _csvWriteContext .createChildObjectContext (null );
575
590
}
576
591
577
592
@ Override
578
593
public final void writeEndObject () throws IOException
579
594
{
580
- if (!_writeContext .inObject ()) {
581
- _reportError ("Current context not Object but " +_writeContext .typeDesc ());
595
+ if (!_csvWriteContext .inObject ()) {
596
+ _reportError ("Current context not Object but " +_csvWriteContext .typeDesc ());
582
597
}
583
- _writeContext = _writeContext .getParent ();
598
+ _csvWriteContext = _csvWriteContext .getParent ();
584
599
// 14-Dec-2015, tatu: To complete skipping of ignored structured value, need this:
585
600
if (_skipWithin != null ) {
586
- if (_writeContext == _skipWithin ) {
601
+ if (_csvWriteContext == _skipWithin ) {
587
602
_skipWithin = null ;
588
603
}
589
604
return ;
@@ -760,16 +775,16 @@ public void writeNull() throws IOException
760
775
if (!_skipValue ) {
761
776
if (!_arraySeparator .isEmpty ()) {
762
777
_addToArray (_schema .getNullValueOrEmpty ());
763
- } else if (_writeContext .inObject ()) {
778
+ } else if (_csvWriteContext .inObject ()) {
764
779
_writer .writeNull (_columnIndex ());
765
- } else if (_writeContext .inArray ()) {
780
+ } else if (_csvWriteContext .inArray ()) {
766
781
// [dataformat-csv#106]: Need to make sure we don't swallow nulls in arrays either
767
782
// 04-Jan-2016, tatu: but check for case of array-wrapping, in which case null stands for absence
768
783
// of Object. In this case, could either add an empty row, or skip -- for now, we'll
769
784
// just skip; can change, if so desired, to expose "root null" as empty rows, possibly
770
785
// based on either schema property, or CsvGenerator.Feature.
771
786
// Note: if nulls are to be written that way, would need to call `finishRow()` right after `writeNull()`
772
- if (!_writeContext .getParent ().inRoot ()) {
787
+ if (!_csvWriteContext .getParent ().inRoot ()) {
773
788
_writer .writeNull (_columnIndex ());
774
789
}
775
790
@@ -909,7 +924,7 @@ public void writeOmittedField(String fieldName) throws IOException
909
924
// assumed to have been removed from schema too
910
925
} else {
911
926
// basically combination of "writeFieldName()" and "writeNull()"
912
- if (_writeContext .writeFieldName (fieldName ) == JsonWriteContext . STATUS_EXPECT_VALUE ) {
927
+ if (! _csvWriteContext .writeFieldName (fieldName )) {
913
928
_reportError ("Can not skip a field, expecting a value" );
914
929
}
915
930
// and all we do is just note index to use for following value write
@@ -929,8 +944,7 @@ public void writeOmittedField(String fieldName) throws IOException
929
944
@ Override
930
945
protected final void _verifyValueWrite (String typeMsg ) throws IOException
931
946
{
932
- int status = _writeContext .writeValue ();
933
- if (status == JsonWriteContext .STATUS_EXPECT_NAME ) {
947
+ if (!_csvWriteContext .writeValue ()) {
934
948
_reportError ("Can not " +typeMsg +", expecting field name" );
935
949
}
936
950
if (_handleFirstLine ) {
0 commit comments