[jOOQ/jOOQ#6028] Add JSONFormat.NullFormat to offer different NULL
encoding options
This commit is contained in:
parent
86d50133ec
commit
3336b7834f
@ -81,6 +81,8 @@ public final class JSONFormat {
|
||||
String[] indented;
|
||||
boolean header;
|
||||
RecordFormat recordFormat;
|
||||
NullFormat objectNulls;
|
||||
NullFormat arrayNulls;
|
||||
boolean wrapSingleColumnRecords;
|
||||
boolean quoteNested;
|
||||
|
||||
@ -94,6 +96,8 @@ public final class JSONFormat {
|
||||
null,
|
||||
true,
|
||||
RecordFormat.ARRAY,
|
||||
NullFormat.NULL_ON_NULL,
|
||||
NullFormat.NULL_ON_NULL,
|
||||
true,
|
||||
false
|
||||
);
|
||||
@ -108,6 +112,8 @@ public final class JSONFormat {
|
||||
String[] indented,
|
||||
boolean header,
|
||||
RecordFormat recordFormat,
|
||||
NullFormat objectNulls,
|
||||
NullFormat arrayNulls,
|
||||
boolean wrapSingleColumnRecords,
|
||||
boolean quoteNested
|
||||
) {
|
||||
@ -124,6 +130,8 @@ public final class JSONFormat {
|
||||
};
|
||||
this.header = header;
|
||||
this.recordFormat = recordFormat;
|
||||
this.objectNulls = objectNulls;
|
||||
this.arrayNulls = arrayNulls;
|
||||
this.wrapSingleColumnRecords = wrapSingleColumnRecords;
|
||||
this.quoteNested = quoteNested;
|
||||
}
|
||||
@ -150,6 +158,8 @@ public final class JSONFormat {
|
||||
null,
|
||||
header,
|
||||
recordFormat,
|
||||
objectNulls,
|
||||
arrayNulls,
|
||||
wrapSingleColumnRecords,
|
||||
quoteNested
|
||||
);
|
||||
@ -176,6 +186,8 @@ public final class JSONFormat {
|
||||
null,
|
||||
header,
|
||||
recordFormat,
|
||||
objectNulls,
|
||||
arrayNulls,
|
||||
wrapSingleColumnRecords,
|
||||
quoteNested
|
||||
);
|
||||
@ -207,6 +219,8 @@ public final class JSONFormat {
|
||||
indented,
|
||||
header,
|
||||
recordFormat,
|
||||
objectNulls,
|
||||
arrayNulls,
|
||||
wrapSingleColumnRecords,
|
||||
quoteNested
|
||||
);
|
||||
@ -239,6 +253,8 @@ public final class JSONFormat {
|
||||
null,
|
||||
header,
|
||||
recordFormat,
|
||||
objectNulls,
|
||||
arrayNulls,
|
||||
wrapSingleColumnRecords,
|
||||
quoteNested
|
||||
);
|
||||
@ -270,6 +286,8 @@ public final class JSONFormat {
|
||||
null,
|
||||
header,
|
||||
recordFormat,
|
||||
objectNulls,
|
||||
arrayNulls,
|
||||
wrapSingleColumnRecords,
|
||||
quoteNested
|
||||
);
|
||||
@ -317,6 +335,8 @@ public final class JSONFormat {
|
||||
indented,
|
||||
newHeader,
|
||||
recordFormat,
|
||||
objectNulls,
|
||||
arrayNulls,
|
||||
wrapSingleColumnRecords,
|
||||
quoteNested
|
||||
);
|
||||
@ -350,6 +370,8 @@ public final class JSONFormat {
|
||||
indented,
|
||||
header,
|
||||
newRecordFormat,
|
||||
objectNulls,
|
||||
arrayNulls,
|
||||
wrapSingleColumnRecords,
|
||||
quoteNested
|
||||
);
|
||||
@ -364,6 +386,78 @@ public final class JSONFormat {
|
||||
return recordFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* The null format to be applied to objects, defaulting to
|
||||
* {@link NullFormat#NULL_ON_NULL}.
|
||||
*/
|
||||
@NotNull
|
||||
public final JSONFormat objectNulls(NullFormat newObjectNulls) {
|
||||
if (mutable) {
|
||||
objectNulls = newObjectNulls;
|
||||
return this;
|
||||
}
|
||||
else
|
||||
return new JSONFormat(
|
||||
mutable,
|
||||
format,
|
||||
newline,
|
||||
globalIndent,
|
||||
indent,
|
||||
indented,
|
||||
header,
|
||||
recordFormat,
|
||||
newObjectNulls,
|
||||
arrayNulls,
|
||||
wrapSingleColumnRecords,
|
||||
quoteNested
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The null format to be applied to objects, defaulting to
|
||||
* {@link NullFormat#NULL_ON_NULL}.
|
||||
*/
|
||||
@NotNull
|
||||
public final NullFormat objectNulls() {
|
||||
return objectNulls;
|
||||
}
|
||||
|
||||
/**
|
||||
* The null format to be applied to arrays, defaulting to
|
||||
* {@link NullFormat#NULL_ON_NULL}.
|
||||
*/
|
||||
@NotNull
|
||||
public final JSONFormat arrayNulls(NullFormat newArrayNulls) {
|
||||
if (mutable) {
|
||||
arrayNulls = newArrayNulls;
|
||||
return this;
|
||||
}
|
||||
else
|
||||
return new JSONFormat(
|
||||
mutable,
|
||||
format,
|
||||
newline,
|
||||
globalIndent,
|
||||
indent,
|
||||
indented,
|
||||
header,
|
||||
recordFormat,
|
||||
objectNulls,
|
||||
newArrayNulls,
|
||||
wrapSingleColumnRecords,
|
||||
quoteNested
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The null format to be applied to arrays, defaulting to
|
||||
* {@link NullFormat#NULL_ON_NULL}.
|
||||
*/
|
||||
@NotNull
|
||||
public final NullFormat arrayNulls() {
|
||||
return arrayNulls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to wrap single column records in the {@link #recordFormat()}.
|
||||
*/
|
||||
@ -383,6 +477,8 @@ public final class JSONFormat {
|
||||
indented,
|
||||
header,
|
||||
recordFormat,
|
||||
objectNulls,
|
||||
arrayNulls,
|
||||
newWrapSingleColumnRecords,
|
||||
quoteNested
|
||||
);
|
||||
@ -415,6 +511,8 @@ public final class JSONFormat {
|
||||
indented,
|
||||
header,
|
||||
recordFormat,
|
||||
objectNulls,
|
||||
arrayNulls,
|
||||
wrapSingleColumnRecords,
|
||||
newQuoteNested
|
||||
);
|
||||
@ -451,4 +549,23 @@ public final class JSONFormat {
|
||||
*/
|
||||
OBJECT,
|
||||
}
|
||||
|
||||
/**
|
||||
* The format of <code>null</code> values in JSON objects or arrays.
|
||||
*/
|
||||
public enum NullFormat {
|
||||
|
||||
/**
|
||||
* A <code>null</code> value in source data is represented by an
|
||||
* explicit <code>null</code> value in the JSON object (the key is
|
||||
* present) or array.
|
||||
*/
|
||||
NULL_ON_NULL,
|
||||
|
||||
/**
|
||||
* A <code>null</code> value in source data is represented by an absent
|
||||
* value in the JSON object (the key is absent) or array.
|
||||
*/
|
||||
ABSENT_ON_NULL,
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,6 +40,7 @@ package org.jooq.impl;
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.Math.min;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static org.jooq.JSONFormat.NullFormat.ABSENT_ON_NULL;
|
||||
import static org.jooq.XMLFormat.RecordFormat.COLUMN_NAME_ELEMENTS;
|
||||
import static org.jooq.XMLFormat.RecordFormat.VALUE_ELEMENTS_WITH_FIELD_ATTRIBUTE;
|
||||
import static org.jooq.conf.SettingsTools.renderLocale;
|
||||
@ -71,6 +72,7 @@ import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.jooq.CSVFormat;
|
||||
import org.jooq.ChartFormat;
|
||||
import org.jooq.ChartFormat.Display;
|
||||
import org.jooq.JSONFormat.NullFormat;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Constants;
|
||||
import org.jooq.Cursor;
|
||||
@ -560,6 +562,9 @@ abstract class AbstractResult<R extends Record> extends AbstractFormattable impl
|
||||
switch (format.recordFormat()) {
|
||||
case ARRAY:
|
||||
for (Record record : this) {
|
||||
if (record == null && format.arrayNulls() == ABSENT_ON_NULL)
|
||||
continue;
|
||||
|
||||
hasRecords = true;
|
||||
writer.append(separator);
|
||||
|
||||
@ -573,6 +578,9 @@ abstract class AbstractResult<R extends Record> extends AbstractFormattable impl
|
||||
break;
|
||||
case OBJECT:
|
||||
for (Record record : this) {
|
||||
if (record == null && format.objectNulls() == ABSENT_ON_NULL)
|
||||
continue;
|
||||
|
||||
hasRecords = true;
|
||||
writer.append(separator);
|
||||
|
||||
@ -628,31 +636,32 @@ abstract class AbstractResult<R extends Record> extends AbstractFormattable impl
|
||||
else if (value instanceof Object[] array) {
|
||||
writer.append('[');
|
||||
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
if (i > 0)
|
||||
boolean first = true;
|
||||
for (Object o : array) {
|
||||
if (o == null && format.arrayNulls() == ABSENT_ON_NULL)
|
||||
continue;
|
||||
|
||||
if (!first)
|
||||
writer.append(',');
|
||||
|
||||
formatJSON0(array[i], writer, format);
|
||||
formatJSON0(o, writer, format);
|
||||
first = false;
|
||||
}
|
||||
|
||||
writer.append(']');
|
||||
}
|
||||
|
||||
// [#7782] Nested records should generate nested JSON data structures
|
||||
else if (value instanceof Formattable f) {
|
||||
else if (value instanceof Formattable f)
|
||||
f.formatJSON(writer, format);
|
||||
}
|
||||
|
||||
else if (value instanceof JSON && !format.quoteNested()) {
|
||||
// [#10744] TODO: Possibly parse and format JSON and JSONB content as well
|
||||
else if (value instanceof JSON && !format.quoteNested())
|
||||
writer.write(((JSON) value).data());
|
||||
}
|
||||
else if (value instanceof JSONB && !format.quoteNested()) {
|
||||
else if (value instanceof JSONB && !format.quoteNested())
|
||||
writer.write(((JSONB) value).data());
|
||||
}
|
||||
|
||||
else {
|
||||
else
|
||||
JSONValue.writeJSONString(value, writer);
|
||||
}
|
||||
}
|
||||
|
||||
static final void formatJSONMap0(
|
||||
@ -675,6 +684,11 @@ abstract class AbstractResult<R extends Record> extends AbstractFormattable impl
|
||||
writer.append('{');
|
||||
|
||||
for (int index = 0; index < size; index++) {
|
||||
Object value = record.get(index);
|
||||
|
||||
if (value == null && format.objectNulls() == ABSENT_ON_NULL)
|
||||
continue;
|
||||
|
||||
writer.append(separator);
|
||||
|
||||
if (format.format())
|
||||
@ -692,7 +706,7 @@ abstract class AbstractResult<R extends Record> extends AbstractFormattable impl
|
||||
}
|
||||
|
||||
int previous = format.globalIndent();
|
||||
formatJSON0(record.get(index), writer, format.globalIndent(format.globalIndent() + format.indent() * (recordLevel + 1)));
|
||||
formatJSON0(value, writer, format.globalIndent(format.globalIndent() + format.indent() * (recordLevel + 1)));
|
||||
format.globalIndent(previous);
|
||||
|
||||
if (format.format() && format.wrapSingleColumnRecords() && size == 1)
|
||||
@ -728,6 +742,11 @@ abstract class AbstractResult<R extends Record> extends AbstractFormattable impl
|
||||
writer.append('[');
|
||||
|
||||
for (int index = 0; index < size; index++) {
|
||||
Object value = record.get(index);
|
||||
|
||||
if (value == null && format.arrayNulls() == ABSENT_ON_NULL)
|
||||
continue;
|
||||
|
||||
writer.append(separator);
|
||||
|
||||
if (format.format())
|
||||
@ -737,7 +756,7 @@ abstract class AbstractResult<R extends Record> extends AbstractFormattable impl
|
||||
writer.append(' ');
|
||||
|
||||
int previous = format.globalIndent();
|
||||
formatJSON0(record.get(index), writer, format.globalIndent(format.globalIndent() + format.indent() * (recordLevel + 1)));
|
||||
formatJSON0(value, writer, format.globalIndent(format.globalIndent() + format.indent() * (recordLevel + 1)));
|
||||
format.globalIndent(previous);
|
||||
|
||||
if (format.format() && format.wrapSingleColumnRecords() && size == 1)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user