java - 为什么我的 Spring 数据的 Page 对象的自定义 json 序列化器没有被调用

标签 java jackson spring-data

这是我的对象映射器配置。我提供了我自己的对象映射器,以便覆盖 Spring boot 2.0 包含的对象映射器。尽管如此,我还包含了 JsonComponentModule() 以便我可以使用 @JsonComponent 注释来获取自定义序列化程序。

public class ObjectMapperConfigurer {
    public static ObjectMapper configureObjectMapper(ObjectMapper objectMapper) {
        return objectMapper.registerModules(
                // First three modules can be found here. https://github.com/FasterXML/jackson-modules-java8
                new Jdk8Module(), // support for other new Java 8 datatypes outside of date/time: most notably Optional, OptionalLong, OptionalDouble
                new JavaTimeModule(), // support for Java 8 date/time types (specified in JSR-310 specification)
                new ParameterNamesModule(), // Support for detecting constructor and factory method ("creator") parameters without having to use @JsonProperty annotation
                // These two modules are provided by spring
                new JsonComponentModule(), // Enables https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#boot-features-json-components
                new GeoModule(), // Enables marshalling of GeoResult<T>, GeoResults<T>, and GeoPage<T>
                new Hibernate5Module().enable(Hibernate5Module.Feature.FORCE_LAZY_LOADING) // Allows jackson to gracefully handle Hibernate lazy loading,
        )
                .setSerializationInclusion(JsonInclude.Include.NON_NULL)
                // Turn on/off some features. https://github.com/FasterXML/jackson-databind/wiki/JacksonFeatures
                .enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS)
                .enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY)
                .enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS)
                .enable(SerializationFeature.INDENT_OUTPUT)
                .enable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS)
                .disable(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS)
                .disable(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS)
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                .disable(MapperFeature.DEFAULT_VIEW_INCLUSION)
                .setFilterProvider(new SimpleFilterProvider().addFilter(FilteringAnnotationInspector.DEFAULT_FILTER, new DepthFilter()))
                .setAnnotationIntrospector(new FilteringAnnotationInspector());
    }

    public static ObjectMapper configureObjectMapper() {
        return configureObjectMapper(new ObjectMapper());
    }

}

这是我的自定义序列化程序。如果序列化的实现错误也没关系,我的核心问题是它没有被调用。

@JsonComponent
public class PageJsonSerializer extends JsonSerializer<Page> {

    @Override
    public void serialize(Page page, JsonGenerator jsonGen, SerializerProvider serializerProvider) throws IOException {
        System.out.println("serializing using pagejsonserializer");
        ObjectMapper om = new ObjectMapper()
                .disable(MapperFeature.DEFAULT_VIEW_INCLUSION)
                .setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
        jsonGen.writeStartObject();
        jsonGen.writeFieldName("size");
        jsonGen.writeNumber(page.getSize());
        jsonGen.writeFieldName("number");
        jsonGen.writeNumber(page.getNumber());
        jsonGen.writeFieldName("totalElements");
        jsonGen.writeNumber(page.getTotalElements());
        jsonGen.writeFieldName("last");
        jsonGen.writeBoolean(page.isLast());
        jsonGen.writeFieldName("totalPages");
        jsonGen.writeNumber(page.getTotalPages());
        jsonGen.writeObjectField("sort", page.getSort());
        jsonGen.writeFieldName("first");
        jsonGen.writeBoolean(page.isFirst());
        jsonGen.writeFieldName("numberOfElements");
        jsonGen.writeNumber(page.getNumberOfElements());
        jsonGen.writeFieldName("content");
        jsonGen.writeRawValue(om.writerWithView(serializerProvider.getActiveView()).writeValueAsString(page.getContent()));
        jsonGen.writeEndObject();
    }
}

这是返回 Page(d) 对象的 Controller 。

@GetMapping(JobController.uri.path)
@PreAuthorize("hasAuthority('" + SpringSecurityConfig.Authority.LIST_JOBS + "')")
public Page<Job> listJobs(Pageable pageable) {
  return jobRepository.findAllByCandidates(currentUserHolder.getUser(), pageable);
}

我希望以上内容会导致调用 PageJsonSerializer 类。我可以看到该类已成功注册到 JsonComponentModule()。我还尝试了类声明的许多不同变体。像下面这样,但都没有任何效果。

public class PageJsonSerializer extends JsonSerializer<Page<?>> {
public class PageJsonSerializer extends JsonSerializer<PageImpl> {

我不确定接下来要检查什么。在调试来自 JobController 的返回行程时,我也在努力查看 Jackson 将要使用序列化程序序列化的对象排在何处。

最后,我认为这不是问题,我正在使用一些 RestControllerAdvice 扩展 AbstractMappingJacksonResponseBodyAdvice,它根据当前用户的角色。

编辑:我刚刚注释掉了 Controller 建议,它仍然没有调用我的自定义反序列化器。

@RestControllerAdvice
@Slf4j
class SecurityJsonViewControllerAdvice extends AbstractMappingJacksonResponseBodyAdvice {


    @Override
    protected void beforeBodyWriteInternal(
            @NotNull MappingJacksonValue bodyContainer,
            @NotNull MediaType contentType,
            @NotNull MethodParameter returnType,
            @NotNull ServerHttpRequest request,
            @NotNull ServerHttpResponse response) {
        if (SecurityContextHolder.getContext().getAuthentication() != null && SecurityContextHolder.getContext().getAuthentication().getAuthorities() != null) {
            Collection<? extends GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
            Class<?> viewClass = User.Role.jsonViewFrom(authorities);
            if (true || log.isDebugEnabled()) {
                log.debug("Deserializing using view {}", viewClass.getSimpleName());
            }
            bodyContainer.setSerializationView(viewClass);
        }
    }
}

最佳答案

在我的例子中,我必须手动配置 MessageConverters。我将其添加到 WebMvcConfigurer 的实现中:

  @Override
  public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
      Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
      builder.serializerByType(PageImpl.class, new PageJsonSerializer());
      converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
  }

关于java - 为什么我的 Spring 数据的 Page 对象的自定义 json 序列化器没有被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55446140/

相关文章:

java - @PreAuthorize 不起作用 - 是否存在无法解析的循环引用?

java - Jackson: map 反序列化

java - Jackson 反序列化抽象类的子类的对象列表

java - 带有 Spring Data JPA @Query 注释的 IN 子句错误

postgresql - docker部署的postgresql镜像运行了一段时间后无法对spring应用程序进行身份验证

java - 我可以使用 .xml < context-param > 作为 .as 类中的常量吗?

java - 微调器文本不显示默认值,也不显示所选值

java - 如何检查由任何非单词标记分隔的包含 'tags' 的字符串是否包含 Java 中的给定标记

java - 为什么迁移到 Java 11 后, header "Accept: application/xml"在 Spring Boot 中不起作用?

neo4j - scala.collection.JavaConversions$SeqWrapper 无法转换为 java.util.Set