Repository: alibaba/fastjson2
Pull request #3503 (2025-04-18 19:51:16)

Bump commons-io:commons-io from 2.18.0 to 2.19.0
Bumps commons-io:commons-io from 2.18.0 to 2.19.0.


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=commons-io:commons-io&package-manager=maven&previous-version=2.18.0&new-version=2.19.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/core/src/main/java/com/alibaba/fastjson2/reader/FieldReaderObject.java b/core/src/main/java/com/alibaba/fastjson2/reader/FieldReaderObject.java
index 19fad388d..ed962ac60 100644
--- a/core/src/main/java/com/alibaba/fastjson2/reader/FieldReaderObject.java
+++ b/core/src/main/java/com/alibaba/fastjson2/reader/FieldReaderObject.java
@@ -182,7 +182,7 @@ public class FieldReaderObject<T>
                 jsonReader.skipValue();
                 return;
             } else if ((contextFeatures & JSONReader.Feature.ErrorOnNoneSerializable.mask) != 0) {
-                if (fieldClass != Object.class || (jsonReader.isObject() || jsonReader.isArray())) {
+                if (fieldClass != Object.class || (jsonReader.isObject() || jsonReader.getType() == JSONB.Constants.BC_TYPED_ANY)) {
                     throw new JSONException("not support none-Serializable");
                 }
             }
diff --git a/core/src/main/java/com/alibaba/fastjson2/reader/ObjectReader.java b/core/src/main/java/com/alibaba/fastjson2/reader/ObjectReader.java
index 055ac7ca5..8cfe97bac 100644
--- a/core/src/main/java/com/alibaba/fastjson2/reader/ObjectReader.java
+++ b/core/src/main/java/com/alibaba/fastjson2/reader/ObjectReader.java
@@ -176,9 +176,12 @@ public interface ObjectReader<T> {
         FieldReader fieldReader = getFieldReader(fieldNameHash);
 
         if (fieldReader == null) {
-            long fieldNameHashLCase = Fnv.hashCode64LCase(fieldName);
-            if (fieldNameHashLCase != fieldNameHash) {
-                fieldReader = getFieldReaderLCase(fieldNameHashLCase);
+            fieldReader = getFieldReaderLCase(fieldNameHash);
+            if (fieldReader == null) {
+                long fieldNameHashLCase = Fnv.hashCode64LCase(fieldName);
+                if (fieldNameHashLCase != fieldNameHash) {
+                    fieldReader = getFieldReaderLCase(fieldNameHashLCase);
+                }
             }
         }
 
diff --git a/core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterAdapter.java b/core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterAdapter.java
index 96a9c19af..4269769b0 100644
--- a/core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterAdapter.java
+++ b/core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterAdapter.java
@@ -675,6 +675,11 @@ public class ObjectWriterAdapter<T>
             if (fieldValue == object) {
                 fieldValue = jsonObject;
             }
+            if (fieldValue instanceof Enum) {
+                if ((features & WriteEnumsUsingName.mask) != 0) {
+                    fieldValue = ((Enum) fieldValue).name();
+                }
+            }
             if (fieldWriter instanceof FieldWriterObject && !(fieldValue instanceof Map)) {
                 ObjectWriter valueWriter = fieldWriter.getInitWriter();
                 if (valueWriter == null) {
diff --git a/core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterCreatorASM.java b/core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterCreatorASM.java
index 6ea78c2e1..4457c5ec7 100644
--- a/core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterCreatorASM.java
+++ b/core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterCreatorASM.java
@@ -4792,7 +4792,11 @@ public class ObjectWriterCreatorASM
         if (member instanceof Method) {
             mw.aload(OBJECT);
             mw.checkcast(TYPE_OBJECT);
-            mw.invokevirtual(TYPE_OBJECT, member.getName(), "()" + ASMUtils.desc(fieldClass));
+            if (objectClass.isInterface()) {
+                mw.invokeinterface(TYPE_OBJECT, member.getName(), "()" + ASMUtils.desc(fieldClass));
+            } else {
+                mw.invokevirtual(TYPE_OBJECT, member.getName(), "()" + ASMUtils.desc(fieldClass));
+            }
             return;
         }
 
diff --git a/core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterProvider.java b/core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterProvider.java
index 37aa85eea..e13ef31bc 100644
--- a/core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterProvider.java
+++ b/core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterProvider.java
@@ -387,10 +387,20 @@ public class ObjectWriterProvider
         }
 
         if (TypeUtils.isProxy(objectClass)) {
+            Class<?> proxyTarget = superclass;
+            if (proxyTarget == Object.class) {
+                Class[] interfaces = objectClass.getInterfaces();
+                for (Class<?> i : interfaces) {
+                    if (!TypeUtils.isProxy(i)) {
+                        proxyTarget = i;
+                        break;
+                    }
+                }
+            }
             if (objectClass == objectType) {
-                objectType = superclass;
+                objectType = proxyTarget;
             }
-            objectClass = superclass;
+            objectClass = proxyTarget;
             if (fieldBased) {
                 fieldBased = false;
                 objectWriter = cacheFieldBased.get(objectType);
diff --git a/extension-solon/src/main/java/com/alibaba/fastjson2/support/solon/Fastjson2RenderFactory.java b/extension-solon/src/main/java/com/alibaba/fastjson2/support/solon/Fastjson2RenderFactory.java
index d744abf35..cb453843a 100644
--- a/extension-solon/src/main/java/com/alibaba/fastjson2/support/solon/Fastjson2RenderFactory.java
+++ b/extension-solon/src/main/java/com/alibaba/fastjson2/support/solon/Fastjson2RenderFactory.java
@@ -67,10 +67,6 @@ public class Fastjson2RenderFactory
         }
 
         if (JsonPropsUtil.apply(this, jsonProps)) {
-            if (jsonProps.longAsString) {
-                this.addFeatures(JSONWriter.Feature.WriteLongAsString);
-            }
-
             boolean writeNulls = jsonProps.nullAsWriteable ||
                     jsonProps.nullNumberAsZero ||
                     jsonProps.nullArrayAsEmpty ||
diff --git a/extension-solon/src/main/java/com/alibaba/fastjson2/support/solon/Fastjson2StringSerializer.java b/extension-solon/src/main/java/com/alibaba/fastjson2/support/solon/Fastjson2StringSerializer.java
index f2c69ec4e..75dd0c7b1 100644
--- a/extension-solon/src/main/java/com/alibaba/fastjson2/support/solon/Fastjson2StringSerializer.java
+++ b/extension-solon/src/main/java/com/alibaba/fastjson2/support/solon/Fastjson2StringSerializer.java
@@ -9,6 +9,8 @@ import com.alibaba.fastjson2.writer.ObjectWriterProvider;
 import org.noear.solon.Utils;
 import org.noear.solon.core.handle.Context;
 import org.noear.solon.core.handle.ModelAndView;
+import org.noear.solon.core.util.MimeType;
+import org.noear.solon.lang.Nullable;
 import org.noear.solon.serialization.ContextSerializer;
 
 import java.io.IOException;
@@ -86,13 +88,21 @@ public class Fastjson2StringSerializer
     }
 
     /**
-     * Getting the content type
+     * Content type
      */
     @Override
-    public String getContentType() {
+    public String mimeType() {
         return "application/json";
     }
 
+    /**
+     * Data type
+     */
+    @Override
+    public Class<String> dataType() {
+        return String.class;
+    }
+
     /**
      * Match or not
      *
@@ -104,7 +114,7 @@ public class Fastjson2StringSerializer
         if (mime == null) {
             return false;
         } else {
-            return mime.contains(label);
+            return mime.contains(label) || mime.startsWith(MimeType.APPLICATION_X_NDJSON_VALUE);
         }
     }
 
@@ -149,7 +159,10 @@ public class Fastjson2StringSerializer
      */
     @Override
     public void serializeToBody(Context ctx, Object data) throws IOException {
-        ctx.contentType(getContentType());
+        // If not set, use default // such as ndjson,sse or deliberately change mime (can be controlled externally)
+        if (ctx.contentTypeNew() == null) {
+            ctx.contentType(this.mimeType());
+        }
 
         if (data instanceof ModelAndView) {
             ctx.output(serialize(((ModelAndView) data).model()));
@@ -164,7 +177,7 @@ public class Fastjson2StringSerializer
      * @param ctx Handling context
      */
     @Override
-    public Object deserializeFromBody(Context ctx) throws IOException {
+    public Object deserializeFromBody(Context ctx, @Nullable Type bodyType) throws IOException {
         String data = ctx.bodyNew();
 
         if (Utils.isNotEmpty(data)) {
diff --git a/pom.xml b/pom.xml
index 00ce69f01..7e153a469 100644
--- a/pom.xml
+++ b/pom.xml
@@ -35,7 +35,7 @@
         <jackson.version>2.18.3</jackson.version>
         <jetty.version>11.0.15</jetty.version>
         <jersey.version>2.44</jersey.version>
-        <solon.version>3.0.1</solon.version>
+        <solon.version>3.2.0</solon.version>
         <springframework5.version>5.3.31</springframework5.version>
         <springframework6.version>6.1.3</springframework6.version>
         <springsecurity5.version>5.8.8</springsecurity5.version>
@@ -160,7 +160,7 @@
             <dependency>
                 <groupId>com.aliyun.odps</groupId>
                 <artifactId>odps-sdk-udf</artifactId>
-                <version>0.51.11-public</version>
+                <version>0.52.0-public</version>
             </dependency>
             <dependency>
                 <groupId>com.carrotsearch</groupId>
@@ -244,7 +244,7 @@
             <dependency>
                 <groupId>commons-io</groupId>
                 <artifactId>commons-io</artifactId>
-                <version>2.18.0</version>
+                <version>2.19.0</version>
             </dependency>
             <dependency>
                 <groupId>commons-lang</groupId>


Test patch:
diff --git a/core/src/test/java/com/alibaba/fastjson2/issues_3400/Issue3408.java b/core/src/test/java/com/alibaba/fastjson2/issues_3400/Issue3408.java
new file mode 100644
index 000000000..b70ae7af2
--- /dev/null
+++ b/core/src/test/java/com/alibaba/fastjson2/issues_3400/Issue3408.java
@@ -0,0 +1,31 @@
+package com.alibaba.fastjson2.issues_3400;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONReader;
+import lombok.Getter;
+import lombok.Setter;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class Issue3408 {
+    @Test
+    public void test() {
+        String str = "{\"data\":[{\"username\":\"mike\"}, {\"user_name\":\"john\"}]}";
+
+        JSONArray jsonArray = JSON.parseObject(str).getJSONArray("data");
+        List<User> data1 = com.alibaba.fastjson.JSONObject.parseArray(JSON.toJSONString(jsonArray), User.class);
+        List<User> data2 = JSON.parseObject(str).getJSONArray("data").toJavaList(User.class, JSONReader.Feature.SupportSmartMatch);
+
+        assertEquals(JSON.toJSONString(data1), JSON.toJSONString(data2));
+    }
+
+    @Getter
+    @Setter
+    public static class User {
+        String userName;
+    }
+}
diff --git a/core/src/test/java/com/alibaba/fastjson2/issues_3400/Issue3445.java b/core/src/test/java/com/alibaba/fastjson2/issues_3400/Issue3445.java
new file mode 100644
index 000000000..22a38431e
--- /dev/null
+++ b/core/src/test/java/com/alibaba/fastjson2/issues_3400/Issue3445.java
@@ -0,0 +1,83 @@
+package com.alibaba.fastjson2.issues_3400;
+
+import com.alibaba.fastjson2.JSON;
+import org.junit.jupiter.api.Test;
+import org.springframework.cglib.proxy.Enhancer;
+import org.springframework.cglib.proxy.MethodInterceptor;
+import org.springframework.cglib.proxy.MethodProxy;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class Issue3445 {
+    @Test
+    public void test() {
+        Class targetClass = Account.class;
+        Enhancer enhancer = new Enhancer();
+        enhancer.setUseCache(true);
+        List<Class<?>> superInterfaces = new ArrayList<Class<?>>();
+        if (targetClass.isInterface()) {
+            superInterfaces.add(targetClass);
+            superInterfaces.add(Map.class);
+        }
+        enhancer.setInterfaces(superInterfaces.toArray(new Class[0]));
+        enhancer.setCallback(new MethodInterceptor() {
+            Map<Object, Object> map = new LinkedHashMap<>();
+
+            @Override
+            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
+                String mname = method.getName();
+                int mname_len = mname.length();
+
+                if (mname.startsWith("set") && method.getReturnType() == void.class) {
+                    map.put(mname.substring(3, mname_len).toLowerCase(), objects[0]);
+                    return null;
+                }
+                if (mname_len == 3 && "put".equals(mname)) {
+                    //非克隆对象
+                    return map.put(objects[0], objects[1]);
+                }
+                if (mname_len == 3 && "get".equals(mname)) {
+                    //非克隆对象
+                    return map.get(objects[0]);
+                }
+                if (mname.equals("entrySet")) {
+                    return map.entrySet();
+                }
+                if (mname.startsWith("get")) {
+                    return map.get(mname.substring(3).toLowerCase());
+                }
+                return null;
+            }
+        });
+
+        Account account = null;
+        try {
+            account = (Account) enhancer.create();
+        } catch (Exception ignored) {
+            // ignore
+        }
+        if (account == null) {
+            return;
+        }
+        account.setName("test");
+        account.setPassword("123");
+
+        assertEquals("{\"name\":\"test\",\"password\":\"123\"}", JSON.toJSONString(account));
+    }
+
+    public interface Account {
+        String getName();
+
+        void setName(String name);
+
+        String getPassword();
+
+        void setPassword(String password);
+    }
+}
diff --git a/core/src/test/java/com/alibaba/fastjson2/issues_3400/Issue3464.java b/core/src/test/java/com/alibaba/fastjson2/issues_3400/Issue3464.java
new file mode 100644
index 000000000..0b5d48e10
--- /dev/null
+++ b/core/src/test/java/com/alibaba/fastjson2/issues_3400/Issue3464.java
@@ -0,0 +1,27 @@
+package com.alibaba.fastjson2.issues_3400;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.JSONWriter;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.junit.Test;
+
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class Issue3464 {
+    @Test
+    public void test() {
+        Data data = new Data(TimeUnit.MINUTES);
+        JSONObject json = (JSONObject) JSON.toJSON(data, JSONWriter.Feature.WriteEnumsUsingName);
+        assertEquals(json.get("unit").getClass().toString(), "class java.lang.String");
+    }
+
+    @Getter
+    @AllArgsConstructor
+    private static class Data {
+        private TimeUnit unit;
+    }
+}
diff --git a/core/src/test/java/com/alibaba/fastjson2/issues_3400/Issue3474.java b/core/src/test/java/com/alibaba/fastjson2/issues_3400/Issue3474.java
new file mode 100644
index 000000000..c5bdccc69
--- /dev/null
+++ b/core/src/test/java/com/alibaba/fastjson2/issues_3400/Issue3474.java
@@ -0,0 +1,21 @@
+package com.alibaba.fastjson2.issues_3400;
+
+import com.alibaba.fastjson2.JSON;
+import lombok.Data;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class Issue3474 {
+    @Test
+    public void test() {
+        String aaa = "{\"file\":[\"url\"]}";
+        Bbb bbb = JSON.parseObject(aaa, Bbb.class);
+        assertEquals("url", bbb.getFile());
+    }
+
+    @Data
+    static class Bbb {
+        String file;
+    }
+}