All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zodiac.fastorm.rdb.codec.JsonValueCodec Maven / Gradle / Ivy

The newest version!
package org.zodiac.fastorm.rdb.codec;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.util.ByteBufferBackedInputStream;

import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zodiac.fastorm.core.ValueCodec;
import org.zodiac.fastorm.rdb.utils.FeatureUtils;
import org.zodiac.sdk.toolkit.util.ExceptionUtil;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.ByteBuffer;
import java.sql.Blob;
import java.sql.Clob;
import java.util.Collection;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class JsonValueCodec implements ValueCodec {

    private static Logger log = LoggerFactory.getLogger(JsonValueCodec.class);

    public static final ObjectMapper OBJECT_MAPPER;

    static {
        OBJECT_MAPPER = new ObjectMapper()
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .setDefaultPropertyInclusion(JsonInclude.Include.NON_NULL)
                .setTimeZone(TimeZone.getDefault());
    }

    private final JavaType jacksonType;

    private final Class targetType;

    private ObjectMapper mapper = OBJECT_MAPPER;

    public JsonValueCodec(Class targetType, JavaType type) {
        this.jacksonType = type;
        this.targetType = targetType;
    }

    public void setMapper(ObjectMapper mapper) {
        this.mapper = mapper;
    }

    @Override
    public Object encode(Object value) {
        Object result = null;
        if (value == null) {
            return null;
        }
        if (value instanceof String) {
            return value;
        }
        try {
            result = mapper.writeValueAsString(value);
        } catch (JsonProcessingException e) {
            ExceptionUtil.chuck(e);
        }
        return result;
    }

    @Override
    public Object decode(Object data) {
        try {
            Object target = data;

            if (data instanceof Clob) {
                target = mapper.readValue(((Clob) data).getCharacterStream(), jacksonType);
            } else if (data instanceof Blob) {
                target = mapper.readValue(((Blob) data).getBinaryStream(), jacksonType);
            } else if (data instanceof InputStream) {
                target = mapper.readValue((InputStream) data, jacksonType);
            } else if (data instanceof byte[]) {
                target = mapper.readValue((byte[]) data, jacksonType);
            } else if (data instanceof String) {
                target = mapper.readValue(((String) data), jacksonType);
            } else if (data instanceof ByteBuffer) {
                return doRead(new ByteBufferBackedInputStream(((ByteBuffer) data)));
            } else if (FeatureUtils.r2dbcIsAlive()) {
                Mono mono = null;
                if (data instanceof io.r2dbc.spi.Clob) {
                    mono = Flux.from(((io.r2dbc.spi.Clob) data).stream())
                               .collect(Collectors.joining())
                               .map(this::doRead);

                } else if (data instanceof io.r2dbc.spi.Blob) {
                    mono = Mono.from(((io.r2dbc.spi.Blob) data).stream())
                               .map(ByteBufferBackedInputStream::new)
                               .map(this::doRead);
                }
                if (mono != null) {
                    if (targetType == Mono.class || targetType == Publisher.class) {
                        return mono;
                    }
                    if (targetType == Flux.class) {
                        return mono.flux();
                    }
                    /*TODO: A better way?*/
                    target = mono.toFuture().get(10, TimeUnit.SECONDS);
                }
            }

            if (targetType.isInstance(target)) {
                return target;
            }
            if (targetType == Mono.class || targetType == Publisher.class) {
                return target == null ? Mono.empty() : Mono.just(target);
            }
            if (targetType == Flux.class) {
                return target == null ? Flux.empty() : Flux.just(target);
            }
            log.warn("unsupported json format:{}", data);
            return target;
        } catch (Throwable e) {
            log.error("decode json error {}", data, e);
            return null;
        }
    }

    protected Object doRead(String str) {
        Object result = null;
        try {
            result = mapper.readValue(str, jacksonType);
        } catch (JsonProcessingException e) {
            ExceptionUtil.chuck(e);
        }
        return result;
    }

    protected Object doRead(InputStream stream) {
        Object result = null;
        try {
            result = mapper.readValue(stream, jacksonType);
        } catch (IOException e) {
            ExceptionUtil.chuck(e);
        }
        return result;
    }

    public static JsonValueCodec of(Class targetType) {
        return new JsonValueCodec(targetType, OBJECT_MAPPER.getTypeFactory().constructType(targetType));
    }

    public static JsonValueCodec ofCollection(Class targetType
            , Class elementType) {
        return new JsonValueCodec(targetType, OBJECT_MAPPER
                .getTypeFactory()
                .constructCollectionType(targetType, elementType));
    }

    public static JsonValueCodec ofMap(Class targetType, Class keyType, Class valueType) {
        return new JsonValueCodec(targetType, OBJECT_MAPPER.getTypeFactory()
                                                           .constructMapType(targetType, keyType, valueType));
    }

    public static JsonValueCodec ofField(Field field) {
        Class type = field.getType();
        Class targetType = type;
        Type genericType = field.getGenericType();
        JavaType jacksonType = null;

        if (type == Mono.class || type == Flux.class) {
            targetType = (Class) ((ParameterizedType) genericType).getActualTypeArguments()[0];
        }
        if (Map.class.isAssignableFrom(targetType)) {
            if (genericType instanceof ParameterizedType) {
                Type[] types = ((ParameterizedType) genericType).getActualTypeArguments();
                jacksonType = OBJECT_MAPPER
                        .getTypeFactory()
                        .constructMapType(targetType, (Class) types[0], (Class) types[1]);
            }

        } else if (Collection.class.isAssignableFrom(targetType)) {
            if (genericType instanceof ParameterizedType) {
                Type[] types = ((ParameterizedType) genericType).getActualTypeArguments();
                jacksonType = OBJECT_MAPPER
                        .getTypeFactory()
                        .constructCollectionType(targetType, (Class) types[0]);
            }
        } else if (targetType.isArray()) {
            jacksonType = OBJECT_MAPPER
                    .getTypeFactory()
                    .constructArrayType(targetType.getComponentType());
        }
        if (jacksonType == null) {
            jacksonType = OBJECT_MAPPER.getTypeFactory().constructType(targetType);
        }

        return new JsonValueCodec(type, jacksonType);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy