alibaba / fastjson2

🚄 FASTJSON2 is a Java JSON library with excellent performance.
Apache License 2.0
3.81k stars 498 forks source link

[BUG]在使用 Dubbo 使用 Fastjson2 做序列化时,遇到字段为枚举类对象的无法完成序列化 #1343

Open houkunlin opened 1 year ago

houkunlin commented 1 year ago

问题描述

简要描述您碰到的问题。

类:

public UserDubboService {
  LoginAccountVo getAccountById(String id);
}

@Data
public LoginAccountVo {
  private String id;
  private LoginType type;
}

@Data
public enum LoginType implements DictEnum<Integer>, IEnum<Integer>, Serializable{
      /**
     * 用户名
     */
    USERNAME(1, "用户名", true),
    /**
     * 手机号
     */
    PHONE(2, "手机号", true),
    /**
     * 电子邮件
     */
    EMAIL(3, "电子邮件", true)
    ;
    private final Integer value;
    private final String title;
    // 是否是本地账号
    private final boolean local;

    @JsonCreator
    public static LoginType create(Integer value) {
        LoginType item = null;
        // .....
        return item;
    }
}

错误位置:com.alibaba.fastjson2.writer.FieldWriter#writeEnumJSONB

异常信息

org.apache.dubbo.rpc.RpcException: Failed to invoke the method getLocalIdentifier in the service com.houkunlin.rpc.UserDubboService. Tried 3 times of the providers [172.29.237.2:20886] (1/1) from the registry 192.168.0.5:8848 on the consumer 172.29.237.2 using the dubbo version 3.2.0-beta.6. Last error is: Failed to invoke remote method: getLocalIdentifier, provider: DefaultServiceInstance{serviceName='system-user-server', host='172.29.237.2', port=20886, enabled=true, healthy=true, metadata={dubbo.metadata-service.url-params={"prefer.serialization":"fastjson2,hessian2","version":"1.0.0","dubbo":"2.0.2","release":"3.2.0-beta.6","side":"provider","port":"20886","protocol":"dubbo"}, dubbo.endpoints=[{"port":20886,"protocol":"dubbo"}], dubbo.metadata.revision=8d596daa6565c6bfebb097f1bf926a68, dubbo.metadata.storage-type=local, timestamp=1681116858869}}, service{name='com.houkunlin.cloud.micro.rpc.UserDubboService',group='null',version='null',protocol='dubbo',port='20886',params={executor-management-mode=default, side=provider, file-cache=false, release=3.2.0-beta.6, methods=getAssignAuthorities,getLeaderIds,getLocalIdentifier,getUserAllPermissionValues,getUserByUserId,getUserByUsername,loginFailureAction,loginSuccessAction,saveUserLog,updatePassword, deprecated=false, dubbo=2.0.2, interface=com.houkunlin.rpc.UserDubboService, service-name-mapping=true, register-mode=instance, generic=false, revision=0.0.7-SNAPSHOT-plain, application=system-user-server, prefer.serialization=fastjson2,hessian2, background=false, dynamic=true, anyhost=true},}, cause: org.apache.dubbo.remoting.RemotingException: Failed to send response: Response [id=136, version=2.0.2, status=20, event=false, error=null, result=AppResponse [value=LoginAccountVo(id=1, userId=1, identifier=admin, identifierDisplay=admin, credential=$2a$10$HUM4HAoPIPPKfe.ldNaue.cmuT3HOI9ocaBXzw1Qj/NhFg7IkHSQu, type=USERNAME, local=true, lastLoginIp=127.0.0.1, lastLoginTime=2023-03-27T17:01:48.941657), exception=null]], cause: java.lang.UnsupportedOperationException
java.lang.UnsupportedOperationException
    at com.alibaba.fastjson2.writer.FieldWriter.writeEnumJSONB(FieldWriter.java:156)
    at com.alibaba.fastjson2.writer.OWG_9_15_LoginAccountVo.writeJSONB(Unknown Source)
    at com.alibaba.fastjson2.JSONB.toBytes(JSONB.java:1136)
    at org.apache.dubbo.common.serialize.fastjson2.FastJson2ObjectOutput.writeObject(FastJson2ObjectOutput.java:106)
    at org.apache.dubbo.rpc.protocol.dubbo.DubboCodec.encodeResponseData(DubboCodec.java:251)
    at org.apache.dubbo.remoting.exchange.codec.ExchangeCodec.encodeResponse(ExchangeCodec.java:317)
    at org.apache.dubbo.remoting.exchange.codec.ExchangeCodec.encode(ExchangeCodec.java:78)
    at org.apache.dubbo.rpc.protocol.dubbo.DubboCountCodec.encode(DubboCountCodec.java:51)
    at org.apache.dubbo.remoting.transport.netty4.NettyChannel.send(NettyChannel.java:192)

环境信息

请填写以下信息:

image

重现步骤

如何操作可以重现该问题:

  1. 使用 xxx.xxx 方法
  2. 输入 ... 数据
  3. 出现 ... 错误
    //可在此输入示例代码

期待的正确结果

对您期望发生的结果进行清晰简洁的描述。

相关日志输出

请复制并粘贴任何相关的日志输出。

附加信息

如果你还有其他需要提供的信息,可以在这里填写(可以提供截图、视频等)。

lorna1 commented 1 year ago

2.0.27 试试 看修复过了

houkunlin commented 1 year ago

@lorna1 试了感觉好像问题依旧,已经确定了所有的依赖中只有 2.0.27 这个版本

@Data
@SuperBuilder
@EqualsAndHashCode(callSuper = true)
@FieldNameConstants
@NoArgsConstructor
@AllArgsConstructor
@TableName("sys_user_account")
public class LoginAccountVo extends BaseEntityVo {
    /**
     * 主键
     */
    private Long id;
    /**
     * 关联用户ID
     */
    private Long userId;
    /**
     * 登录标识(系统规则):帐号(用户名、手机号、电子邮箱等)实际账号。
     */
    private String identifier;
    /**
     * 登录标识(区分大小写):帐号(用户名、手机号、电子邮箱等)展示信息,用户实际输入内容
     */
    private String identifierDisplay;
    /**
     * 登录凭据:密码
     */
    private String credential;
    /**
     * 帐号类型:用户名、手机号、电子邮箱
     */
    private LoginAccountType type;
    /**
     * 是否是帐内帐号
     */
    private boolean local;
    /**
     * 最后一次登录IP
     */
    private String lastLoginIp;
    /**
     * 最后一次登录时间
     */
    private LocalDateTime lastLoginTime;

    public void setType(final LoginAccountType type) {
        this.type = type;
        this.local = type.isLocal();
    }
}

import com.baomidou.mybatisplus.annotation.IEnum;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.houkunlin.system.dict.starter.DictEnum;
import com.houkunlin.system.dict.starter.json.DictConverter;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.io.Serializable;
@Getter
@DictConverter
@AllArgsConstructor
public enum LoginAccountType implements DictEnum<Integer>, IEnum<Integer>, Serializable {
    /**
     * 用户名
     */
    USERNAME(1, "用户名", true),
    /**
     * 手机号
     */
    PHONE(2, "手机号", true),
    /**
     * 电子邮件
     */
    EMAIL(3, "电子邮件", true)
    ;
    private final Integer value;
    private final String title;
    // 是否是本地账号
    private final boolean local;

    @JsonCreator
    public static LoginAccountType create(Integer value) {
        return DictEnum.valueOf(values(), value);
    }

    /**
     * 处理登录标识,统一转换大小写问题
     *
     * @param identifier 登录标识
     * @return 结果
     */
    public String handleIdentifier(final String identifier) {
        if (!local) {
            return identifier;
        }
        return identifier == null ? null : identifier.toLowerCase();
    }
}

Dubbo Server 端:

2023-04-10T21:47:17.457+08:00  WARN 62040 --- [20886-thread-32] o.a.d.r.exchange.codec.ExchangeCodec     :  [DUBBO] Fail to encode response: Response [id=53, version=2.0.2, status=20, event=false, error=null, result=AppResponse [value=LoginAccountVo(id=1, userId=1, identifier=admin, identifierDisplay=admin, credential=$2a$10$HUM4HAoPIPPKfe.ldNaue.cmuT3HOI9ocaBXzw1Qj/NhFg7IkHSQu, type=USERNAME, local=true, lastLoginIp=127.0.0.1, lastLoginTime=2023-03-27T17:01:48.941657), exception=null]], send bad_response info instead, cause: null, dubbo version: 3.2.0-beta.6, current host: 172.29.237.2, error code: 6-14. This may be caused by , go to https://dubbo.apache.org/faq/6/14 to find instructions. 

