[jOOQ/jOOQ#10072] Out of the box support mapping between JSON and POJOs using Jackson/Gson

This commit is contained in:
Lukas Eder 2020-04-15 17:21:00 +02:00
parent 70a293d1f9
commit 8446f10c10
2 changed files with 62 additions and 1 deletions

View File

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

View File

@ -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 <code>true</code> 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<String> trueValues = new HashSet<>();
Set<String> 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)) {