Skip to content

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

@ldcsaa

Description

@ldcsaa

需求或者改进建议

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;
	}

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions