alibaba / alibaba/fastjson2

fastjson 能否提供字段级别的null输出控制,类似Jackson2 的 @JsonInclude(value=Include.NON_NULL) 注解

Open
#1,730 2 comments 0 reactions 0 assignees View on GitHub
enhancement
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.