[alibaba/fastjson]反序列化时候调用的构造函数问题

2025-11-13 757 views
7

如下图的Exception,在用fastjson反序列的时候,发现一直是调用带参数的构造函数的,即使用@JSONCreator指定了构造函数,也还是不会调用无参构造函数。

public class TestException extends Exception {

    @JSONCreator
    public TestException() {

    }

    public TestException(String data) {
        super("Data : " + data);
    }

}

这使得TestException多处传递之后,message内容就嵌套了...是不是还有啥高级配置要弄弄?

回答

2

补充一下例子:

public class TestException extends Exception {

    @JSONCreator
    public TestException() {

    }

    public TestException(String data) {
        super("Data-" + data);
    }

    public static void main(String[] args) {
        TestException testException = new TestException("aaa");
        System.out.println("before:" + testException.getMessage());
        String json = JSONObject.toJSONString(testException);
        TestException o = JSONObject.parseObject(json, TestException.class);
        System.out.println("after:" + o.getMessage());
    }

}
3

这个问题很典型啊,是因为fastjson对Throwable的子类反序列化时在选择构造方法的时候顺序定死了,优先含有cause参数的构造方法,其次是含有String参数的构造方法,最后才是无参构造函数,在你这个例子中,反序列化使用的是TestException(String data) 又把之前的message作为value传进去了,所以出了你这个问题。 实现代码如下,在类ThrowableDeserializer中

        for (Constructor<?> constructor : exClass.getConstructors()) {
            Class<?>[] types = constructor.getParameterTypes();
            if (types.length == 0) {
                defaultConstructor = constructor;
                continue;
            }

            if (types.length == 1 && types[0] == String.class) {
                messageConstructor = constructor;
                continue;
            }

            if (types.length == 2 && types[0] == String.class && types[1] == Throwable.class) {
                causeConstructor = constructor;
                continue;
            }
        }

        if (causeConstructor != null) {
            return (Throwable) causeConstructor.newInstance(message, cause);
        }

        if (messageConstructor != null) {
            return (Throwable) messageConstructor.newInstance(message);
        }

        if (defaultConstructor != null) {
            return (Throwable) defaultConstructor.newInstance();
        }

这里并没有走注解逻辑,我想想怎么修复这个问题。

9

另外@JSONCreator注解,只对没有默认构造函数或者当前类是接口或抽象类的时候才会对该注解进行解析

boolean isInterfaceOrAbstract = clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers());
 if (defaultConstructor == null || isInterfaceOrAbstract) {
            creatorConstructor = getCreatorConstructor(clazz);
//...其他逻辑
0

为啥要调用缺省构造函数呢?如果调用缺省构造函数,message就传不进去了哈

1

抱歉,回复晚了。主要是在做feign的扩展的时候,为了增强伪rpc的异常捕获,需要对json转成异常再抛出。由于业务开发的有些异常类的message拼接逻辑在构造函数里,因此出现了我上面例子的现象。目前通过编码规范来规避了,感谢回复~