diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultConverterProvider.java b/jOOQ/src/main/java/org/jooq/impl/DefaultConverterProvider.java
index 340a551ab0..f751fcc374 100644
--- a/jOOQ/src/main/java/org/jooq/impl/DefaultConverterProvider.java
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultConverterProvider.java
@@ -80,8 +80,10 @@ public final class DefaultConverterProvider implements ConverterProvider {
if (tWrapper == uWrapper
|| uWrapper.isAssignableFrom(tWrapper)
|| isCollection(tWrapper) && isCollection(uWrapper)
+
|| tWrapper == Optional.class
|| uWrapper == Optional.class
+
|| uWrapper == String.class
|| uWrapper == byte[].class
|| Number.class.isAssignableFrom(uWrapper) // No fail-fast implemented yet!
@@ -93,7 +95,7 @@ public final class DefaultConverterProvider implements ConverterProvider {
|| isDate(tWrapper) && isDate(uWrapper)
|| isEnum(tWrapper) && isEnum(uWrapper)
|| isUUID(tWrapper) && isUUID(uWrapper)
- || isJSON(tWrapper) && isJSON(uWrapper)
+ || isJSON(tWrapper) // && isJSON(uWrapper)
|| Record.class.isAssignableFrom(tWrapper)
|| Struct.class.isAssignableFrom(tWrapper) && UDTRecord.class.isAssignableFrom(uWrapper)
) {
diff --git a/jOOQ/src/main/java/org/jooq/tools/Convert.java b/jOOQ/src/main/java/org/jooq/tools/Convert.java
index cf5326cb37..19453d5a2e 100644
--- a/jOOQ/src/main/java/org/jooq/tools/Convert.java
+++ b/jOOQ/src/main/java/org/jooq/tools/Convert.java
@@ -48,6 +48,7 @@ import static org.jooq.types.Unsigned.ushort;
import java.io.File;
import java.lang.reflect.Array;
+import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URI;
@@ -109,6 +110,8 @@ import org.jooq.types.UShort;
*/
public final class Convert {
+ private static final JooqLogger log = JooqLogger.getLogger(Convert.class);
+
/**
* All string values that can be transformed into a boolean true value.
*/
@@ -124,6 +127,16 @@ public final class Convert {
*/
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;
+
static {
Set trueValues = new HashSet<>();
Set falseValues = new HashSet<>();
@@ -160,6 +173,32 @@ public final class Convert {
TRUE_VALUES = Collections.unmodifiableSet(trueValues);
FALSE_VALUES = Collections.unmodifiableSet(falseValues);
+
+ Object jsonMapper = null;
+ Method jsonReadMethod = null;
+
+ try {
+ Class> klass = Class.forName("com.fasterxml.jackson.databind.ObjectMapper");
+
+ jsonMapper = klass.getConstructor().newInstance();
+ jsonReadMethod = klass.getMethod("readValue", String.class, Class.class);
+ }
+ catch (Exception e1) {
+ log.debug("Jackson not found on the classpath");
+
+ try {
+ Class> klass = Class.forName("com.google.gson.Gson");
+
+ jsonMapper = klass.getConstructor().newInstance();
+ jsonReadMethod = klass.getMethod("fromJson", String.class, Class.class);
+ }
+ catch (Exception e2) {
+ log.debug("Gson not found on the classpath");
+ }
+ }
+
+ JSON_MAPPER = jsonMapper;
+ JSON_READ_METHOD = jsonReadMethod;
}
/**
@@ -1019,6 +1058,26 @@ public final class Convert {
return (U) JSONB.valueOf((String) from);
}
+ // [#10072] Out of the box Jackson JSON mapping support
+ else if (fromClass == JSON.class && JSON_MAPPER != null) {
+ try {
+ return (U) JSON_READ_METHOD.invoke(JSON_MAPPER, ((JSON) from).data(), toClass);
+ }
+ catch (Exception e) {
+ throw new DataTypeException("Error while mapping JSON to POJO using Jackson", e);
+ }
+ }
+
+ // [#10072] Out of the box Jackson JSON mapping support
+ else if (fromClass == JSONB.class && JSON_MAPPER != null) {
+ try {
+ return (U) JSON_READ_METHOD.invoke(JSON_MAPPER, ((JSONB) from).data(), toClass);
+ }
+ catch (Exception e) {
+ throw new DataTypeException("Error while mapping JSON to POJO using Jackson", e);
+ }
+ }
+
// [#3023] Record types can be converted using the supplied Configuration's
// RecordMapperProvider
else if (Record.class.isAssignableFrom(fromClass)) {