diff --git a/jOOQ/src/main/java/org/jooq/DataType.java b/jOOQ/src/main/java/org/jooq/DataType.java
index 880894959e..36e3ae6e7e 100644
--- a/jOOQ/src/main/java/org/jooq/DataType.java
+++ b/jOOQ/src/main/java/org/jooq/DataType.java
@@ -77,7 +77,6 @@ import org.jooq.Converters.UnknownType;
import org.jooq.exception.DataTypeException;
import org.jooq.impl.DSL;
import org.jooq.impl.SQLDataType;
-import org.jooq.tools.Convert;
import org.jooq.types.DayToSecond;
import org.jooq.types.YearToMonth;
import org.jooq.types.YearToSecond;
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java b/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java
index 75ca60f16d..b10d865be6 100644
--- a/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java
@@ -92,7 +92,6 @@ import org.jooq.Result;
import org.jooq.Row;
import org.jooq.SQLDialect;
import org.jooq.XML;
-import org.jooq.tools.Convert;
import org.jooq.types.Interval;
import org.jooq.types.UNumber;
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractField.java b/jOOQ/src/main/java/org/jooq/impl/AbstractField.java
index 751c580cfa..733f1f74a9 100644
--- a/jOOQ/src/main/java/org/jooq/impl/AbstractField.java
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractField.java
@@ -101,7 +101,6 @@ import org.jooq.SortField;
import org.jooq.SortOrder;
import org.jooq.WindowIgnoreNullsStep;
import org.jooq.WindowPartitionByStep;
-import org.jooq.tools.Convert;
/**
* @author Lukas Eder
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java
index 759ee08415..2538cc0d66 100644
--- a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java
@@ -101,7 +101,6 @@ import org.jooq.XMLFormat;
import org.jooq.exception.IOException;
import org.jooq.exception.InvalidResultException;
import org.jooq.exception.MappingException;
-import org.jooq.tools.Convert;
import org.jooq.tools.JooqLogger;
import org.jooq.tools.StringUtils;
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractRoutine.java b/jOOQ/src/main/java/org/jooq/impl/AbstractRoutine.java
index d165f5cb7f..54ac477b37 100644
--- a/jOOQ/src/main/java/org/jooq/impl/AbstractRoutine.java
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractRoutine.java
@@ -141,7 +141,6 @@ import org.jooq.conf.SettingsTools;
import org.jooq.exception.ControlFlowSignal;
import org.jooq.exception.MappingException;
import org.jooq.impl.ResultsImpl.ResultOrRowsImpl;
-import org.jooq.tools.Convert;
import org.jooq.tools.reflect.Reflect;
/**
diff --git a/jOOQ/src/main/java/org/jooq/impl/Convert.java b/jOOQ/src/main/java/org/jooq/impl/Convert.java
new file mode 100644
index 0000000000..590e15daaa
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/Convert.java
@@ -0,0 +1,1303 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Other licenses:
+ * -----------------------------------------------------------------------------
+ * Commercial licenses for this work are available. These replace the above
+ * ASL 2.0 and offer limited warranties, support, maintenance, and commercial
+ * database integrations.
+ *
+ * For more information, please visit: http://www.jooq.org/licenses
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+package org.jooq.impl;
+
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.MILLI_OF_DAY;
+import static java.time.temporal.ChronoField.MILLI_OF_SECOND;
+import static org.jooq.impl.Internal.arrayType;
+import static org.jooq.tools.reflect.Reflect.accessible;
+import static org.jooq.tools.reflect.Reflect.wrapper;
+import static org.jooq.types.Unsigned.ubyte;
+import static org.jooq.types.Unsigned.uint;
+import static org.jooq.types.Unsigned.ulong;
+import static org.jooq.types.Unsigned.ushort;
+
+import java.io.File;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.URI;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.sql.Date;
+import java.sql.ResultSet;
+import java.sql.Struct;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.Temporal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.UUID;
+import java.util.regex.Pattern;
+
+import javax.xml.bind.JAXB;
+
+// ...
+import org.jooq.Converter;
+import org.jooq.ConverterProvider;
+import org.jooq.EnumType;
+import org.jooq.Field;
+import org.jooq.JSON;
+import org.jooq.JSONB;
+import org.jooq.QualifiedRecord;
+import org.jooq.Record;
+import org.jooq.Result;
+import org.jooq.SQLDialect;
+import org.jooq.XML;
+import org.jooq.exception.DataTypeException;
+import org.jooq.tools.Ints;
+import org.jooq.tools.JooqLogger;
+import org.jooq.tools.Longs;
+import org.jooq.tools.jdbc.MockArray;
+import org.jooq.tools.jdbc.MockResultSet;
+import org.jooq.tools.reflect.Reflect;
+import org.jooq.types.UByte;
+import org.jooq.types.UInteger;
+import org.jooq.types.ULong;
+import org.jooq.types.UShort;
+import org.jooq.util.xml.jaxb.InformationSchema;
+
+/**
+ * Utility methods for type conversions
+ *
+ * This class provides less type-safety than the general jOOQ API methods. For
+ * instance, it accepts arbitrary {@link Converter} objects in methods like
+ * {@link #convert(Collection, Converter)} and {@link #convert(Object, Class)},
+ * trying to retrofit the Object argument to the type provided in
+ * {@link Converter#fromType()} before performing the actual conversion.
+ *
+ * For better future configurability via {@link ConverterProvider} etc, this
+ * type has been moved to jOOQ's internals in jOOQ 3.15.0 ([#11898]) and is no
+ * longer accessible to users.
+ *
+ * @author Lukas Eder
+ */
+final class Convert {
+
+ private static final JooqLogger log = JooqLogger.getLogger(Convert.class);
+
+ /**
+ * All string values that can be transformed into a boolean
+ * true value.
+ */
+ static final Set TRUE_VALUES;
+
+ /**
+ * All string values that can be transformed into a boolean false value.
+ */
+ static final Set FALSE_VALUES;
+
+ /**
+ * A UUID pattern for UUIDs with or without hyphens
+ */
+ private static final Pattern UUID_PATTERN = Pattern.compile("(\\p{XDigit}{8})-?(\\p{XDigit}{4})-?(\\p{XDigit}{4})-?(\\p{XDigit}{4})-?(\\p{XDigit}{12})");
+
+ /**
+ * The Jackson ObjectMapper or Gson instance, if available.
+ */
+ private static final Object JSON_MAPPER;
+
+ /**
+ * The Jackson ObjectMapper::readValue or Gson::fromJson method, if available.
+ */
+ private static final Method JSON_READ_METHOD;
+
+ /**
+ * The Jackson ObjectMapper::writeValueToString or Gson::toJson method, if available.
+ */
+ private static final Method JSON_WRITE_METHOD;
+
+ /**
+ * Whether a JAXB implementation is available.
+ */
+ private static final boolean JAXB_AVAILABLE;
+
+ static {
+ Set trueValues = new HashSet<>();
+ Set falseValues = new HashSet<>();
+
+ trueValues.add("1");
+ trueValues.add("1.0");
+ trueValues.add("y");
+ trueValues.add("Y");
+ trueValues.add("yes");
+ trueValues.add("YES");
+ trueValues.add("true");
+ trueValues.add("TRUE");
+ trueValues.add("t");
+ trueValues.add("T");
+ trueValues.add("on");
+ trueValues.add("ON");
+ trueValues.add("enabled");
+ trueValues.add("ENABLED");
+
+ falseValues.add("0");
+ falseValues.add("0.0");
+ falseValues.add("n");
+ falseValues.add("N");
+ falseValues.add("no");
+ falseValues.add("NO");
+ falseValues.add("false");
+ falseValues.add("FALSE");
+ falseValues.add("f");
+ falseValues.add("F");
+ falseValues.add("off");
+ falseValues.add("OFF");
+ falseValues.add("disabled");
+ falseValues.add("DISABLED");
+
+ TRUE_VALUES = Collections.unmodifiableSet(trueValues);
+ FALSE_VALUES = Collections.unmodifiableSet(falseValues);
+
+ Object jsonMapper = null;
+ Method jsonReadMethod = null;
+ Method jsonWriteMethod = null;
+ boolean jaxbAvailable = false;
+
+ try {
+ Class> klass = Class.forName("com.fasterxml.jackson.databind.ObjectMapper");
+
+ jsonMapper = klass.getDeclaredConstructor().newInstance();
+ jsonReadMethod = klass.getMethod("readValue", String.class, Class.class);
+ jsonWriteMethod = klass.getMethod("writeValueAsString", Object.class);
+ log.debug("Jackson is available");
+ }
+ catch (Exception e1) {
+ log.debug("Jackson not available", e1.getMessage());
+
+ try {
+ Class> klass = Class.forName("com.google.gson.Gson");
+
+ jsonMapper = klass.getDeclaredConstructor().newInstance();
+ jsonReadMethod = klass.getMethod("fromJson", String.class, Class.class);
+ jsonWriteMethod = klass.getMethod("toJson", Object.class);
+ log.debug("Gson is available");
+ }
+ catch (Exception e2) {
+ log.debug("Gson not available", e2.getMessage());
+ }
+ }
+
+ JSON_MAPPER = jsonMapper;
+ JSON_READ_METHOD = jsonReadMethod;
+ JSON_WRITE_METHOD = jsonWriteMethod;
+
+ try {
+ JAXB.marshal(new InformationSchema(), new StringWriter());
+ jaxbAvailable = true;
+ log.debug("JAXB is available");
+ }
+
+ // [#10145] Depending on whether jOOQ is modularised or not, this can also
+ // be a NoClassDefFoundError.
+ catch (Throwable t) {
+ log.debug("JAXB not available", t.getMessage());
+ }
+
+ JAXB_AVAILABLE = jaxbAvailable;
+ }
+
+ /**
+ * Convert an array of values to a matching data type
+ *
+ * This converts values[i] to fields[i].getType()
+ */
+ static final Object[] convert(Object[] values, Field>[] fields) {
+ if (values == null)
+ return null;
+
+ // [#1005] Convert values from the VALUES clause to appropriate
+ // values as specified by the INTO clause's column list.
+ Object[] result = new Object[values.length];
+
+ // TODO [#1008] Should fields be cast? Check this with
+ // appropriate integration tests
+ for (int i = 0; i < values.length; i++)
+ if (values[i] instanceof Field>)
+ result[i] = values[i];
+ else
+ result[i] = convert(values[i], fields[i].getType());
+
+ return result;
+ }
+
+ /**
+ * Convert an array of values to a matching data type
+ *
+ * This converts values[i] to types[i]
+ */
+ static final Object[] convert(Object[] values, Class>[] types) {
+ if (values == null)
+ return null;
+
+ // [#1005] Convert values from the VALUES clause to appropriate
+ // values as specified by the INTO clause's column list.
+ Object[] result = new Object[values.length];
+
+ // TODO [#1008] Should fields be cast? Check this with
+ // appropriate integration tests
+ for (int i = 0; i < values.length; i++)
+ if (values[i] instanceof Field>)
+ result[i] = values[i];
+ else
+ result[i] = convert(values[i], types[i]);
+
+ return result;
+ }
+ /**
+ * Convert an array into another one using a converter
+ *
+ * This uses {@link #convertArray(Object[], Class)} to convert the array to
+ * an array of {@link Converter#fromType()} first, before converting that
+ * array again to {@link Converter#toType()}
+ *
+ * @param from The array to convert
+ * @param converter The data type converter
+ * @return A converted array
+ * @throws DataTypeException - When the conversion is not possible
+ */
+ @SuppressWarnings("unchecked")
+ static final U[] convertArray(Object[] from, Converter, ? extends U> converter) throws DataTypeException {
+ if (from == null)
+ return null;
+
+ Object[] arrayOfT = convertArray(from, converter.fromType());
+ Object[] arrayOfU = (Object[]) Array.newInstance(converter.toType(), from.length);
+
+ for (int i = 0; i < arrayOfT.length; i++)
+ arrayOfU[i] = convert(arrayOfT[i], converter);
+
+ return (U[]) arrayOfU;
+ }
+
+ /**
+ * Convert an array into another one by these rules
+ *
+ *
+ *
If toClass is not an array class, then make it an array
+ * class first
+ *
If toClass is an array class, then create an instance
+ * from it, and convert all elements in the from array one by
+ * one, using {@link #convert(Object, Class)}
+ *
+ *
+ * @param from The array to convert
+ * @param toClass The target array type
+ * @return A converted array
+ * @throws DataTypeException - When the conversion is not possible
+ */
+ @SuppressWarnings("unchecked")
+ static final Object[] convertArray(Object[] from, Class> toClass) throws DataTypeException {
+ if (from == null)
+ return null;
+ else if (!toClass.isArray())
+ return convertArray(from, arrayType(toClass));
+ else if (toClass == from.getClass())
+ return from;
+ else {
+ final Class> toComponentType = toClass.getComponentType();
+
+ if (from.length == 0)
+ return Arrays.copyOf(from, from.length, (Class extends Object[]>) toClass);
+ else if (from[0] != null && from[0].getClass() == toComponentType)
+ return Arrays.copyOf(from, from.length, (Class extends Object[]>) toClass);
+ else {
+ final Object[] result = (Object[]) Array.newInstance(toComponentType, from.length);
+
+ for (int i = 0; i < from.length; i++)
+ result[i] = convert(from[i], toComponentType);
+
+ return result;
+ }
+ }
+ }
+
+ static final U[] convertCollection(Collection from, Class extends U[]> to){
+ return new ConvertAll(to).from(from);
+ }
+
+ /**
+ * Convert an object to a type.
+ *
+ * @param from The source object
+ * @param converter The data type converter
+ * @return The target type object
+ * @throws DataTypeException - When the conversion is not possible
+ */
+ @SuppressWarnings("unchecked")
+ static final U convert(Object from, Converter, ? extends U> converter) throws DataTypeException {
+
+ // [#5865] [#6799] [#11099] This leads to significant performance improvements especially when
+ // used from MockResultSet, which is likely to host IdentityConverters
+ if (converter instanceof IdentityConverter)
+ return (U) from;
+ else
+ return convert0(from, converter);
+ }
+
+ /**
+ * Conversion type-safety
+ */
+ @SuppressWarnings("unchecked")
+ private static final U convert0(Object from, Converter converter) throws DataTypeException {
+ Class fromType = converter.fromType();
+
+ if (fromType == Object.class)
+ return converter.from((T) from);
+
+ ConvertAll convertAll = new ConvertAll<>(fromType);
+ return converter.from(convertAll.from(from));
+ }
+
+ /**
+ * Convert an object to a type. These are the conversion rules:
+ *
+ *
null is always converted to null, or the
+ * primitive default value, or {@link Optional#empty()}, regardless of the
+ * target type.
+ *
Identity conversion (converting a value to its own type) is always
+ * possible.
+ *
Primitive types can be converted to their wrapper types and vice
+ * versa
+ *
All types can be converted to String
+ *
All types can be converted to Object
+ *
All Number types can be converted to other
+ * Number types
+ *
All Number or String types can be converted
+ * to Boolean. Possible (case-insensitive) values for
+ * true:
+ *
+ *
1
+ *
1.0
+ *
y
+ *
yes
+ *
true
+ *
on
+ *
enabled
+ *
+ *
+ * Possible (case-insensitive) values for false:
+ *
+ *
0
+ *
0.0
+ *
n
+ *
no
+ *
false
+ *
off
+ *
disabled
+ *
+ *
+ * All other values evaluate to null
+ *
All {@link java.util.Date} subtypes ({@link Date}, {@link Time},
+ * {@link Timestamp}), as well as most {@link Temporal} subtypes (
+ * {@link LocalDate}, {@link LocalTime}, {@link LocalDateTime},
+ * {@link OffsetTime}, {@link OffsetDateTime}, as well as {@link Instant})
+ * can be converted into each other.
+ *
All String types can be converted into {@link URI},
+ * {@link URL} and {@link File}
+ *
byte[] and {@link ByteBuffer} can be converted into one
+ * another
+ *
byte[] can be converted into String, using
+ * the platform's default charset
+ *
Object[] can be converted into any other array type, if
+ * array elements can be converted, too
+ *
All types can be converted into types containing a single argument
+ * constructor whose argument is a type that can be converted to according
+ * to the above rules.
+ *
All other combinations that are not listed above will result in a
+ * {@link DataTypeException}
+ *
+ *
+ * @param from The object to convert
+ * @param toClass The target type
+ * @return The converted object
+ * @throws DataTypeException - When the conversion is not possible
+ */
+ @SuppressWarnings("unchecked")
+ static final T convert(Object from, Class extends T> toClass) throws DataTypeException {
+ if (from != null && from.getClass() == toClass)
+ return (T) from;
+ else
+ return convert0(from, new ConvertAll(toClass));
+ }
+
+ /**
+ * Convert a collection of objects to a list of T, using
+ * {@link #convert(Object, Class)}
+ *
+ * @param collection The list of objects
+ * @param type The target type
+ * @return The list of converted objects
+ * @throws DataTypeException - When the conversion is not possible
+ * @see #convert(Object, Class)
+ */
+ static final List convert(Collection> collection, Class extends T> type) throws DataTypeException {
+ return convert(collection, new ConvertAll<>(type));
+ }
+
+ /**
+ * Convert a collection of objects to a list of T, using
+ * {@link #convert(Object, Converter)}
+ *
+ * @param collection The collection of objects
+ * @param converter The data type converter
+ * @return The list of converted objects
+ * @throws DataTypeException - When the conversion is not possible
+ * @see #convert(Object, Converter)
+ */
+ static final List convert(Collection> collection, Converter, ? extends U> converter) throws DataTypeException {
+ return convert0(collection, converter);
+ }
+
+ /**
+ * Type safe conversion
+ */
+ private static final List convert0(Collection> collection, Converter converter) throws DataTypeException {
+ ConvertAll all = new ConvertAll<>(converter.fromType());
+ List result = new ArrayList<>(collection.size());
+
+ for (Object o : collection)
+ result.add(convert(all.from(o), converter));
+
+ return result;
+ }
+
+ /**
+ * No instances
+ */
+ private Convert() {}
+
+ /**
+ * The converter to convert them all.
+ */
+ private static class ConvertAll implements Converter