You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot REST接口不同返回的User字段过滤报错修复求助

问题解决:Jackson @JsonFilter导致单个用户接口序列化报错

问题背景

在Spring Boot REST API中,需实现两个接口:

  • /users:返回过滤部分字段的User列表
  • /users/{id}:返回包含所有User字段及HATEOAS链接的单个用户信息

当前实现:

  1. User类标注了@JsonFilter("UserFilter")
  2. /users接口通过MappingJacksonValue配置字段过滤,可正常工作
  3. /users/{id}接口返回EntityModel<User>,调用时抛出HttpMessageConversionException,根源为InvalidDefinitionException,提示无法解析ID为'UserFilter'的PropertyFilter,未配置FilterProvider

报错原因

当User类添加类级别@JsonFilter注解后,Jackson会要求所有序列化该类实例的场景必须提供对应的FilterProvider配置。而/users/{id}接口直接返回EntityModel<User>,未配置任何FilterProvider,导致Jackson无法找到对应过滤器,触发序列化异常。

解决方案

方案1:给单个用户接口配置全字段序列化的FilterProvider

修改/users/{id}接口实现,将EntityModel<User>包装到MappingJacksonValue中,配置FilterProvider序列化所有字段:

@RestController
public class UserController {
    @Autowired
    private UserDaoService userDaoService;

    // 原有正常的列表过滤接口
    @GetMapping("/users")
    public MappingJacksonValue retrieveAllUsers() {
        List<User> users = userDaoService.findAll();
        SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.filterOutAllExcept("id", "name");
        SimpleFilterProvider filterProvider = new SimpleFilterProvider().addFilter("UserFilter", filter);
        MappingJacksonValue mapping = new MappingJacksonValue(users);
        mapping.setFilters(filterProvider);
        return mapping;
    }

    // 修改后的单个用户接口
    @GetMapping("/users/{id}")
    public MappingJacksonValue retrieveUser(@PathVariable int id) {
        User user = userDaoService.findOne(id);
        if (user == null) {
            throw new UserNotFoundException("id:" + id);
        }

        // 构建HATEOAS实体模型
        EntityModel<User> entityModel = EntityModel.of(user);
        WebMvcLinkBuilder linkToUsers = linkTo(methodOn(UserController.class).retrieveAllUsers());
        entityModel.add(linkToUsers.withRel("all-users"));

        // 配置FilterProvider,序列化所有User字段
        SimpleFilterProvider filterProvider = new SimpleFilterProvider();
        filterProvider.addFilter("UserFilter", SimpleBeanPropertyFilter.serializeAll());
        MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(entityModel);
        mappingJacksonValue.setFilters(filterProvider);

        return mappingJacksonValue;
    }
}

方案2:使用@JsonView替代@JsonFilter(更优雅的场景区分)

若需要更清晰的序列化场景划分,推荐使用@JsonView替代@JsonFilter:

  1. 定义视图接口:
public interface UserViews {
    // 基础视图:用于列表接口
    interface Basic {}
    // 扩展视图:用于单个用户接口,继承基础视图包含所有基础字段
    interface Extended extends Basic {}
}
  1. 修改User类,给字段标注对应视图:
public class User {
    @JsonView(UserViews.Basic.class)
    private int id;

    @JsonView(UserViews.Basic.class)
    private String name;

    // 仅在扩展视图中显示的字段
    @JsonView(UserViews.Extended.class)
    private String email;

    @JsonView(UserViews.Extended.class)
    private LocalDate birthDate;

    // getter/setter省略
}
  1. 修改Controller接口,指定对应的视图:
@RestController
public class UserController {
    @Autowired
    private UserDaoService userDaoService;

    // 列表接口:使用基础视图
    @GetMapping("/users")
    @JsonView(UserViews.Basic.class)
    public List<User> retrieveAllUsers() {
        return userDaoService.findAll();
    }

    // 单个用户接口:使用扩展视图,无需处理FilterProvider
    @GetMapping("/users/{id}")
    @JsonView(UserViews.Extended.class)
    public EntityModel<User> retrieveUser(@PathVariable int id) {
        User user = userDaoService.findOne(id);
        if (user == null) {
            throw new UserNotFoundException("id:" + id);
        }

        EntityModel<User> entityModel = EntityModel.of(user);
        WebMvcLinkBuilder linkToUsers = linkTo(methodOn(UserController.class).retrieveAllUsers());
        entityModel.add(linkToUsers.withRel("all-users"));

        return entityModel;
    }
}

相关代码与报错信息

User类代码

import com.fasterxml.jackson.annotation.JsonFilter;
import java.time.LocalDate;

@JsonFilter("UserFilter")
public class User {
    private int id;
    private String name;
    private String email;
    private LocalDate birthDate;

    // 构造器、getter/setter省略
}

报错栈信息

org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.example.demo.User]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot resolve PropertyFilter with id 'UserFilter'; no FilterProvider configured
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:465)
    at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:104)
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:290)
    ...
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot resolve PropertyFilter with id 'UserFilter'; no FilterProvider configured
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._handleMissingFilter(DefaultSerializerProvider.java:496)
    ...

预期输出(/users/{id}接口)

{
  "id": 3,
  "name": "Alice",
  "email": "alice@example.com",
  "birthDate": "1990-01-15",
  "_links": {
    "all-users": {
      "href": "http://localhost:8080/users"
    }
  }
}

内容的提问来源于stack exchange,提问作者Sihle Calana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 23:19:51