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

shade.com.alibaba.fastjson2.util.JdbcSupport Maven / Gradle / Ivy

There is a newer version: 1.3.7
Show newest version
package com.alibaba.fastjson2.util;

import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.codec.DateTimeCodec;
import com.alibaba.fastjson2.reader.ObjectReader;
import com.alibaba.fastjson2.reader.ObjectReaderImplDate;
import com.alibaba.fastjson2.support.LambdaMiscCodec;
import com.alibaba.fastjson2.writer.ObjectWriter;

import java.io.Reader;
import java.lang.invoke.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
import java.util.function.Function;
import java.util.function.LongFunction;
import java.util.function.ObjIntConsumer;
import java.util.function.ToIntFunction;

import static com.alibaba.fastjson2.support.LambdaMiscCodec.*;

public class JdbcSupport {
    static Class CLASS_STRUCT;
    static volatile boolean CLASS_STRUCT_ERROR;

    static Class CLASS_CLOB;
    static volatile boolean CLASS_CLOB_ERROR;

    static volatile LongFunction TIMESTAMP_CREATOR;
    static volatile boolean TIMESTAMP_CREATOR_ERROR;

    static volatile LongFunction DATE_CREATOR;
    static volatile boolean DATE_CREATOR_ERROR;

    static volatile LongFunction TIME_CREATOR;
    static volatile boolean TIME_CREATOR_ERROR;

    public static ObjectReader createTimeReader(Class objectClass, String format, Locale locale) {
        return new TimeReader(objectClass, format, locale);
    }

    public static ObjectReader createTimestampReader(Class objectClass, String format, Locale locale) {
        return new TimestampReader(objectClass, format, locale);
    }

    public static ObjectReader createDateReader(Class objectClass, String format, Locale locale) {
        return new DateReader(objectClass, format, locale);
    }

    public static ObjectWriter createTimeWriter(String format) {
        if (format == null) {
            return TimeWriter.INSTANCE;
        }

        return new TimeWriter(format);
    }

    public static Object createTimestamp(long millis) {
        if (TIMESTAMP_CREATOR == null && !TIMESTAMP_CREATOR_ERROR) {
            try {
                TIMESTAMP_CREATOR = createFunction("java.sql.Timestamp");
            } catch (Throwable ignored) {
                TIMESTAMP_CREATOR_ERROR = true;
            }
        }

        if (TIMESTAMP_CREATOR == null) {
            throw new JSONException("create java.sql.Timestamp error");
        }

        return TIMESTAMP_CREATOR.apply(millis);
    }

    public static Object createDate(long millis) {
        if (DATE_CREATOR == null && !DATE_CREATOR_ERROR) {
            try {
                DATE_CREATOR = createFunction("java.sql.Date");
            } catch (Throwable ignored) {
                DATE_CREATOR_ERROR = true;
            }
        }

        if (DATE_CREATOR == null) {
            throw new JSONException("create java.sql.Date error");
        }

        return DATE_CREATOR.apply(millis);
    }

    public static Object createTime(long millis) {
        if (TIME_CREATOR == null && !TIME_CREATOR_ERROR) {
            try {
                TIME_CREATOR = createFunction("java.sql.Time");
            } catch (Throwable ignored) {
                TIME_CREATOR_ERROR = true;
            }
        }

        if (TIME_CREATOR == null) {
            throw new JSONException("create java.sql.Timestamp error");
        }

        return TIME_CREATOR.apply(millis);
    }

    static LongFunction createFunction(String className) throws Throwable {
        Class timestampClass = Class.forName(className);
        MethodHandles.Lookup lookup = JDKUtils.trustedLookup(timestampClass);
        MethodHandle constructor = lookup.findConstructor(timestampClass, MethodType.methodType(void.class, long.class));
        CallSite callSite = LambdaMetafactory.metafactory(
                lookup,
                "apply",
                MethodType.methodType(LongFunction.class),
                MethodType.methodType(Object.class, long.class),
                constructor,
                MethodType.methodType(Object.class, long.class)
        );
        MethodHandle target = callSite.getTarget();
        return (LongFunction) target.invokeExact();
    }

    public static ObjectWriter createClobWriter(Class objectClass) {
        return new ClobWriter(objectClass);
    }

