Skip to content

Commit 4ae7f4a

Browse files
committed
Merge branch '2.18'
2 parents 2a691af + 3180323 commit 4ae7f4a

File tree

5 files changed

+167
-27
lines changed

5 files changed

+167
-27
lines changed

csv/src/main/java/tools/jackson/dataformat/csv/CsvGenerator.java

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,14 @@ private Feature(boolean defaultState) {
201201
*/
202202
protected int _nextColumnByName = -1;
203203

204+
/**
205+
* Decorator to use for decorating the column value to follow, if any;
206+
* {@code null} if none.
207+
*
208+
* @since 2.18
209+
*/
210+
protected CsvValueDecorator _nextColumnDecorator;
211+
204212
/**
205213
* Flag set when property to write is unknown, and the matching value
206214
* is to be skipped quietly.
@@ -396,14 +404,16 @@ private final void _writeFieldName(String name) throws JacksonException
396404
if (_skipWithin != null) { // new in 2.7
397405
_skipValue = true;
398406
_nextColumnByName = -1;
407+
_nextColumnDecorator = null;
399408
return;
400409
}
401410
// note: we are likely to get next column name, so pass it as hint
402411
CsvSchema.Column col = _schema.column(name, _nextColumnByName+1);
403412
if (col == null) {
413+
_nextColumnByName = -1;
414+
_nextColumnDecorator = null;
404415
if (isEnabled(StreamWriteFeature.IGNORE_UNKNOWN)) {
405416
_skipValue = true;
406-
_nextColumnByName = -1;
407417
return;
408418
}
409419
// not a low-level error, so:
@@ -412,6 +422,7 @@ private final void _writeFieldName(String name) throws JacksonException
412422
_skipValue = false;
413423
// and all we do is just note index to use for following value write
414424
_nextColumnByName = col.getIndex();
425+
_nextColumnDecorator = col.getValueDecorator();
415426
}
416427

417428
/*
@@ -534,8 +545,13 @@ public JsonGenerator writeEndArray() throws JacksonException
534545
return this;
535546
}
536547
if (!_arraySeparator.isEmpty()) {
548+
String value = _arrayContents.toString();
549+
// 26-Aug-2024, tatu: [dataformats-text#495] Decorations!
550+
if (_nextColumnDecorator != null) {
551+
value = _nextColumnDecorator.decorateValue(this, value);
552+
}
537553
_arraySeparator = CsvSchema.NO_ARRAY_ELEMENT_SEPARATOR;
538-
_writer.write(_columnIndex(), _arrayContents.toString());
554+
_writer.write(_columnIndex(), value);
539555
}
540556
// 20-Nov-2014, tatu: When doing "untyped"/"raw" output, this means that row
541557
// is now done. But not if writing such an array property, so:
@@ -610,6 +626,10 @@ public JsonGenerator writeString(String text) throws JacksonException
610626
if (!_arraySeparator.isEmpty()) {
611627
_addToArray(text);
612628
} else {
629+
// 26-Aug-2024, tatu: [dataformats-text#495] Decorations!
630+
if (_nextColumnDecorator != null) {
631+
text = _nextColumnDecorator.decorateValue(this, text);
632+
}
613633
_writer.write(_columnIndex(), text);
614634
}
615635
}
@@ -623,6 +643,11 @@ public JsonGenerator writeString(char[] text, int offset, int len) throws Jackso
623643
if (!_skipValue) {
624644
if (!_arraySeparator.isEmpty()) {
625645
_addToArray(new String(text, offset, len));
646+
// 26-Aug-2024, tatu: [dataformats-text#495] Decorations!
647+
} else if (_nextColumnDecorator != null) {
648+
String str = new String(text, offset, len);
649+
_writer.write(_columnIndex(),
650+
_nextColumnDecorator.decorateValue(this, str));
626651
} else {
627652
_writer.write(_columnIndex(), text, offset, len);
628653
}
@@ -638,7 +663,12 @@ public JsonGenerator writeString(SerializableString sstr) throws JacksonExceptio
638663
if (!_arraySeparator.isEmpty()) {
639664
_addToArray(sstr.getValue());
640665
} else {
641-
_writer.write(_columnIndex(), sstr.getValue());
666+
// 26-Aug-2024, tatu: [dataformats-text#495] Decorations!
667+
String text = sstr.getValue();
668+
if (_nextColumnDecorator != null) {
669+
text = _nextColumnDecorator.decorateValue(this, text);
670+
}
671+
_writer.write(_columnIndex(), text);
642672
}
643673
}
644674
return this;
@@ -727,6 +757,7 @@ public JsonGenerator writeBinary(Base64Variant b64variant, byte[] data, int offs
727757
if (data == null) {
728758
return writeNull();
729759
}
760+
730761
_verifyValueWrite("write Binary value");
731762
if (!_skipValue) {
732763
// ok, better just Base64 encode as a String...
@@ -738,6 +769,10 @@ public JsonGenerator writeBinary(Base64Variant b64variant, byte[] data, int offs
738769
if (!_arraySeparator.isEmpty()) {
739770
_addToArray(encoded);
740771
} else {
772+
// 26-Aug-2024, tatu: [dataformats-text#495] Decorations!
773+
if (_nextColumnDecorator != null) {
774+
encoded = _nextColumnDecorator.decorateValue(this, encoded);
775+
}
741776
_writer.write(_columnIndex(), encoded);
742777
}
743778
}
@@ -758,7 +793,13 @@ public JsonGenerator writeBoolean(boolean state) throws JacksonException
758793
if (!_arraySeparator.isEmpty()) {
759794
_addToArray(state ? "true" : "false");
760795
} else {
761-
_writer.write(_columnIndex(), state);
796+
// 26-Aug-2024, tatu: [dataformats-text#495] Decorations!
797+
if (_nextColumnDecorator != null) {
798+
String text = _nextColumnDecorator.decorateValue(this, state ? "true" : "false");
799+
_writer.write(_columnIndex(), text);
800+
} else {
801+
_writer.write(_columnIndex(), state);
802+
}
762803
}
763804
}
764805
return this;
@@ -773,6 +814,15 @@ public JsonGenerator writeNull() throws JacksonException
773814
if (!_arraySeparator.isEmpty()) {
774815
_addToArray(_schema.getNullValueOrEmpty());
775816
} else if (_streamWriteContext.inObject()) {
817+
// 26-Aug-2024, tatu: [dataformats-text#495] Decorations?
818+
if (_nextColumnDecorator != null) {
819+
String nvl = _nextColumnDecorator.decorateNull(this);
820+
if (nvl != null) {
821+
_writer.write(_columnIndex(), nvl);
822+
return this;
823+
}
824+
}
825+
776826
_writer.writeNull(_columnIndex());
777827
} else if (_streamWriteContext.inArray()) {
778828
// [dataformat-csv#106]: Need to make sure we don't swallow nulls in arrays either
@@ -782,6 +832,14 @@ public JsonGenerator writeNull() throws JacksonException
782832
// based on either schema property, or CsvGenerator.Feature.
783833
// Note: if nulls are to be written that way, would need to call `finishRow()` right after `writeNull()`
784834
if (!_streamWriteContext.getParent().inRoot()) {
835+
// 26-Aug-2024, tatu: [dataformats-text#495] Decorations?
836+
if (_nextColumnDecorator != null) {
837+
String nvl = _nextColumnDecorator.decorateNull(this);
838+
if (nvl != null) {
839+
_writer.write(_columnIndex(), nvl);
840+
return this;
841+
}
842+
}
785843
_writer.writeNull(_columnIndex());
786844
}
787845

@@ -807,6 +865,10 @@ public JsonGenerator writeNumber(int v) throws JacksonException
807865
if (!_skipValue) {
808866
if (!_arraySeparator.isEmpty()) {
809867
_addToArray(String.valueOf(v));
868+
// 26-Aug-2024, tatu: [dataformats-text#495] Decorations?
869+
} else if (_nextColumnDecorator != null) {
870+
_writer.write(_columnIndex(),
871+
_nextColumnDecorator.decorateValue(this, String.valueOf(v)));
810872
} else {
811873
_writer.write(_columnIndex(), v);
812874
}
@@ -825,6 +887,10 @@ public JsonGenerator writeNumber(long v) throws JacksonException
825887
if (!_skipValue) {
826888
if (!_arraySeparator.isEmpty()) {
827889
_addToArray(String.valueOf(v));
890+
// 26-Aug-2024, tatu: [dataformats-text#495] Decorations?
891+
} else if (_nextColumnDecorator != null) {
892+
_writer.write(_columnIndex(),
893+
_nextColumnDecorator.decorateValue(this, String.valueOf(v)));
828894
} else {
829895
_writer.write(_columnIndex(), v);
830896
}
@@ -842,6 +908,10 @@ public JsonGenerator writeNumber(BigInteger v) throws JacksonException
842908
if (!_skipValue) {
843909
if (!_arraySeparator.isEmpty()) {
844910
_addToArray(String.valueOf(v));
911+
// 26-Aug-2024, tatu: [dataformats-text#495] Decorations?
912+
} else if (_nextColumnDecorator != null) {
913+
_writer.write(_columnIndex(),
914+
_nextColumnDecorator.decorateValue(this, String.valueOf(v)));
845915
} else {
846916
_writer.write(_columnIndex(), v);
847917

@@ -857,6 +927,10 @@ public JsonGenerator writeNumber(double v) throws JacksonException
857927
if (!_skipValue) {
858928
if (!_arraySeparator.isEmpty()) {
859929
_addToArray(String.valueOf(v));
930+
// 26-Aug-2024, tatu: [dataformats-text#495] Decorations?
931+
} else if (_nextColumnDecorator != null) {
932+
_writer.write(_columnIndex(),
933+
_nextColumnDecorator.decorateValue(this, String.valueOf(v)));
860934
} else {
861935
_writer.write(_columnIndex(), v);
862936
}
@@ -871,6 +945,10 @@ public JsonGenerator writeNumber(float v) throws JacksonException
871945
if (!_skipValue) {
872946
if (!_arraySeparator.isEmpty()) {
873947
_addToArray(String.valueOf(v));
948+
// 26-Aug-2024, tatu: [dataformats-text#495] Decorations?
949+
} else if (_nextColumnDecorator != null) {
950+
_writer.write(_columnIndex(),
951+
_nextColumnDecorator.decorateValue(this, String.valueOf(v)));
874952
} else {
875953
_writer.write(_columnIndex(), v);
876954
}
@@ -889,6 +967,11 @@ public JsonGenerator writeNumber(BigDecimal v) throws JacksonException
889967
boolean plain = isEnabled(StreamWriteFeature.WRITE_BIGDECIMAL_AS_PLAIN);
890968
if (!_arraySeparator.isEmpty()) {
891969
_addToArray(plain ? v.toPlainString() : v.toString());
970+
// 26-Aug-2024, tatu: [dataformats-text#495] Decorations?
971+
} else if (_nextColumnDecorator != null) {
972+
String numStr = plain ? v.toPlainString() : v.toString();
973+
_writer.write(_columnIndex(),
974+
_nextColumnDecorator.decorateValue(this, numStr));
892975
} else {
893976
_writer.write(_columnIndex(), v, plain);
894977
}
@@ -906,6 +989,10 @@ public JsonGenerator writeNumber(String encodedValue) throws JacksonException
906989
if (!_skipValue) {
907990
if (!_arraySeparator.isEmpty()) {
908991
_addToArray(encodedValue);
992+
// 26-Aug-2024, tatu: [dataformats-text#495] Decorations?
993+
} else if (_nextColumnDecorator != null) {
994+
_writer.write(_columnIndex(),
995+
_nextColumnDecorator.decorateValue(this, encodedValue));
909996
} else {
910997
_writer.write(_columnIndex(), encodedValue);
911998
}

csv/src/main/java/tools/jackson/dataformat/csv/CsvValueDecorator.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,35 @@ public interface CsvValueDecorator
2626
* @param gen Generator that will be used for actual serialization
2727
* @param plainValue Value to decorate
2828
*
29-
* @return Decorated value (which may be {@code plainValue} as-is)
29+
* @return Decorated value (which may be {@code plainValue} as-is) but
30+
* Must Not be {@code null}
3031
*
3132
* @throws JacksonException if attempt to decorate the value somehow fails
3233
*/
3334
public String decorateValue(CsvGenerator gen, String plainValue)
3435
throws JacksonException;
3536

37+
/**
38+
* Method called instead of {@link #decorateValue} in case where value being
39+
* written is from Java {@code null} value: this is often left as-is, without
40+
* decoration (and this is the default implementation), but may be
41+
* decorated.
42+
* To let default Null Value Replacement be used, should return {@code null}:
43+
* this is the default implementation.
44+
*
45+
* @param gen Generator that will be used for actual serialization
46+
*
47+
* @return Decorated value to use, IF NOT {@code null}: if {@code null} will use
48+
* default null replacement value.
49+
*
50+
* @throws JacksonException if attempt to decorate the value somehow fails
51+
*/
52+
public default String decorateNull(CsvGenerator gen)
53+
throws JacksonException
54+
{
55+
return null;
56+
}
57+
3658
/**
3759
* Method called during deserialization, to remove possible decoration
3860
* applied with {@link #decorateValue}.

csv/src/main/java/tools/jackson/dataformat/csv/CsvValueDecorators.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,23 @@ public class CsvValueDecorators
2626
*/
2727
public final static CsvValueDecorator STRICT_BRACKETS_DECORATOR
2828
= new StringPrefixSuffixDecorator("[", "]", false);
29-
29+
30+
/**
31+
* Factory method for constructing a {@link StringPrefixSuffixDecorator} with
32+
* given prefix and suffix, both optional.
33+
*/
34+
public static CsvValueDecorator optionalPrefixSuffixDecorator(String prefix, String suffix) {
35+
return new StringPrefixSuffixDecorator(prefix, suffix, true);
36+
}
37+
38+
/**
39+
* Factory method for constructing a {@link StringPrefixSuffixDecorator} with
40+
* given prefix and suffix, both required.
41+
*/
42+
public static CsvValueDecorator requiredPrefixSuffixDecorator(String prefix, String suffix) {
43+
return new StringPrefixSuffixDecorator(prefix, suffix, false);
44+
}
45+
3046
/**
3147
* Decorated that adds static prefix and suffix around value to decorate value;
3248
* removes the same when un-decorating. Handling of the case where decoration

0 commit comments

Comments
 (0)