[jOOQ/jOOQ#18190] Converter<String, String> is not applied in multisets

This commit is contained in:
Lukas Eder 2025-03-20 13:03:34 +01:00
parent 26d878092e
commit 79c88c3031
2 changed files with 49 additions and 9 deletions

View File

@ -54,6 +54,7 @@ import static org.jooq.impl.DSL.name;
import static org.jooq.impl.DefaultDataType.getDataType;
import static org.jooq.impl.SQLDataType.VARCHAR;
import static org.jooq.impl.Tools.convertHexToBytes;
import static org.jooq.impl.Tools.converterContext;
import static org.jooq.impl.Tools.fields;
import static org.jooq.impl.Tools.newRecord;
import static org.jooq.tools.StringUtils.defaultIfBlank;
@ -68,7 +69,10 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.jooq.ContextConverter;
import org.jooq.ConverterContext;
import org.jooq.DSLContext;
import org.jooq.DataType;
import org.jooq.Field;
import org.jooq.Fields;
import org.jooq.Record;
@ -247,13 +251,16 @@ final class JSONReader<R extends Record> {
private static final Set<SQLDialect> ENCODE_BINARY_AS_TEXT = SQLDialect.supportedBy(MARIADB);
private static final List<Object> patchRecord(DSLContext ctx, boolean multiset, Fields result, List<Object> record) {
ConverterContext cc = null;
for (int i = 0; i < result.fields().length; i++) {
Field<?> field = result.field(i);
Object value = record.get(i);
DataType<?> t = field.getDataType();
// [#8829] LoaderImpl expects binary data to be encoded in base64,
// not according to org.jooq.tools.Convert
if (field.getDataType().isBinary() && value instanceof String s) {
if (t.isBinary() && value instanceof String s) {
if (multiset) {
// [#12134] PostgreSQL encodes binary data as hex
@ -278,12 +285,26 @@ final class JSONReader<R extends Record> {
record.set(i, Base64.getDecoder().decode(s));
}
// [#18190] For historic reasons, Record.from() will not apply Converter<T, T>, so any potential
// Converter<String, String> should be applied eagerly, before loading data into the record.
else if (multiset
&& t instanceof ConvertedDataType
&& t.getFromType() == String.class
&& t.getToType() == String.class
&& (value == null || value instanceof String)
) {
record.set(i, ((ContextConverter<String, String>) t.getConverter()).from(
(String) value,
cc == null ? (cc = converterContext(ctx.configuration())) : cc
));
}
// [#12155] Recurse for nested MULTISET
else if (multiset && field.getDataType().isMultiset()) {
else if (multiset && t.isMultiset()) {
record.set(i, read(
ctx,
(AbstractRow) field.getDataType().getRow(),
(Class) field.getDataType().getRecordType(),
(AbstractRow) t.getRow(),
(Class) t.getRecordType(),
multiset,
value
));
@ -291,9 +312,9 @@ final class JSONReader<R extends Record> {
// [#14657] Recurse for nested ROW
// [#18152] Handle also the Map encoding of nested ROW values
else if (multiset && field.getDataType().isRecord() && (value instanceof List || value instanceof Map)) {
AbstractRow<? extends Record> actualRow = (AbstractRow) field.getDataType().getRow();
Class<? extends Record> recordType = field.getDataType().getRecordType();
else if (multiset && t.isRecord() && (value instanceof List || value instanceof Map)) {
AbstractRow<? extends Record> actualRow = (AbstractRow) t.getRow();
Class<? extends Record> recordType = t.getRecordType();
List<Object> l;

View File

@ -44,6 +44,7 @@ import static org.jooq.impl.DefaultDataType.getDataType;
import static org.jooq.impl.SQLDataType.VARCHAR;
import static org.jooq.impl.Tools.EMPTY_FIELD;
import static org.jooq.impl.Tools.allMatch;
import static org.jooq.impl.Tools.converterContext;
import static org.jooq.impl.Tools.fields;
import static org.jooq.impl.Tools.newRecord;
import static org.jooq.impl.Tools.row0;
@ -60,6 +61,9 @@ import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.jooq.ContextConverter;
import org.jooq.Converter;
import org.jooq.ConverterContext;
import org.jooq.DSLContext;
import org.jooq.DataType;
import org.jooq.Field;
@ -108,11 +112,15 @@ final class XMLHandler<R extends Record> extends DefaultHandler {
}
final R into(R r) {
ConverterContext cc = null;
// [#12134] Patch base64 encoded binary values
for (int i = 0; i < fields.size(); i++) {
if (fields.get(i).getDataType().isBinary()) {
if (values.get(i) instanceof String s) {
Object v = values.get(i);
DataType<?> t = fields.get(i).getDataType();
if (v instanceof String s) {
if (t.isBinary()) {
@ -121,6 +129,17 @@ final class XMLHandler<R extends Record> extends DefaultHandler {
values.set(i, Base64.getDecoder().decode(s));
}
}
// [#18190] For historic reasons, Record.from() will not apply Converter<T, T>, so any potential
// Converter<String, String> should be applied eagerly, before loading data into the record.
if (v == null || v instanceof String) {
if (t instanceof ConvertedDataType && t.getFromType() == String.class && t.getToType() == String.class) {
values.set(i, ((ContextConverter<String, String>) t.getConverter()).from(
(String) v,
cc == null ? (cc = converterContext(ctx.configuration())) : cc
));
}
}
}
r.from(values);