Spring Boot REST接口不同返回的User字段过滤报错修复求助
问题解决:Jackson @JsonFilter导致单个用户接口序列化报错
问题背景
在Spring Boot REST API中,需实现两个接口:
/users:返回过滤部分字段的User列表/users/{id}:返回包含所有User字段及HATEOAS链接的单个用户信息
当前实现:
- User类标注了
@JsonFilter("UserFilter") /users接口通过MappingJacksonValue配置字段过滤,可正常工作/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:
- 定义视图接口:
public interface UserViews { // 基础视图:用于列表接口 interface Basic {} // 扩展视图:用于单个用户接口,继承基础视图包含所有基础字段 interface Extended extends Basic {} }
- 修改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省略 }
- 修改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
相关产品推荐
相关产品推荐