    public static ObjectWriter createTimestampWriter(Class objectClass, String format) {
        return new TimestampWriter(objectClass, format);
    }

    public static boolean isClob(Class objectClass) {
        if (CLASS_CLOB == null && !CLASS_CLOB_ERROR) {
            try {
                CLASS_CLOB = Class.forName("java.sql.Clob");
            } catch (Throwable e) {
                CLASS_CLOB_ERROR = true;
            }
        }

        return CLASS_CLOB != null && CLASS_CLOB.isAssignableFrom(objectClass);
    }

    static class ClobWriter
            implements ObjectWriter {
        final Class objectClass;
        final Function function;

        public ClobWriter(Class objectClass) {
            if (CLASS_CLOB == null && !CLASS_CLOB_ERROR) {
                try {
                    CLASS_CLOB = Class.forName("java.sql.Clob");
                } catch (Throwable e) {
                    CLASS_CLOB_ERROR = true;
                }
            }

            if (CLASS_CLOB == null) {
                throw new JSONException("class java.sql.Clob not found");
            }

            this.objectClass = objectClass;
            try {
                Method getCharacterStream = CLASS_CLOB.getMethod("getCharacterStream");
                function = LambdaMiscCodec.createFunction(getCharacterStream);
            } catch (Throwable e) {
                throw new JSONException("getMethod getCharacterStream error", e);
            }
        }

        @Override
        public void write(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
            Reader reader = (Reader) function.apply(object);
            jsonWriter.writeString(reader);
        }
    }

    static class TimeReader
            extends ObjectReaderImplDate {
        final LongFunction function;
        final Function functionValueOf;

        public TimeReader(Class objectClass, String format, Locale locale) {
            super(format, locale);
            try {
                function = createLongFunction(
                        objectClass.getConstructor(long.class)
                );

                Method methodValueOf = objectClass.getMethod("valueOf", String.class);
                functionValueOf = LambdaMiscCodec.createFunction(methodValueOf);
            } catch (NoSuchMethodException e) {
                throw new IllegalStateException("illegal state", e);
            }
        }

        @Override
        public Object readJSONBObject(JSONReader jsonReader, Type fieldType, Object fieldName, long features) {
            return readObject(jsonReader, fieldType, fieldName, features);
        }

        @Override
        public Object readObject(JSONReader jsonReader, Type fieldType, Object fieldName, long features) {
            if (jsonReader.isInt()) {
                long millis = jsonReader.readInt64Value();

                if (formatUnixTime) {
                    millis *= 1000;
                }
                return function.apply(millis);
            }

            if (jsonReader.readIfNull()) {
                return null;
            }

            if (formatISO8601 || formatMillis) {
                long millis = jsonReader.readMillisFromString();
                return function.apply(millis);
            }

            if (formatUnixTime) {
                long seconds = jsonReader.readInt64();
                return function.apply(seconds * 1000L);
            }

            long millis;
            if (format != null) {
                DateTimeFormatter formatter = getDateFormatter(jsonReader.getLocale());

                ZonedDateTime zdt;
                if (formatter != null) {
                    String str = jsonReader.readString();
                    if (str.isEmpty()) {
                        return null;
                    }

                    LocalDateTime ldt;
                    if (!formatHasHour) {
                        ldt = LocalDateTime.of(
                                LocalDate.parse(str, formatter),
                                LocalTime.MIN
                        );
                    } else if (!formatHasDay) {
                        ldt = LocalDateTime.of(
                                LocalDate.of(1970, 1, 1),
                                LocalTime.parse(str, formatter)
                        );
                    } else {
                        ldt = LocalDateTime.parse(str, formatter);
                    }
                    zdt = ldt.atZone(jsonReader.getContext().getZoneId());
                } else {
                    zdt = jsonReader.readZonedDateTime();
                }
                millis = zdt.toInstant().toEpochMilli();
            } else {
                String str = jsonReader.readString();
                if ("0000-00-00".equals(str) || "0000-00-00 00:00:00".equals(str)) {
                    millis = 0;
                } else {
                    if (str.length() == 9 && str.charAt(8) == 'Z') {
                        LocalTime localTime = DateUtils.parseLocalTime(
                                str.charAt(0),
                                str.charAt(1),
                                str.charAt(2),
                                str.charAt(3),
                                str.charAt(4),
                                str.charAt(5),
                                str.charAt(6),
                                str.charAt(7)
                        );
                        millis = LocalDateTime.of(DateUtils.LOCAL_DATE_19700101, localTime)
                                .atZone(DateUtils.DEFAULT_ZONE_ID)
                                .toInstant()
                                .toEpochMilli();
                    } else {
                        if (str.isEmpty() || "null".equals(str)) {
                            return null;
                        }
                        return functionValueOf.apply(str);
                    }
                }
            }

            return function.apply(millis);
        }
    }

