[jOOQ/jOOQ#6028] Add JSONFormat.NullFormat to offer different NULL

encoding options
This commit is contained in:
Lukas Eder 2023-08-17 10:38:15 +02:00
parent 86d50133ec
commit 3336b7834f
2 changed files with 150 additions and 14 deletions

View File

@ -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,
}
}

View File

@ -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)