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 aca63fd83 feat(java): refine java json serde (#3806)
aca63fd83 is described below

commit aca63fd837bbb3fba55bc404e86abf7dc01e9797
Author: Shawn Yang <[email protected]>
AuthorDate: Wed Jul 1 12:03:45 2026 +0530

    feat(java): refine java json serde (#3806)
    
    ## Why?
    
    
    
    ## What does this PR do?
    
    
    
    ## Related issues
    
    
    
    ## 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 or equivalent persisted links of the
    final clean AI review results from both fresh reviewers described in
    `AI_POLICY.md`, the Fory-guided reviewer and the independent general
    reviewer, 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?
    
    ## Benchmark
---
 .../org/apache/fory/json/codec/CodecUtils.java     |  21 ++++
 .../java/org/apache/fory/json/codec/MapCodec.java  |  37 ++++++-
 .../org/apache/fory/json/codec/ScalarCodecs.java   |  48 +++++++---
 .../fory/json/resolver/JsonSharedRegistry.java     |  16 +++-
 .../org/apache/fory/json/JsonContainerTest.java    |  39 ++++++++
 .../java/org/apache/fory/json/JsonScalarTest.java  | 106 ++++++++++++++++++++-
 .../apache/fory/json/data/CoreScalarFields.java    |   1 -
 7 files changed, 248 insertions(+), 20 deletions(-)

diff --git 
a/java/fory-json/src/main/java/org/apache/fory/json/codec/CodecUtils.java 
b/java/fory-json/src/main/java/org/apache/fory/json/codec/CodecUtils.java
index df7383df8..8d6bc4888 100644
--- a/java/fory-json/src/main/java/org/apache/fory/json/codec/CodecUtils.java
+++ b/java/fory-json/src/main/java/org/apache/fory/json/codec/CodecUtils.java
@@ -21,7 +21,9 @@ package org.apache.fory.json.codec;
 
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
+import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 import org.apache.fory.collection.Tuple2;
 import org.apache.fory.reflect.TypeRef;
 
@@ -80,6 +82,15 @@ public final class CodecUtils {
     if (arguments.size() == 1) {
       return arguments.get(0);
     }
+    Class<?> rawType = typeRef.getRawType();
+    if (Collection.class.isAssignableFrom(rawType)) {
+      if (!typeRef.hasExplicitTypeArguments() && 
rawType.getTypeParameters().length > 0) {
+        return TypeRef.of(Object.class);
+      }
+      @SuppressWarnings({"rawtypes", "unchecked"})
+      TypeRef<?> collectionType = ((TypeRef) typeRef).getSupertype((Class) 
Collection.class);
+      return 
collectionType.resolveType(Collection.class.getTypeParameters()[0]);
+    }
     return TypeRef.of(Object.class);
   }
 
@@ -88,6 +99,16 @@ public final class CodecUtils {
     if (arguments.size() == 2) {
       return Tuple2.of(arguments.get(0), arguments.get(1));
     }
+    Class<?> rawType = typeRef.getRawType();
+    if (Map.class.isAssignableFrom(rawType)) {
+      if (!typeRef.hasExplicitTypeArguments() && 
rawType.getTypeParameters().length > 0) {
+        return Tuple2.of(TypeRef.of(Object.class), TypeRef.of(Object.class));
+      }
+      @SuppressWarnings({"rawtypes", "unchecked"})
+      TypeRef<?> mapType = ((TypeRef) typeRef).getSupertype((Class) Map.class);
+      Type[] parameters = Map.class.getTypeParameters();
+      return Tuple2.of(mapType.resolveType(parameters[0]), 
mapType.resolveType(parameters[1]));
+    }
     return Tuple2.of(TypeRef.of(String.class), TypeRef.of(Object.class));
   }
 }
diff --git 
a/java/fory-json/src/main/java/org/apache/fory/json/codec/MapCodec.java 
b/java/fory-json/src/main/java/org/apache/fory/json/codec/MapCodec.java
index 54ab7628a..a5fc0b4fd 100644
--- a/java/fory-json/src/main/java/org/apache/fory/json/codec/MapCodec.java
+++ b/java/fory-json/src/main/java/org/apache/fory/json/codec/MapCodec.java
@@ -60,11 +60,11 @@ public abstract class MapCodec extends AbstractJsonCodec {
   public static MapCodec create(Class<?> rawType, TypeRef<?> typeRef, 
JsonTypeResolver resolver) {
     Tuple2<TypeRef<?>, TypeRef<?>> keyValueTypeRefs = 
CodecUtils.mapKeyValueTypeRefs(typeRef);
     Type keyType = keyValueTypeRefs.f0.getType();
-    Class<?> keyRawType = CodecUtils.rawType(keyType, String.class);
+    Class<?> keyRawType = CodecUtils.rawType(keyType, Object.class);
     Type valueType = keyValueTypeRefs.f1.getType();
     Class<?> valueRawType = CodecUtils.rawType(valueType, Object.class);
     MapFactory factory = mapFactory(rawType, keyRawType);
-    if (keyRawType == String.class || keyRawType == Object.class) {
+    if (keyRawType == String.class) {
       if (valueRawType == String.class) {
         return new StringStringMapCodec(typeRef, factory);
       }
@@ -96,6 +96,10 @@ public abstract class MapCodec extends AbstractJsonCodec {
         return new StringBigDecimalMapCodec(typeRef, factory);
       }
     }
+    if (keyRawType == Object.class) {
+      return new GenericMapCodec(
+          typeRef, factory, MapKeyCodec.OBJECT, valueType, valueRawType, 
resolver);
+    }
     if (valueRawType == String.class && isNumericKey(keyRawType)) {
       return new NumberStringMapCodec(typeRef, factory, 
MapKeyCodec.of(keyRawType));
     }
@@ -838,6 +842,30 @@ public abstract class MapCodec extends AbstractJsonCodec {
             return (String) key;
           }
 
+          @Override
+          public Object fromName(String name) {
+            return name;
+          }
+        };
+    MapKeyCodec OBJECT =
+        new MapKeyCodec() {
+          @Override
+          public String toName(Object key) {
+            if (key == null) {
+              throw new ForyJsonException("JSON map key cannot be null");
+            }
+            if (key instanceof String) {
+              return (String) key;
+            }
+            if (key instanceof Number || key instanceof Boolean || key 
instanceof Character) {
+              return key.toString();
+            }
+            if (key instanceof Enum) {
+              return ((Enum<?>) key).name();
+            }
+            throw new ForyJsonException("Unsupported JSON map key type " + 
key.getClass());
+          }
+
           @Override
           public Object fromName(String name) {
             return name;
@@ -857,9 +885,12 @@ public abstract class MapCodec extends AbstractJsonCodec {
     }
 
     static MapKeyCodec of(Class<?> rawType) {
-      if (rawType == String.class || rawType == Object.class) {
+      if (rawType == String.class) {
         return STRING;
       }
+      if (rawType == Object.class) {
+        return OBJECT;
+      }
       if (rawType.isEnum()) {
         return new EnumKeyCodec(rawType);
       }
diff --git 
a/java/fory-json/src/main/java/org/apache/fory/json/codec/ScalarCodecs.java 
b/java/fory-json/src/main/java/org/apache/fory/json/codec/ScalarCodecs.java
index 224af03c6..2b58fc72c 100644
--- a/java/fory-json/src/main/java/org/apache/fory/json/codec/ScalarCodecs.java
+++ b/java/fory-json/src/main/java/org/apache/fory/json/codec/ScalarCodecs.java
@@ -19,6 +19,7 @@
 
 package org.apache.fory.json.codec;
 
+import java.io.File;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.net.MalformedURLException;
@@ -26,6 +27,7 @@ import java.net.URI;
 import java.net.URL;
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
+import java.nio.file.Paths;
 import java.time.Duration;
 import java.time.Instant;
 import java.time.LocalDate;
@@ -70,7 +72,6 @@ import org.apache.fory.json.resolver.JsonTypeResolver;
 import org.apache.fory.json.writer.JsonWriter;
 import org.apache.fory.json.writer.StringJsonWriter;
 import org.apache.fory.json.writer.Utf8JsonWriter;
-import org.apache.fory.reflect.ReflectionUtils;
 import org.apache.fory.type.BFloat16;
 import org.apache.fory.type.Float16;
 
@@ -119,7 +120,11 @@ public final class ScalarCodecs {
       if (number.indexOf('.') >= 0 || number.indexOf('e') >= 0 || 
number.indexOf('E') >= 0) {
         return Double.parseDouble(number);
       }
-      return Long.parseLong(number);
+      try {
+        return Long.parseLong(number);
+      } catch (NumberFormatException e) {
+        return new BigInteger(number);
+      }
     }
   }
 
@@ -510,7 +515,15 @@ public final class ScalarCodecs {
 
     @Override
     final Object readNonNull(JsonReader reader, JsonTypeInfo typeInfo, 
JsonTypeResolver resolver) {
-      return fromJsonString(reader.readString());
+      String value = reader.readString();
+      try {
+        return fromJsonString(value);
+      } catch (ForyJsonException e) {
+        throw e;
+      } catch (RuntimeException e) {
+        throw new ForyJsonException(
+            "Invalid " + typeInfo.rawType().getName() + " JSON string: " + 
value, e);
+      }
     }
 
     abstract String toJsonString(Object value);
@@ -633,21 +646,31 @@ public final class ScalarCodecs {
     }
   }
 
-  public static final class ClassCodec extends StringValueCodec {
-    public static final ClassCodec INSTANCE = new ClassCodec();
+  public static final class FileCodec extends StringValueCodec {
+    public static final FileCodec INSTANCE = new FileCodec();
 
     @Override
     String toJsonString(Object value) {
-      return ((Class<?>) value).getName();
+      return ((File) value).getPath();
     }
 
     @Override
     Object fromJsonString(String value) {
-      try {
-        return ReflectionUtils.loadClass(value);
-      } catch (RuntimeException e) {
-        throw new ForyJsonException("Cannot load class " + value, e);
-      }
+      return new File(value);
+    }
+  }
+
+  public static final class PathCodec extends StringValueCodec {
+    public static final PathCodec INSTANCE = new PathCodec();
+
+    @Override
+    String toJsonString(Object value) {
+      return value.toString();
+    }
+
+    @Override
+    Object fromJsonString(String value) {
+      return Paths.get(value);
     }
   }
 
@@ -874,6 +897,9 @@ public final class ScalarCodecs {
 
     @Override
     Object fromJsonString(String value) {
+      if (value.length() > 10 && value.charAt(10) == 'T') {
+        return LocalDate.parse(value.substring(0, 10));
+      }
       return LocalDate.parse(value);
     }
   }
diff --git 
a/java/fory-json/src/main/java/org/apache/fory/json/resolver/JsonSharedRegistry.java
 
b/java/fory-json/src/main/java/org/apache/fory/json/resolver/JsonSharedRegistry.java
index 0d662ab95..4fe557959 100644
--- 
a/java/fory-json/src/main/java/org/apache/fory/json/resolver/JsonSharedRegistry.java
+++ 
b/java/fory-json/src/main/java/org/apache/fory/json/resolver/JsonSharedRegistry.java
@@ -19,12 +19,14 @@
 
 package org.apache.fory.json.resolver;
 
+import java.io.File;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.net.URI;
 import java.net.URL;
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
+import java.nio.file.Path;
 import java.time.Duration;
 import java.time.Instant;
 import java.time.LocalDate;
@@ -57,6 +59,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.regex.Pattern;
+import org.apache.fory.json.ForyJsonException;
 import org.apache.fory.json.codec.ArrayCodec;
 import org.apache.fory.json.codec.BaseObjectCodec;
 import org.apache.fory.json.codec.CodecUtils;
@@ -95,6 +98,10 @@ public final class JsonSharedRegistry {
     if (codec != null) {
       return codec;
     }
+    if (rawType == Class.class) {
+      // JSON strings must not be treated as class-loading authority by the 
default codecs.
+      throw new ForyJsonException("Unsupported JSON type " + rawType);
+    }
     if (rawType.isEnum()) {
       return new ScalarCodecs.EnumCodec(rawType);
     }
@@ -121,6 +128,12 @@ public final class JsonSharedRegistry {
     if (ByteBuffer.class.isAssignableFrom(rawType)) {
       return ScalarCodecs.ByteBufferCodec.INSTANCE;
     }
+    if (File.class.isAssignableFrom(rawType)) {
+      return ScalarCodecs.FileCodec.INSTANCE;
+    }
+    if (Path.class.isAssignableFrom(rawType)) {
+      return ScalarCodecs.PathCodec.INSTANCE;
+    }
     if (Collection.class.isAssignableFrom(rawType)) {
       return CollectionCodec.create(rawType, typeRef, localResolver);
     }
@@ -202,15 +215,16 @@ public final class JsonSharedRegistry {
     exactCodecs.put(BigDecimal.class, ScalarCodecs.BigDecimalCodec.INSTANCE);
     exactCodecs.put(Float16.class, ScalarCodecs.Float16Codec.INSTANCE);
     exactCodecs.put(BFloat16.class, ScalarCodecs.BFloat16Codec.INSTANCE);
-    exactCodecs.put(Class.class, ScalarCodecs.ClassCodec.INSTANCE);
     exactCodecs.put(StringBuilder.class, 
ScalarCodecs.StringBuilderCodec.INSTANCE);
     exactCodecs.put(StringBuffer.class, 
ScalarCodecs.StringBufferCodec.INSTANCE);
     exactCodecs.put(AtomicBoolean.class, 
ScalarCodecs.AtomicBooleanCodec.INSTANCE);
     exactCodecs.put(AtomicInteger.class, 
ScalarCodecs.AtomicIntegerCodec.INSTANCE);
     exactCodecs.put(AtomicLong.class, ScalarCodecs.AtomicLongCodec.INSTANCE);
     exactCodecs.put(Currency.class, ScalarCodecs.CurrencyCodec.INSTANCE);
+    exactCodecs.put(File.class, ScalarCodecs.FileCodec.INSTANCE);
     exactCodecs.put(URI.class, ScalarCodecs.UriCodec.INSTANCE);
     exactCodecs.put(URL.class, ScalarCodecs.UrlCodec.INSTANCE);
+    exactCodecs.put(Path.class, ScalarCodecs.PathCodec.INSTANCE);
     exactCodecs.put(Pattern.class, ScalarCodecs.PatternCodec.INSTANCE);
     exactCodecs.put(UUID.class, ScalarCodecs.UuidCodec.INSTANCE);
     exactCodecs.put(Locale.class, ScalarCodecs.LocaleCodec.INSTANCE);
diff --git 
a/java/fory-json/src/test/java/org/apache/fory/json/JsonContainerTest.java 
b/java/fory-json/src/test/java/org/apache/fory/json/JsonContainerTest.java
index 9357fea10..43bec41c6 100644
--- a/java/fory-json/src/test/java/org/apache/fory/json/JsonContainerTest.java
+++ b/java/fory-json/src/test/java/org/apache/fory/json/JsonContainerTest.java
@@ -26,6 +26,7 @@ import static org.testng.Assert.assertTrue;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -61,6 +62,22 @@ public class JsonContainerTest extends ForyJsonTestModels {
     assertEquals(values.get(1).total, 4);
   }
 
+  @Test
+  public void readCollectionSubclassElementType() {
+    ForyJson json = ForyJson.builder().build();
+    Shelf shelf = json.fromJson("{\"notes\":[{\"title\":\"first\"}]}", 
Shelf.class);
+    assertEquals(shelf.notes.get(0).getClass(), Note.class);
+    assertEquals(shelf.notes.get(0).title, "first");
+  }
+
+  @Test
+  public void readMapSubclassValueType() {
+    ForyJson json = ForyJson.builder().build();
+    PaletteGroups groups = json.fromJson("{\"warm\":{\"primary\":\"red\"}}", 
PaletteGroups.class);
+    assertEquals(groups.get("warm").getClass(), PaletteCodes.class);
+    assertEquals(groups.get("warm").get("primary"), "red");
+  }
+
   @Test
   public void readTypeRefMapBytes() {
     ForyJson json = ForyJson.builder().build();
@@ -136,6 +153,14 @@ public class JsonContainerTest extends ForyJsonTestModels {
     assertEquals(read.scores, enumScores());
   }
 
+  @Test
+  public void writeRootMapNumericKeys() {
+    ForyJson json = ForyJson.builder().build();
+    Map<Integer, Integer> value =
+        json.fromJson("{\"7\":70,\"8\":80}", new TypeRef<Map<Integer, 
Integer>>() {});
+    assertEquals(json.toJson(new LinkedHashMap<>(value)), 
"{\"7\":70,\"8\":80}");
+  }
+
   @Test
   public void readTypeRefOptional() {
     ForyJson json = ForyJson.builder().build();
@@ -235,4 +260,18 @@ public class JsonContainerTest extends ForyJsonTestModels {
     assertEquals(json.fromJson("[\"a\",\"你\"]", char[].class), new char[] 
{'a', '你'});
     assertThrows(ForyJsonException.class, () -> json.fromJson("[1,null]", 
int[].class));
   }
+
+  public static final class Shelf {
+    public NoteList notes;
+  }
+
+  public static final class NoteList extends ArrayList<Note> {}
+
+  public static final class Note {
+    public String title;
+  }
+
+  public static final class PaletteGroups extends HashMap<String, 
PaletteCodes> {}
+
+  public static final class PaletteCodes extends HashMap<String, String> {}
 }
diff --git 
a/java/fory-json/src/test/java/org/apache/fory/json/JsonScalarTest.java 
b/java/fory-json/src/test/java/org/apache/fory/json/JsonScalarTest.java
index e79ee060f..84c1f8afb 100644
--- a/java/fory-json/src/test/java/org/apache/fory/json/JsonScalarTest.java
+++ b/java/fory-json/src/test/java/org/apache/fory/json/JsonScalarTest.java
@@ -22,7 +22,13 @@ package org.apache.fory.json;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertThrows;
 
+import java.io.File;
+import java.math.BigInteger;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.util.Optional;
 import org.apache.fory.json.data.BoxedScalars;
 import org.apache.fory.json.data.CoreScalarFields;
@@ -118,9 +124,8 @@ public class JsonScalarTest extends ForyJsonTestModels {
             + 
"\"builder\":\"build\",\"bytes\":[1,-2,3],\"calendar\":123456789,"
             + 
"\"charset\":\"UTF-8\",\"currency\":\"EUR\",\"date\":\"2026-06-21\","
             + "\"instant\":\"2026-06-21T01:02:03Z\",\"locale\":\"zh-Hans-CN\","
-            + 
"\"maybe\":\"yes\",\"optionalInt\":4,\"timeZone\":\"UTC\",\"type\":\""
-            + PublicFields.class.getName()
-            + "\",\"uri\":\"https://fory.apache.org/json\",";
+            + "\"maybe\":\"yes\",\"optionalInt\":4,\"timeZone\":\"UTC\","
+            + "\"uri\":\"https://fory.apache.org/json\",";
             + "\"url\":\"https://fory.apache.org/\",";
             + "\"uuid\":\"123e4567-e89b-12d3-a456-426614174000\"}";
     assertEquals(json.toJson(value), expected);
@@ -140,7 +145,6 @@ public class JsonScalarTest extends ForyJsonTestModels {
     assertEquals(read.maybe, Optional.of("yes"));
     assertEquals(read.optionalInt.getAsInt(), 4);
     assertEquals(read.timeZone.getID(), "UTC");
-    assertEquals(read.type, PublicFields.class);
     assertEquals(read.uri, value.uri);
     assertEquals(read.url, value.url);
     assertEquals(read.uuid, value.uuid);
@@ -157,6 +161,83 @@ public class JsonScalarTest extends ForyJsonTestModels {
         "\uD83D\uDE00\u1234");
   }
 
+  @Test
+  public void readUntypedLargeInteger() {
+    ForyJson json = ForyJson.builder().build();
+    BigInteger unsigned = new BigInteger("18446744073709550616");
+    assertEquals(json.fromJson(unsigned.toString(), Object.class), unsigned);
+    JSONObject object = json.fromJson("{\"count\":18446744073709550616}", 
JSONObject.class);
+    assertEquals(object.get("count"), unsigned);
+  }
+
+  @Test
+  public void rejectClassTypeByDefault() {
+    ForyJson json = ForyJson.builder().build();
+    assertThrows(ForyJsonException.class, () -> json.toJson(String.class));
+    assertThrows(ForyJsonException.class, () -> json.toJson(int.class));
+    assertThrows(ForyJsonException.class, () -> 
json.fromJson("\"java.lang.String\"", Class.class));
+    assertThrows(ForyJsonException.class, () -> json.fromJson("\"int\"", 
Class.class));
+  }
+
+  @Test
+  public void rejectClassFields() {
+    ForyJson json = ForyJson.builder().build();
+    assertThrows(ForyJsonException.class, () -> json.toJson(new 
ClassFieldHolder()));
+    assertThrows(
+        ForyJsonException.class,
+        () -> json.fromJson("{\"type\":\"java.lang.String\"}", 
ClassFieldHolder.class));
+  }
+
+  @Test
+  public void rejectClassArrays() {
+    ForyJson json = ForyJson.builder().build();
+    assertThrows(ForyJsonException.class, () -> json.toJson(new Class<?>[] 
{String.class}));
+    assertThrows(
+        ForyJsonException.class, () -> json.fromJson("[\"java.lang.String\"]", 
Class[].class));
+    assertThrows(ForyJsonException.class, () -> json.toJson(new 
ClassArrayFields()));
+    assertThrows(
+        ForyJsonException.class,
+        () -> json.fromJson("{\"types\":[\"java.lang.String\"]}", 
ClassArrayFields.class));
+  }
+
+  @Test
+  public void writeReadFileAndPath() {
+    ForyJson json = ForyJson.builder().build();
+    File file = new File("fory-json-file.txt");
+    Path path = Paths.get("fory-json-path.txt");
+    assertEquals(json.toJson(file), "\"fory-json-file.txt\"");
+    assertEquals(json.fromJson("\"fory-json-file.txt\"", File.class), file);
+    assertEquals(json.toJson(path), "\"fory-json-path.txt\"");
+    assertEquals(json.fromJson("\"fory-json-path.txt\"", Path.class), path);
+
+    FilePathFields fields =
+        json.fromJson(
+            
"{\"file\":\"fory-json-file.txt\",\"path\":\"fory-json-path.txt\"}",
+            FilePathFields.class);
+    assertEquals(fields.file, file);
+    assertEquals(fields.path, path);
+    assertEquals(
+        json.toJson(fields), 
"{\"file\":\"fory-json-file.txt\",\"path\":\"fory-json-path.txt\"}");
+  }
+
+  @Test
+  public void readLocalDateFromDateTime() {
+    ForyJson json = ForyJson.builder().build();
+    LocalDate expected = LocalDate.of(2023, 7, 2);
+    assertEquals(json.fromJson("\"2023-07-02T16:00:00.000Z\"", 
LocalDate.class), expected);
+    LocalDateFields fields =
+        json.fromJson("{\"value\":\"2023-07-02T16:00:00.000Z\"}", 
LocalDateFields.class);
+    assertEquals(fields.value, expected);
+  }
+
+  @Test
+  public void wrapStringScalarParseErrors() {
+    ForyJson json = ForyJson.builder().build();
+    assertThrows(
+        ForyJsonException.class,
+        () -> json.fromJson("\"2024-02-03 04:05:06\"", LocalDateTime.class));
+  }
+
   @Test
   public void rejectLeadingZero() {
     ForyJson json = ForyJson.builder().build();
@@ -165,4 +246,21 @@ public class JsonScalarTest extends ForyJsonTestModels {
         ForyJsonException.class,
         () -> json.fromJson("{\"id\":01}".getBytes(StandardCharsets.UTF_8), 
PublicFields.class));
   }
+
+  public static final class ClassFieldHolder {
+    public Class<?> type = String.class;
+  }
+
+  public static final class ClassArrayFields {
+    public Class<?>[] types = new Class<?>[] {String.class};
+  }
+
+  public static final class FilePathFields {
+    public File file;
+    public Path path;
+  }
+
+  public static final class LocalDateFields {
+    public LocalDate value;
+  }
 }
diff --git 
a/java/fory-json/src/test/java/org/apache/fory/json/data/CoreScalarFields.java 
b/java/fory-json/src/test/java/org/apache/fory/json/data/CoreScalarFields.java
index 7aee8e9ea..4b6b15c60 100644
--- 
a/java/fory-json/src/test/java/org/apache/fory/json/data/CoreScalarFields.java
+++ 
b/java/fory-json/src/test/java/org/apache/fory/json/data/CoreScalarFields.java
@@ -52,7 +52,6 @@ public final class CoreScalarFields {
   public Optional<String> maybe = Optional.of("yes");
   public OptionalInt optionalInt = OptionalInt.of(4);
   public TimeZone timeZone = TimeZone.getTimeZone("UTC");
-  public Class<?> type = PublicFields.class;
   public URI uri = URI.create("https://fory.apache.org/json";);
   public URL url = JsonTestData.url("https://fory.apache.org/";);
   public UUID uuid = UUID.fromString("123e4567-e89b-12d3-a456-426614174000");


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to