[jOOQ/jOOQ#19142] Result::formatJSON should offer a way to configure the binary data encoding

This commit is contained in:
Lukas Eder 2025-10-06 15:49:03 +02:00
parent c4b3c6614f
commit b91b735808
3 changed files with 96 additions and 19 deletions

View File

@ -39,6 +39,9 @@ package org.jooq;
import static org.jooq.tools.StringUtils.rightPad;
import java.util.Base64;
import java.util.HexFormat;
import org.jetbrains.annotations.NotNull;
/**
@ -87,6 +90,7 @@ public final class JSONFormat {
boolean quoteNested;
boolean nanAsString;
boolean infinityAsString;
BinaryFormat binaryFormat;
public JSONFormat() {
this(
@ -103,7 +107,8 @@ public final class JSONFormat {
true,
false,
false,
false
false,
BinaryFormat.BASE64
);
}
@ -121,7 +126,8 @@ public final class JSONFormat {
boolean wrapSingleColumnRecords,
boolean quoteNested,
boolean nanAsString,
boolean infinityAsString
boolean infinityAsString,
BinaryFormat binaryFormat
) {
this.mutable = mutable;
this.format = format;
@ -142,6 +148,7 @@ public final class JSONFormat {
this.quoteNested = quoteNested;
this.nanAsString = nanAsString;
this.infinityAsString = infinityAsString;
this.binaryFormat = binaryFormat;
}
/**
@ -171,7 +178,8 @@ public final class JSONFormat {
wrapSingleColumnRecords,
quoteNested,
nanAsString,
infinityAsString
infinityAsString,
binaryFormat
);
else
return this;
@ -201,7 +209,8 @@ public final class JSONFormat {
wrapSingleColumnRecords,
quoteNested,
nanAsString,
infinityAsString
infinityAsString,
binaryFormat
);
}
@ -236,7 +245,8 @@ public final class JSONFormat {
wrapSingleColumnRecords,
quoteNested,
nanAsString,
infinityAsString
infinityAsString,
binaryFormat
);
}
@ -272,7 +282,8 @@ public final class JSONFormat {
wrapSingleColumnRecords,
quoteNested,
nanAsString,
infinityAsString
infinityAsString,
binaryFormat
);
}
@ -307,7 +318,8 @@ public final class JSONFormat {
wrapSingleColumnRecords,
quoteNested,
nanAsString,
infinityAsString
infinityAsString,
binaryFormat
);
}
@ -358,7 +370,8 @@ public final class JSONFormat {
wrapSingleColumnRecords,
quoteNested,
nanAsString,
infinityAsString
infinityAsString,
binaryFormat
);
}
@ -395,7 +408,8 @@ public final class JSONFormat {
wrapSingleColumnRecords,
quoteNested,
nanAsString,
infinityAsString
infinityAsString,
binaryFormat
);
}
@ -433,7 +447,8 @@ public final class JSONFormat {
wrapSingleColumnRecords,
quoteNested,
nanAsString,
infinityAsString
infinityAsString,
binaryFormat
);
}
@ -471,7 +486,8 @@ public final class JSONFormat {
wrapSingleColumnRecords,
quoteNested,
nanAsString,
infinityAsString
infinityAsString,
binaryFormat
);
}
@ -508,7 +524,8 @@ public final class JSONFormat {
newWrapSingleColumnRecords,
quoteNested,
nanAsString,
infinityAsString
infinityAsString,
binaryFormat
);
}
@ -544,7 +561,8 @@ public final class JSONFormat {
wrapSingleColumnRecords,
newQuoteNested,
nanAsString,
infinityAsString
infinityAsString,
binaryFormat
);
}
@ -582,7 +600,8 @@ public final class JSONFormat {
wrapSingleColumnRecords,
quoteNested,
newNanAsString,
infinityAsString
infinityAsString,
binaryFormat
);
}
@ -624,7 +643,8 @@ public final class JSONFormat {
wrapSingleColumnRecords,
quoteNested,
nanAsString,
newInfinityAsString
newInfinityAsString,
binaryFormat
);
}
@ -640,6 +660,42 @@ public final class JSONFormat {
return infinityAsString;
}
/**
* The {@link BinaryFormat} to use when formatting binary data.
*/
@NotNull
public final JSONFormat binaryFormat(BinaryFormat newBinaryFormat) {
if (mutable) {
binaryFormat = newBinaryFormat;
return this;
}
else
return new JSONFormat(
mutable,
format,
newline,
globalIndent,
indent,
indented,
header,
recordFormat,
objectNulls,
arrayNulls,
wrapSingleColumnRecords,
quoteNested,
nanAsString,
infinityAsString,
newBinaryFormat
);
}
/**
* The {@link BinaryFormat} to use when formatting binary data.
*/
public final BinaryFormat binaryFormat() {
return binaryFormat;
}
/**
* The format of individual JSON records.
*/
@ -682,4 +738,20 @@ public final class JSONFormat {
*/
ABSENT_ON_NULL,
}
/**
* The format of binary values in JSON documents.
*/
public enum BinaryFormat {
/**
* Binary values are formatted as {@link Base64} encoded strings.
*/
BASE64,
/**
* Binary values are formatted as {@link HexFormat} encoded strings.
*/
HEX
}
}

View File

@ -73,6 +73,7 @@ import javax.xml.parsers.ParserConfigurationException;
import org.jooq.CSVFormat;
import org.jooq.ChartFormat;
import org.jooq.ChartFormat.Display;
import org.jooq.JSONFormat.BinaryFormat;
import org.jooq.JSONFormat.NullFormat;
import org.jooq.Configuration;
import org.jooq.Constants;
@ -635,7 +636,11 @@ abstract class AbstractResult<R extends Record> extends AbstractFormattable impl
// [#2741] TODO: This logic will be externalised in new SPI
if (value instanceof byte[] a) {
JSONValue.writeJSONString(Base64.getEncoder().encodeToString(a), writer);
if (format.binaryFormat() == BinaryFormat.HEX)
JSONValue.writeJSONString(Tools.convertBytesToHex(a), writer);
else
JSONValue.writeJSONString(Base64.getEncoder().encodeToString(a), writer);
}
// [#6563] Arrays can be serialised natively in JSON

View File

@ -236,9 +236,9 @@ final class JSONReader<R extends Record> {
return result;
}
private static final Set<SQLDialect> ENCODE_BINARY_AS_HEX = SQLDialect.supportedBy(H2, POSTGRES, SQLITE, TRINO, YUGABYTEDB);
private static final Set<SQLDialect> ENCODE_BINARY_AS_TEXT = SQLDialect.supportedBy(MARIADB);
private static final Pattern P_MYSQL_BINARY_PREFIX = Pattern.compile("^base64:type\\d+:(.*)$");
static final Set<SQLDialect> ENCODE_BINARY_AS_HEX = SQLDialect.supportedBy(H2, POSTGRES, SQLITE, TRINO, YUGABYTEDB);
static final Set<SQLDialect> ENCODE_BINARY_AS_TEXT = SQLDialect.supportedBy(MARIADB);
private static final Pattern P_MYSQL_BINARY_PREFIX = Pattern.compile("^base64:type\\d+:(.*)$");
private static final List<Object> patchRecord(
DSLContext ctx,