    static class TimeWriter
            extends DateTimeCodec
            implements ObjectWriter {
        public static final TimeWriter INSTANCE = new TimeWriter(null);

        public TimeWriter(String format) {
            super(format);
        }

        @Override
        public void write(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
            if (object == null) {
                jsonWriter.writeNull();
                return;
            }

            JSONWriter.Context context = jsonWriter.context;
            if (formatUnixTime || context.isDateFormatUnixTime()) {
                long millis = ((Date) object).getTime();
                long seconds = millis / 1000;
                jsonWriter.writeInt64(seconds);
                return;
            }

            if (formatMillis || context.isDateFormatMillis()) {
                long millis = ((Date) object).getTime();
                jsonWriter.writeInt64(millis);
                return;
            }

            if (formatISO8601 || context.isDateFormatISO8601()) {
                ZoneId zoneId = context.getZoneId();
                long millis = ((Date) object).getTime();
                Instant instant = Instant.ofEpochMilli(millis);
                ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, zoneId);
                int offsetSeconds = zdt.getOffset().getTotalSeconds();

                int year = zdt.getYear();
                int month = zdt.getMonthValue();
                int dayOfMonth = zdt.getDayOfMonth();
                int hour = zdt.getHour();
                int minute = zdt.getMinute();
                int second = zdt.getSecond();
                int nano = 0;
                jsonWriter.writeDateTimeISO8601(year, month, dayOfMonth, hour, minute, second, nano, offsetSeconds, true);
                return;
            }

            DateTimeFormatter dateFormatter = null;
            if (format != null && !format.contains("dd")) {
                dateFormatter = getDateFormatter();
            }

            if (dateFormatter == null) {
                String format = context.getDateFormat();
                if (format != null && !format.contains("dd")) {
                    dateFormatter = context.getDateFormatter();
                }
            }

            if (dateFormatter == null) {
                jsonWriter.writeString(object.toString());
                return;
            }

            Date time = (Date) object;

            ZoneId zoneId = context.getZoneId();
            Instant instant = Instant.ofEpochMilli(time.getTime());
            ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, zoneId);

