fastjson 能否提供字段级别的null输出控制,类似Jackson2 的 @JsonInclude(value=Include.NON_NULL) 注解
- Dominant language
- Java
- Stars
- 4.4k
- Forks
- 613
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 6
Description
### 需求或者改进建议
fastjson2 的 `JSONWriter.Feature.WriteMapNullValue` 是对象级别的,序列化对象时null字段要么全部输出,要么不输出。
我现在有一个场景:校验错误字段`validationErrors`在有值的时候才输出,没有值就不输出,无论是否设置了 `JSONWriter.Feature.WriteMapNullValue`。
Jackson2 的 `@JsonInclude(value=Include.NON_NULL)` 能很好实现这个需求,但fastjson2 我没看到类似的功能
#### 附加信息
*源码示例*
```
public class Response implements Serializable
{
public static final String MSG_OK = "ok";
@Schema(title="状态码", example="0", requiredMode=RequiredMode.REQUIRED, nullable=false)
private Integer statusCode = OK;
@Schema(title="状态描述", example=MSG_OK, requiredMode=RequiredMode.NOT_REQUIRED, nullable=true)
private String msg = MSG_OK;
/* fastjson2 如何实现??? */
@JsonInclude(value=Include.NON_NULL)
@Schema(title="参数校验错误列表", example="name is empty", requiredMode=RequiredMode.NOT_REQUIRED, nullable=true)
private Map> validationErrors;
@Schema(title="业务模型对象", example="Any Object", requiredMode=RequiredMode.NOT_REQUIRED, nullable=true)
private T result;
}
```
#### 目前的解决办法
*我目前是通过自定义 PropertyFilter 实现,每个属性判断都要经过这个Filter,还涉及到反射操作,不知对运行效率有多大影响*
```
@Documented
@Retention(RUNTIME)
@Target(ElementType.FIELD)
public @interface JSONFieldExclude
{
Exclude value() default Exclude.ALWAYS;
public static enum Exclude
{
NULL,
ABSENT,
EMPTY,
ALWAYS
}
}
```
```
public class FastJsonExcludePropertyFilter implements PropertyFilter
{
@Override
public boolean apply(Object object, String name, Object value)
{
if(object == null)
return true;
Class clazz = object.getClass();
if(Map.class.isAssignableFrom(clazz) || Collection.class.isAssignableFrom(clazz) || clazz.isArray())
return true;
try
{
Field field = clazz.getDeclaredField(name);
JSONFieldExclude annotation = field.getAnnotation(JSONFieldExclude.class);
if(annotation == null)
return true;
JSONFieldExclude.Exclude exclude = annotation.value();
if(exclude == Exclude.ALWAYS)
return false;
else if(exclude == Exclude.NULL)
return Objects.nonNull(value);
else if(exclude == Exclude.ABSENT)
{
if(Objects.isNull(value))
return false;
if(value instanceof Optional opt)
return opt.isPresent();
}
else if(exclude == Exclude.EMPTY)
{
if(Objects.isNull(value))
return false;
if(value instanceof Optional opt)
return opt.isPresent();
else if(value instanceof String str)
return !str.isEmpty();
else if(value instanceof Collection col)
return !col.isEmpty();
else if(value instanceof Map map)
return !map.isEmpty();
else if(clazz.isArray())
return Array.getLength(value) > 0;
}
else
{
throw new IllegalArgumentException("Unexpected value: " + exclude);
}
}
catch(NoSuchFieldException | SecurityException e)
{
}
return true;
}
}
```
Contributor guide
Research direction
Start by reviewing JSONWriter.Feature.WriteMapNullValue and the PropertyFilter workaround shown in the issue, then trace fastjson2's Java serialization path for field metadata. Compare the requested field-level null behavior with the global feature and existing annotation handling. Done means the behavior is defined, tested, and usable without requiring a reflective filter.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100