This is an automated email from the ASF dual-hosted git repository.
chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git
The following commit(s) were added to refs/heads/main by this push:
new 1d8db7376 fix(java): support skip optional sql serializers for java11+
(#3553)
1d8db7376 is described below
commit 1d8db737689f979bf9fda322f5f4e341c15ca7ff
Author: Shawn Yang <[email protected]>
AuthorDate: Sun Apr 12 13:37:29 2026 +0800
fix(java): support skip optional sql serializers for java11+ (#3553)
## Why?
## What does this PR do?
- move optional SQL serializer access behind reflective helpers so
startup does not touch `java.sql` unless those classes are actually used
- add a JPMS regression test for building without `java.sql` and
preserve time ref-tracking behavior for lazy serializer registrations
## Related issues
Fixes #1695
## AI Contribution Checklist
- [ ] Substantial AI assistance was used in this PR: `yes` / `no`
- [ ] If `yes`, I included a completed [AI Contribution
Checklist](https://github.com/apache/fory/blob/main/AI_POLICY.md#9-contributor-checklist-for-ai-assisted-prs)
in this PR description and the required `AI Usage Disclosure`.
- [ ] If `yes`, my PR description includes the required `ai_review`
summary and screenshot evidence of the final clean AI review results
from both fresh reviewers on the current PR diff or current HEAD after
the latest code changes.
## Does this PR introduce any user-facing change?
- [ ] Does this PR introduce any public API change?
- [ ] Does this PR introduce any binary protocol compatibility change?
---
.../org/apache/fory/resolver/ClassResolver.java | 14 +-
.../org/apache/fory/resolver/XtypeResolver.java | 15 +-
.../apache/fory/serializer/SqlTimeSerializers.java | 159 +++++++++++++++++++++
.../apache/fory/serializer/TimeSerializers.java | 94 +-----------
.../main/java/org/apache/fory/type/TypeUtils.java | 55 +++++--
.../apache/fory/JpmsOptionalClassLoadingTest.java | 84 +++++++++++
.../fory/serializer/TimeSerializersTest.java | 4 +-
.../format/encoder/BaseBinaryEncoderBuilder.java | 3 +-
.../apache/fory/format/row/binary/BinaryUtils.java | 4 +-
9 files changed, 319 insertions(+), 113 deletions(-)
diff --git
a/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java
b/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java
index 3a7dbbd2c..f82f6fd07 100644
--- a/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java
+++ b/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java
@@ -35,7 +35,6 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
-import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
@@ -127,6 +126,7 @@ import org.apache.fory.serializer.Serializer;
import org.apache.fory.serializer.SerializerFactory;
import org.apache.fory.serializer.Serializers;
import org.apache.fory.serializer.Shareable;
+import org.apache.fory.serializer.SqlTimeSerializers;
import org.apache.fory.serializer.TimeSerializers;
import org.apache.fory.serializer.UnknownClass;
import org.apache.fory.serializer.UnknownClass.UnknownEmptyStruct;
@@ -329,6 +329,16 @@ public class ClassResolver extends TypeResolver {
ArraySerializers.registerDefaultSerializers(this);
PrimitiveListSerializers.registerDefaultSerializers(this);
TimeSerializers.registerDefaultSerializers(this);
+ if (SqlTimeSerializers.isSqlModuleAvailable()) {
+ SqlTimeSerializers.registerDefaultSerializers(this);
+ } else {
+ Preconditions.checkArgument(
+ extRegistry.classIdGenerator +
SqlTimeSerializers.getNumReservedTypeIds()
+ <= INTERNAL_NATIVE_ID_LIMIT,
+ "Internal type id overflow: %s",
+ extRegistry.classIdGenerator +
SqlTimeSerializers.getNumReservedTypeIds());
+ extRegistry.classIdGenerator +=
SqlTimeSerializers.getNumReservedTypeIds();
+ }
OptionalSerializers.registerDefaultSerializers(this);
CollectionSerializers.registerDefaultSerializers(this);
MapSerializers.registerDefaultSerializers(this);
@@ -374,7 +384,7 @@ public class ClassResolver extends TypeResolver {
private void registerCommonUsedClasses() {
registerInternal(LinkedList.class, TreeSet.class);
registerInternal(LinkedHashMap.class, TreeMap.class);
- registerInternal(Date.class, Timestamp.class, LocalDateTime.class,
Instant.class);
+ registerInternal(Date.class, LocalDateTime.class, Instant.class);
registerInternal(BigInteger.class, BigDecimal.class);
registerInternal(Optional.class, OptionalInt.class);
registerInternal(Boolean[].class, Byte[].class, Short[].class,
Character[].class);
diff --git
a/java/fory-core/src/main/java/org/apache/fory/resolver/XtypeResolver.java
b/java/fory-core/src/main/java/org/apache/fory/resolver/XtypeResolver.java
index 3fb39fb6f..d02da96a8 100644
--- a/java/fory-core/src/main/java/org/apache/fory/resolver/XtypeResolver.java
+++ b/java/fory-core/src/main/java/org/apache/fory/resolver/XtypeResolver.java
@@ -29,7 +29,6 @@ import static org.apache.fory.type.Types.INVALID_USER_TYPE_ID;
import java.math.BigDecimal;
import java.math.BigInteger;
-import java.sql.Timestamp;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
@@ -87,6 +86,7 @@ import org.apache.fory.serializer.SerializationUtils;
import org.apache.fory.serializer.Serializer;
import org.apache.fory.serializer.Serializers;
import org.apache.fory.serializer.Shareable;
+import org.apache.fory.serializer.SqlTimeSerializers;
import org.apache.fory.serializer.TimeSerializers;
import org.apache.fory.serializer.UnionSerializer;
import org.apache.fory.serializer.UnknownClass;
@@ -943,9 +943,16 @@ public class XtypeResolver extends TypeResolver {
registerType(Types.DURATION, Duration.class, new
TimeSerializers.DurationSerializer(config));
registerType(Types.TIMESTAMP, Instant.class, new
TimeSerializers.InstantSerializer(config));
registerType(Types.TIMESTAMP, Date.class, new
TimeSerializers.DateSerializer(config));
- registerType(
- Types.TIMESTAMP, java.sql.Date.class, new
TimeSerializers.SqlDateSerializer(config));
- registerType(Types.TIMESTAMP, Timestamp.class, new
TimeSerializers.TimestampSerializer(config));
+ if (SqlTimeSerializers.isSqlModuleAvailable()) {
+ registerType(
+ Types.TIMESTAMP,
+ TypeUtils.SQL_DATE_TYPE.getRawType(),
+ SqlTimeSerializers.newSqlDateSerializer(config));
+ registerType(
+ Types.TIMESTAMP,
+ TypeUtils.TIMESTAMP_TYPE.getRawType(),
+ SqlTimeSerializers.newTimestampSerializer(config));
+ }
registerType(
Types.TIMESTAMP, LocalDateTime.class, new
TimeSerializers.LocalDateTimeSerializer(config));
registerType(Types.DATE, LocalDate.class, new
TimeSerializers.LocalDateSerializer(config));
diff --git
a/java/fory-core/src/main/java/org/apache/fory/serializer/SqlTimeSerializers.java
b/java/fory-core/src/main/java/org/apache/fory/serializer/SqlTimeSerializers.java
new file mode 100644
index 000000000..dc1247a0e
--- /dev/null
+++
b/java/fory-core/src/main/java/org/apache/fory/serializer/SqlTimeSerializers.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.fory.serializer;
+
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.time.Instant;
+import org.apache.fory.config.Config;
+import org.apache.fory.context.CopyContext;
+import org.apache.fory.context.ReadContext;
+import org.apache.fory.context.WriteContext;
+import org.apache.fory.memory.MemoryBuffer;
+import org.apache.fory.resolver.TypeResolver;
+
+/** Optional SQL time serializers loaded only when {@code java.sql} types are
actually used. */
+public final class SqlTimeSerializers {
+ private static final String SQL_DATE_CLASS_NAME = "java.sql.Date";
+ private static final String SQL_TIME_CLASS_NAME = "java.sql.Time";
+ private static final String SQL_TIMESTAMP_CLASS_NAME = "java.sql.Timestamp";
+ private static final int NUM_RESERVED_TYPE_IDS = 3;
+ private static final boolean SQL_MODULE_AVAILABLE =
+ isClassAvailable(SQL_DATE_CLASS_NAME)
+ && isClassAvailable(SQL_TIME_CLASS_NAME)
+ && isClassAvailable(SQL_TIMESTAMP_CLASS_NAME);
+
+ private SqlTimeSerializers() {}
+
+ public static boolean isSqlModuleAvailable() {
+ return SQL_MODULE_AVAILABLE;
+ }
+
+ public static int getNumReservedTypeIds() {
+ return NUM_RESERVED_TYPE_IDS;
+ }
+
+ public static Serializer<?> newSqlDateSerializer(Config config) {
+ return new SqlDateSerializer(config);
+ }
+
+ public static Serializer<?> newTimestampSerializer(Config config) {
+ return new TimestampSerializer(config);
+ }
+
+ public static void registerDefaultSerializers(TypeResolver resolver) {
+ Config config = resolver.getConfig();
+ resolver.registerInternalSerializer(java.sql.Date.class,
newSqlDateSerializer(config));
+ resolver.registerInternalSerializer(Time.class, new
SqlTimeSerializer(config));
+ resolver.registerInternalSerializer(Timestamp.class,
newTimestampSerializer(config));
+ }
+
+ private static boolean isClassAvailable(String className) {
+ try {
+ Class.forName(className, false,
SqlTimeSerializers.class.getClassLoader());
+ return true;
+ } catch (ClassNotFoundException e) {
+ return false;
+ }
+ }
+
+ public static final class SqlDateSerializer
+ extends TimeSerializers.BaseDateSerializer<java.sql.Date> {
+ public SqlDateSerializer(Config config) {
+ super(config, java.sql.Date.class);
+ }
+
+ public SqlDateSerializer(Config config, boolean needToWriteRef) {
+ super(config, java.sql.Date.class, needToWriteRef);
+ }
+
+ @Override
+ protected java.sql.Date newInstance(long time) {
+ return new java.sql.Date(time);
+ }
+
+ @Override
+ public java.sql.Date copy(CopyContext copyContext, java.sql.Date value) {
+ return newInstance(value.getTime());
+ }
+ }
+
+ public static final class SqlTimeSerializer extends
TimeSerializers.BaseDateSerializer<Time> {
+ public SqlTimeSerializer(Config config) {
+ super(config, Time.class);
+ }
+
+ public SqlTimeSerializer(Config config, boolean needToWriteRef) {
+ super(config, Time.class, needToWriteRef);
+ }
+
+ @Override
+ protected Time newInstance(long time) {
+ return new Time(time);
+ }
+
+ @Override
+ public Time copy(CopyContext copyContext, Time value) {
+ return newInstance(value.getTime());
+ }
+ }
+
+ public static final class TimestampSerializer extends
TimeSerializers.TimeSerializer<Timestamp> {
+ public TimestampSerializer(Config config) {
+ super(config, Timestamp.class);
+ }
+
+ public TimestampSerializer(Config config, boolean needToWriteRef) {
+ super(config, Timestamp.class, needToWriteRef);
+ }
+
+ @Override
+ public void write(WriteContext writeContext, Timestamp value) {
+ MemoryBuffer buffer = writeContext.getBuffer();
+ if (config.isXlang()) {
+ Instant instant = value.toInstant();
+ buffer.writeInt64(instant.getEpochSecond());
+ buffer.writeInt32(instant.getNano());
+ } else {
+ long time = value.getTime() - (value.getNanos() / 1_000_000);
+ buffer.writeInt64(time);
+ buffer.writeInt32(value.getNanos());
+ }
+ }
+
+ @Override
+ public Timestamp read(ReadContext readContext) {
+ MemoryBuffer buffer = readContext.getBuffer();
+ if (config.isXlang()) {
+ long seconds = buffer.readInt64();
+ int nanos = buffer.readInt32();
+ return Timestamp.from(Instant.ofEpochSecond(seconds, nanos));
+ }
+ Timestamp t = new Timestamp(buffer.readInt64());
+ t.setNanos(buffer.readInt32());
+ return t;
+ }
+
+ @Override
+ public Timestamp copy(CopyContext copyContext, Timestamp value) {
+ return new Timestamp(value.getTime());
+ }
+ }
+}
diff --git
a/java/fory-core/src/main/java/org/apache/fory/serializer/TimeSerializers.java
b/java/fory-core/src/main/java/org/apache/fory/serializer/TimeSerializers.java
index 95ce87e0a..a49da25d5 100644
---
a/java/fory-core/src/main/java/org/apache/fory/serializer/TimeSerializers.java
+++
b/java/fory-core/src/main/java/org/apache/fory/serializer/TimeSerializers.java
@@ -19,8 +19,6 @@
package org.apache.fory.serializer;
-import java.sql.Time;
-import java.sql.Timestamp;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
@@ -44,7 +42,7 @@ import org.apache.fory.context.CopyContext;
import org.apache.fory.context.ReadContext;
import org.apache.fory.context.WriteContext;
import org.apache.fory.memory.MemoryBuffer;
-import org.apache.fory.resolver.TypeResolver;
+import org.apache.fory.resolver.ClassResolver;
import org.apache.fory.util.DateTimeUtils;
/** Serializers for all time related types. */
@@ -119,91 +117,6 @@ public class TimeSerializers {
}
}
- public static final class SqlDateSerializer extends
BaseDateSerializer<java.sql.Date> {
- public SqlDateSerializer(Config config) {
- super(config, java.sql.Date.class);
- }
-
- public SqlDateSerializer(Config config, boolean needToWriteRef) {
- super(config, java.sql.Date.class, needToWriteRef);
- }
-
- @Override
- protected java.sql.Date newInstance(long time) {
- return new java.sql.Date(time);
- }
-
- @Override
- public java.sql.Date copy(CopyContext copyContext, java.sql.Date value) {
- return newInstance(value.getTime());
- }
- }
-
- public static final class SqlTimeSerializer extends BaseDateSerializer<Time>
{
-
- public SqlTimeSerializer(Config config) {
- super(config, Time.class);
- }
-
- public SqlTimeSerializer(Config config, boolean needToWriteRef) {
- super(config, Time.class, needToWriteRef);
- }
-
- @Override
- protected Time newInstance(long time) {
- return new Time(time);
- }
-
- @Override
- public Time copy(CopyContext copyContext, Time value) {
- return newInstance(value.getTime());
- }
- }
-
- public static final class TimestampSerializer extends
TimeSerializer<Timestamp> {
-
- public TimestampSerializer(Config config) {
- // conflict with instant
- super(config, Timestamp.class);
- }
-
- public TimestampSerializer(Config config, boolean needToWriteRef) {
- super(config, Timestamp.class, needToWriteRef);
- }
-
- @Override
- public void write(WriteContext writeContext, Timestamp value) {
- MemoryBuffer buffer = writeContext.getBuffer();
- if (config.isXlang()) {
- Instant instant = value.toInstant();
- buffer.writeInt64(instant.getEpochSecond());
- buffer.writeInt32(instant.getNano());
- } else {
- long time = value.getTime() - (value.getNanos() / 1_000_000);
- buffer.writeInt64(time);
- buffer.writeInt32(value.getNanos());
- }
- }
-
- @Override
- public Timestamp read(ReadContext readContext) {
- MemoryBuffer buffer = readContext.getBuffer();
- if (config.isXlang()) {
- long seconds = buffer.readInt64();
- int nanos = buffer.readInt32();
- return Timestamp.from(Instant.ofEpochSecond(seconds, nanos));
- }
- Timestamp t = new Timestamp(buffer.readInt64());
- t.setNanos(buffer.readInt32());
- return t;
- }
-
- @Override
- public Timestamp copy(CopyContext copyContext, Timestamp value) {
- return new Timestamp(value.getTime());
- }
- }
-
public static final class LocalDateSerializer extends
ImmutableTimeSerializer<LocalDate>
implements Shareable {
public LocalDateSerializer(Config config) {
@@ -723,12 +636,9 @@ public class TimeSerializers {
}
}
- public static void registerDefaultSerializers(TypeResolver resolver) {
+ public static void registerDefaultSerializers(ClassResolver resolver) {
Config config = resolver.getConfig();
resolver.registerInternalSerializer(Date.class, new
DateSerializer(config));
- resolver.registerInternalSerializer(java.sql.Date.class, new
SqlDateSerializer(config));
- resolver.registerInternalSerializer(Time.class, new
SqlTimeSerializer(config));
- resolver.registerInternalSerializer(Timestamp.class, new
TimestampSerializer(config));
resolver.registerInternalSerializer(LocalDate.class, new
LocalDateSerializer(config));
resolver.registerInternalSerializer(LocalTime.class, new
LocalTimeSerializer(config));
resolver.registerInternalSerializer(LocalDateTime.class, new
LocalDateTimeSerializer(config));
diff --git a/java/fory-core/src/main/java/org/apache/fory/type/TypeUtils.java
b/java/fory-core/src/main/java/org/apache/fory/type/TypeUtils.java
index caa8b3ab9..aa941e882 100644
--- a/java/fory-core/src/main/java/org/apache/fory/type/TypeUtils.java
+++ b/java/fory-core/src/main/java/org/apache/fory/type/TypeUtils.java
@@ -32,9 +32,6 @@ import java.lang.reflect.WildcardType;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
-import java.sql.Date;
-import java.sql.Time;
-import java.sql.Timestamp;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
@@ -96,6 +93,10 @@ import org.apache.fory.util.record.RecordUtils;
/** Type utils for common type inference and extraction. */
@SuppressWarnings({"UnstableApiUsage", "unchecked"})
public class TypeUtils {
+ private static final String SQL_DATE_CLASS_NAME = "java.sql.Date";
+ private static final String SQL_TIME_CLASS_NAME = "java.sql.Time";
+ private static final String SQL_TIMESTAMP_CLASS_NAME = "java.sql.Timestamp";
+
public static final String JAVA_BOOLEAN = "boolean";
public static final String JAVA_BYTE = "byte";
public static final String JAVA_SHORT = "short";
@@ -124,9 +125,9 @@ public class TypeUtils {
public static final TypeRef<?> STRING_TYPE = TypeRef.of(String.class);
public static final TypeRef<?> BIG_DECIMAL_TYPE =
TypeRef.of(BigDecimal.class);
public static final TypeRef<?> BIG_INTEGER_TYPE =
TypeRef.of(BigInteger.class);
- public static final TypeRef<?> DATE_TYPE = TypeRef.of(Date.class);
+ public static final TypeRef<?> SQL_DATE_TYPE =
optionalTypeRef(SQL_DATE_CLASS_NAME);
public static final TypeRef<?> LOCAL_DATE_TYPE = TypeRef.of(LocalDate.class);
- public static final TypeRef<?> TIMESTAMP_TYPE = TypeRef.of(Timestamp.class);
+ public static final TypeRef<?> TIMESTAMP_TYPE =
optionalTypeRef(SQL_TIMESTAMP_CLASS_NAME);
public static final TypeRef<?> INSTANT_TYPE = TypeRef.of(Instant.class);
public static final TypeRef<?> BINARY_TYPE = TypeRef.of(byte[].class);
public static final TypeRef<?> ITERABLE_TYPE = TypeRef.of(Iterable.class);
@@ -194,9 +195,9 @@ public class TypeUtils {
SUPPORTED_TYPES.add(STRING_TYPE);
SUPPORTED_TYPES.add(BIG_DECIMAL_TYPE);
// SUPPORTED_TYPES.add(BIG_INTEGER_TYPE);
- SUPPORTED_TYPES.add(DATE_TYPE);
+ addIfNotNull(SUPPORTED_TYPES, SQL_DATE_TYPE);
SUPPORTED_TYPES.add(LOCAL_DATE_TYPE);
- SUPPORTED_TYPES.add(TIMESTAMP_TYPE);
+ addIfNotNull(SUPPORTED_TYPES, TIMESTAMP_TYPE);
SUPPORTED_TYPES.add(INSTANT_TYPE);
SUPPORTED_TYPES.add(OPTIONAL_TYPE);
SUPPORTED_TYPES.add(OPTIONAL_INT_TYPE);
@@ -263,6 +264,33 @@ public class TypeUtils {
backward.put(value, key);
}
+ private static void addIfNotNull(Set<TypeRef<?>> set, TypeRef<?> typeRef) {
+ if (typeRef != null) {
+ set.add(typeRef);
+ }
+ }
+
+ private static TypeRef<?> optionalTypeRef(String className) {
+ Class<?> cls = loadOptionalClass(className);
+ return cls == null ? null : TypeRef.of(cls);
+ }
+
+ private static Class<?> loadOptionalClass(String className) {
+ ClassLoader contextClassLoader =
Thread.currentThread().getContextClassLoader();
+ if (contextClassLoader != null) {
+ try {
+ return Class.forName(className, false, contextClassLoader);
+ } catch (ClassNotFoundException ignored) {
+ // Fall through to the defining class loader.
+ }
+ }
+ try {
+ return Class.forName(className, false, TypeUtils.class.getClassLoader());
+ } catch (ClassNotFoundException ignored) {
+ return null;
+ }
+ }
+
public static boolean isNullable(Class<?> clz) {
return !isPrimitive(clz);
}
@@ -965,9 +993,6 @@ public class TypeUtils {
leafTypes.addAll(
Arrays.asList(
java.util.Date.class,
- java.sql.Date.class,
- Time.class,
- Timestamp.class,
LocalDate.class,
LocalTime.class,
LocalDateTime.class,
@@ -985,6 +1010,16 @@ public class TypeUtils {
Calendar.class,
GregorianCalendar.class,
TimeZone.class));
+ addOptionalLeafType(SQL_DATE_CLASS_NAME);
+ addOptionalLeafType(SQL_TIME_CLASS_NAME);
+ addOptionalLeafType(SQL_TIMESTAMP_CLASS_NAME);
+ }
+
+ private static void addOptionalLeafType(String className) {
+ Class<?> cls = loadOptionalClass(className);
+ if (cls != null) {
+ leafTypes.add(cls);
+ }
}
private static final WeakHashMap<Class<?>, Boolean> hasExpandableLeafsCache
= new WeakHashMap<>();
diff --git
a/java/fory-core/src/test/java/org/apache/fory/JpmsOptionalClassLoadingTest.java
b/java/fory-core/src/test/java/org/apache/fory/JpmsOptionalClassLoadingTest.java
new file mode 100644
index 000000000..d34fb18a9
--- /dev/null
+++
b/java/fory-core/src/test/java/org/apache/fory/JpmsOptionalClassLoadingTest.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.fory;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.nio.charset.StandardCharsets;
+import org.apache.fory.memory.Platform;
+import org.testng.SkipException;
+import org.testng.annotations.Test;
+
+public class JpmsOptionalClassLoadingTest {
+ @Test
+ public void testBuildWithoutJavaSqlModule() throws Exception {
+ if (Platform.JAVA_VERSION < 9) {
+ throw new SkipException("Skip on jdk" + Platform.JAVA_VERSION);
+ }
+ String javaBin =
+ System.getProperty("java.home") + File.separator + "bin" +
File.separator + "java";
+ Process process =
+ new ProcessBuilder(
+ javaBin,
+ "--limit-modules",
+ "java.base,java.logging,jdk.unsupported",
+ "-cp",
+ System.getProperty("java.class.path"),
+ NoJavaSqlMain.class.getName())
+ .redirectErrorStream(true)
+ .start();
+ String output = readFully(process.getInputStream());
+ assertEquals(process.waitFor(), 0, output);
+ }
+
+ private static String readFully(InputStream inputStream) throws IOException {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int read;
+ while ((read = inputStream.read(buffer)) != -1) {
+ outputStream.write(buffer, 0, read);
+ }
+ return new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
+ }
+
+ public static final class NoJavaSqlMain {
+ public static void main(String[] args) {
+ Fory fory = Fory.builder().requireClassRegistration(false).build();
+ byte[] bytes = fory.serialize(new SampleValue("fory"));
+ SampleValue value = (SampleValue) fory.deserialize(bytes);
+ if (!"fory".equals(value.value)) {
+ throw new AssertionError("Unexpected round-trip value " + value.value);
+ }
+ }
+ }
+
+ public static final class SampleValue implements Serializable {
+ private final String value;
+
+ public SampleValue(String value) {
+ this.value = value;
+ }
+ }
+}
diff --git
a/java/fory-core/src/test/java/org/apache/fory/serializer/TimeSerializersTest.java
b/java/fory-core/src/test/java/org/apache/fory/serializer/TimeSerializersTest.java
index 5306ac826..af5309b02 100644
---
a/java/fory-core/src/test/java/org/apache/fory/serializer/TimeSerializersTest.java
+++
b/java/fory-core/src/test/java/org/apache/fory/serializer/TimeSerializersTest.java
@@ -334,7 +334,7 @@ public class TimeSerializersTest extends ForyTestBase {
fory.registerSerializer(
Date.class, new TimeSerializers.DateSerializer(fory.getConfig(),
true));
fory.registerSerializer(
- java.sql.Date.class, new
TimeSerializers.SqlDateSerializer(fory.getConfig(), true));
+ java.sql.Date.class, new
SqlTimeSerializers.SqlDateSerializer(fory.getConfig(), true));
fory.registerSerializer(
Instant.class, new
TimeSerializers.InstantSerializer(fory.getConfig(), true));
{
@@ -365,7 +365,7 @@ public class TimeSerializersTest extends ForyTestBase {
TimeStructRef1.class, CodegenSerializer.loadCodegenSerializer(fory,
TimeStructRef1.class));
fory.registerSerializer(Date.class, new
TimeSerializers.DateSerializer(fory.getConfig(), true));
fory.registerSerializer(
- java.sql.Date.class, new
TimeSerializers.SqlDateSerializer(fory.getConfig(), true));
+ java.sql.Date.class, new
SqlTimeSerializers.SqlDateSerializer(fory.getConfig(), true));
fory.registerSerializer(
Instant.class, new TimeSerializers.InstantSerializer(fory.getConfig(),
true));
{
diff --git
a/java/fory-format/src/main/java/org/apache/fory/format/encoder/BaseBinaryEncoderBuilder.java
b/java/fory-format/src/main/java/org/apache/fory/format/encoder/BaseBinaryEncoderBuilder.java
index e27bbdb27..2d214e287 100644
---
a/java/fory-format/src/main/java/org/apache/fory/format/encoder/BaseBinaryEncoderBuilder.java
+++
b/java/fory-format/src/main/java/org/apache/fory/format/encoder/BaseBinaryEncoderBuilder.java
@@ -646,7 +646,8 @@ public abstract class BaseBinaryEncoderBuilder extends
CodecBuilder {
return new StaticInvoke(
DateTimeUtils.class, "daysToLocalDate", TypeUtils.LOCAL_DATE_TYPE,
false, value);
} else if (rawType == java.sql.Date.class) {
- return new StaticInvoke(DateTimeUtils.class, "toJavaDate",
TypeUtils.DATE_TYPE, false, value);
+ return new StaticInvoke(
+ DateTimeUtils.class, "toJavaDate", TypeUtils.SQL_DATE_TYPE, false,
value);
} else if (rawType == java.sql.Timestamp.class) {
return new StaticInvoke(
DateTimeUtils.class, "toJavaTimestamp", TypeUtils.TIMESTAMP_TYPE,
false, value);
diff --git
a/java/fory-format/src/main/java/org/apache/fory/format/row/binary/BinaryUtils.java
b/java/fory-format/src/main/java/org/apache/fory/format/row/binary/BinaryUtils.java
index 29cd2e160..b2ada55dd 100644
---
a/java/fory-format/src/main/java/org/apache/fory/format/row/binary/BinaryUtils.java
+++
b/java/fory-format/src/main/java/org/apache/fory/format/row/binary/BinaryUtils.java
@@ -51,7 +51,7 @@ public class BinaryUtils {
return "getFloat64";
} else if (TypeUtils.BIG_DECIMAL_TYPE.equals(type)) {
return "getDecimal";
- } else if (TypeUtils.DATE_TYPE.equals(type)) {
+ } else if (TypeUtils.SQL_DATE_TYPE.equals(type)) {
return "getDate";
} else if (TypeUtils.TIMESTAMP_TYPE.equals(type)) {
return "getTimestamp";
@@ -103,7 +103,7 @@ public class BinaryUtils {
return TypeUtils.PRIMITIVE_DOUBLE_TYPE;
} else if (TypeUtils.BIG_DECIMAL_TYPE.equals(type)) {
return TypeUtils.BIG_DECIMAL_TYPE;
- } else if (TypeUtils.DATE_TYPE.equals(type)) {
+ } else if (TypeUtils.SQL_DATE_TYPE.equals(type)) {
return TypeUtils.INT_TYPE;
} else if (TypeUtils.TIMESTAMP_TYPE.equals(type)) {
return TypeUtils.LONG_TYPE;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]