java.lang.UnsupportedOperationException: null
    at com.alibaba.fastjson2.writer.FieldWriter.writeEnumJSONB(FieldWriter.java:160) ~[fastjson2-2.0.27.jar:na]
    at com.alibaba.fastjson2.writer.OWG_9_15_LoginAccountVo.writeJSONB(Unknown Source) ~[na:na]
    at com.alibaba.fastjson2.JSONB.toBytes(JSONB.java:1152) ~[fastjson2-2.0.27.jar:na]
    at org.apache.dubbo.common.serialize.fastjson2.FastJson2ObjectOutput.writeObject(FastJson2ObjectOutput.java:106) ~[dubbo-3.2.0-beta.6.jar:3.2.0-beta.6]
    at org.apache.dubbo.rpc.protocol.dubbo.DubboCodec.encodeResponseData(DubboCodec.java:251) ~[dubbo-3.2.0-beta.6.jar:3.2.0-beta.6]
    at org.apache.dubbo.remoting.exchange.codec.ExchangeCodec.encodeResponse(ExchangeCodec.java:317) ~[dubbo-remoting-api-3.2.0-beta.6.jar:3.2.0-beta.6]
    at org.apache.dubbo.remoting.exchange.codec.ExchangeCodec.encode(ExchangeCodec.java:78) ~[dubbo-remoting-api-3.2.0-beta.6.jar:3.2.0-beta.6]
    at org.apache.dubbo.rpc.protocol.dubbo.DubboCountCodec.encode(DubboCountCodec.java:51) ~[dubbo-3.2.0-beta.6.jar:3.2.0-beta.6]
    at org.apache.dubbo.remoting.transport.netty4.NettyChannel.send(NettyChannel.java:192) ~[dubbo-3.2.0-beta.6.jar:3.2.0-beta.6]
    at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel.send(HeaderExchangeChannel.java:99) ~[dubbo-remoting-api-3.2.0-beta.6.jar:3.2.0-beta.6]
    at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel.send(HeaderExchangeChannel.java:88) ~[dubbo-remoting-api-3.2.0-beta.6.jar:3.2.0-beta.6]
    at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.lambda$handleRequest$0(HeaderExchangeHandler.java:113) ~[dubbo-remoting-api-3.2.0-beta.6.jar:3.2.0-beta.6]
    at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture.uniWhenCompleteStage(CompletableFuture.java:887) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture.whenComplete(CompletableFuture.java:2325) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture.whenComplete(CompletableFuture.java:144) ~[na:na]
    at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:104) ~[dubbo-remoting-api-3.2.0-beta.6.jar:3.2.0-beta.6]
    at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:186) ~[dubbo-remoting-api-3.2.0-beta.6.jar:3.2.0-beta.6]
    at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:53) ~[dubbo-remoting-api-3.2.0-beta.6.jar:3.2.0-beta.6]
    at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:62) ~[dubbo-remoting-api-3.2.0-beta.6.jar:3.2.0-beta.6]
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]
    at org.apache.dubbo.common.threadlocal.InternalRunnable.run(InternalRunnable.java:41) ~[dubbo-common-3.2.0-beta.6.jar:3.2.0-beta.6]
    at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]

Dubbo Reference:

2023-04-10T21:47:17.375+08:00  WARN 58132 --- [o-auto-1-exec-8] o.a.d.r.c.s.wrapper.MockClusterInvoker   :  [DUBBO] fail-mock: getLocalIdentifier fail-mock enabled , url : consumer://172.29.237.2/com.houkunlin.rpc.UserDubboService?application=api-auth-server&background=false&check=true&dubbo=2.0.2&executor-management-mode=default&file-cache=false&interface=com.houkunlin.rpc.UserDubboService&methods=getAssignAuthorities,getLeaderIds,getLocalIdentifier,getUserAllPermissionValues,getUserByUserId,getUserByUsername,loginFailureAction,loginSuccessAction,saveUserLog,updatePassword&mock=true&pid=58132&qos.enable=true&qos.port=9692&register-mode=instance&register.ip=172.29.237.2&release=3.2.0-beta.6&revision=0.0.7-SNAPSHOT-plain&side=consumer&sticky=false&timestamp=1681133878428&unloadClusterRelated=false, dubbo version: 3.2.0-beta.6, current host: 172.29.237.2, error code: 2-17. This may be caused by failed to mock invoke, go to https://dubbo.apache.org/faq/2/17 to find instructions. 

org.apache.dubbo.rpc.RpcException: Failed to invoke the method getLocalIdentifier in the service com.houkunlin.rpc.UserDubboService. Tried 3 times of the providers [172.29.237.2:20886] (1/1) from the registry 192.168.0.5:8848 on the consumer 172.29.237.2 using the dubbo version 3.2.0-beta.6. Last error is: Failed to invoke remote method: getLocalIdentifier, provider: DefaultServiceInstance{serviceName='system-user-server', host='172.29.237.2', port=20886, enabled=true, healthy=true, metadata={dubbo.metadata-service.url-params={"prefer.serialization":"fastjson2,hessian2","version":"1.0.0","dubbo":"2.0.2","release":"3.2.0-beta.6","side":"provider","port":"20886","protocol":"dubbo"}, dubbo.endpoints=[{"port":20886,"protocol":"dubbo"}], dubbo.metadata.revision=8d596daa6565c6bfebb097f1bf926a68, dubbo.metadata.storage-type=local, timestamp=1681134174006}}, service{name='com.houkunlin.rpc.UserDubboService',group='null',version='null',protocol='dubbo',port='20886',params={executor-management-mode=default, side=provider, file-cache=false, release=3.2.0-beta.6, methods=getAssignAuthorities,getLeaderIds,getLocalIdentifier,getUserAllPermissionValues,getUserByUserId,getUserByUsername,loginFailureAction,loginSuccessAction,saveUserLog,updatePassword, deprecated=false, dubbo=2.0.2, interface=com.houkunlin.rpc.UserDubboService, service-name-mapping=true, register-mode=instance, generic=false, revision=0.0.7-SNAPSHOT-plain, application=system-user-server, prefer.serialization=fastjson2,hessian2, background=false, dynamic=true, anyhost=true},}, cause: org.apache.dubbo.remoting.RemotingException: Failed to send response: Response [id=50, version=2.0.2, status=20, event=false, error=null, result=AppResponse [value=LoginAccountVo(id=1, userId=1, identifier=admin, identifierDisplay=admin, credential=$2a$10$HUM4HAoPIPPKfe.ldNaue.cmuT3HOI9ocaBXzw1Qj/NhFg7IkHSQu, type=USERNAME, local=true, lastLoginIp=127.0.0.1, lastLoginTime=2023-03-27T17:01:48.941657), exception=null]], cause: java.lang.UnsupportedOperationException
java.lang.UnsupportedOperationException
    at com.alibaba.fastjson2.writer.FieldWriter.writeEnumJSONB(FieldWriter.java:160)
    at com.alibaba.fastjson2.writer.OWG_9_15_LoginAccountVo.writeJSONB(Unknown Source)
    at com.alibaba.fastjson2.JSONB.toBytes(JSONB.java:1152)
    at org.apache.dubbo.common.serialize.fastjson2.FastJson2ObjectOutput.writeObject(FastJson2ObjectOutput.java:106)
    at org.apache.dubbo.rpc.protocol.dubbo.DubboCodec.encodeResponseData(DubboCodec.java:251)
    at org.apache.dubbo.remoting.exchange.codec.ExchangeCodec.encodeResponse(ExchangeCodec.java:317)
    at org.apache.dubbo.remoting.exchange.codec.ExchangeCodec.encode(ExchangeCodec.java:78)
    at org.apache.dubbo.rpc.protocol.dubbo.DubboCountCodec.encode(DubboCountCodec.java:51)
    at org.apache.dubbo.remoting.transport.netty4.NettyChannel.send(NettyChannel.java:192)
    at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel.send(HeaderExchangeChannel.java:99)
    at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel.send(HeaderExchangeChannel.java:88)
    at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.lambda$handleRequest$0(HeaderExchangeHandler.java:113)
    at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
    at java.base/java.util.concurrent.CompletableFuture.uniWhenCompleteStage(CompletableFuture.java:887)
    at java.base/java.util.concurrent.CompletableFuture.whenComplete(CompletableFuture.java:2325)
    at java.base/java.util.concurrent.CompletableFuture.whenComplete(CompletableFuture.java:144)
    at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:104)
    at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:186)
    at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:53)
    at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:62)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at org.apache.dubbo.common.threadlocal.InternalRunnable.run(InternalRunnable.java:41)
    at java.base/java.lang.Thread.run(Thread.java:833)

image

houkunlin commented 1 year ago

发现在 com.alibaba.fastjson2.writer.ObjectWriterCreatorASMcom.alibaba.fastjson2.writer.ObjectWriterCreatorASM#createFieldWriter 方法中,枚举对象是返回了一个 return new FieldWriterObject(fieldName, ordinal, features, format, label, field.getGenericType(), fieldClass, field, null); 字段写入类,而不是 FieldWriterEnum ,经过断点发现

        if (fieldClass.isEnum()) {
            BeanInfo beanInfo = new BeanInfo();
            provider.getBeanInfo(beanInfo, fieldClass);

            boolean writeEnumAsJavaBean = beanInfo.writeEnumAsJavaBean;
            if (!writeEnumAsJavaBean) {
                ObjectWriter objectWriter = provider.cache.get(fieldClass);
                if (objectWriter != null && !(objectWriter instanceof ObjectWriterImplEnum)) {
                    writeEnumAsJavaBean = true;
                }
            }

            Member enumValueField = BeanUtils.getEnumValueField(fieldClass, provider);

            if (enumValueField == null && !writeEnumAsJavaBean) {
                String[] enumAnnotationNames = BeanUtils.getEnumAnnotationNames(fieldClass);
                if (enumAnnotationNames == null) {
                    return new FieldWriterEnum(fieldName, ordinal, features, format, label, fieldType, (Class<? extends Enum>) fieldClass, field, null);
                }
            }
        }

其中的 Member enumValueField = BeanUtils.getEnumValueField(fieldClass, provider); 得到了一个 getValue() 的方法对象,这个 getValue() 是因为使用 Jackson 的 @JsonValue 注解,因此拿到了这么一个方法对象,导致最后没有返回 FieldWriterEnum 而是返回了 FieldWriterObject ,但是 FieldWriterObject 又无法处理这个枚举。

我前面的枚举类实际为:

@Getter
@DictConverter
@AllArgsConstructor
public enum LoginAccountType implements DictEnum<Integer>, IEnum<Integer>, Serializable {
    /**
     * 用户名
     */
    USERNAME(1, "用户名", true),
    /**
     * 手机号
     */
    PHONE(2, "手机号", true),
    /**
     * 电子邮件
     */
    EMAIL(3, "电子邮件", true)
    ;
    private final Integer value;
    private final String title;
    // 是否是本地账号
    private final boolean local;

    @JsonValue
    public Integer getValue() {return value;}

    @JsonCreator
    public static LoginAccountType create(Integer value) {
        return DictEnum.valueOf(values(), value);
    }

    /**
     * 处理登录标识,统一转换大小写问题
     *
     * @param identifier 登录标识
     * @return 结果
     */
    public String handleIdentifier(final String identifier) {
        if (!local) {
            return identifier;
        }
        return identifier == null ? null : identifier.toLowerCase();
    }
}
ghost commented 1 year ago

解决了吗

houkunlin commented 1 year ago

解决了吗

官方解决没解决我不知道,因为我后来本地覆盖重写了 com.alibaba.fastjson2.writer.ObjectWriterCreatorASM 的内容,之后一切运行正常,暂时没有测试官方的代码是否解决了此问题

ghost commented 1 year ago

大佬,能看看重写的代码嘛 ---- 回复的原邮件 ---- | 发件人 | @.> | | 发送日期 | 2023年07月19日 11:29 | | 收件人 | alibaba/fastjson2 @.> | | 抄送人 | rpp001 @.>, Comment @.> | | 主题 | Re: [alibaba/fastjson2] [BUG]在使用 Dubbo 使用 Fastjson2 做序列化时,遇到字段为枚举类对象的无法完成序列化 (Issue #1343) |

解决了吗

官方解决没解决我不知道,因为我后来本地覆盖重写了 com.alibaba.fastjson2.writer.ObjectWriterCreatorASM 的内容,之后一切运行正常,暂时没有测试官方的代码是否解决了此问题

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

wenshao commented 1 year ago

能帮试下2.0.36版本是否问题已经解决了?

houkunlin commented 1 year ago

@rpp001 把官方的 ObjectWriterCreatorASM.java 类文件复制到本地,搜索文件内容 enumValueField == null && !writeEnumAsJavaBean,会得到如下的判断条件代码(代码片段1):

if (enumValueField == null && !writeEnumAsJavaBean) {
    String[] enumAnnotationNames = BeanUtils.getEnumAnnotationNames(fieldClass);
    if (enumAnnotationNames == null) {
        return new FieldWriterEnum(fieldName, ordinal, features, format, label, fieldType, (Class<? extends Enum>) fieldClass, field, null);
    }
}

我把这个判断条件改成了如下样子(代码片段2):

if (!writeEnumAsJavaBean) {
    if (enumValueField == null) {
        String[] enumAnnotationNames = BeanUtils.getEnumAnnotationNames(fieldClass);
        if (enumAnnotationNames == null) {
            return new FieldWriterEnum(fieldName, ordinal, features, format, label, fieldType, (Class<? extends Enum>) fieldClass, field, null);
        }
    } else {
        // 这一行是新增的代码
        return new FieldWriterEnum(fieldName, ordinal, features, format, label, fieldType, (Class<? extends Enum>) fieldClass, field, null);
    }
}

@wenshao 2.0.36 我没有测试,我当前的版本是 2.0.33 ,我是用了Dubbo,没有单独引入 fastjson2。 在 2.0.33 中发现ObjectWriterCreatorASM.java中依旧是 代码片段1 的内容,并且在 2.0.33 版本中 com.alibaba.fastjson2.writer.FieldWriter#writeEnumJSONB 依旧是抛出了 throw new UnsupportedOperationException

如果 2.0.36 ObjectWriterCreatorASM 对我的枚举依旧 return 了 FieldWriter 来处理,并且 com.alibaba.fastjson2.writer.FieldWriter#writeEnumJSONB 未发生内容变更,那我这个问题应该还是依旧会存在的。

ghost commented 1 year ago

谢谢大佬,2. 0. 36还是有问题的 ---- 回复的原邮件 ---- | 发件人 | @.> | | 发送日期 | 2023年07月19日 12:00 | | 收件人 | alibaba/fastjson2 @.> | | 抄送人 | rpp001 @.>, Mention @.> | | 主题 | Re: [alibaba/fastjson2] [BUG]在使用 Dubbo 使用 Fastjson2 做序列化时,遇到字段为枚举类对象的无法完成序列化 (Issue #1343) |

@rpp001 把官方的 ObjectWriterCreatorASM.java 类文件复制到本地,搜索文件内容 enumValueField == null && !writeEnumAsJavaBean,会得到如下的判断条件代码(代码片段1):

if (enumValueField == null && !writeEnumAsJavaBean) { String[] enumAnnotationNames = BeanUtils.getEnumAnnotationNames(fieldClass); if (enumAnnotationNames == null) { returnnewFieldWriterEnum(fieldName, ordinal, features, format, label, fieldType, (Class<? extendsEnum>) fieldClass, field, null); } }

我把这个判断条件改成了如下样子(代码片段2):

if (!writeEnumAsJavaBean) { if (enumValueField == null) { String[] enumAnnotationNames = BeanUtils.getEnumAnnotationNames(fieldClass); if (enumAnnotationNames == null) { returnnewFieldWriterEnum(fieldName, ordinal, features, format, label, fieldType, (Class<? extendsEnum>) fieldClass, field, null); } } else { // 这一行是新增的代码returnnewFieldWriterEnum(fieldName, ordinal, features, format, label, fieldType, (Class<? extendsEnum>) fieldClass, field, null); } }

@wenshao 2.0.36 我没有测试,我当前的版本是 2.0.33 ,我是用了Dubbo,没有单独引入 fastjson2。 在 2.0.33 中发现ObjectWriterCreatorASM.java中依旧是 代码片段1 的内容,并且在 2.0.33 版本中 com.alibaba.fastjson2.writer.FieldWriter#writeEnumJSONB 依旧是抛出了 throw new UnsupportedOperationException 。

如果 2.0.36 ObjectWriterCreatorASM 对我的枚举依旧 return 了 FieldWriter 来处理,并且 com.alibaba.fastjson2.writer.FieldWriter#writeEnumJSONB 未发生内容变更,那我这个问题应该还是依旧会存在的。

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>

houkunlin commented 1 year ago

@wenshao 前面表诉有问题。更正一下:

并且在 2.0.33 版本中 com.alibaba.fastjson2.writer.FieldWriterObject 未实现 writeEnumJSONB 方法,依旧是抛出了 throw new UnsupportedOperationException 。

如果 2.0.36 ObjectWriterCreatorASM 对我的枚举依旧 return 了 FieldWriterObject 来处理,并且 com.alibaba.fastjson2.writer.FieldWriterObject 未实现 writeEnumJSONB 方法内容,那我这个问题应该还是依旧会存在的。

firmianaQ commented 1 year ago

2.0.40 版本好像没问题了

firmianaQ commented 3 months ago

dubbo版本: 3.2.14 fastjson2版本: 2.0.51 编译完代码重启服务,第一次调用dubbo接口,枚举序列化失败,后续就正常

java.io.IOException: org.apache.dubbo.common.serialize.SerializationException: com.alibaba.fastjson2.JSONException: get value writer error, valueType : class com.xxxx.seller.api.enumd.SellerShiftNoEnum at org.apache.dubbo.common.serialize.DefaultSerializationExceptionWrapper.handleToIOException(DefaultSerializationExceptionWrapper.java:353) at org.apache.dubbo.common.serialize.DefaultSerializationExceptionWrapper.access$000(DefaultSerializationExceptionWrapper.java:27) at org.apache.dubbo.common.serialize.DefaultSerializationExceptionWrapper$ProxyObjectOutput.writeObject(DefaultSerializationExceptionWrapper.java:319) at org.apache.dubbo.rpc.protocol.dubbo.DubboCodec.encodeResponseData(DubboCodec.java:315) at org.apache.dubbo.remoting.exchange.codec.ExchangeCodec.encodeResponse(ExchangeCodec.java:342) at org.apache.dubbo.remoting.exchange.codec.ExchangeCodec.encode(ExchangeCodec.java:81) at org.apache.dubbo.rpc.protocol.dubbo.DubboCountCodec.encode(DubboCountCodec.java:50) at org.apache.dubbo.remoting.transport.netty4.NettyChannel.send(NettyChannel.java:193) at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel.send(HeaderExchangeChannel.java:109) at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel.send(HeaderExchangeChannel.java:97) at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.lambda$handleRequest$0(HeaderExchangeHandler.java:120) at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863) at java.base/java.util.concurrent.CompletableFuture.uniWhenCompleteStage(CompletableFuture.java:887) at java.base/java.util.concurrent.CompletableFuture.whenComplete(CompletableFuture.java:2325) at java.base/java.util.concurrent.CompletableFuture.whenComplete(CompletableFuture.java:144) at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:111) at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:205) at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:52) at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:64) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at org.apache.dubbo.common.threadlocal.InternalRunnable.run(InternalRunnable.java:39) at java.base/java.lang.Thread.run(Thread.java:840) Caused by: org.apache.dubbo.common.serialize.SerializationException: com.alibaba.fastjson2.JSONException: get value writer error, valueType : class com.xxxx.seller.api.enumd.SellerShiftNoEnum ... 23 common frames omitted Caused by: com.alibaba.fastjson2.JSONException: get value writer error, valueType : class com.xxxx.seller.api.enumd.SellerShiftNoEnum at com.alibaba.fastjson2.writer.FieldWriterObject.writeEnumJSONB(FieldWriterObject.java:236) at com.alibaba.fastjson2.writer.OWG_14_24_SellerBillVO.writeJSONB(Unknown Source) at com.alibaba.fastjson2.writer.ObjectWriterImplList.writeJSONB(ObjectWriterImplList.java:223) at com.alibaba.fastjson2.writer.OWG_11_6_PageResult.writeJSONB(Unknown Source) at com.alibaba.fastjson2.JSONB.toBytes(JSONB.java:1276) at org.apache.dubbo.common.serialize.fastjson2.FastJson2ObjectOutput.writeObject(FastJson2ObjectOutput.java:107) at org.apache.dubbo.common.serialize.DefaultSerializationExceptionWrapper$ProxyObjectOutput.writeObject(DefaultSerializationExceptionWrapper.java:317) ... 20 common frames omitted