JdbcSupport.java
package com.alibaba.fastjson2.util;
import com.alibaba.fastjson2.JSONB;
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.writer.ObjectWriter;
import java.io.Reader;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
public class JdbcSupport {
static Class CLASS_STRUCT;
static volatile boolean CLASS_STRUCT_ERROR;
static Class CLASS_CLOB;
static volatile boolean CLASS_CLOB_ERROR;
public static ObjectReader createTimeReader(Class objectClass, String format, Locale locale) {
return new TimeReader(format, locale);
}
public static ObjectReader createTimestampReader(Class objectClass, String format, Locale locale) {
return new TimestampReader(format, locale);
}
public static ObjectReader createDateReader(Class objectClass, String format, Locale locale) {
return new DateReader(format, locale);
}
public static ObjectWriter createTimeWriter(String format) {
if (format == null) {
return TimeWriter.INSTANCE;
}
return new TimeWriter(format);
}
public static Object createTimestamp(long millis) {
return new Timestamp(millis);
}
public static Object createDate(long millis) {
return new java.sql.Date(millis);
}
public static Object createTime(long millis) {
return new java.sql.Time(millis);
}
public static ObjectWriter createClobWriter(Class objectClass) {
return new ClobWriter(objectClass);
}
public static ObjectWriter createTimestampWriter(Class objectClass, String format) {
return new TimestampWriter(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;
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;
}
@Override
public void write(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
java.sql.Clob clob = (java.sql.Clob) object;
Reader reader;
try {
reader = clob.getCharacterStream();
} catch (SQLException e) {
throw new JSONException("Clob.getCharacterStream error", e);
}
jsonWriter.writeString(reader);
}
}
static class TimeReader
extends ObjectReaderImplDate {
public TimeReader(String format, Locale locale) {
super(format, locale);
}
@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 new Time(millis);
}
if (jsonReader.readIfNull()) {
return null;
}
if (formatISO8601 || formatMillis) {
long millis = jsonReader.readMillisFromString();
return new Time(millis);
}
if (formatUnixTime) {
long seconds = jsonReader.readInt64();
return new Time(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 Time.valueOf(str);
}
}
}
return new Time(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 {
public TimestampWriter(String format) {
super(format);
}
@Override
public void writeJSONB(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
if (object == null) {
jsonWriter.writeNull();
return;
}
Timestamp date = (Timestamp) object;
if (format != null) {
write(jsonWriter, object, fieldName, fieldType, features);
return;
}
LocalDateTime localDateTime = date.toLocalDateTime();
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;
Timestamp date = (Timestamp) 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 = date.getNanos();
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 {
public TimestampReader(String format, Locale locale) {
super(format, locale);
}
@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;
}
byte type = jsonReader.getType();
if (type == JSONB.Constants.BC_LOCAL_DATETIME) {
LocalDateTime ldt = jsonReader.readLocalDateTime();
Instant instant = ldt.atZone(jsonReader.getContext().getZoneId()).toInstant();
return createTimestamp(
instant.toEpochMilli(),
instant.getNano());
}
return readObject(jsonReader, fieldType, fieldName, features);
}
Object createTimestamp(long millis, int nanos) {
Timestamp timestamp = new Timestamp(millis);
if (nanos != 0) {
timestamp.setNanos(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) {
LocalDateTime localDateTime = jsonReader.readLocalDateTime();
if (localDateTime != null) {
return Timestamp.valueOf(localDateTime);
}
if (jsonReader.wasNull()) {
return null;
}
long millis = jsonReader.readMillisFromString();
if (millis == 0 && jsonReader.wasNull()) {
return null;
}
return new Timestamp(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 {
public DateReader(String format, Locale locale) {
super(format, locale);
}
@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 new java.sql.Date(millis);
}
if (jsonReader.readIfNull()) {
return null;
}
if (formatUnixTime) {
if (jsonReader.isString()) {
String str = jsonReader.readString();
long millis = Long.parseLong(str);
millis *= 1000L;
return new java.sql.Date(millis);
}
}
if (format == null || formatISO8601 || formatMillis) {
LocalDateTime localDateTime = jsonReader.readLocalDateTime();
if (localDateTime != null) {
return java.sql.Date.valueOf(localDateTime.toLocalDate());
}
if (jsonReader.wasNull()) {
return null;
}
long millis = jsonReader.readMillisFromString();
if (millis == 0 && jsonReader.wasNull()) {
return null;
}
return new java.sql.Date(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 new java.sql.Date(
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);
}
}