alibaba / fastjson2

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

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

Open ldcsaa opened 1 year ago

ldcsaa commented 1 year ago

需求或者改进建议

fastjson2 的 JSONWriter.Feature.WriteMapNullValue 是对象级别的,序列化对象时null字段要么全部输出,要么不输出。 我现在有一个场景:校验错误字段validationErrors在有值的时候才输出,没有值就不输出,无论是否设置了 JSONWriter.Feature.WriteMapNullValue。 Jackson2 的 @JsonInclude(value=Include.NON_NULL) 能很好实现这个需求,但fastjson2 我没看到类似的功能

附加信息

源码示例

public class Response<T> 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<String, List<String>> 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;
    }

}
wenshao commented 1 year ago

请参考文档 https://github.com/alibaba/fastjson2/blob/main/docs/features_cn.md 中第5点的WriteNulls,如下方式使用

    public static class Bean {
        @JSONField(serializeFeatures = Feature.WriteNulls)
        public int id;
    }
ldcsaa commented 1 year ago

请参考文档 https://github.com/alibaba/fastjson2/blob/main/docs/features_cn.md 中第5点的WriteNulls,如下方式使用

    public static class Bean {
        @JSONField(serializeFeatures = Feature.WriteNulls)
        public int id;
    }

正好相反,我的需求是 null 值不输出~~