Почему мой пользовательский сериализатор json для объекта Page данных Spring не вызывается - PullRequest
1 голос
/ 01 апреля 2019

Вот моя конфигурация объектного сопоставителя.Я предоставляю свой собственный объектный сопоставитель, так что включенный в весенний загрузчик объектный сопоставитель 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).

@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.

Наконец, и я не думаю, что это проблема, я 'используя RestControllerAdvice расширение AbstractMappingJacksonResponseBodyAdvice, которое выбирает jsonView, который я хочу использовать, основываясь на роли currentUser.

РЕДАКТИРОВАТЬ: Я только что закомментировал совет контроллера, и он все еще не вызывает мой пользовательский десериализатор.

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

1 Ответ

1 голос
/ 01 апреля 2019

Я смог решить мою проблему, выполнив две вещи.

@Component
public class PageJsonSerializer extends StdSerializer<Page> {

расширение StdSerializer вместо JsonSerializer Я на самом деле не знаю, было ли это частью решения.

Я думаю, что реальная помощь пришла от регистрации сериализатора вручную вместо того, чтобы полагаться на @JsonComponent.

Так что мой ObjectMapperConfigurer теперь выглядит так.

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
                // Manually registering my serializer. 
                new SimpleModule().addSerializer(Page.class, pageJsonSerializer),
... all the same
}

Я также удалил JsonComponentModule из моего ObjectMapper, так как он, кажется, сломан.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...