            String str = dateFormatter.format(zdt);
            jsonWriter.writeString(str);
        }
    }

    static class TimestampWriter
            extends DateTimeCodec
            implements ObjectWriter {
        final ToIntFunction functionGetNano;
        final Function functionToLocalDateTime;

        public TimestampWriter(Class objectClass, String format) {
            super(format);
            try {
                functionGetNano = createToIntFunction(
                        objectClass.getMethod("getNanos")
                );
                Method methodToLocalDateTime = objectClass.getMethod("toLocalDateTime");
                functionToLocalDateTime = LambdaMiscCodec.createFunction(methodToLocalDateTime);
            } catch (NoSuchMethodException e) {
                throw new JSONException("illegal state", e);
            }
        }

        @Override
        public void writeJSONB(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
            if (object == null) {
                jsonWriter.writeNull();
                return;
            }

            Date date = (Date) object;

            int nanos;
            nanos = functionGetNano.applyAsInt(object);

            if (nanos == 0) {
                jsonWriter.writeMillis(date.getTime());
                return;
            }

            LocalDateTime localDateTime = (LocalDateTime) functionToLocalDateTime.apply(object);
            jsonWriter.writeLocalDateTime(localDateTime);
        }

        @Override
        public void write(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
            if (object == null) {
                jsonWriter.writeNull();
                return;
            }

            JSONWriter.Context ctx = jsonWriter.context;

            Date date = (Date) object;

            if (formatUnixTime || ctx.isDateFormatUnixTime()) {
                long millis = date.getTime();
                jsonWriter.writeInt64(millis / 1000L);
                return;
            }

            ZoneId zoneId = ctx.getZoneId();
            Instant instant = date.toInstant();
            ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, zoneId);
            int offsetSeconds = zdt.getOffset().getTotalSeconds();

            if ((formatISO8601 || ctx.isDateFormatISO8601()) && (zdt.getNano() % 1000_000 == 0)) {
                int year = zdt.getYear();
                int month = zdt.getMonthValue();
                int dayOfMonth = zdt.getDayOfMonth();
                int hour = zdt.getHour();
                int minute = zdt.getMinute();
                int second = zdt.getSecond();
                int nano = zdt.getNano();
                int millis = nano / 1000_000;
                jsonWriter.writeDateTimeISO8601(year, month, dayOfMonth, hour, minute, second, millis, offsetSeconds, true);
                return;
            }

            DateTimeFormatter dateFormatter = getDateFormatter();
            if (dateFormatter == null) {
                dateFormatter = ctx.getDateFormatter();
            }

            if (dateFormatter == null) {
                if (formatMillis || ctx.isDateFormatMillis()) {
                    long millis = date.getTime();
                    jsonWriter.writeInt64(millis);
                    return;
                }

                int nanos = functionGetNano.applyAsInt(date);

                if (nanos == 0) {
                    jsonWriter.writeInt64(date.getTime());
                    return;
                }

                int year = zdt.getYear();
                int month = zdt.getMonthValue();
                int dayOfMonth = zdt.getDayOfMonth();
                int hour = zdt.getHour();
                int minute = zdt.getMinute();
                int second = zdt.getSecond();
                if (nanos % 1000_000 == 0) {
                    jsonWriter.writeDateTimeISO8601(year, month, dayOfMonth, hour, minute, second, nanos / 1000_000, offsetSeconds, false);
                } else {
                    jsonWriter.writeLocalDateTime(zdt.toLocalDateTime());
                }
            } else {
                String str = dateFormatter.format(zdt);
                jsonWriter.writeString(str);
            }
        }
    }

    static class TimestampReader
            extends ObjectReaderImplDate {
        final LongFunction function;
        final ObjIntConsumer functionSetNanos;
        final Function functionValueOf;

        public TimestampReader(Class objectClass, String format, Locale locale) {
            super(format, locale);
            try {
                Constructor constructor = objectClass.getConstructor(long.class);
                this.function = createLongFunction(constructor);
            } catch (Throwable e) {
                throw new IllegalStateException("illegal state", e);
            }

            try {
                Method methodSetNanos = objectClass.getMethod("setNanos", int.class);
                functionSetNanos = createObjIntConsumer(methodSetNanos);
            } catch (NoSuchMethodException e) {
                throw new IllegalStateException("illegal state", e);
            }

            Function functionValueOf = null;
            try {
                Method methodValueOf = objectClass.getMethod("valueOf", LocalDateTime.class);
                functionValueOf = LambdaMiscCodec.createFunction(methodValueOf);
            } catch (Throwable ignored) {
                // ignored
            }
            this.functionValueOf = functionValueOf;
        }

        @Override
        public Object readJSONBObject(JSONReader jsonReader, Type fieldType, Object fieldName, long features) {
            if (jsonReader.isInt()) {
                long millis = jsonReader.readInt64Value();

                if (formatUnixTime) {
                    millis *= 1000;
                }

                return createTimestamp(millis, 0);
            }

            if (jsonReader.readIfNull()) {
                return null;
            }

            return readObject(jsonReader, fieldType, fieldName, features);
        }

        Object createTimestamp(long millis, int nanos) {
            Object timestamp = function.apply(millis);
            if (nanos != 0) {
                functionSetNanos.accept(timestamp, nanos);
            }
            return timestamp;
        }

        @Override
        public Object readObject(JSONReader jsonReader, Type fieldType, Object fieldName, long features) {
            if (jsonReader.isInt()) {
                long millis = jsonReader.readInt64Value();

                if (formatUnixTime) {
                    millis *= 1000L;
                }

                return createTimestamp(millis, 0);
            }

            if (jsonReader.nextIfNullOrEmptyString()) {
                return null;
            }

            if (format == null || formatISO8601 || formatMillis) {
                if (functionValueOf != null) {
                    LocalDateTime localDateTime = jsonReader.readLocalDateTime();
                    if (localDateTime != null) {
                        return functionValueOf.apply(localDateTime);
                    }

                    if (jsonReader.wasNull()) {
                        return null;
                    }
                }

                long millis = jsonReader.readMillisFromString();
                if (millis == 0 && jsonReader.wasNull()) {
                    return null;
                }
                return function.apply(millis);
            }

            String str = jsonReader.readString();
            if (str.isEmpty()) {
                return null;
            }

            DateTimeFormatter dateFormatter = getDateFormatter();

            Instant instant;
            if (!formatHasHour) {
                LocalDate localDate = LocalDate.parse(str, dateFormatter);
                LocalDateTime ldt = LocalDateTime.of(localDate, LocalTime.MIN);
                instant = ldt.atZone(jsonReader.getContext().getZoneId()).toInstant();
            } else {
                LocalDateTime ldt = LocalDateTime.parse(str, dateFormatter);
                instant = ldt.atZone(jsonReader.getContext().getZoneId()).toInstant();
            }

            long millis = instant.toEpochMilli();
            int nanos = instant.getNano();

            return createTimestamp(millis, nanos);
        }
    }

    static class DateReader
            extends ObjectReaderImplDate {
        final LongFunction function;
        final Function functionValueOf;

        public DateReader(Class objectClass, String format, Locale locale) {
            super(format, locale);

            try {
                Constructor constructor = objectClass.getConstructor(long.class);
                this.function = createLongFunction(constructor);
            } catch (Throwable e) {
                throw new IllegalStateException("illegal state", e);
            }

            try {
                Method methodValueOf = objectClass.getMethod("valueOf", LocalDate.class);
                functionValueOf = LambdaMiscCodec.createFunction(methodValueOf);
            } catch (NoSuchMethodException | SecurityException e) {
                throw new IllegalStateException("illegal state", e);
            }
        }

        @Override
        public Object readJSONBObject(JSONReader jsonReader, Type fieldType, Object fieldName, long features) {
            return readObject(jsonReader, fieldType, fieldName, features);
        }

        @Override
        public Object readObject(JSONReader jsonReader, Type fieldType, Object fieldName, long features) {
            if (jsonReader.isInt()) {
                long millis = jsonReader.readInt64Value();

                if (formatUnixTime) {
                    millis *= 1000L;
                }

                return function.apply(millis);
            }

            if (jsonReader.readIfNull()) {
                return null;
            }

            if (formatUnixTime) {
                if (jsonReader.isString()) {
                    String str = jsonReader.readString();
                    long millis = Long.parseLong(str);
                    millis *= 1000L;
                    return function.apply(millis);
                }
            }

            if (format == null || formatISO8601 || formatMillis) {
                LocalDateTime localDateTime = jsonReader.readLocalDateTime();
                if (localDateTime != null) {
                    return functionValueOf.apply(localDateTime.toLocalDate());
                }

                if (jsonReader.wasNull()) {
                    return null;
                }

                long millis = jsonReader.readMillisFromString();
                if (millis == 0 && jsonReader.wasNull()) {
                    return null;
                }
                return function.apply(millis);
            }

            String str = jsonReader.readString();
            if (str.isEmpty()) {
                return null;
            }

            DateTimeFormatter dateFormatter = getDateFormatter();

            Instant instant;
            if (!formatHasHour) {
                LocalDate localDate = LocalDate.parse(str, dateFormatter);
                LocalDateTime ldt = LocalDateTime.of(localDate, LocalTime.MIN);
                instant = ldt.atZone(jsonReader.getContext().getZoneId()).toInstant();
            } else {
                LocalDateTime ldt = LocalDateTime.parse(str, dateFormatter);
                instant = ldt.atZone(jsonReader.getContext().getZoneId()).toInstant();
            }

            return function.apply(
                    instant.toEpochMilli()
            );
        }
    }

    public static boolean isStruct(Class objectClass) {
        if (CLASS_STRUCT == null && !CLASS_STRUCT_ERROR) {
            try {
                CLASS_STRUCT = Class.forName("java.sql.Struct");
            } catch (Throwable e) {
                CLASS_STRUCT_ERROR = true;
            }
        }

        return CLASS_STRUCT != null && CLASS_STRUCT.isAssignableFrom(objectClass);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy