对 ObjectWriterCreatorASM 中 enumValueField == null 条件的疑问
- Dominant language
- Java
- Stars
- 4.4k
- Forks
- 613
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 6
Description
对下面代码块中的 enumValueField == null 条件判断有点疑问。
https://github.com/alibaba/fastjson2/blob/1ca0ab6f7e468cf8174ef048df3743665e9262bd/core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterCreatorASM.java#L3399-L3419
我在使用 Dubbo 时,遇到一个枚举无法序列化问题,经过排查后发现,我的 enumValueField 得到了一个 `getValue()` 的 Method 对象,并且 `String[] enumAnnotationNames = BeanUtils.getEnumAnnotationNames(fieldClass);` 值为null,因此这个枚举最终使用了 `FieldWriterObject` 来处理
enumValueField 的 `getValue()` 拿到的是使用了 `@com.fasterxml.jackson.annotation.JsonValue` 注解的方法。
在我对此代码修改后进行本地覆盖运行项目时,一切正常,我修改后的代码如下,仅仅只是调整了条件判断,我改了后我项目中的枚举能够正常序列化,但是我不知道会不会有其他未知的负面问题:
```java
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 (!writeEnumAsJavaBean) {
if (enumValueField == null) {
String[] enumAnnotationNames = BeanUtils.getEnumAnnotationNames(fieldClass);
if (enumAnnotationNames == null) {
return new FieldWriterEnum(fieldName, ordinal, features, format, label, fieldType, (Class) fieldClass, field, null);
}
} else {
return new FieldWriterEnum(fieldName, ordinal, features, format, label, fieldType, (Class) fieldClass, field, null);
}
}
}
```
我的枚举相关类如下:
```java
@Data
@SuperBuilder
@EqualsAndHashCode(callSuper = true)
@FieldNameConstants
@NoArgsConstructor
@AllArgsConstructor
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();
}
}
@Getter
@DictConverter
@AllArgsConstructor
public enum LoginAccountType implements DictEnum, IEnum, Serializable {
/**
* 用户名
*/
USERNAME(1, "用户名", true),
/**
* 手机号
*/
PHONE(2, "手机号", true),
/**
* 电子邮件
*/
EMAIL(3, "电子邮件", true)
;
private final Integer value;
private final String title;
// 是否是本地账号
private final boolean local;
@com.fasterxml.jackson.annotation.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();
}
}
/**
* 数据字典枚举接口。系统字典枚举接口
*
* @author HouKunLin
*/
public interface DictEnum {
/**
* 通过枚举值从枚举列表中获取枚举对象
*
* @param values 枚举对象列表
* @param value 枚举值
* @param 枚举值类型
* @return 枚举对象
*/
static & DictEnum> E valueOf(E[] values, T value) {
for (final E enums : values) {
if (enums.getValue().equals(value)) {
return enums;
}
}
return null;
}
/**
* 字典值
*
* @return 字典值
*/
@com.fasterxml.jackson.annotation.JsonValue
T getValue();
/**
* 字典文本
*
* @return 字典文本
*/
String getTitle();
/**
* 判断字典值是否相等
*
* @param o 传入的值,可为当前的枚举对象
* @return 判断是否相等
*/
default boolean eq(Object o) {
return this == o || Objects.equal(o, getValue());
}
}
package com.baomidou.mybatisplus.annotation;
public interface IEnum {
/**
* 枚举数据库存储值
*/
T getValue();
}
```
Contributor guide
Research direction
Start at core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterCreatorASM.java around lines 3399-3419, then inspect BeanUtils.getEnumValueField and getEnumAnnotationNames. Reproduce the case with an enum whose getValue method has Jackson's @JsonValue annotation and compare FieldWriterEnum with FieldWriterObject. Done means the intended enum serialization behavior is established and covered by a regression test.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100